2
* Functions for constant time operations on data and testing of
3
* constant time annotations using valgrind.
5
* For more information about constant time programming see
6
* Wagner, Molnar, et al "The Program Counter Security Model"
8
* (C) 2010 Falko Strenzke
9
* (C) 2015,2016 Jack Lloyd
11
* Botan is released under the Simplified BSD License (see license.txt)
14
#ifndef BOTAN_TIMING_ATTACK_CM_H_
15
#define BOTAN_TIMING_ATTACK_CM_H_
17
#include <botan/secmem.h>
20
#if defined(BOTAN_HAS_VALGRIND)
21
#include <valgrind/memcheck.h>
29
* Use valgrind to mark the contents of memory as being undefined.
30
* Valgrind will accept operations which manipulate undefined values,
31
* but will warn if an undefined value is used to decided a conditional
32
* jump or a load/store address. So if we poison all of our inputs we
33
* can confirm that the operations in question are truly const time
34
* when compiled by whatever compiler is in use.
36
* Even better, the VALGRIND_MAKE_MEM_* macros work even when the
37
* program is not run under valgrind (though with a few cycles of
38
* overhead, which is unfortunate in final binaries as these
39
* annotations tend to be used in fairly important loops).
41
* This approach was first used in ctgrind (https://github.com/agl/ctgrind)
42
* but calling the valgrind mecheck API directly works just as well and
43
* doesn't require a custom patched valgrind.
46
inline void poison(const T* p, size_t n)
48
#if defined(BOTAN_HAS_VALGRIND)
49
VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
57
inline void unpoison(const T* p, size_t n)
59
#if defined(BOTAN_HAS_VALGRIND)
60
VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T));
68
inline void unpoison(T& p)
70
#if defined(BOTAN_HAS_VALGRIND)
71
VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T));
78
* T should be an unsigned machine integer type
79
* Expand to a mask used for other operations
80
* @param in an integer
81
* @return If n is zero, returns zero. Otherwise
82
* returns a T with all bits set for use as a mask with
86
inline T expand_mask(T x)
89
// First fold r down to a single bit
90
for(size_t i = 1; i != sizeof(T)*8; i *= 2)
92
r = r | static_cast<T>(r >> i);
95
r = static_cast<T>(~(r - 1));
100
inline T expand_top_bit(T a)
102
return expand_mask<T>(a >> (sizeof(T)*8-1));
106
inline T select(T mask, T from0, T from1)
108
return static_cast<T>((from0 & mask) | (from1 & ~mask));
111
template<typename PredT, typename ValT>
112
inline ValT val_or_zero(PredT pred_val, ValT val)
114
return select(CT::expand_mask<ValT>(pred_val), val, static_cast<ValT>(0));
118
inline T is_zero(T x)
120
return static_cast<T>(~expand_mask(x));
124
inline T is_equal(T x, T y)
126
return is_zero<T>(x ^ y);
130
inline T is_less(T a, T b)
132
return expand_top_bit<T>(a ^ ((a^b) | ((a-b)^a)));
136
inline T is_lte(T a, T b)
138
return CT::is_less(a, b) | CT::is_equal(a, b);
142
inline void conditional_copy_mem(T value,
148
const T mask = CT::expand_mask(value);
150
for(size_t i = 0; i != elems; ++i)
152
to[i] = CT::select(mask, from0[i], from1[i]);
157
inline void cond_zero_mem(T cond,
161
const T mask = CT::expand_mask(cond);
164
for(size_t i = 0; i != elems; ++i)
166
array[i] = CT::select(mask, zero, array[i]);
170
inline secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length)
172
size_t leading_zeros = 0;
174
uint8_t only_zeros = 0xFF;
176
for(size_t i = 0; i != length; ++i)
178
only_zeros = only_zeros & CT::is_zero<uint8_t>(in[i]);
179
leading_zeros += CT::select<uint8_t>(only_zeros, 1, 0);
182
return secure_vector<uint8_t>(in + leading_zeros, in + length);
185
inline secure_vector<uint8_t> strip_leading_zeros(const secure_vector<uint8_t>& in)
187
return strip_leading_zeros(in.data(), in.size());