Botan 3.9.0
Crypto and TLS for C&
Botan::CT Namespace Reference

Classes

class  Choice
class  Mask
class  Option

Concepts

concept  custom_poisonable
concept  custom_unpoisonable
concept  poisonable
concept  unpoisonable
concept  ct_conditional_assignable

Functions

template<typename T>
constexpr CT::Mask< T > all_zeros (const T elem[], size_t len)
template<typename T>
constexpr Mask< T > conditional_assign_mem (Choice cnd, T *dest, const T *src, size_t elems)
template<typename T>
constexpr Mask< T > conditional_assign_mem (T cnd, T *dest, const T *src, size_t elems)
template<typename T>
constexpr Mask< T > conditional_copy_mem (Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
template<typename T>
constexpr Mask< T > conditional_copy_mem (T cnd, T *dest, const T *if_set, const T *if_unset, 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)
BOTAN_TEST_API CT::Option< size_t > copy_output (CT::Choice accept, std::span< uint8_t > output, std::span< const uint8_t > input, size_t offset)
size_t count_leading_zero_bytes (std::span< const uint8_t > input)
template<typename T>
constexpr CT::Mask< T > is_equal (const T x[], const T y[], size_t len)
template<typename T>
constexpr CT::Mask< T > is_equal (std::span< const T > x, std::span< const T > y)
template<typename T>
constexpr CT::Mask< T > is_not_equal (const T x[], const T y[], size_t len)
secure_vector< uint8_t > strip_leading_zeros (std::span< const uint8_t > input)
template<std::unsigned_integral T>
requires (!std::same_as<bool, T>)
constexpr T value_barrier (T x)
Constant Time Check Annotation Helpers
template<typename T>
constexpr void poison (const T *p, size_t n)
template<typename T>
constexpr void unpoison (const T *p, size_t n)
bool poison_has_effect ()
Constant Time Check Annotation Convenience overloads
template<std::integral T>
constexpr void poison (const T &p)
template<std::integral T>
constexpr void unpoison (const T &p)
template<ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_poisonable<R>)
constexpr void poison (const R &r)
template<ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_unpoisonable<R>)
constexpr void unpoison (const R &r)
template<custom_poisonable T>
constexpr void poison (const T &x)
template<custom_unpoisonable T>
constexpr void unpoison (const T &x)
template<typename T>
requires requires(const T& v) { ::Botan::CT::poison(v); }
constexpr void poison (const std::optional< T > &x)
template<typename T>
requires requires(const T& v) { ::Botan::CT::unpoison(v); }
constexpr void unpoison (const std::optional< T > &x)
Higher-level Constant Time Check Annotation Helpers
template<std::ranges::range R>
requires poisonable<std::ranges::range_value_t<R>>
constexpr void poison_range (const R &r)
template<std::ranges::range R>
requires unpoisonable<std::ranges::range_value_t<R>>
constexpr void unpoison_range (const R &r)
template<poisonable... Ts>
requires (sizeof...(Ts) > 0)
constexpr void poison_all (const Ts &... ts)
template<unpoisonable... Ts>
requires (sizeof...(Ts) > 0)
constexpr void unpoison_all (const Ts &... ts)
template<typename... Ts>
requires (sizeof...(Ts) > 0) && (poisonable<Ts> && ...) && (unpoisonable<Ts> && ...)
constexpr auto scoped_poison (const Ts &... xs)
template<poisonable T>
requires (std::is_rvalue_reference_v<decltype(v)>)
decltype(auto) driveby_poison (T &&v)
template<unpoisonable T>
requires (std::is_rvalue_reference_v<decltype(v)>)
decltype(auto) driveby_unpoison (T &&v)

Function Documentation

◆ all_zeros()

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

Definition at line 813 of file ct_utils.h.

813 {
814 T sum = 0;
815 for(size_t i = 0; i != len; ++i) {
816 sum |= elem[i];
817 }
818 return CT::Mask<T>::is_zero(sum);
819}
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:465

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

Referenced by Botan::EC_Point::add(), Botan::EC_Point::add_affine(), Botan::Scalar448::bytes_are_reduced(), Botan::Ed25519_FieldElement::is_zero(), Botan::Gf448Elem::is_zero(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::is_zero().

◆ conditional_assign_mem() [1/2]

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

Conditional memory assignment (constant time)

If mask is set overwrites dest with src

Definition at line 789 of file ct_utils.h.

789 {
790 const auto mask = CT::Mask<T>::from_choice(cnd);
791 mask.select_n(dest, src, dest, elems);
792 return mask;
793}
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:430

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

◆ conditional_assign_mem() [2/2]

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

Conditional memory assignment (constant time)

If mask is set overwrites dest with src

Definition at line 777 of file ct_utils.h.

777 {
778 const auto mask = CT::Mask<T>::expand(cnd);
779 mask.select_n(dest, src, dest, elems);
780 return mask;
781}
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:420

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

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

◆ conditional_copy_mem() [1/2]

template<typename T>
Mask< T > Botan::CT::conditional_copy_mem ( Mask< T > mask,
T * dest,
const T * if_set,
const T * if_unset,
size_t elems )
inlineconstexpr

Conditional memory copy (constant time)

If mask is set, then sets dest to if_set, otherwise sets dest to if_unset

Definition at line 760 of file ct_utils.h.

760 {
761 mask.select_n(dest, if_set, if_unset, elems);
762 return mask;
763}
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
Definition ct_utils.h:593

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

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

◆ conditional_copy_mem() [2/2]

template<typename T>
Mask< T > Botan::CT::conditional_copy_mem ( T cnd,
T * dest,
const T * if_set,
const T * if_unset,
size_t elems )
inlineconstexpr

Definition at line 766 of file ct_utils.h.

766 {
767 const auto mask = CT::Mask<T>::expand(cnd);
768 return CT::conditional_copy_mem(mask, dest, if_set, if_unset, elems);
769}
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
Definition ct_utils.h:760

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

◆ conditional_swap()

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

Definition at line 796 of file ct_utils.h.

796 {
797 const auto swap = CT::Mask<T>::expand(cnd);
798 swap.conditional_swap(x, y);
799}

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

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

◆ conditional_swap_ptr()

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

Definition at line 802 of file ct_utils.h.

802 {
803 uintptr_t xp = reinterpret_cast<uintptr_t>(x);
804 uintptr_t yp = reinterpret_cast<uintptr_t>(y);
805
806 conditional_swap<uintptr_t>(cnd, xp, yp);
807
808 x = reinterpret_cast<T>(xp); // NOLINT(*-no-int-to-ptr)
809 y = reinterpret_cast<T>(yp); // NOLINT(*-no-int-to-ptr)
810}
constexpr void conditional_swap(bool cnd, T &x, T &y)
Definition ct_utils.h:796

References conditional_swap().

◆ copy_output()

CT::Option< size_t > Botan::CT::copy_output ( CT::Choice accept,
std::span< uint8_t > output,
std::span< const uint8_t > input,
size_t offset )

Constant time conditional copy out with offset

If accept is set and offset <= input_length, sets output[0..] to input[offset:input_length] and returns input_length - offset. The remaining bytes of output are zeroized.

Otherwise, output is zeroized, and returns an empty Ct::Option

The input and output spans may not overlap, and output must be at least as large as input.

This function attempts to avoid leaking the following to side channels

  • if accept was set or not
  • the value of offset
  • the value of input

This function leaks the length of the input

Zeroize the entire output buffer to get started

Definition at line 13 of file ct_utils.cpp.

16 {
17 // This leaks information about the input length, but this happens
18 // unavoidably since we are unable to ready any bytes besides those
19 // in input[0..n]
20 BOTAN_ARG_CHECK(output.size() >= input.size(), "Invalid span lengths");
21
22 /*
23 * We do not poison the input here because if we did we would have
24 * to unpoison it at exit. We assume instead that callers have
25 * already poisoned the input and will unpoison it at their own
26 * time.
27 */
28 CT::poison(offset);
29
30 /**
31 * Zeroize the entire output buffer to get started
32 */
33 clear_mem(output);
34
35 /*
36 * If the offset is greater than input length, then the arguments are
37 * invalid. Ideally we would throw an exception, but that leaks
38 * information about the offset. Instead treat it as if the input
39 * was invalid.
40 */
41 accept = accept && CT::Mask<size_t>::is_lte(offset, input.size()).as_choice();
42
43 /*
44 * If the input is invalid, then set offset == input_length
45 */
46 offset = CT::Mask<size_t>::from_choice(accept).select(offset, input.size());
47
48 /*
49 * Move the desired output bytes to the front using a slow (O^n)
50 * but constant time loop that does not leak the value of the offset
51 */
52 for(size_t i = 0; i != input.size(); ++i) {
53 /*
54 * If bad_input was set then we modified offset to equal the input_length.
55 * In that case, this_loop will be greater than input_length, and so is_eq
56 * mask will always be false. As a result none of the input values will be
57 * written to output.
58 *
59 * This is ignoring the possibility of integer overflow of offset + i. But
60 * for this to happen the input would have to consume nearly the entire
61 * address space.
62 */
63 const size_t this_loop = offset + i;
64
65 /*
66 start index from i rather than 0 since we know j must be >= i + offset
67 to have any effect, and starting from i does not reveal information
68 */
69 for(size_t j = i; j != input.size(); ++j) {
70 const uint8_t b = input[j];
71 const auto is_eq = CT::Mask<size_t>::is_equal(j, this_loop);
72 output[i] |= is_eq.if_set_return(b);
73 }
74 }
75
76 // This will always be zero if the input was invalid
77 const size_t output_bytes = input.size() - offset;
78
79 CT::unpoison_all(output, output_bytes);
80
81 return CT::Option<size_t>(output_bytes, accept);
82}
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:491
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:470
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:205
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:54
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:119

References BOTAN_ARG_CHECK, Botan::clear_mem(), Botan::CT::Mask< T >::from_choice(), Botan::CT::Mask< T >::is_equal(), Botan::CT::Mask< T >::is_lte(), poison(), and unpoison_all().

Referenced by strip_leading_zeros().

◆ count_leading_zero_bytes()

size_t Botan::CT::count_leading_zero_bytes ( std::span< const uint8_t > input)

Definition at line 84 of file ct_utils.cpp.

84 {
85 size_t leading_zeros = 0;
86 auto only_zeros = Mask<uint8_t>::set();
87 for(uint8_t b : input) {
88 only_zeros &= CT::Mask<uint8_t>::is_zero(b);
89 leading_zeros += only_zeros.if_set_return(1);
90 }
91 return leading_zeros;
92}
static constexpr Mask< T > set()
Definition ct_utils.h:410

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

Referenced by strip_leading_zeros().

◆ driveby_poison()

template<poisonable T>
requires (std::is_rvalue_reference_v<decltype(v)>)
decltype(auto) Botan::CT::driveby_poison ( T && v)
nodiscard

Poisons an r-value v and forwards it as the return value.

Definition at line 230 of file ct_utils.h.

232{
233 poison(v);
234 return std::forward<T>(v);
235}

References poison().

◆ driveby_unpoison()

template<unpoisonable T>
requires (std::is_rvalue_reference_v<decltype(v)>)
decltype(auto) Botan::CT::driveby_unpoison ( T && v)
nodiscard

Unpoisons an r-value v and forwards it as the return value.

Definition at line 241 of file ct_utils.h.

243{
244 unpoison(v);
245 return std::forward<T>(v);
246}
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:65

References unpoison().

Referenced by Botan::Classic_McEliece_PublicKeyInternal::create_from_private_key(), Botan::Dilithium_Algos::infinity_norm_within_bound(), Botan::HSS_LMS_PrivateKey::private_key_bits(), and Botan::BlockCipherModePaddingMethod::unpad().

◆ is_equal() [1/2]

template<typename T>
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 826 of file ct_utils.h.

826 {
827 if(std::is_constant_evaluated()) {
828 T difference = 0;
829
830 for(size_t i = 0; i != len; ++i) {
831 difference = difference | (x[i] ^ y[i]);
832 }
833
834 return CT::Mask<T>::is_zero(difference);
835 } else {
836 volatile T difference = 0;
837
838 for(size_t i = 0; i != len; ++i) {
839 difference = difference | (x[i] ^ y[i]);
840 }
841
842 return CT::Mask<T>::is_zero(difference);
843 }
844}

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

Referenced by Botan::argon2_check_pwhash(), botan_constant_time_compare(), Botan::Gf448Elem::bytes_are_canonical_representation(), Botan::check_bcrypt(), Botan::Classic_McEliece_PrivateKeyInternal::check_key(), Botan::Ed25519_PublicKey::check_key(), Botan::X448_PrivateKey::check_key(), Botan::check_passhash9(), Botan::constant_time_compare(), Botan::FrodoMatrix::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::Classic_McEliece_Field_Ordering::ct_is_equal(), Botan::Kyber_KEM_Decryptor::decapsulate(), Botan::ML_KEM_Decryptor::decapsulate(), Botan::TLS::Session::decrypt(), Botan::CryptoBox::decrypt_bin(), is_equal(), is_not_equal(), Botan::EC_AffinePoint::operator==(), Botan::Gf448Elem::operator==(), Botan::IntMod< MontgomeryRep< ScalarParams > >::operator==(), Botan::Classic_McEliece_Decryptor::raw_kem_decrypt(), Botan::RTSS_Share::reconstruct(), Botan::signature_check(), Botan::Sodium::sodium_memcmp(), Botan::TLS::Finished_12::verify(), and Botan::MessageAuthenticationCode::verify_mac_result().

◆ is_equal() [2/2]

template<typename T>
CT::Mask< T > Botan::CT::is_equal ( std::span< const T > x,
std::span< const T > y )
inlineconstexpr

Compare two spans and return a Mask which is set iff they were identical.

If the spans are of different length then the function returns early without looking at either span

Definition at line 853 of file ct_utils.h.

853 {
854 if(x.size() != y.size()) {
855 return CT::Mask<T>::cleared();
856 }
857
858 return is_equal(x.data(), y.data(), x.size());
859}
static constexpr Mask< T > cleared()
Definition ct_utils.h:415
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:826

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

◆ is_not_equal()

template<typename T>
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 866 of file ct_utils.h.

866 {
867 return ~CT::is_equal(x, y, len);
868}

References is_equal().

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

◆ poison() [1/5]

template<ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_poisonable<R>)
void Botan::CT::poison ( const R & r)
constexpr

Poison a contiguous buffer of trivial objects (e.g. integers and such)

Definition at line 119 of file ct_utils.h.

119 {
120 std::span s{r};
121 poison(s.data(), s.size());
122}

References poison().

◆ poison() [2/5]

template<typename T>
requires requires(const T& v) { ::Botan::CT::poison(v); }
void Botan::CT::poison ( const std::optional< T > & x)
constexpr

Poison an optional object if it has a value.

Definition at line 150 of file ct_utils.h.

150 {
151 if(x.has_value()) {
152 poison(x.value());
153 }
154}

References poison().

◆ poison() [3/5]

template<std::integral T>
void Botan::CT::poison ( const T & p)
constexpr

Poison a single integral object

Definition at line 105 of file ct_utils.h.

105 {
106 poison(&p, 1);
107}

References poison().

◆ poison() [4/5]

template<custom_poisonable T>
void Botan::CT::poison ( const T & x)
constexpr

Poison a class type that provides a public _const_time_poison() method For instance: BigInt, CT::Mask<>, FrodoMatrix, ...

Definition at line 136 of file ct_utils.h.

136 {
137 x._const_time_poison();
138}

◆ poison() [5/5]

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

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

54 {
55#if defined(BOTAN_HAS_VALGRIND)
56 if(!std::is_constant_evaluated()) {
57 VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
58 }
59#endif
60
61 BOTAN_UNUSED(p, n);
62}
#define BOTAN_UNUSED
Definition assert.h:144

References BOTAN_UNUSED.

Referenced by Botan::BigInt::_const_time_poison(), Botan::bitvector_base< secure_allocator >::_const_time_poison(), Botan::Classic_McEliece_Field_Ordering::_const_time_poison(), Botan::Classic_McEliece_Polynomial::_const_time_poison(), Botan::CRYSTALS::Polynomial< DilithiumPolyTraits, Botan::CRYSTALS::Domain::NTT >::_const_time_poison(), Botan::CT::Mask< T >::_const_time_poison(), Botan::Dilithium_PrivateKeyInternal::_const_time_poison(), Botan::FrodoMatrix::_const_time_poison(), Botan::HSS_LMS_PrivateKeyInternal::_const_time_poison(), Botan::IntMod< MontgomeryRep< ScalarParams > >::_const_time_poison(), Botan::Montgomery_Int::_const_time_poison(), Botan::basemul_exec(), Botan::BlindedScalarBits< C, WindowBits+1 >::BlindedScalarBits(), Botan::Classic_McEliece_PrivateKey::Classic_McEliece_PrivateKey(), copy_output(), Botan::curve25519_donna(), driveby_poison(), Botan::ed25519_basepoint_mul(), Botan::Kyber_KEM_Encryptor::encapsulate(), Botan::Dilithium_Algos::expand_keypair(), Botan::Kyber_Algos::expand_keypair(), Botan::map_to_curve_sswu(), Botan::WindowedBoothMulTable< C, W >::mul(), Botan::mul2_exec(), poison(), poison(), poison(), poison_all(), poison_range(), and Botan::varpoint_exec().

◆ poison_all()

template<poisonable... Ts>
requires (sizeof...(Ts) > 0)
void Botan::CT::poison_all ( const Ts &... ts)
constexpr

◆ poison_has_effect()

bool Botan::CT::poison_has_effect ( )
inline

Checks whether CT::poison() and CT::unpoison() actually have an effect.

If the build is not instrumented and/or not run using an analysis tool like valgrind, the functions are no-ops and the return value is false.

Returns
true if CT::poison() and CT::unpoison() are effective

Definition at line 83 of file ct_utils.h.

83 {
84#if defined(BOTAN_HAS_VALGRIND)
85 return RUNNING_ON_VALGRIND;
86#else
87 return false;
88#endif
89}

◆ poison_range()

template<std::ranges::range R>
requires poisonable<std::ranges::range_value_t<R>>
void Botan::CT::poison_range ( const R & r)
constexpr

Poison a range of objects by calling poison on each element.

Definition at line 179 of file ct_utils.h.

179 {
180 for(const auto& v : r) {
181 poison(v);
182 }
183}

References poison().

Referenced by Botan::CRYSTALS::PolynomialMatrix< DilithiumPolyTraits >::_const_time_poison(), and Botan::CRYSTALS::PolynomialVector< DilithiumPolyTraits, Botan::CRYSTALS::Domain::NTT >::_const_time_poison().

◆ scoped_poison()

template<typename... Ts>
requires (sizeof...(Ts) > 0) && (poisonable<Ts> && ...) && (unpoisonable<Ts> && ...)
auto Botan::CT::scoped_poison ( const Ts &... xs)
nodiscardconstexpr

Poisons an arbitrary number of poisonable values, and unpoisons them when the returned object runs out-of-scope

Use this when you want to poison a value that remains valid longer than the scope you are currently in. For instance, a private key structure that is a member of a Signature_Operation object, that may be used for multiple signatures.

Definition at line 220 of file ct_utils.h.

220 {
221 auto scope = scoped_cleanup([&] { unpoison_all(xs...); });
222 poison_all(xs...);
223 return scope;
224}
Helper class to create a RAII-style cleanup callback.
Definition stl_util.h:346
constexpr void poison_all(const Ts &... ts)
Definition ct_utils.h:199

References poison_all(), and unpoison_all().

Referenced by Botan::BlockCipherModePaddingMethod::add_padding(), Botan::X448_PrivateKey::check_key(), Botan::Classic_McEliece_PrivateKey::Classic_McEliece_PrivateKey(), Botan::Kyber_KEM_Decryptor::decapsulate(), Botan::ML_KEM_Decryptor::decapsulate(), Botan::Expanded_Keypair_Codec::decode_keypair(), Botan::Ed448_PrivateKey::Ed448_PrivateKey(), Botan::ML_KEM_Encryptor::encapsulate(), Botan::Expanded_Keypair_Codec::encode_keypair(), Botan::HSS_LMS_PrivateKey::HSS_LMS_PrivateKey(), Botan::HSS_LMS_PrivateKey::HSS_LMS_PrivateKey(), Botan::HSS_LMS_PrivateKey::private_key_bits(), Botan::Classic_McEliece_Decryptor::raw_kem_decrypt(), Botan::BlockCipherModePaddingMethod::unpad(), and Botan::X448_PrivateKey::X448_PrivateKey().

◆ strip_leading_zeros()

secure_vector< uint8_t > Botan::CT::strip_leading_zeros ( std::span< const uint8_t > input)

Definition at line 94 of file ct_utils.cpp.

94 {
95 const size_t leading_zeros = CT::count_leading_zero_bytes(input);
96
97 secure_vector<uint8_t> output(input.size());
98
99 const auto written = CT::copy_output(CT::Choice::yes(), output, input, leading_zeros);
100
101 /*
102 This is potentially not const time, depending on how std::vector is
103 implemented. But since we are always reducing length, it should
104 just amount to setting the member var holding the length.
105 */
106 output.resize(written.value_or(0));
107
108 return output;
109}
static constexpr Choice yes()
Definition ct_utils.h:333
BOTAN_TEST_API CT::Option< size_t > copy_output(CT::Choice accept, std::span< uint8_t > output, std::span< const uint8_t > input, size_t offset)
Definition ct_utils.cpp:13
size_t count_leading_zero_bytes(std::span< const uint8_t > input)
Definition ct_utils.cpp:84
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69

References copy_output(), count_leading_zero_bytes(), and Botan::CT::Choice::yes().

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

◆ unpoison() [1/5]

template<ranges::spanable_range R>
requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_unpoisonable<R>)
void Botan::CT::unpoison ( const R & r)
constexpr

Definition at line 126 of file ct_utils.h.

126 {
127 std::span s{r};
128 unpoison(s.data(), s.size());
129}

References unpoison().

◆ unpoison() [2/5]

template<typename T>
requires requires(const T& v) { ::Botan::CT::unpoison(v); }
void Botan::CT::unpoison ( const std::optional< T > & x)
constexpr

Definition at line 158 of file ct_utils.h.

158 {
159 if(x.has_value()) {
160 unpoison(x.value());
161 }
162}

References unpoison().

◆ unpoison() [3/5]

template<std::integral T>
void Botan::CT::unpoison ( const T & p)
constexpr

Definition at line 110 of file ct_utils.h.

110 {
111 unpoison(&p, 1);
112}

References unpoison().

◆ unpoison() [4/5]

template<custom_unpoisonable T>
void Botan::CT::unpoison ( const T & x)
constexpr

Definition at line 141 of file ct_utils.h.

141 {
142 x._const_time_unpoison();
143}

◆ unpoison() [5/5]

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

Definition at line 65 of file ct_utils.h.

65 {
66#if defined(BOTAN_HAS_VALGRIND)
67 if(!std::is_constant_evaluated()) {
68 VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T));
69 }
70#endif
71
72 BOTAN_UNUSED(p, n);
73}

References BOTAN_UNUSED.

Referenced by Botan::BigInt::_const_time_unpoison(), Botan::bitvector_base< secure_allocator >::_const_time_unpoison(), Botan::Classic_McEliece_Field_Ordering::_const_time_unpoison(), Botan::Classic_McEliece_Matrix::_const_time_unpoison(), Botan::Classic_McEliece_Polynomial::_const_time_unpoison(), Botan::Classic_McEliece_PublicKeyInternal::_const_time_unpoison(), Botan::CRYSTALS::Polynomial< DilithiumPolyTraits, Botan::CRYSTALS::Domain::NTT >::_const_time_unpoison(), Botan::CT::Mask< T >::_const_time_unpoison(), Botan::Dilithium_PrivateKeyInternal::_const_time_unpoison(), Botan::FrodoMatrix::_const_time_unpoison(), Botan::HSS_LMS_PrivateKeyInternal::_const_time_unpoison(), Botan::HSS_LMS_PublicKeyInternal::_const_time_unpoison(), Botan::IntMod< MontgomeryRep< ScalarParams > >::_const_time_unpoison(), Botan::LMS_PublicKey::_const_time_unpoison(), Botan::Montgomery_Int::_const_time_unpoison(), Botan::basemul_exec(), Botan::bigint_cmp(), Botan::Classic_McEliece_Matrix::Classic_McEliece_Matrix(), Botan::Classic_McEliece_Polynomial_Ring::compute_minimal_polynomial(), Botan::Classic_McEliece_Matrix::create_matrix(), Botan::Classic_McEliece_Matrix::create_matrix_and_apply_pivots(), Botan::curve25519_donna(), Botan::Kyber_KEM_Decryptor::decapsulate(), Botan::ML_KEM_Decryptor::decapsulate(), driveby_unpoison(), Botan::ed25519_basepoint_mul(), Botan::Ed448_PrivateKey::Ed448_PrivateKey(), Botan::Expanded_Keypair_Codec::encode_keypair(), Botan::Dilithium_Algos::expand_keypair(), Botan::Kyber_Algos::expand_keypair(), Botan::HSS_LMS_PrivateKey::HSS_LMS_PrivateKey(), Botan::HSS_LMS_PrivateKey::HSS_LMS_PrivateKey(), Botan::map_to_curve_sswu(), Botan::WindowedBoothMulTable< C, W >::mul(), Botan::mul2_exec(), Botan::Classic_McEliece_Decryptor::raw_kem_decrypt(), Botan::CT::Mask< T >::select_and_unpoison(), Botan::LMOTS_Private_Key::sign(), Botan::LMS_PrivateKey::sign_and_get_pk(), Botan::BigInt::top_bits_free(), unpoison(), unpoison(), unpoison(), unpoison_all(), unpoison_range(), Botan::CT::Mask< T >::unpoisoned_value(), Botan::varpoint_exec(), Botan::X448_PrivateKey::X448_PrivateKey(), and Botan::BlindedScalarBits< C, WindowBits+1 >::~BlindedScalarBits().

◆ unpoison_all()

◆ unpoison_range()

template<std::ranges::range R>
requires unpoisonable<std::ranges::range_value_t<R>>
void Botan::CT::unpoison_range ( const R & r)
constexpr

◆ value_barrier()

template<std::unsigned_integral T>
requires (!std::same_as<bool, T>)
T Botan::CT::value_barrier ( T x)
inlineconstexpr

This function returns its argument, but (if called in a non-constexpr context) attempts to prevent the compiler from reasoning about the value or the possible range of values. Such optimizations have a way of breaking constant time code.

The method that is use is decided at configuration time based on the target compiler and architecture (see ct_value_barrier blocks in src/build-data/cc). The decision can be overridden by the user with the configure.py option --ct-value-barrier-type=

There are three options currently possible in the data files and with the option:

  • asm: Use an inline assembly expression which (currently) prevents Clang and GCC from optimizing based on the possible value of the input expression.
  • volatile: Launder the input through a volatile variable. This is likely to cause significant performance regressions since the value must be actually stored and loaded back from memory each time.
  • none: disable constant time barriers entirely. This is used with MSVC, which is not known to perform optimizations that break constant time code and which does not support GCC-style inline asm.

Definition at line 277 of file ct_utils.h.

277 {
278 if(std::is_constant_evaluated()) {
279 return x;
280 } else {
281#if defined(BOTAN_CT_VALUE_BARRIER_USE_ASM)
282 /*
283 * We may want a "stronger" statement such as
284 * asm volatile("" : "+r,m"(x) : : "memory);
285 * (see https://theunixzoo.co.uk/blog/2021-10-14-preventing-optimisations.html)
286 * however the current approach seems sufficient with current compilers,
287 * and is minimally damaging with regards to degrading code generation.
288 */
289 asm("" : "+r"(x) : /* no input */);
290 return x;
291#elif defined(BOTAN_CT_VALUE_BARRIER_USE_VOLATILE)
292 volatile T vx = x;
293 return vx;
294#else
295 return x;
296#endif
297 }
298}

Referenced by Botan::CT::Mask< T >::expand(), Botan::CT::Mask< T >::expand_top_bit(), Botan::CT::Choice::from_int(), Botan::CT::Mask< T >::is_any_of(), Botan::CT::Mask< T >::is_equal(), Botan::CT::Mask< T >::is_within_range(), Botan::CT::Mask< T >::is_zero(), Botan::Classic_McEliece_GF::operator*(), Botan::FrodoMatrix::sample(), Botan::BigInt::top_bits_free(), Botan::CT::Choice::value(), and Botan::CT::Mask< T >::value().