Botan  2.10.0
Crypto and TLS for C++11
Classes | Functions
Botan::CT Namespace Reference

Classes

class  Mask
 

Functions

template<typename T >
Mask< Tconditional_copy_mem (T cnd, T *to, const T *from0, const T *from1, size_t elems)
 
template<typename T >
void conditional_swap (bool cnd, T &x, T &y)
 
template<typename T >
void conditional_swap_ptr (bool cnd, T &x, T &y)
 
secure_vector< uint8_t > copy_output (CT::Mask< uint8_t > bad_input, const uint8_t input[], size_t input_length, size_t offset)
 
template<typename T >
void poison (const T *p, size_t n)
 
secure_vector< uint8_t > strip_leading_zeros (const uint8_t in[], size_t length)
 
secure_vector< uint8_t > strip_leading_zeros (const secure_vector< uint8_t > &in)
 
template<typename T >
void unpoison (const T *p, size_t n)
 
template<typename T >
void unpoison (T &p)
 

Function Documentation

◆ conditional_copy_mem()

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

Definition at line 339 of file ct_utils.h.

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

Referenced by Botan::bigint_monty_redc_16(), Botan::bigint_monty_redc_24(), Botan::bigint_monty_redc_32(), Botan::bigint_monty_redc_4(), Botan::bigint_monty_redc_6(), Botan::bigint_monty_redc_8(), Botan::bigint_sub_abs(), and Botan::BigInt::mod_add().

344  {
345  const auto mask = CT::Mask<T>::expand(cnd);
346  mask.select_n(to, from0, from1, elems);
347  return mask;
348  }

◆ conditional_swap()

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

Definition at line 351 of file ct_utils.h.

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

Referenced by Botan::bigint_sub_abs().

352  {
353  const auto swap = CT::Mask<T>::expand(cnd);
354 
355  T t0 = swap.select(y, x);
356  T t1 = swap.select(x, y);
357  x = t0;
358  y = t1;
359  }
fe T
Definition: ge.cpp:37

◆ conditional_swap_ptr()

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

Definition at line 362 of file ct_utils.h.

References copy_output(), strip_leading_zeros(), and T.

Referenced by Botan::bigint_sub_abs().

363  {
364  uintptr_t xp = reinterpret_cast<uintptr_t>(x);
365  uintptr_t yp = reinterpret_cast<uintptr_t>(y);
366 
367  conditional_swap<uintptr_t>(cnd, xp, yp);
368 
369  x = reinterpret_cast<T>(xp);
370  y = reinterpret_cast<T>(yp);
371  }
fe T
Definition: ge.cpp:37

◆ copy_output()

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

If bad_mask is unset, return in[delim_idx:input_length] copied to new buffer. If bad_mask is set, return an all zero vector of unspecified length.

Definition at line 13 of file ct_utils.cpp.

References Botan::CT::Mask< T >::if_set_zero_out(), Botan::CT::Mask< T >::is_equal(), Botan::CT::Mask< T >::is_lte(), and unpoison().

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

17  {
18  if(input_length == 0)
19  return secure_vector<uint8_t>();
20 
21  /*
22  * Ensure at runtime that offset <= input_length. This is an invalid input,
23  * but we can't throw without using the poisoned value. Instead, if it happens,
24  * set offset to be equal to the input length (so output_bytes becomes 0 and
25  * the returned vector is empty)
26  */
27  const auto valid_offset = CT::Mask<size_t>::is_lte(offset, input_length);
28  offset = valid_offset.select(offset, input_length);
29 
30  const size_t output_bytes = input_length - offset;
31 
32  secure_vector<uint8_t> output(input_length);
33 
34  /*
35  Move the desired output bytes to the front using a slow (O^n)
36  but constant time loop that does not leak the value of the offset
37  */
38  for(size_t i = 0; i != input_length; ++i)
39  {
40  /*
41  start index from i rather than 0 since we know j must be >= i + offset
42  to have any effect, and starting from i does not reveal information
43  */
44  for(size_t j = i; j != input_length; ++j)
45  {
46  const uint8_t b = input[j];
47  const auto is_eq = CT::Mask<size_t>::is_equal(j, offset + i);
48  output[i] |= is_eq.if_set_return(b);
49  }
50  }
51 
52  bad_input.if_set_zero_out(output.data(), output.size());
53 
54  /*
55  This is potentially not const time, depending on how std::vector is
56  implemented. But since we are always reducing length, it should
57  just amount to setting the member var holding the length.
58  */
59  CT::unpoison(output.data(), output.size());
60  CT::unpoison(output_bytes);
61  output.resize(output_bytes);
62  return output;
63  }
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:59

◆ 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 48 of file ct_utils.h.

References BOTAN_UNUSED, and T.

Referenced by Botan::BigInt::const_time_lookup(), Botan::BigInt::ct_cond_assign(), Botan::ct_inverse_mod_odd_modulus(), Botan::curve25519_donna(), Botan::IDEA::decrypt_n(), Botan::TLS::TLS_CBC_HMAC_AEAD_Decryption::finish(), Botan::oaep_find_delim(), Botan::GHASH::provider(), Botan::EME_PKCS1v15::unpad(), Botan::PKCS7_Padding::unpad(), Botan::ANSI_X923_Padding::unpad(), Botan::OneAndZeros_Padding::unpad(), and Botan::ESP_Padding::unpad().

49  {
50 #if defined(BOTAN_HAS_VALGRIND)
51  VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
52 #else
53  BOTAN_UNUSED(p);
54  BOTAN_UNUSED(n);
55 #endif
56  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
fe T
Definition: ge.cpp:37

◆ strip_leading_zeros() [1/2]

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

Definition at line 65 of file ct_utils.cpp.

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(), conditional_swap_ptr(), strip_leading_zeros(), and Botan::TLS::Callbacks::tls_dh_agree().

66  {
67  size_t leading_zeros = 0;
68 
69  auto only_zeros = Mask<uint8_t>::set();
70 
71  for(size_t i = 0; i != length; ++i)
72  {
73  only_zeros &= CT::Mask<uint8_t>::is_zero(in[i]);
74  leading_zeros += only_zeros.if_set_return(1);
75  }
76 
77  return copy_output(CT::Mask<uint8_t>::cleared(), in, length, leading_zeros);
78  }
secure_vector< uint8_t > copy_output(CT::Mask< uint8_t > bad_input, const uint8_t input[], size_t input_length, size_t offset)
Definition: ct_utils.cpp:13

◆ strip_leading_zeros() [2/2]

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

Definition at line 385 of file ct_utils.h.

References strip_leading_zeros().

386  {
387  return strip_leading_zeros(in.data(), in.size());
388  }
secure_vector< uint8_t > strip_leading_zeros(const secure_vector< uint8_t > &in)
Definition: ct_utils.h:385

◆ unpoison() [1/2]

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

◆ unpoison() [2/2]

template<typename T >
void Botan::CT::unpoison ( T p)
inline

Definition at line 70 of file ct_utils.h.

References BOTAN_UNUSED, and T.

71  {
72 #if defined(BOTAN_HAS_VALGRIND)
73  VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T));
74 #else
75  BOTAN_UNUSED(p);
76 #endif
77  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
fe T
Definition: ge.cpp:37