diff options
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/utils/ct_utils.h')
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/utils/ct_utils.h | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h b/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h new file mode 100644 index 0000000000..0132678742 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h @@ -0,0 +1,208 @@ +/* +* Functions for constant time operations on data and testing of +* constant time annotations using valgrind. +* +* For more information about constant time programming see +* Wagner, Molnar, et al "The Program Counter Security Model" +* +* (C) 2010 Falko Strenzke +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIMING_ATTACK_CM_H_ +#define BOTAN_TIMING_ATTACK_CM_H_ + +#include <botan/secmem.h> +#include <vector> + +#if defined(BOTAN_HAS_VALGRIND) + #include <valgrind/memcheck.h> +#endif + +namespace Botan { + +namespace CT { + +/** +* Use valgrind to mark the contents of memory as being undefined. +* Valgrind will accept operations which manipulate undefined values, +* but will warn if an undefined value is used to decided a conditional +* jump or a load/store address. So if we poison all of our inputs we +* can confirm that the operations in question are truly const time +* when compiled by whatever compiler is in use. +* +* Even better, the VALGRIND_MAKE_MEM_* macros work even when the +* program is not run under valgrind (though with a few cycles of +* overhead, which is unfortunate in final binaries as these +* annotations tend to be used in fairly important loops). +* +* This approach was first used in ctgrind (https://github.com/agl/ctgrind) +* but calling the valgrind mecheck API directly works just as well and +* doesn't require a custom patched valgrind. +*/ +template<typename T> +inline void poison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template<typename T> +inline void unpoison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template<typename T> +inline void unpoison(T& p) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); +#else + BOTAN_UNUSED(p); +#endif + } + +/* +* T should be an unsigned machine integer type +* Expand to a mask used for other operations +* @param in an integer +* @return If n is zero, returns zero. Otherwise +* returns a T with all bits set for use as a mask with +* select. +*/ +template<typename T> +inline T expand_mask(T x) + { + T r = x; + // First fold r down to a single bit + for(size_t i = 1; i != sizeof(T)*8; i *= 2) + { + r = r | static_cast<T>(r >> i); + } + r &= 1; + r = static_cast<T>(~(r - 1)); + return r; + } + +template<typename T> +inline T expand_top_bit(T a) + { + return expand_mask<T>(a >> (sizeof(T)*8-1)); + } + +template<typename T> +inline T select(T mask, T from0, T from1) + { + return static_cast<T>((from0 & mask) | (from1 & ~mask)); + } + +template<typename T> +inline T select2(T mask0, T val0, T mask1, T val1, T val2) + { + return select<T>(mask0, val0, select<T>(mask1, val1, val2)); + } + +template<typename T> +inline T select3(T mask0, T val0, T mask1, T val1, T mask2, T val2, T val3) + { + return select2<T>(mask0, val0, mask1, val1, select<T>(mask2, val2, val3)); + } + +template<typename PredT, typename ValT> +inline ValT val_or_zero(PredT pred_val, ValT val) + { + return select(CT::expand_mask<ValT>(pred_val), val, static_cast<ValT>(0)); + } + +template<typename T> +inline T is_zero(T x) + { + return static_cast<T>(~expand_mask(x)); + } + +template<typename T> +inline T is_equal(T x, T y) + { + return is_zero<T>(x ^ y); + } + +template<typename T> +inline T is_less(T a, T b) + { + return expand_top_bit<T>(a ^ ((a^b) | ((a-b)^a))); + } + +template<typename T> +inline T is_lte(T a, T b) + { + return CT::is_less(a, b) | CT::is_equal(a, b); + } + +template<typename T> +inline T conditional_copy_mem(T value, + T* to, + const T* from0, + const T* from1, + size_t elems) + { + const T mask = CT::expand_mask(value); + + for(size_t i = 0; i != elems; ++i) + { + to[i] = CT::select(mask, from0[i], from1[i]); + } + + return mask; + } + +template<typename T> +inline void cond_zero_mem(T cond, + T* array, + size_t elems) + { + const T mask = CT::expand_mask(cond); + const T zero(0); + + for(size_t i = 0; i != elems; ++i) + { + array[i] = CT::select(mask, zero, array[i]); + } + } + +inline secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length) + { + size_t leading_zeros = 0; + + uint8_t only_zeros = 0xFF; + + for(size_t i = 0; i != length; ++i) + { + only_zeros = only_zeros & CT::is_zero<uint8_t>(in[i]); + leading_zeros += CT::select<uint8_t>(only_zeros, 1, 0); + } + + return secure_vector<uint8_t>(in + leading_zeros, in + length); + } + +inline secure_vector<uint8_t> strip_leading_zeros(const secure_vector<uint8_t>& in) + { + return strip_leading_zeros(in.data(), in.size()); + } + +} + +} + +#endif |