Botan 3.0.0-alpha0
Crypto and TLS for C&
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_u8, 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 secure_vector< uint8_t > &in)
 
secure_vector< uint8_t > strip_leading_zeros (const uint8_t in[], size_t length)
 
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

◆ conditional_swap()

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

Definition at line 372 of file ct_utils.h.

373 {
374 const auto swap = CT::Mask<T>::expand(cnd);
375
376 T t0 = swap.select(y, x);
377 T t1 = swap.select(x, y);
378 x = t0;
379 y = t1;
380 }
fe T
Definition: ge.cpp:36

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

Referenced by Botan::bigint_sub_abs().

◆ conditional_swap_ptr()

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

Definition at line 383 of file ct_utils.h.

384 {
385 uintptr_t xp = reinterpret_cast<uintptr_t>(x);
386 uintptr_t yp = reinterpret_cast<uintptr_t>(y);
387
388 conditional_swap<uintptr_t>(cnd, xp, yp);
389
390 x = reinterpret_cast<T>(xp);
391 y = reinterpret_cast<T>(yp);
392 }

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.

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

References b, 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().

◆ 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.

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

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(), copy_output(), Botan::curve25519_donna(), Botan::TLS::TLS_CBC_HMAC_AEAD_Decryption::finish(), 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 414 of file ct_utils.h.

415 {
416 return strip_leading_zeros(in.data(), in.size());
417 }
secure_vector< uint8_t > strip_leading_zeros(const secure_vector< uint8_t > &in)
Definition: ct_utils.h:414

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 87 of file ct_utils.cpp.

88 {
89 size_t leading_zeros = 0;
90
91 auto only_zeros = Mask<uint8_t>::set();
92
93 for(size_t i = 0; i != length; ++i)
94 {
95 only_zeros &= CT::Mask<uint8_t>::is_zero(in[i]);
96 leading_zeros += only_zeros.if_set_return(1);
97 }
98
99 return copy_output(CT::Mask<uint8_t>::cleared(), in, length, leading_zeros);
100 }
secure_vector< uint8_t > copy_output(CT::Mask< uint8_t > bad_input_u8, const uint8_t input[], size_t input_length, size_t offset)
Definition: ct_utils.cpp:11

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

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

69 {
70#if defined(BOTAN_HAS_VALGRIND)
71 VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T));
72#else
73 BOTAN_UNUSED(p);
74#endif
75 }

References BOTAN_UNUSED, and T.