/src/botan/build/include/botan/internal/ct_utils.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Functions for constant time operations on data and testing of |
3 | | * constant time annotations using valgrind. |
4 | | * |
5 | | * For more information about constant time programming see |
6 | | * Wagner, Molnar, et al "The Program Counter Security Model" |
7 | | * |
8 | | * (C) 2010 Falko Strenzke |
9 | | * (C) 2015,2016,2018 Jack Lloyd |
10 | | * |
11 | | * Botan is released under the Simplified BSD License (see license.txt) |
12 | | */ |
13 | | |
14 | | #ifndef BOTAN_CT_UTILS_H_ |
15 | | #define BOTAN_CT_UTILS_H_ |
16 | | |
17 | | #include <botan/secmem.h> |
18 | | #include <botan/internal/bit_ops.h> |
19 | | #include <type_traits> |
20 | | #include <vector> |
21 | | |
22 | | #if defined(BOTAN_HAS_VALGRIND) |
23 | | #include <valgrind/memcheck.h> |
24 | | #endif |
25 | | |
26 | | namespace Botan { |
27 | | |
28 | | namespace CT { |
29 | | |
30 | | /** |
31 | | * Use valgrind to mark the contents of memory as being undefined. |
32 | | * Valgrind will accept operations which manipulate undefined values, |
33 | | * but will warn if an undefined value is used to decided a conditional |
34 | | * jump or a load/store address. So if we poison all of our inputs we |
35 | | * can confirm that the operations in question are truly const time |
36 | | * when compiled by whatever compiler is in use. |
37 | | * |
38 | | * Even better, the VALGRIND_MAKE_MEM_* macros work even when the |
39 | | * program is not run under valgrind (though with a few cycles of |
40 | | * overhead, which is unfortunate in final binaries as these |
41 | | * annotations tend to be used in fairly important loops). |
42 | | * |
43 | | * This approach was first used in ctgrind (https://github.com/agl/ctgrind) |
44 | | * but calling the valgrind mecheck API directly works just as well and |
45 | | * doesn't require a custom patched valgrind. |
46 | | */ |
47 | | template<typename T> |
48 | | inline void poison(const T* p, size_t n) |
49 | 83.9k | { |
50 | | #if defined(BOTAN_HAS_VALGRIND) |
51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); |
52 | | #else |
53 | 83.9k | BOTAN_UNUSED(p, n); |
54 | 83.9k | #endif |
55 | 83.9k | } void Botan::CT::poison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 49 | 81.2k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 81.2k | BOTAN_UNUSED(p, n); | 54 | 81.2k | #endif | 55 | 81.2k | } |
void Botan::CT::poison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 49 | 2.70k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 2.70k | BOTAN_UNUSED(p, n); | 54 | 2.70k | #endif | 55 | 2.70k | } |
Unexecuted instantiation: void Botan::CT::poison<unsigned short>(unsigned short const*, unsigned long) Unexecuted instantiation: void Botan::CT::poison<unsigned int>(unsigned int const*, unsigned long) |
56 | | |
57 | | template<typename T> |
58 | | inline void unpoison(const T* p, size_t n) |
59 | 83.9k | { |
60 | | #if defined(BOTAN_HAS_VALGRIND) |
61 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); |
62 | | #else |
63 | 83.9k | BOTAN_UNUSED(p, n); |
64 | 83.9k | #endif |
65 | 83.9k | } void Botan::CT::unpoison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 59 | 80.6k | { | 60 | | #if defined(BOTAN_HAS_VALGRIND) | 61 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 62 | | #else | 63 | 80.6k | BOTAN_UNUSED(p, n); | 64 | 80.6k | #endif | 65 | 80.6k | } |
void Botan::CT::unpoison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 59 | 3.30k | { | 60 | | #if defined(BOTAN_HAS_VALGRIND) | 61 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 62 | | #else | 63 | 3.30k | BOTAN_UNUSED(p, n); | 64 | 3.30k | #endif | 65 | 3.30k | } |
Unexecuted instantiation: void Botan::CT::unpoison<unsigned short>(unsigned short const*, unsigned long) Unexecuted instantiation: void Botan::CT::unpoison<unsigned int>(unsigned int const*, unsigned long) |
66 | | |
67 | | template<typename T> |
68 | | inline void unpoison(T& p) |
69 | 1.14G | { |
70 | | #if defined(BOTAN_HAS_VALGRIND) |
71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); |
72 | | #else |
73 | 1.14G | BOTAN_UNUSED(p); |
74 | 1.14G | #endif |
75 | 1.14G | } void Botan::CT::unpoison<unsigned long>(unsigned long&) Line | Count | Source | 69 | 982M | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 982M | BOTAN_UNUSED(p); | 74 | 982M | #endif | 75 | 982M | } |
void Botan::CT::unpoison<unsigned long const>(unsigned long const&) Line | Count | Source | 69 | 13.2M | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 13.2M | BOTAN_UNUSED(p); | 74 | 13.2M | #endif | 75 | 13.2M | } |
void Botan::CT::unpoison<unsigned char>(unsigned char&) Line | Count | Source | 69 | 109k | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 109k | BOTAN_UNUSED(p); | 74 | 109k | #endif | 75 | 109k | } |
Unexecuted instantiation: void Botan::CT::unpoison<Botan::CT::Mask<unsigned char> >(Botan::CT::Mask<unsigned char>&) void Botan::CT::unpoison<long>(long&) Line | Count | Source | 69 | 146M | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 146M | BOTAN_UNUSED(p); | 74 | 146M | #endif | 75 | 146M | } |
void Botan::CT::unpoison<unsigned char const>(unsigned char const&) Line | Count | Source | 69 | 278 | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 278 | BOTAN_UNUSED(p); | 74 | 278 | #endif | 75 | 278 | } |
void Botan::CT::unpoison<unsigned short>(unsigned short&) Line | Count | Source | 69 | 162 | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 162 | BOTAN_UNUSED(p); | 74 | 162 | #endif | 75 | 162 | } |
void Botan::CT::unpoison<Botan::CT::Mask<unsigned short> const>(Botan::CT::Mask<unsigned short> const&) Line | Count | Source | 69 | 81 | { | 70 | | #if defined(BOTAN_HAS_VALGRIND) | 71 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 72 | | #else | 73 | 81 | BOTAN_UNUSED(p); | 74 | 81 | #endif | 75 | 81 | } |
|
76 | | |
77 | | /** |
78 | | * A Mask type used for constant-time operations. A Mask<T> always has value |
79 | | * either 0 (all bits cleared) or ~0 (all bits set). All operations in a Mask<T> |
80 | | * are intended to compile to code which does not contain conditional jumps. |
81 | | * This must be verified with tooling (eg binary disassembly or using valgrind) |
82 | | * since you never know what a compiler might do. |
83 | | */ |
84 | | template<typename T> |
85 | | class Mask |
86 | | { |
87 | | public: |
88 | | static_assert(std::is_unsigned<T>::value, "CT::Mask only defined for unsigned integer types"); |
89 | | |
90 | | Mask(const Mask<T>& other) = default; |
91 | | Mask<T>& operator=(const Mask<T>& other) = default; |
92 | | |
93 | | /** |
94 | | * Derive a Mask from a Mask of a larger type |
95 | | */ |
96 | | template<typename U> |
97 | | Mask(Mask<U> o) : m_mask(static_cast<T>(o.value())) |
98 | 9.44k | { |
99 | 9.44k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); |
100 | 9.44k | } Botan::CT::Mask<unsigned char>::Mask<unsigned long>(Botan::CT::Mask<unsigned long>) Line | Count | Source | 98 | 9.44k | { | 99 | 9.44k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); | 100 | 9.44k | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned short>::Mask<unsigned int>(Botan::CT::Mask<unsigned int>) |
101 | | |
102 | | /** |
103 | | * Return a Mask<T> with all bits set |
104 | | */ |
105 | | static Mask<T> set() |
106 | 191k | { |
107 | 191k | return Mask<T>(static_cast<T>(~0)); |
108 | 191k | } Botan::CT::Mask<unsigned char>::set() Line | Count | Source | 106 | 109k | { | 107 | 109k | return Mask<T>(static_cast<T>(~0)); | 108 | 109k | } |
Botan::CT::Mask<unsigned long>::set() Line | Count | Source | 106 | 81.6k | { | 107 | 81.6k | return Mask<T>(static_cast<T>(~0)); | 108 | 81.6k | } |
|
109 | | |
110 | | /** |
111 | | * Return a Mask<T> with all bits cleared |
112 | | */ |
113 | | static Mask<T> cleared() |
114 | 4.76M | { |
115 | 4.76M | return Mask<T>(0); |
116 | 4.76M | } Botan::CT::Mask<unsigned long>::cleared() Line | Count | Source | 114 | 4.76M | { | 115 | 4.76M | return Mask<T>(0); | 116 | 4.76M | } |
Botan::CT::Mask<unsigned char>::cleared() Line | Count | Source | 114 | 812 | { | 115 | 812 | return Mask<T>(0); | 116 | 812 | } |
|
117 | | |
118 | | /** |
119 | | * Return a Mask<T> which is set if v is != 0 |
120 | | */ |
121 | | static Mask<T> expand(T v) |
122 | 2.44G | { |
123 | 2.44G | return ~Mask<T>::is_zero(v); |
124 | 2.44G | } Botan::CT::Mask<unsigned long>::expand(unsigned long) Line | Count | Source | 122 | 2.42G | { | 123 | 2.42G | return ~Mask<T>::is_zero(v); | 124 | 2.42G | } |
Botan::CT::Mask<unsigned char>::expand(unsigned char) Line | Count | Source | 122 | 26.7M | { | 123 | 26.7M | return ~Mask<T>::is_zero(v); | 124 | 26.7M | } |
Botan::CT::Mask<unsigned short>::expand(unsigned short) Line | Count | Source | 122 | 162 | { | 123 | 162 | return ~Mask<T>::is_zero(v); | 124 | 162 | } |
|
125 | | |
126 | | /** |
127 | | * Return a Mask<T> which is set if m is set |
128 | | */ |
129 | | template<typename U> |
130 | | static Mask<T> expand(Mask<U> m) |
131 | 484 | { |
132 | 484 | static_assert(sizeof(U) < sizeof(T), "sizes ok"); |
133 | 484 | return ~Mask<T>::is_zero(m.value()); |
134 | 484 | } |
135 | | |
136 | | /** |
137 | | * Return a Mask<T> which is set if v is == 0 or cleared otherwise |
138 | | */ |
139 | | static Mask<T> is_zero(T x) |
140 | 5.89G | { |
141 | 5.89G | return Mask<T>(ct_is_zero<T>(x)); |
142 | 5.89G | } Botan::CT::Mask<unsigned long>::is_zero(unsigned long) Line | Count | Source | 140 | 5.84G | { | 141 | 5.84G | return Mask<T>(ct_is_zero<T>(x)); | 142 | 5.84G | } |
Botan::CT::Mask<unsigned char>::is_zero(unsigned char) Line | Count | Source | 140 | 47.5M | { | 141 | 47.5M | return Mask<T>(ct_is_zero<T>(x)); | 142 | 47.5M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned int>::is_zero(unsigned int) Botan::CT::Mask<unsigned short>::is_zero(unsigned short) Line | Count | Source | 140 | 31.3k | { | 141 | 31.3k | return Mask<T>(ct_is_zero<T>(x)); | 142 | 31.3k | } |
|
143 | | |
144 | | /** |
145 | | * Return a Mask<T> which is set if x == y |
146 | | */ |
147 | | static Mask<T> is_equal(T x, T y) |
148 | 3.38G | { |
149 | 3.38G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); |
150 | 3.38G | } Botan::CT::Mask<unsigned long>::is_equal(unsigned long, unsigned long) Line | Count | Source | 148 | 3.36G | { | 149 | 3.36G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 150 | 3.36G | } |
Botan::CT::Mask<unsigned char>::is_equal(unsigned char, unsigned char) Line | Count | Source | 148 | 20.2M | { | 149 | 20.2M | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 150 | 20.2M | } |
Botan::CT::Mask<unsigned short>::is_equal(unsigned short, unsigned short) Line | Count | Source | 148 | 31.1k | { | 149 | 31.1k | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 150 | 31.1k | } |
|
151 | | |
152 | | /** |
153 | | * Return a Mask<T> which is set if x < y |
154 | | */ |
155 | | static Mask<T> is_lt(T x, T y) |
156 | 2.42G | { |
157 | 2.42G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); |
158 | 2.42G | } Botan::CT::Mask<unsigned long>::is_lt(unsigned long, unsigned long) Line | Count | Source | 156 | 2.42G | { | 157 | 2.42G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 158 | 2.42G | } |
Botan::CT::Mask<unsigned char>::is_lt(unsigned char, unsigned char) Line | Count | Source | 156 | 1.23M | { | 157 | 1.23M | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 158 | 1.23M | } |
Botan::CT::Mask<unsigned short>::is_lt(unsigned short, unsigned short) Line | Count | Source | 156 | 31.4k | { | 157 | 31.4k | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 158 | 31.4k | } |
|
159 | | |
160 | | /** |
161 | | * Return a Mask<T> which is set if x > y |
162 | | */ |
163 | | static Mask<T> is_gt(T x, T y) |
164 | 1.64M | { |
165 | 1.64M | return Mask<T>::is_lt(y, x); |
166 | 1.64M | } Botan::CT::Mask<unsigned long>::is_gt(unsigned long, unsigned long) Line | Count | Source | 164 | 1.61M | { | 165 | 1.61M | return Mask<T>::is_lt(y, x); | 166 | 1.61M | } |
Botan::CT::Mask<unsigned char>::is_gt(unsigned char, unsigned char) Line | Count | Source | 164 | 142 | { | 165 | 142 | return Mask<T>::is_lt(y, x); | 166 | 142 | } |
Botan::CT::Mask<unsigned short>::is_gt(unsigned short, unsigned short) Line | Count | Source | 164 | 31.1k | { | 165 | 31.1k | return Mask<T>::is_lt(y, x); | 166 | 31.1k | } |
|
167 | | |
168 | | /** |
169 | | * Return a Mask<T> which is set if x <= y |
170 | | */ |
171 | | static Mask<T> is_lte(T x, T y) |
172 | 1.63M | { |
173 | 1.63M | return ~Mask<T>::is_gt(x, y); |
174 | 1.63M | } Botan::CT::Mask<unsigned long>::is_lte(unsigned long, unsigned long) Line | Count | Source | 172 | 1.60M | { | 173 | 1.60M | return ~Mask<T>::is_gt(x, y); | 174 | 1.60M | } |
Botan::CT::Mask<unsigned short>::is_lte(unsigned short, unsigned short) Line | Count | Source | 172 | 31.1k | { | 173 | 31.1k | return ~Mask<T>::is_gt(x, y); | 174 | 31.1k | } |
|
175 | | |
176 | | /** |
177 | | * Return a Mask<T> which is set if x >= y |
178 | | */ |
179 | | static Mask<T> is_gte(T x, T y) |
180 | 755M | { |
181 | 755M | return ~Mask<T>::is_lt(x, y); |
182 | 755M | } |
183 | | |
184 | | static Mask<T> is_within_range(T v, T l, T u) |
185 | 26.1M | { |
186 | | //return Mask<T>::is_gte(v, l) & Mask<T>::is_lte(v, u); |
187 | | |
188 | 26.1M | const T v_lt_l = v^((v^l) | ((v-l)^v)); |
189 | 26.1M | const T v_gt_u = u^((u^v) | ((u-v)^u)); |
190 | 26.1M | const T either = v_lt_l | v_gt_u; |
191 | 26.1M | return ~Mask<T>(expand_top_bit(either)); |
192 | 26.1M | } |
193 | | |
194 | | static Mask<T> is_any_of(T v, std::initializer_list<T> accepted) |
195 | 8.73M | { |
196 | 8.73M | T accept = 0; |
197 | | |
198 | 8.73M | for(auto a: accepted) |
199 | 34.9M | { |
200 | 34.9M | const T diff = a ^ v; |
201 | 34.9M | const T eq_zero = ~diff & (diff - 1); |
202 | 34.9M | accept |= eq_zero; |
203 | 34.9M | } |
204 | | |
205 | 8.73M | return Mask<T>(expand_top_bit(accept)); |
206 | 8.73M | } |
207 | | |
208 | | /** |
209 | | * AND-combine two masks |
210 | | */ |
211 | | Mask<T>& operator&=(Mask<T> o) |
212 | 1.80M | { |
213 | 1.80M | m_mask &= o.value(); |
214 | 1.80M | return (*this); |
215 | 1.80M | } Botan::CT::Mask<unsigned long>::operator&=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 212 | 1.61M | { | 213 | 1.61M | m_mask &= o.value(); | 214 | 1.61M | return (*this); | 215 | 1.61M | } |
Botan::CT::Mask<unsigned char>::operator&=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 212 | 191k | { | 213 | 191k | m_mask &= o.value(); | 214 | 191k | return (*this); | 215 | 191k | } |
|
216 | | |
217 | | /** |
218 | | * XOR-combine two masks |
219 | | */ |
220 | | Mask<T>& operator^=(Mask<T> o) |
221 | | { |
222 | | m_mask ^= o.value(); |
223 | | return (*this); |
224 | | } |
225 | | |
226 | | /** |
227 | | * OR-combine two masks |
228 | | */ |
229 | | Mask<T>& operator|=(Mask<T> o) |
230 | 77.9M | { |
231 | 77.9M | m_mask |= o.value(); |
232 | 77.9M | return (*this); |
233 | 77.9M | } Botan::CT::Mask<unsigned long>::operator|=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 230 | 77.1M | { | 231 | 77.1M | m_mask |= o.value(); | 232 | 77.1M | return (*this); | 233 | 77.1M | } |
Botan::CT::Mask<unsigned char>::operator|=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 230 | 766k | { | 231 | 766k | m_mask |= o.value(); | 232 | 766k | return (*this); | 233 | 766k | } |
Botan::CT::Mask<unsigned short>::operator|=(Botan::CT::Mask<unsigned short>) Line | Count | Source | 230 | 31.0k | { | 231 | 31.0k | m_mask |= o.value(); | 232 | 31.0k | return (*this); | 233 | 31.0k | } |
|
234 | | |
235 | | /** |
236 | | * AND-combine two masks |
237 | | */ |
238 | | friend Mask<T> operator&(Mask<T> x, Mask<T> y) |
239 | 170M | { |
240 | 170M | return Mask<T>(x.value() & y.value()); |
241 | 170M | } Botan::CT::operator&(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 239 | 554k | { | 240 | 554k | return Mask<T>(x.value() & y.value()); | 241 | 554k | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 239 | 170M | { | 240 | 170M | return Mask<T>(x.value() & y.value()); | 241 | 170M | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned short>, Botan::CT::Mask<unsigned short>) Line | Count | Source | 239 | 31.2k | { | 240 | 31.2k | return Mask<T>(x.value() & y.value()); | 241 | 31.2k | } |
|
242 | | |
243 | | /** |
244 | | * XOR-combine two masks |
245 | | */ |
246 | | friend Mask<T> operator^(Mask<T> x, Mask<T> y) |
247 | 262k | { |
248 | 262k | return Mask<T>(x.value() ^ y.value()); |
249 | 262k | } |
250 | | |
251 | | /** |
252 | | * OR-combine two masks |
253 | | */ |
254 | | friend Mask<T> operator|(Mask<T> x, Mask<T> y) |
255 | 926M | { |
256 | 926M | return Mask<T>(x.value() | y.value()); |
257 | 926M | } Botan::CT::operator|(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 255 | 192k | { | 256 | 192k | return Mask<T>(x.value() | y.value()); | 257 | 192k | } |
Botan::CT::operator|(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 255 | 926M | { | 256 | 926M | return Mask<T>(x.value() | y.value()); | 257 | 926M | } |
|
258 | | |
259 | | /** |
260 | | * Negate this mask |
261 | | */ |
262 | | Mask<T> operator~() const |
263 | 3.23G | { |
264 | 3.23G | return Mask<T>(~value()); |
265 | 3.23G | } Botan::CT::Mask<unsigned long>::operator~() const Line | Count | Source | 263 | 3.17G | { | 264 | 3.17G | return Mask<T>(~value()); | 265 | 3.17G | } |
Botan::CT::Mask<unsigned char>::operator~() const Line | Count | Source | 263 | 53.4M | { | 264 | 53.4M | return Mask<T>(~value()); | 265 | 53.4M | } |
Botan::CT::Mask<unsigned short>::operator~() const Line | Count | Source | 263 | 62.4k | { | 264 | 62.4k | return Mask<T>(~value()); | 265 | 62.4k | } |
|
266 | | |
267 | | /** |
268 | | * Return x if the mask is set, or otherwise zero |
269 | | */ |
270 | | T if_set_return(T x) const |
271 | 7.44G | { |
272 | 7.44G | return m_mask & x; |
273 | 7.44G | } Botan::CT::Mask<unsigned long>::if_set_return(unsigned long) const Line | Count | Source | 271 | 7.44G | { | 272 | 7.44G | return m_mask & x; | 273 | 7.44G | } |
Botan::CT::Mask<unsigned char>::if_set_return(unsigned char) const Line | Count | Source | 271 | 191k | { | 272 | 191k | return m_mask & x; | 273 | 191k | } |
Botan::CT::Mask<unsigned short>::if_set_return(unsigned short) const Line | Count | Source | 271 | 162 | { | 272 | 162 | return m_mask & x; | 273 | 162 | } |
|
274 | | |
275 | | /** |
276 | | * Return x if the mask is cleared, or otherwise zero |
277 | | */ |
278 | | T if_not_set_return(T x) const |
279 | 78.4M | { |
280 | 78.4M | return ~m_mask & x; |
281 | 78.4M | } Botan::CT::Mask<unsigned long>::if_not_set_return(unsigned long) const Line | Count | Source | 279 | 77.3M | { | 280 | 77.3M | return ~m_mask & x; | 281 | 77.3M | } |
Botan::CT::Mask<unsigned char>::if_not_set_return(unsigned char) const Line | Count | Source | 279 | 1.05M | { | 280 | 1.05M | return ~m_mask & x; | 281 | 1.05M | } |
Botan::CT::Mask<unsigned short>::if_not_set_return(unsigned short) const Line | Count | Source | 279 | 276 | { | 280 | 276 | return ~m_mask & x; | 281 | 276 | } |
|
282 | | |
283 | | /** |
284 | | * If this mask is set, return x, otherwise return y |
285 | | */ |
286 | | T select(T x, T y) const |
287 | 14.0G | { |
288 | 14.0G | return choose(value(), x, y); |
289 | 14.0G | } Botan::CT::Mask<unsigned long>::select(unsigned long, unsigned long) const Line | Count | Source | 287 | 13.9G | { | 288 | 13.9G | return choose(value(), x, y); | 289 | 13.9G | } |
Botan::CT::Mask<unsigned char>::select(unsigned char, unsigned char) const Line | Count | Source | 287 | 82.1M | { | 288 | 82.1M | return choose(value(), x, y); | 289 | 82.1M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned short>::select(unsigned short, unsigned short) const |
290 | | |
291 | | T select_and_unpoison(T x, T y) const |
292 | 606 | { |
293 | 606 | T r = this->select(x, y); |
294 | 606 | CT::unpoison(r); |
295 | 606 | return r; |
296 | 606 | } Botan::CT::Mask<unsigned long>::select_and_unpoison(unsigned long, unsigned long) const Line | Count | Source | 292 | 464 | { | 293 | 464 | T r = this->select(x, y); | 294 | 464 | CT::unpoison(r); | 295 | 464 | return r; | 296 | 464 | } |
Botan::CT::Mask<unsigned char>::select_and_unpoison(unsigned char, unsigned char) const Line | Count | Source | 292 | 142 | { | 293 | 142 | T r = this->select(x, y); | 294 | 142 | CT::unpoison(r); | 295 | 142 | return r; | 296 | 142 | } |
|
297 | | |
298 | | /** |
299 | | * If this mask is set, return x, otherwise return y |
300 | | */ |
301 | | Mask<T> select_mask(Mask<T> x, Mask<T> y) const |
302 | 1.21G | { |
303 | 1.21G | return Mask<T>(select(x.value(), y.value())); |
304 | 1.21G | } |
305 | | |
306 | | /** |
307 | | * Conditionally set output to x or y, depending on if mask is set or |
308 | | * cleared (resp) |
309 | | */ |
310 | | void select_n(T output[], const T x[], const T y[], size_t len) const |
311 | 404M | { |
312 | 3.49G | for(size_t i = 0; i != len; ++i) |
313 | 3.08G | output[i] = this->select(x[i], y[i]); |
314 | 404M | } Botan::CT::Mask<unsigned long>::select_n(unsigned long*, unsigned long const*, unsigned long const*, unsigned long) const Line | Count | Source | 311 | 404M | { | 312 | 3.49G | for(size_t i = 0; i != len; ++i) | 313 | 3.08G | output[i] = this->select(x[i], y[i]); | 314 | 404M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned char>::select_n(unsigned char*, unsigned char const*, unsigned char const*, unsigned long) const |
315 | | |
316 | | /** |
317 | | * If this mask is set, zero out buf, otherwise do nothing |
318 | | */ |
319 | | void if_set_zero_out(T buf[], size_t elems) |
320 | 80.6k | { |
321 | 482k | for(size_t i = 0; i != elems; ++i) |
322 | 401k | { |
323 | 401k | buf[i] = this->if_not_set_return(buf[i]); |
324 | 401k | } |
325 | 80.6k | } |
326 | | |
327 | | /** |
328 | | * Return the value of the mask, unpoisoned |
329 | | */ |
330 | | T unpoisoned_value() const |
331 | 770M | { |
332 | 770M | T r = value(); |
333 | 770M | CT::unpoison(r); |
334 | 770M | return r; |
335 | 770M | } Botan::CT::Mask<unsigned long>::unpoisoned_value() const Line | Count | Source | 331 | 770M | { | 332 | 770M | T r = value(); | 333 | 770M | CT::unpoison(r); | 334 | 770M | return r; | 335 | 770M | } |
Botan::CT::Mask<unsigned char>::unpoisoned_value() const Line | Count | Source | 331 | 109k | { | 332 | 109k | T r = value(); | 333 | 109k | CT::unpoison(r); | 334 | 109k | return r; | 335 | 109k | } |
Botan::CT::Mask<unsigned short>::unpoisoned_value() const Line | Count | Source | 331 | 81 | { | 332 | 81 | T r = value(); | 333 | 81 | CT::unpoison(r); | 334 | 81 | return r; | 335 | 81 | } |
|
336 | | |
337 | | /** |
338 | | * Return true iff this mask is set |
339 | | */ |
340 | | bool is_set() const |
341 | 770M | { |
342 | 770M | return unpoisoned_value() != 0; |
343 | 770M | } Botan::CT::Mask<unsigned long>::is_set() const Line | Count | Source | 341 | 770M | { | 342 | 770M | return unpoisoned_value() != 0; | 343 | 770M | } |
Botan::CT::Mask<unsigned char>::is_set() const Line | Count | Source | 341 | 109k | { | 342 | 109k | return unpoisoned_value() != 0; | 343 | 109k | } |
Botan::CT::Mask<unsigned short>::is_set() const Line | Count | Source | 341 | 81 | { | 342 | 81 | return unpoisoned_value() != 0; | 343 | 81 | } |
|
344 | | |
345 | | /** |
346 | | * Return the underlying value of the mask |
347 | | */ |
348 | | T value() const |
349 | 22.9G | { |
350 | 22.9G | return m_mask; |
351 | 22.9G | } Botan::CT::Mask<unsigned long>::value() const Line | Count | Source | 349 | 22.7G | { | 350 | 22.7G | return m_mask; | 351 | 22.7G | } |
Botan::CT::Mask<unsigned char>::value() const Line | Count | Source | 349 | 138M | { | 350 | 138M | return m_mask; | 351 | 138M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned int>::value() const Botan::CT::Mask<unsigned short>::value() const Line | Count | Source | 349 | 156k | { | 350 | 156k | return m_mask; | 351 | 156k | } |
|
352 | | |
353 | | private: |
354 | 13.9G | Mask(T m) : m_mask(m) {} Botan::CT::Mask<unsigned long>::Mask(unsigned long) Line | Count | Source | 354 | 13.7G | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned char>::Mask(unsigned char) Line | Count | Source | 354 | 138M | Mask(T m) : m_mask(m) {} |
Unexecuted instantiation: Botan::CT::Mask<unsigned int>::Mask(unsigned int) Botan::CT::Mask<unsigned short>::Mask(unsigned short) Line | Count | Source | 354 | 156k | Mask(T m) : m_mask(m) {} |
|
355 | | |
356 | | T m_mask; |
357 | | }; |
358 | | |
359 | | template<typename T> |
360 | | inline Mask<T> conditional_copy_mem(T cnd, |
361 | | T* to, |
362 | | const T* from0, |
363 | | const T* from1, |
364 | | size_t elems) |
365 | 126M | { |
366 | 126M | const auto mask = CT::Mask<T>::expand(cnd); |
367 | 126M | mask.select_n(to, from0, from1, elems); |
368 | 126M | return mask; |
369 | 126M | } |
370 | | |
371 | | template<typename T> |
372 | | inline void conditional_swap(bool cnd, T& x, T& y) |
373 | 42.1M | { |
374 | 42.1M | const auto swap = CT::Mask<T>::expand(cnd); |
375 | | |
376 | 42.1M | T t0 = swap.select(y, x); |
377 | 42.1M | T t1 = swap.select(x, y); |
378 | 42.1M | x = t0; |
379 | 42.1M | y = t1; |
380 | 42.1M | } |
381 | | |
382 | | template<typename T> |
383 | | inline void conditional_swap_ptr(bool cnd, T& x, T& y) |
384 | 21.0M | { |
385 | 21.0M | uintptr_t xp = reinterpret_cast<uintptr_t>(x); |
386 | 21.0M | uintptr_t yp = reinterpret_cast<uintptr_t>(y); |
387 | | |
388 | 21.0M | conditional_swap<uintptr_t>(cnd, xp, yp); |
389 | | |
390 | 21.0M | x = reinterpret_cast<T>(xp); |
391 | 21.0M | y = reinterpret_cast<T>(yp); |
392 | 21.0M | } |
393 | | |
394 | | /** |
395 | | * If bad_input is unset, return input[offset:input_length] copied to new |
396 | | * buffer. If bad_input is set, return an empty vector. In all cases, the capacity |
397 | | * of the vector is equal to input_length |
398 | | * |
399 | | * This function attempts to avoid leaking the following: |
400 | | * - if bad_input was set or not |
401 | | * - the value of offset |
402 | | * - the values in input[] |
403 | | * |
404 | | * This function leaks the value of input_length |
405 | | */ |
406 | | BOTAN_TEST_API |
407 | | secure_vector<uint8_t> copy_output(CT::Mask<uint8_t> bad_input, |
408 | | const uint8_t input[], |
409 | | size_t input_length, |
410 | | size_t offset); |
411 | | |
412 | | secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length); |
413 | | |
414 | | inline secure_vector<uint8_t> strip_leading_zeros(const secure_vector<uint8_t>& in) |
415 | 0 | { |
416 | 0 | return strip_leading_zeros(in.data(), in.size()); |
417 | 0 | } |
418 | | |
419 | | } |
420 | | |
421 | | } |
422 | | |
423 | | #endif |