Botan 3.2.0
Crypto and TLS for C&
ct_utils.cpp
Go to the documentation of this file.
1/*
2* (C) 2018,2021 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/ct_utils.h>
8
9namespace Botan::CT {
10
12 const uint8_t input[],
13 size_t input_length,
14 size_t offset) {
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}
83
84secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length) {
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}
96
97} // namespace Botan::CT
static Mask< T > is_gt(T x, T y)
Definition ct_utils.h:136
static Mask< T > is_equal(T x, T y)
Definition ct_utils.h:126
static Mask< T > is_zero(T x)
Definition ct_utils.h:121
static Mask< T > expand(T v)
Definition ct_utils.h:107
static Mask< T > set()
Definition ct_utils.h:97
void poison(const T *p, size_t n)
Definition ct_utils.h:46
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
void unpoison(const T *p, size_t n)
Definition ct_utils.h:55
secure_vector< uint8_t > strip_leading_zeros(const uint8_t in[], size_t length)
Definition ct_utils.cpp:84
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61