Botan 3.4.0
Crypto and TLS for C&
Classes | Functions
Botan::CT Namespace Reference

Classes

class  Mask
 

Functions

template<typename T >
constexpr CT::Mask< Tall_zeros (const T elem[], size_t len)
 
template<typename T >
constexpr Mask< Tconditional_assign_mem (T cnd, T *sink, const T *src, size_t elems)
 
template<typename T >
constexpr Mask< Tconditional_copy_mem (Mask< T > mask, T *to, const T *from0, const T *from1, size_t elems)
 
template<typename T >
constexpr Mask< Tconditional_copy_mem (T cnd, T *to, const T *from0, const T *from1, size_t elems)
 
template<typename T >
constexpr void conditional_swap (bool cnd, T &x, T &y)
 
template<typename T >
constexpr void conditional_swap_ptr (bool cnd, T &x, T &y)
 
secure_vector< uint8_t > copy_output (CT::Mask< uint8_t > bad_input_u8, const uint8_t input[], size_t input_length, size_t offset)
 
template<typename T >
constexpr CT::Mask< Tis_equal (const T x[], const T y[], size_t len)
 
template<typename T >
constexpr CT::Mask< Tis_not_equal (const T x[], const T y[], size_t len)
 
template<typename T >
void poison (const T *p, size_t n)
 
secure_vector< uint8_t > strip_leading_zeros (const secure_vector< uint8_t > &in)
 
secure_vector< uint8_t > strip_leading_zeros (const uint8_t in[], size_t length)
 
template<typename T >
constexpr void unpoison (const T *p, size_t n)
 
template<typename T >
constexpr void unpoison (T &p)
 

Function Documentation

◆ all_zeros()

template<typename T >
constexpr CT::Mask< T > Botan::CT::all_zeros ( const T elem[],
size_t len )
inlineconstexpr

Definition at line 332 of file ct_utils.h.

332 {
333 T sum = 0;
334 for(size_t i = 0; i != len; ++i) {
335 sum |= elem[i];
336 }
337 return CT::Mask<T>::is_zero(sum);
338}
FE_25519 T
Definition ge.cpp:34

References Botan::CT::Mask< T >::is_zero(), and T.

Referenced by Botan::EC_Point::add(), Botan::EC_Point::add_affine(), Botan::Scalar448::bytes_are_reduced(), Botan::TLS::Client_Key_Exchange::Client_Key_Exchange(), Botan::TLS::Client_Key_Exchange::Client_Key_Exchange(), and Botan::Gf448Elem::is_zero().

◆ conditional_assign_mem()

template<typename T >
constexpr Mask< T > Botan::CT::conditional_assign_mem ( T cnd,
T * sink,
const T * src,
size_t elems )
inlineconstexpr

Definition at line 304 of file ct_utils.h.

304 {
305 const auto mask = CT::Mask<T>::expand(cnd);
306 mask.select_n(sink, src, sink, elems);
307 return mask;
308}

References Botan::CT::Mask< T >::expand().

Referenced by Botan::bigint_monty_maybe_sub(), Botan::bigint_monty_maybe_sub(), and Botan::Gf448Elem::ct_cond_assign().

◆ conditional_copy_mem() [1/2]

template<typename T >
constexpr Mask< T > Botan::CT::conditional_copy_mem ( Mask< T > mask,
T * to,
const T * from0,
const T * from1,
size_t elems )
inlineconstexpr

Definition at line 292 of file ct_utils.h.

292 {
293 mask.select_n(to, from0, from1, elems);
294 return mask;
295}
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
Definition ct_utils.h:251

References Botan::CT::Mask< T >::select_n().

Referenced by Botan::bigint_sub_abs(), conditional_copy_mem(), and Botan::BigInt::mod_add().

◆ conditional_copy_mem() [2/2]

template<typename T >
constexpr Mask< T > Botan::CT::conditional_copy_mem ( T cnd,
T * to,
const T * from0,
const T * from1,
size_t elems )
inlineconstexpr

Definition at line 298 of file ct_utils.h.

298 {
299 const auto mask = CT::Mask<T>::expand(cnd);
300 return CT::conditional_copy_mem(mask, to, from0, from1, elems);
301}

References conditional_copy_mem(), and Botan::CT::Mask< T >::expand().

◆ conditional_swap()

template<typename T >
constexpr void Botan::CT::conditional_swap ( bool cnd,
T & x,
T & y )
inlineconstexpr

Definition at line 311 of file ct_utils.h.

311 {
312 const auto swap = CT::Mask<T>::expand(cnd);
313
314 T t0 = swap.select(y, x);
315 T t1 = swap.select(x, y);
316 x = t0;
317 y = t1;
318}

References Botan::CT::Mask< T >::expand(), and T.

Referenced by Botan::bigint_sub_abs(), and Botan::Gf448Elem::ct_cond_swap().

◆ conditional_swap_ptr()

template<typename T >
constexpr void Botan::CT::conditional_swap_ptr ( bool cnd,
T & x,
T & y )
inlineconstexpr

Definition at line 321 of file ct_utils.h.

321 {
322 uintptr_t xp = reinterpret_cast<uintptr_t>(x);
323 uintptr_t yp = reinterpret_cast<uintptr_t>(y);
324
325 conditional_swap<uintptr_t>(cnd, xp, yp);
326
327 x = reinterpret_cast<T>(xp);
328 y = reinterpret_cast<T>(yp);
329}

References T.

Referenced by Botan::bigint_sub_abs().

◆ copy_output()

BOTAN_TEST_API secure_vector< uint8_t > Botan::CT::copy_output ( CT::Mask< uint8_t > bad_input,
const uint8_t input[],
size_t input_length,
size_t offset )

If bad_input is unset, return input[offset:input_length] copied to new buffer. If bad_input is set, return an empty vector. In all cases, the capacity of the vector is equal to input_length

This function attempts to avoid leaking the following:

  • if bad_input was set or not
  • the value of offset
  • the values in input[]

This function leaks the value of input_length

Definition at line 11 of file ct_utils.cpp.

14 {
15 /*
16 * We do not poison the input here because if we did we would have
17 * to unpoison it at exit. We assume instead that callers have
18 * already poisoned the input and will unpoison it at their own
19 * time.
20 */
21 CT::poison(&offset, sizeof(size_t));
22
23 secure_vector<uint8_t> output(input_length);
24
25 auto bad_input = CT::Mask<size_t>::expand(bad_input_u8);
26
27 /*
28 * If the offset is greater than input_length then the arguments are
29 * invalid. Ideally we would through an exception but that leaks
30 * information about the offset. Instead treat it as if the input
31 * was invalid.
32 */
33 bad_input |= CT::Mask<size_t>::is_gt(offset, input_length);
34
35 /*
36 * If the input is invalid, then set offset == input_length as a result
37 * at the end we will set output_bytes == 0 causing the final result to
38 * be an empty vector.
39 */
40 offset = bad_input.select(input_length, offset);
41
42 /*
43 Move the desired output bytes to the front using a slow (O^n)
44 but constant time loop that does not leak the value of the offset
45 */
46 for(size_t i = 0; i != input_length; ++i) {
47 /*
48 * If bad_input was set then we modified offset to equal the input_length.
49 * In that case, this_loop will be greater than input_length, and so is_eq
50 * mask will always be false. As a result none of the input values will be
51 * written to output.
52 *
53 * This is ignoring the possibility of integer overflow of offset + i. But
54 * for this to happen the input would have to consume nearly the entire
55 * address space, and we just allocated an output buffer of equal size.
56 */
57 const size_t this_loop = offset + i;
58
59 /*
60 start index from i rather than 0 since we know j must be >= i + offset
61 to have any effect, and starting from i does not reveal information
62 */
63 for(size_t j = i; j != input_length; ++j) {
64 const uint8_t b = input[j];
65 const auto is_eq = CT::Mask<size_t>::is_equal(j, this_loop);
66 output[i] |= is_eq.if_set_return(b);
67 }
68 }
69
70 const size_t output_bytes = input_length - offset;
71
72 CT::unpoison(output.data(), output.size());
73 CT::unpoison(output_bytes);
74
75 /*
76 This is potentially not const time, depending on how std::vector is
77 implemented. But since we are always reducing length, it should
78 just amount to setting the member var holding the length.
79 */
80 output.resize(output_bytes);
81 return output;
82}
constexpr T select(T x, T y) const
Definition ct_utils.h:234
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61

References Botan::CT::Mask< T >::expand(), Botan::CT::Mask< T >::is_equal(), Botan::CT::Mask< T >::is_gt(), poison(), and unpoison().

Referenced by Botan::oaep_find_delim(), strip_leading_zeros(), and Botan::EME_PKCS1v15::unpad().

◆ is_equal()

template<typename T >
constexpr CT::Mask< T > Botan::CT::is_equal ( const T x[],
const T y[],
size_t len )
inlineconstexpr

Compare two arrays of equal size and return a Mask indicating if they are equal or not. The mask is set if they are identical.

Definition at line 345 of file ct_utils.h.

345 {
346 if(std::is_constant_evaluated()) {
347 T difference = 0;
348
349 for(size_t i = 0; i != len; ++i) {
350 difference = difference | (x[i] ^ y[i]);
351 }
352
353 return CT::Mask<T>::is_zero(difference);
354 } else {
355 volatile T difference = 0;
356
357 for(size_t i = 0; i != len; ++i) {
358 difference = difference | (x[i] ^ y[i]);
359 }
360
361 return CT::Mask<T>::is_zero(difference);
362 }
363}

References Botan::CT::Mask< T >::is_zero(), and T.

Referenced by Botan::argon2_check_pwhash(), botan_constant_time_compare(), Botan::Gf448Elem::bytes_are_canonical_representation(), Botan::check_bcrypt(), Botan::X448_PrivateKey::check_key(), Botan::Ed25519_PublicKey::check_key(), Botan::check_passhash9(), Botan::FrodoMatrix::constant_time_compare(), Botan::constant_time_compare(), Botan::Sodium::crypto_secretbox_open_detached(), Botan::Sodium::crypto_verify_16(), Botan::Sodium::crypto_verify_32(), Botan::Sodium::crypto_verify_64(), Botan::ct_compare_u8(), Botan::TLS::Session::decrypt(), Botan::CryptoBox::decrypt_bin(), Botan::ed25519_verify(), is_not_equal(), Botan::Gf448Elem::operator==(), Botan::RTSS_Share::reconstruct(), Botan::Sodium::sodium_memcmp(), Botan::TLS::Finished_12::verify(), and Botan::MessageAuthenticationCode::verify_mac_result().

◆ is_not_equal()

template<typename T >
constexpr CT::Mask< T > Botan::CT::is_not_equal ( const T x[],
const T y[],
size_t len )
inlineconstexpr

Compare two arrays of equal size and return a Mask indicating if they are equal or not. The mask is set if they differ.

Definition at line 370 of file ct_utils.h.

370 {
371 return ~CT::is_equal(x, y, len);
372}

References is_equal().

Referenced by Botan::Sodium::crypto_secretbox_xsalsa20poly1305_open(), and Botan::oaep_find_delim().

◆ poison()

template<typename T >
void Botan::CT::poison ( const T * p,
size_t n )
inline

Use valgrind to mark the contents of memory as being undefined. Valgrind will accept operations which manipulate undefined values, but will warn if an undefined value is used to decided a conditional jump or a load/store address. So if we poison all of our inputs we can confirm that the operations in question are truly const time when compiled by whatever compiler is in use.

Even better, the VALGRIND_MAKE_MEM_* macros work even when the program is not run under valgrind (though with a few cycles of overhead, which is unfortunate in final binaries as these annotations tend to be used in fairly important loops).

This approach was first used in ctgrind (https://github.com/agl/ctgrind) but calling the valgrind mecheck API directly works just as well and doesn't require a custom patched valgrind.

Definition at line 46 of file ct_utils.h.

46 {
47#if defined(BOTAN_HAS_VALGRIND)
48 if(!std::is_constant_evaluated()) {
49 VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
50 }
51#endif
52
53 BOTAN_UNUSED(p, n);
54}
#define BOTAN_UNUSED
Definition assert.h:118

References BOTAN_UNUSED, and T.

Referenced by Botan::PKCS7_Padding::add_padding(), Botan::ANSI_X923_Padding::add_padding(), Botan::OneAndZeros_Padding::add_padding(), Botan::ESP_Padding::add_padding(), Botan::BOTAN_FUNC_ISA(), copy_output(), Botan::curve25519_donna(), Botan::oaep_find_delim(), Botan::PKCS7_Padding::unpad(), Botan::ANSI_X923_Padding::unpad(), Botan::OneAndZeros_Padding::unpad(), Botan::ESP_Padding::unpad(), and Botan::EME_PKCS1v15::unpad().

◆ strip_leading_zeros() [1/2]

secure_vector< uint8_t > Botan::CT::strip_leading_zeros ( const secure_vector< uint8_t > & in)
inline

Definition at line 394 of file ct_utils.h.

394 {
395 return strip_leading_zeros(in.data(), in.size());
396}
secure_vector< uint8_t > strip_leading_zeros(const uint8_t in[], size_t length)
Definition ct_utils.cpp:84

References strip_leading_zeros().

◆ strip_leading_zeros() [2/2]

secure_vector< uint8_t > Botan::CT::strip_leading_zeros ( const uint8_t in[],
size_t length )

Definition at line 84 of file ct_utils.cpp.

84 {
85 size_t leading_zeros = 0;
86
87 auto only_zeros = Mask<uint8_t>::set();
88
89 for(size_t i = 0; i != length; ++i) {
90 only_zeros &= CT::Mask<uint8_t>::is_zero(in[i]);
91 leading_zeros += only_zeros.if_set_return(1);
92 }
93
94 return copy_output(CT::Mask<uint8_t>::cleared(), in, length, leading_zeros);
95}

References copy_output(), Botan::CT::Mask< T >::is_zero(), and Botan::CT::Mask< T >::set().

Referenced by Botan::TLS::Client_Key_Exchange::Client_Key_Exchange(), Botan::TLS::Client_Key_Exchange::Client_Key_Exchange(), and strip_leading_zeros().

◆ unpoison() [1/2]

template<typename T >
constexpr void Botan::CT::unpoison ( const T * p,
size_t n )
inlineconstexpr

◆ unpoison() [2/2]

template<typename T >
constexpr void Botan::CT::unpoison ( T & p)
inlineconstexpr

Definition at line 68 of file ct_utils.h.

68 {
69#if defined(BOTAN_HAS_VALGRIND)
70 if(!std::is_constant_evaluated()) {
71 VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T));
72 }
73#endif
74
75 BOTAN_UNUSED(p);
76}

References BOTAN_UNUSED, and T.