1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/*
* (C) 2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/ct_utils.h>
namespace Botan {
namespace CT {
secure_vector<uint8_t> copy_output(CT::Mask<uint8_t> bad_input,
const uint8_t input[],
size_t input_length,
size_t offset)
{
if(input_length == 0)
return secure_vector<uint8_t>();
/*
* Ensure at runtime that offset <= input_length. This is an invalid input,
* but we can't throw without using the poisoned value. Instead, if it happens,
* set offset to be equal to the input length (so output_bytes becomes 0 and
* the returned vector is empty)
*/
const auto valid_offset = CT::Mask<size_t>::is_lte(offset, input_length);
offset = valid_offset.select(offset, input_length);
const size_t output_bytes = input_length - offset;
secure_vector<uint8_t> output(input_length);
/*
Move the desired output bytes to the front using a slow (O^n)
but constant time loop that does not leak the value of the offset
*/
for(size_t i = 0; i != input_length; ++i)
{
/*
start index from i rather than 0 since we know j must be >= i + offset
to have any effect, and starting from i does not reveal information
*/
for(size_t j = i; j != input_length; ++j)
{
const uint8_t b = input[j];
const auto is_eq = CT::Mask<size_t>::is_equal(j, offset + i);
output[i] |= is_eq.if_set_return(b);
}
}
bad_input.if_set_zero_out(output.data(), output.size());
/*
This is potentially not const time, depending on how std::vector is
implemented. But since we are always reducing length, it should
just amount to setting the member var holding the length.
*/
CT::unpoison(output.data(), output.size());
CT::unpoison(output_bytes);
output.resize(output_bytes);
return output;
}
secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length)
{
size_t leading_zeros = 0;
auto only_zeros = Mask<uint8_t>::set();
for(size_t i = 0; i != length; ++i)
{
only_zeros &= CT::Mask<uint8_t>::is_zero(in[i]);
leading_zeros += only_zeros.if_set_return(1);
}
return copy_output(CT::Mask<uint8_t>::cleared(), in, length, leading_zeros);
}
}
}
|