From ea07110c86c7ae2601e71dd3c1134873ccfd721f Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Fri, 16 Oct 2015 17:39:43 -0400 Subject: Make PKCS #1 and OAEP decoding constant time to avoid oracle attacks via timing channels. Add annotations for checking constant-time code using ctgrind to PKCS #1 and OAEP, as well as IDEA and Curve25519 which were already written as constant time code. --- src/build-data/buildh.in | 6 + src/lib/block/idea/idea.cpp | 37 ++++-- src/lib/block/idea_sse2/idea_sse2.cpp | 10 +- src/lib/pk_pad/eme_oaep/oaep.cpp | 32 +++--- src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp | 46 +++++--- src/lib/pubkey/curve25519/donna.cpp | 9 ++ src/lib/utils/ct_utils.h | 207 ++++++++++++++++++++++++++++++++++ src/lib/utils/info.txt | 4 +- src/lib/utils/ta_utils.cpp | 66 ----------- src/lib/utils/ta_utils.h | 57 ---------- 10 files changed, 306 insertions(+), 168 deletions(-) create mode 100644 src/lib/utils/ct_utils.h delete mode 100644 src/lib/utils/ta_utils.cpp delete mode 100644 src/lib/utils/ta_utils.h (limited to 'src') diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 31069f0ae..3061c9608 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -91,6 +91,12 @@ #define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD 0 #define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1 +/* +* Define BOTAN_USE_CTGRIND to enable checking constant time +* annotations using ctgrind https://github.com/agl/ctgrind +*/ +//#define BOTAN_USE_CTGRIND + /* * RNGs will automatically poll the system for additional seed material * after producing this many bytes of output. diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp index ddfd8e5fb..c7706b372 100644 --- a/src/lib/block/idea/idea.cpp +++ b/src/lib/block/idea/idea.cpp @@ -1,12 +1,13 @@ /* * IDEA -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include +#include namespace Botan { @@ -19,8 +20,7 @@ inline u16bit mul(u16bit x, u16bit y) { const u32bit P = static_cast(x) * y; - // P ? 0xFFFF : 0 - const u16bit P_mask = !P - 1; + const u16bit Z_mask = static_cast(ct_expand_mask_32(P) & 0xFFFF); const u32bit P_hi = P >> 16; const u32bit P_lo = P & 0xFFFF; @@ -28,7 +28,7 @@ inline u16bit mul(u16bit x, u16bit y) const u16bit r_1 = (P_lo - P_hi) + (P_lo < P_hi); const u16bit r_2 = 1 - x - y; - return (r_1 & P_mask) | (r_2 & ~P_mask); + return ct_select_mask_16(Z_mask, r_1, r_2); } /* @@ -62,12 +62,16 @@ void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) { const size_t BLOCK_SIZE = 8; + BOTAN_CONST_TIME_POISON(in, blocks * 8); + BOTAN_CONST_TIME_POISON(out, blocks * 8); + BOTAN_CONST_TIME_POISON(K, 52 * 2); + for(size_t i = 0; i != blocks; ++i) { - u16bit X1 = load_be(in, 0); - u16bit X2 = load_be(in, 1); - u16bit X3 = load_be(in, 2); - u16bit X4 = load_be(in, 3); + u16bit X1 = load_be(in + BLOCK_SIZE*i, 0); + u16bit X2 = load_be(in + BLOCK_SIZE*i, 1); + u16bit X3 = load_be(in + BLOCK_SIZE*i, 2); + u16bit X4 = load_be(in + BLOCK_SIZE*i, 3); for(size_t j = 0; j != 8; ++j) { @@ -94,11 +98,12 @@ void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) X3 += K[49]; X4 = mul(X4, K[51]); - store_be(out, X1, X3, X2, X4); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; + store_be(out + BLOCK_SIZE*i, X1, X3, X2, X4); } + + BOTAN_CONST_TIME_UNPOISON(in, blocks * 8); + BOTAN_CONST_TIME_UNPOISON(out, blocks * 8); + BOTAN_CONST_TIME_UNPOISON(K, 52 * 2); } } @@ -127,6 +132,10 @@ void IDEA::key_schedule(const byte key[], size_t) EK.resize(52); DK.resize(52); + BOTAN_CONST_TIME_POISON(key, 16); + BOTAN_CONST_TIME_POISON(EK.data(), 52 * 2); + BOTAN_CONST_TIME_POISON(DK.data(), 52 * 2); + for(size_t i = 0; i != 8; ++i) EK[i] = load_be(key, i); @@ -158,6 +167,10 @@ void IDEA::key_schedule(const byte key[], size_t) DK[2] = -EK[50]; DK[1] = -EK[49]; DK[0] = mul_inv(EK[48]); + + BOTAN_CONST_TIME_UNPOISON(key, 16); + BOTAN_CONST_TIME_UNPOISON(EK.data(), 52 * 2); + BOTAN_CONST_TIME_UNPOISON(DK.data(), 52 * 2); } void IDEA::clear() diff --git a/src/lib/block/idea_sse2/idea_sse2.cpp b/src/lib/block/idea_sse2/idea_sse2.cpp index a2a54ac32..51b5e909b 100644 --- a/src/lib/block/idea_sse2/idea_sse2.cpp +++ b/src/lib/block/idea_sse2/idea_sse2.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace Botan { @@ -130,6 +131,10 @@ void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) */ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) { + BOTAN_CONST_TIME_POISON(in, 64); + BOTAN_CONST_TIME_POISON(out, 64); + BOTAN_CONST_TIME_POISON(EK, 52*2); + const __m128i* in_mm = reinterpret_cast(in); __m128i B0 = _mm_loadu_si128(in_mm + 0); @@ -153,7 +158,6 @@ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) B3 = mul(B3, EK[6*i+3]); __m128i T0 = B2; - B2 = _mm_xor_si128(B2, B0); B2 = mul(B2, EK[6*i+4]); @@ -190,6 +194,10 @@ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) _mm_storeu_si128(out_mm + 1, B2); _mm_storeu_si128(out_mm + 2, B1); _mm_storeu_si128(out_mm + 3, B3); + + BOTAN_CONST_TIME_UNPOISON(in, 64); + BOTAN_CONST_TIME_UNPOISON(out, 64); + BOTAN_CONST_TIME_UNPOISON(EK, 52*2); } } diff --git a/src/lib/pk_pad/eme_oaep/oaep.cpp b/src/lib/pk_pad/eme_oaep/oaep.cpp index f214c25d2..48a9b5c63 100644 --- a/src/lib/pk_pad/eme_oaep/oaep.cpp +++ b/src/lib/pk_pad/eme_oaep/oaep.cpp @@ -1,13 +1,13 @@ /* * OAEP -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2010,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include -#include +#include namespace Botan { @@ -92,33 +92,33 @@ secure_vector OAEP::unpad(const byte in[], size_t in_length, input.data(), m_Phash.size(), &input[m_Phash.size()], input.size() - m_Phash.size()); - bool waiting_for_delim = true; - bool bad_input = false; + BOTAN_CONST_TIME_POISON(input.data(), input.size()); + size_t delim_idx = 2 * m_Phash.size(); + byte waiting_for_delim = 0xFF; + byte bad_input = 0; - /* - * GCC 4.5 on x86-64 compiles this in a way that is still vunerable - * to timing analysis. Other compilers, or GCC on other platforms, - * may or may not. - */ for(size_t i = delim_idx; i < input.size(); ++i) { - const bool zero_p = !input[i]; - const bool one_p = input[i] == 0x01; + const byte zero_m = ct_is_zero_8(input[i]); + const byte one_m = ct_is_equal_8(input[i], 1); - const bool add_1 = waiting_for_delim && zero_p; + const byte add_m = waiting_for_delim & zero_m; - bad_input |= waiting_for_delim && !(zero_p || one_p); + bad_input |= waiting_for_delim & ~(zero_m | one_m); - delim_idx += add_1; + delim_idx += ct_select_mask_8(add_m, 1, 0); - waiting_for_delim &= zero_p; + waiting_for_delim &= zero_m; } // If we never saw any non-zero byte, then it's not valid input bad_input |= waiting_for_delim; + bad_input |= ct_expand_mask_8(!same_mem(&input[m_Phash.size()], m_Phash.data(), m_Phash.size())); - bad_input |= !same_mem(&input[m_Phash.size()], m_Phash.data(), m_Phash.size()); + BOTAN_CONST_TIME_UNPOISON(input.data(), input.size()); + BOTAN_CONST_TIME_UNPOISON(&bad_input, sizeof(bad_input)); + BOTAN_CONST_TIME_UNPOISON(&delim_idx, sizeof(delim_idx)); if(bad_input) throw Decoding_Error("Invalid OAEP encoding"); diff --git a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp index 65d29cd59..219e93251 100644 --- a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp +++ b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp @@ -1,11 +1,12 @@ /* -* PKCS1 EME -* (C) 1999-2007 Jack Lloyd +* PKCS #1 v1.5 Type 2 (encryption) padding +* (C) 1999-2007,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include +#include namespace Botan { @@ -38,22 +39,39 @@ secure_vector EME_PKCS1v15::pad(const byte in[], size_t inlen, * PKCS1 Unpad Operation */ secure_vector EME_PKCS1v15::unpad(const byte in[], size_t inlen, - size_t key_len) const + size_t key_len) const { - if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02) + if(inlen != key_len / 8 || inlen < 10) throw Decoding_Error("PKCS1::unpad"); - size_t separator = 0; - for(size_t j = 0; j != inlen; ++j) - if(in[j] == 0) - { - separator = j; - break; - } - if(separator < 9) - throw Decoding_Error("PKCS1::unpad"); + BOTAN_CONST_TIME_POISON(in, inlen); + + byte bad_input_m = 0; + byte seen_zero_m = 0; + size_t delim_idx = 0; + + bad_input_m |= ~ct_is_equal_8(in[0], 2); + + for(size_t i = 1; i != inlen; ++i) + { + const byte is_zero_m = ct_is_zero_8(in[i]); + + delim_idx += ct_select_mask_8(~seen_zero_m, 1, 0); + + bad_input_m |= is_zero_m & ct_expand_mask_8(i < 9); + seen_zero_m |= is_zero_m; + } + + bad_input_m |= ~seen_zero_m; + + BOTAN_CONST_TIME_UNPOISON(in, inlen); + BOTAN_CONST_TIME_UNPOISON(&bad_input_m, sizeof(bad_input_m)); + BOTAN_CONST_TIME_UNPOISON(&delim_idx, sizeof(delim_idx)); + + if(bad_input_m) + throw Decoding_Error("Invalid PKCS #1 v1.5 encryption padding"); - return secure_vector(&in[separator + 1], &in[inlen]); + return secure_vector(&in[delim_idx + 1], &in[inlen]); } /* diff --git a/src/lib/pubkey/curve25519/donna.cpp b/src/lib/pubkey/curve25519/donna.cpp index 4fab78cb8..ab9363761 100644 --- a/src/lib/pubkey/curve25519/donna.cpp +++ b/src/lib/pubkey/curve25519/donna.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace Botan { @@ -418,6 +419,10 @@ crecip(felem out, const felem z) { int curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { + + BOTAN_CONST_TIME_POISON(secret, 32); + BOTAN_CONST_TIME_POISON(basepoint, 32); + limb bp[5], x[5], z[5], zmone[5]; uint8_t e[32]; int i; @@ -432,6 +437,10 @@ curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { crecip(zmone, z); fmul(z, x, zmone); fcontract(mypublic, z); + + BOTAN_CONST_TIME_UNPOISON(secret, 32); + BOTAN_CONST_TIME_UNPOISON(basepoint, 32); + BOTAN_CONST_TIME_UNPOISON(mypublic, 32); return 0; } diff --git a/src/lib/utils/ct_utils.h b/src/lib/utils/ct_utils.h new file mode 100644 index 000000000..02148001e --- /dev/null +++ b/src/lib/utils/ct_utils.h @@ -0,0 +1,207 @@ +/* +* Functions for constant time operations on data and testing of +* constant time annotations using ctgrind. +* +* For more information about constant time programming see +* Wagner, Molnar, et al "The Program Counter Security Model" +* +* (C) 2010 Falko Strenzke +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIMING_ATTACK_CM_H__ +#define BOTAN_TIMING_ATTACK_CM_H__ + +#include +#include + +#if defined(BOTAN_USE_CTGRIND) + +// These are external symbols from libctgrind.so +extern "C" void ct_poison(const void* address, size_t length); +extern "C" void ct_unpoison(const void* address, size_t length); + +#endif + +namespace Botan { + +#if defined(BOTAN_USE_CTGRIND) + +#define BOTAN_CONST_TIME_POISON(p, l) ct_poison(p, l) +#define BOTAN_CONST_TIME_UNPOISON(p, l) ct_unpoison(p, l) + +#else + +#define BOTAN_CONST_TIME_POISON(p, l) +#define BOTAN_CONST_TIME_UNPOISON(p, l) + +#endif + +/* +* Constant time operations for 32 bit values: +* mask, select, zero, equals, min, max +*/ + +/* +* Expand to a mask used for other operations +* @param in an integer +* @return 0 if in == 0 else 0xFFFFFFFF +*/ + +inline uint32_t ct_expand_mask_32(uint32_t x) + { + uint32_t r = x; + r |= r >> 1; + r |= r >> 2; + r |= r >> 4; + r |= r >> 8; + r |= r >> 16; + r &= 1; + r = ~(r - 1); + return r; + } + +inline uint32_t ct_select_mask_32(uint32_t mask, uint32_t a, uint32_t b) + { + return (a & mask) | (b & ~mask); + } + +inline uint32_t ct_select_cond_32(bool cond, uint32_t a, uint32_t b) + { + return ct_select_mask_32(ct_expand_mask_32(static_cast(cond)), a, b); + } + +inline uint32_t ct_get_high_bit_32(uint32_t x) + { + return (x >> (8 * sizeof(x) - 1)); + } + +/* +* If x is zero, return 0xFFFF... +* Otherwise returns zero +*/ +inline uint32_t ct_is_zero_32(uint32_t x) + { + return ct_expand_mask_32(ct_get_high_bit_32(~x & (x-1))); + } + +inline uint32_t ct_is_equal_32(uint32_t x, uint32_t y) + { + return ct_is_zero_32(x ^ y); + } + +/** +* Branch-free maximum +* Note: assumes twos-complement signed representation +* @param a an integer +* @param b an integer +* @return max(a,b) +*/ +inline uint32_t ct_max_32(uint32_t a, uint32_t b) + { + const uint32_t s = b - a; + return ct_select_cond_32(ct_get_high_bit_32(s), a, b); + } + +/** +* Branch-free minimum +* Note: assumes twos-complement signed representation +* @param a an integer +* @param b an integer +* @return min(a,b) +*/ +inline uint32_t ct_min_32(uint32_t a, uint32_t b) + { + const uint32_t s = b - a; + return ct_select_cond_32(ct_get_high_bit_32(s), b, a); + } + +/* +* Constant time operations for 16 bit values: +* mask, select, zero, equals +*/ +inline uint16_t ct_expand_mask_16(uint16_t x) + { + uint16_t r = x; + r |= r >> 1; + r |= r >> 2; + r |= r >> 4; + r |= r >> 8; + r &= 1; + r = ~(r - 1); + return r; + } + +inline uint16_t ct_select_mask_16(uint16_t mask, uint16_t a, uint16_t b) + { + return (a & mask) | (b & ~mask); + } + +inline uint16_t ct_select_cond_16(bool cond, uint16_t a, uint16_t b) + { + return ct_select_mask_16(ct_expand_mask_16(static_cast(cond)), a, b); + } + +inline uint16_t ct_get_high_bit_16(uint16_t x) + { + return (x >> (8 * sizeof(x) - 1)); + } + +inline uint16_t ct_is_zero_16(uint16_t x) + { + //uint16_t z = x & (x - 1) + //return ct_expand_mask_16((~x & (x-1)) + return ct_expand_mask_16(ct_get_high_bit_16(~x & (x-1))); + } + +inline uint16_t ct_is_equal_16(uint16_t x, uint16_t y) + { + return ct_is_zero_16(x ^ y); + } + +/* +* Constant time operations for 8 bit values: +* mask, select, zero, equals +*/ + +inline uint8_t ct_expand_mask_8(uint8_t x) + { + uint8_t r = x; + r |= r >> 4; + r |= r >> 2; + r |= r >> 1; + r &= 1; + r = ~(r - 1); + return r; + } + +inline uint8_t ct_select_mask_8(uint8_t mask, uint8_t a, uint8_t b) + { + return (a & mask) | (b & ~mask); + } + +inline uint8_t ct_select_cond_8(bool cond, uint8_t a, uint8_t b) + { + return ct_select_mask_8(ct_expand_mask_8(static_cast(cond)), a, b); + } + +inline uint8_t ct_get_high_bit_8(uint8_t x) + { + return (x >> (8 * sizeof(x) - 1)); + } + +inline uint8_t ct_is_zero_8(uint8_t x) + { + return ct_expand_mask_8(ct_get_high_bit_8(~x & (x-1))); + } + +inline uint8_t ct_is_equal_8(uint8_t x, uint8_t y) + { + return ct_is_zero_8(x ^ y); + } + +} + +#endif diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt index 79026d7a9..228fccd82 100644 --- a/src/lib/utils/info.txt +++ b/src/lib/utils/info.txt @@ -8,8 +8,8 @@ bswap.h calendar.h charset.h cpuid.h -database.h data_src.h +database.h exceptn.h loadstor.h mem_ops.h @@ -22,11 +22,11 @@ version.h bit_ops.h +ct_utils.h donna128.h filesystem.h prefetch.h rounding.h semaphore.h stl_util.h -ta_utils.h diff --git a/src/lib/utils/ta_utils.cpp b/src/lib/utils/ta_utils.cpp deleted file mode 100644 index 8aee726ec..000000000 --- a/src/lib/utils/ta_utils.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -* Timing Attack Countermeasure Functions -* (C) 2010 Falko Strenzke, Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include - -namespace Botan { - -namespace TA_CM { - -/* -* We use volatile in these functions in an attempt to ensure that the -* compiler doesn't optimize in a way that would create branching -* operations. -* -* Note: this needs further testing; on at least x86-64 with GCC, -* volatile is not required to get branch-free operations, it just -* makes the functions much longer/slower. It may not be required -* anywhere. -*/ - -namespace { - -template -T expand_mask(T x) - { - volatile T r = x; - for(size_t i = 1; i != sizeof(T) * 8; i *= 2) - r |= r >> i; - r &= 1; - r = ~(r - 1); - return r; - } - -} - -u32bit expand_mask_u32bit(u32bit in) - { - return expand_mask(in); - } - -u16bit expand_mask_u16bit(u16bit in) - { - return expand_mask(in); - } - -u32bit max_32(u32bit a, u32bit b) - { - const u32bit a_larger = b - a; /* negative if a larger */ - const u32bit mask = expand_mask(a_larger >> 31); - return (a & mask) | (b & ~mask); - } - -u32bit min_32(u32bit a, u32bit b) - { - const u32bit a_larger = b - a; /* negative if a larger */ - const u32bit mask = expand_mask(a_larger >> 31); - return (a & ~mask) | (b & mask); - } - -} - -} diff --git a/src/lib/utils/ta_utils.h b/src/lib/utils/ta_utils.h deleted file mode 100644 index 9353214b2..000000000 --- a/src/lib/utils/ta_utils.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Timing Attack Countermeasure Functions -* (C) 2010 Falko Strenzke, Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_TIMING_ATTACK_CM_H__ -#define BOTAN_TIMING_ATTACK_CM_H__ - -#include - -namespace Botan { - -namespace TA_CM { - -/** -* Function used in timing attack countermeasures -* See Wagner, Molnar, et al "The Program Counter Security Model" -* -* @param in an integer -* @return 0 if in == 0 else 0xFFFFFFFF -*/ -u32bit expand_mask_u32bit(u32bit in); - - -/** - * Expand an input to a bit mask depending on it being being zero or - * non-zero - * @ param in the input - * @return the mask 0xFFFF if tst is non-zero and 0 otherwise - */ -u16bit expand_mask_u16bit(u16bit in); - -/** -* Branch-free maximum -* Note: assumes twos-complement signed representation -* @param a an integer -* @param b an integer -* @return max(a,b) -*/ -u32bit max_32(u32bit a, u32bit b); - -/** -* Branch-free minimum -* Note: assumes twos-complement signed representation -* @param a an integer -* @param b an integer -* @return min(a,b) -*/ -u32bit min_32(u32bit a, u32bit b); - -} - -} - -#endif -- cgit v1.2.3 From ada3ce066d1edfe95ee8bffa82f0c2846908a4e1 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sat, 17 Oct 2015 23:21:14 -0400 Subject: Cleanups in ct and oaep In OAEP expand the const time block to cover MGF1 also --- src/lib/pk_pad/eme_oaep/oaep.cpp | 20 ++++---- src/lib/utils/ct_utils.h | 99 +++++----------------------------------- 2 files changed, 23 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/lib/pk_pad/eme_oaep/oaep.cpp b/src/lib/pk_pad/eme_oaep/oaep.cpp index 48a9b5c63..b114afb8b 100644 --- a/src/lib/pk_pad/eme_oaep/oaep.cpp +++ b/src/lib/pk_pad/eme_oaep/oaep.cpp @@ -61,7 +61,7 @@ secure_vector OAEP::pad(const byte in[], size_t in_length, * OAEP Unpad Operation */ secure_vector OAEP::unpad(const byte in[], size_t in_length, - size_t key_length) const + size_t key_length) const { /* Must be careful about error messages here; if an attacker can @@ -84,17 +84,19 @@ secure_vector OAEP::unpad(const byte in[], size_t in_length, secure_vector input(key_length); buffer_insert(input, key_length - in_length, in, in_length); - mgf1_mask(*m_hash, - &input[m_Phash.size()], input.size() - m_Phash.size(), - input.data(), m_Phash.size()); + BOTAN_CONST_TIME_POISON(input.data(), input.size()); + + const size_t hlen = m_Phash.size(); mgf1_mask(*m_hash, - input.data(), m_Phash.size(), - &input[m_Phash.size()], input.size() - m_Phash.size()); + &input[hlen], input.size() - hlen, + input.data(), hlen); - BOTAN_CONST_TIME_POISON(input.data(), input.size()); + mgf1_mask(*m_hash, + input.data(), hlen, + &input[hlen], input.size() - hlen); - size_t delim_idx = 2 * m_Phash.size(); + size_t delim_idx = 2 * hlen; byte waiting_for_delim = 0xFF; byte bad_input = 0; @@ -114,7 +116,7 @@ secure_vector OAEP::unpad(const byte in[], size_t in_length, // If we never saw any non-zero byte, then it's not valid input bad_input |= waiting_for_delim; - bad_input |= ct_expand_mask_8(!same_mem(&input[m_Phash.size()], m_Phash.data(), m_Phash.size())); + bad_input |= ct_expand_mask_8(!same_mem(&input[hlen], m_Phash.data(), hlen)); BOTAN_CONST_TIME_UNPOISON(input.data(), input.size()); BOTAN_CONST_TIME_UNPOISON(&bad_input, sizeof(bad_input)); diff --git a/src/lib/utils/ct_utils.h b/src/lib/utils/ct_utils.h index 02148001e..4ae735330 100644 --- a/src/lib/utils/ct_utils.h +++ b/src/lib/utils/ct_utils.h @@ -39,26 +39,22 @@ namespace Botan { #endif -/* -* Constant time operations for 32 bit values: -* mask, select, zero, equals, min, max -*/ - /* * Expand to a mask used for other operations * @param in an integer * @return 0 if in == 0 else 0xFFFFFFFF */ - inline uint32_t ct_expand_mask_32(uint32_t x) { + // First fold x down to a single bit: uint32_t r = x; - r |= r >> 1; - r |= r >> 2; - r |= r >> 4; - r |= r >> 8; r |= r >> 16; + r |= r >> 8; + r |= r >> 4; + r |= r >> 2; + r |= r >> 1; r &= 1; + // assumes 2s complement signed representation r = ~(r - 1); return r; } @@ -68,23 +64,9 @@ inline uint32_t ct_select_mask_32(uint32_t mask, uint32_t a, uint32_t b) return (a & mask) | (b & ~mask); } -inline uint32_t ct_select_cond_32(bool cond, uint32_t a, uint32_t b) - { - return ct_select_mask_32(ct_expand_mask_32(static_cast(cond)), a, b); - } - -inline uint32_t ct_get_high_bit_32(uint32_t x) - { - return (x >> (8 * sizeof(x) - 1)); - } - -/* -* If x is zero, return 0xFFFF... -* Otherwise returns zero -*/ inline uint32_t ct_is_zero_32(uint32_t x) { - return ct_expand_mask_32(ct_get_high_bit_32(~x & (x-1))); + return ~ct_expand_mask_32(x); } inline uint32_t ct_is_equal_32(uint32_t x, uint32_t y) @@ -92,43 +74,13 @@ inline uint32_t ct_is_equal_32(uint32_t x, uint32_t y) return ct_is_zero_32(x ^ y); } -/** -* Branch-free maximum -* Note: assumes twos-complement signed representation -* @param a an integer -* @param b an integer -* @return max(a,b) -*/ -inline uint32_t ct_max_32(uint32_t a, uint32_t b) - { - const uint32_t s = b - a; - return ct_select_cond_32(ct_get_high_bit_32(s), a, b); - } - -/** -* Branch-free minimum -* Note: assumes twos-complement signed representation -* @param a an integer -* @param b an integer -* @return min(a,b) -*/ -inline uint32_t ct_min_32(uint32_t a, uint32_t b) - { - const uint32_t s = b - a; - return ct_select_cond_32(ct_get_high_bit_32(s), b, a); - } - -/* -* Constant time operations for 16 bit values: -* mask, select, zero, equals -*/ inline uint16_t ct_expand_mask_16(uint16_t x) { uint16_t r = x; - r |= r >> 1; - r |= r >> 2; - r |= r >> 4; r |= r >> 8; + r |= r >> 4; + r |= r >> 2; + r |= r >> 1; r &= 1; r = ~(r - 1); return r; @@ -139,21 +91,9 @@ inline uint16_t ct_select_mask_16(uint16_t mask, uint16_t a, uint16_t b) return (a & mask) | (b & ~mask); } -inline uint16_t ct_select_cond_16(bool cond, uint16_t a, uint16_t b) - { - return ct_select_mask_16(ct_expand_mask_16(static_cast(cond)), a, b); - } - -inline uint16_t ct_get_high_bit_16(uint16_t x) - { - return (x >> (8 * sizeof(x) - 1)); - } - inline uint16_t ct_is_zero_16(uint16_t x) { - //uint16_t z = x & (x - 1) - //return ct_expand_mask_16((~x & (x-1)) - return ct_expand_mask_16(ct_get_high_bit_16(~x & (x-1))); + return ~ct_expand_mask_16(x); } inline uint16_t ct_is_equal_16(uint16_t x, uint16_t y) @@ -161,11 +101,6 @@ inline uint16_t ct_is_equal_16(uint16_t x, uint16_t y) return ct_is_zero_16(x ^ y); } -/* -* Constant time operations for 8 bit values: -* mask, select, zero, equals -*/ - inline uint8_t ct_expand_mask_8(uint8_t x) { uint8_t r = x; @@ -182,19 +117,9 @@ inline uint8_t ct_select_mask_8(uint8_t mask, uint8_t a, uint8_t b) return (a & mask) | (b & ~mask); } -inline uint8_t ct_select_cond_8(bool cond, uint8_t a, uint8_t b) - { - return ct_select_mask_8(ct_expand_mask_8(static_cast(cond)), a, b); - } - -inline uint8_t ct_get_high_bit_8(uint8_t x) - { - return (x >> (8 * sizeof(x) - 1)); - } - inline uint8_t ct_is_zero_8(uint8_t x) { - return ct_expand_mask_8(ct_get_high_bit_8(~x & (x-1))); + return ~ct_expand_mask_8(x); } inline uint8_t ct_is_equal_8(uint8_t x, uint8_t y) -- cgit v1.2.3