Botan 3.6.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
9#include <botan/mem_ops.h>
10
11namespace Botan {
12
14 std::span<uint8_t> output,
15 std::span<const uint8_t> input,
16 size_t offset) {
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}
83
84size_t CT::count_leading_zero_bytes(std::span<const uint8_t> input) {
85 size_t leading_zeros = 0;
86 auto only_zeros = Mask<uint8_t>::set();
87 for(size_t i = 0; i != input.size(); ++i) {
88 only_zeros &= CT::Mask<uint8_t>::is_zero(input[i]);
89 leading_zeros += only_zeros.if_set_return(1);
90 }
91 return leading_zeros;
92}
93
94secure_vector<uint8_t> CT::strip_leading_zeros(std::span<const uint8_t> input) {
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}
110
111} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
static constexpr Choice yes()
Definition ct_utils.h:306
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:455
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:394
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:434
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:429
secure_vector< uint8_t > strip_leading_zeros(std::span< const uint8_t > input)
Definition ct_utils.cpp:94
constexpr void unpoison_all(Ts &&... ts)
Definition ct_utils.h:201
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)
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:53
const SIMD_8x32 & b
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:120