diff options
author | Jack Lloyd <[email protected]> | 2016-01-03 19:56:04 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-01-03 19:56:04 -0500 |
commit | 77b8eb8a4ed5f5b63710afd85766e8f30d0bd2d9 (patch) | |
tree | d17fcc018b990faaedc523dc6025ca655dcd4805 | |
parent | 9ec5243e2dc8fba1d024269f1a756af7df0421b8 (diff) |
Use valgrind's memcheck API for checking const time annotations
Has the same effect as using ctgrind, but without requiring a
custom-compiled valgrind binary.
Add ct checking annotations to the SSSE3 AES code.
-rw-r--r-- | doc/news.rst | 17 | ||||
-rw-r--r-- | src/build-data/buildh.in | 6 | ||||
-rw-r--r-- | src/lib/block/aes_ssse3/aes_ssse3.cpp | 33 | ||||
-rw-r--r-- | src/lib/utils/ct_utils.h | 41 |
4 files changed, 74 insertions, 23 deletions
diff --git a/doc/news.rst b/doc/news.rst index 89f9aa6de..04996a938 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -17,10 +17,10 @@ Version 1.11.26, Not Yet Released indicating support for the extended master secret flag, which is needed for proper handling of the extension. -* Root all exceptions thrown by the library in the `Botan::Exception` class. - Previously the library would in many cases throw `std::runtime_error` - or `std::invalid_argument` exceptions which would make it hard to determine - the source of the error in some cases. +* Root all exceptions thrown by the library in the ``Botan::Exception`` class. + Previously the library would in many cases throw ``std::runtime_error`` + or ``std::invalid_argument`` exceptions which would make it hard to + determine the source of the error in some cases. * The command line interface has been mostly rewritten. The syntax of many of the sub-programs has changed, and a number have been @@ -65,7 +65,7 @@ Version 1.11.26, Not Yet Released are corner cases where this can occur, such as pointing to the very end of a buffer. -* The function `RandomNumberGenerator::gen_mask` (added in 1.11.20) +* The function ``RandomNumberGenerator::gen_mask`` (added in 1.11.20) had undefined behavior when called with a bits value of 32 or higher, and was tested to behave in unpleasant ways (such as returning zero) when compiled by common compilers. This function was @@ -73,6 +73,13 @@ Version 1.11.26, Not Yet Released something without a use case to justify it it seemed simpler to remove it. Undefined behavior found by Daniel Neus. +* Support for using ``ctgrind`` for checking const time blocks has + been replaced by calling the valgrind memcheck APIs directly. This + allows const-time behavior to be tested without requiring a modified + valgrind binary. Adding the appropriate calls requires defining + BOTAN_HAS_VALGRIND in build.h. A binary compiled with this flag set + can still run normally (though with some slight runtime overhead). + * Export MGF1 function mgf1_mask GH #380 Version 1.11.25, 2015-12-07 diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 967e067e4..6ee309bdc 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -98,10 +98,10 @@ #define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1 /* -* Define BOTAN_USE_CTGRIND to enable checking constant time -* annotations using ctgrind https://github.com/agl/ctgrind +* Define BOTAN_HAS_VALGRIND to enable checking constant time annotations +* TODO: expose as configure.py flag --with-valgrind */ -//#define BOTAN_USE_CTGRIND +#define BOTAN_HAS_VALGRIND /* * RNGs will automatically poll the system for additional seed material diff --git a/src/lib/block/aes_ssse3/aes_ssse3.cpp b/src/lib/block/aes_ssse3/aes_ssse3.cpp index bfc76ecee..373a5265a 100644 --- a/src/lib/block/aes_ssse3/aes_ssse3.cpp +++ b/src/lib/block/aes_ssse3/aes_ssse3.cpp @@ -1,6 +1,6 @@ /* * AES using SSSE3 -* (C) 2010 Jack Lloyd +* (C) 2010,2016 Jack Lloyd * * This is more or less a direct translation of public domain x86-64 * assembly written by Mike Hamburg, described in "Accelerating AES @@ -12,6 +12,7 @@ #include <botan/aes_ssse3.h> #include <botan/cpuid.h> +#include <botan/internal/ct_utils.h> #include <tmmintrin.h> namespace Botan { @@ -345,11 +346,16 @@ void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 10)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* @@ -362,11 +368,16 @@ void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 10)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* @@ -423,11 +434,16 @@ void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 12)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* @@ -440,11 +456,16 @@ void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 12)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* @@ -530,11 +551,16 @@ void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(EK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 14)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* @@ -547,11 +573,16 @@ void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const const __m128i* keys = reinterpret_cast<const __m128i*>(DK.data()); + CT::poison(in, blocks * block_size()); + for(size_t i = 0; i != blocks; ++i) { __m128i B = _mm_loadu_si128(in_mm + i); _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 14)); } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); } /* diff --git a/src/lib/utils/ct_utils.h b/src/lib/utils/ct_utils.h index 2307dd587..a10e242a6 100644 --- a/src/lib/utils/ct_utils.h +++ b/src/lib/utils/ct_utils.h @@ -1,12 +1,12 @@ /* * Functions for constant time operations on data and testing of -* constant time annotations using ctgrind. +* 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 Jack Lloyd +* (C) 2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -17,23 +17,36 @@ #include <botan/secmem.h> #include <vector> -#if defined(BOTAN_USE_CTGRIND) - -// These are external symbols from libctgrind.so -extern "C" void ct_poison(const void* address, size_t length); -extern "C" void ct_unpoison(const void* address, size_t length); - +#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(T* p, size_t n) +inline void poison(const T* p, size_t n) { -#if defined(BOTAN_USE_CTGRIND) - ct_poison(p, sizeof(T)*n); +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); #else BOTAN_UNUSED(p); BOTAN_UNUSED(n); @@ -41,10 +54,10 @@ inline void poison(T* p, size_t n) } template<typename T> -inline void unpoison(T* p, size_t n) +inline void unpoison(const T* p, size_t n) { -#if defined(BOTAN_USE_CTGRIND) - ct_unpoison(p, sizeof(T)*n); +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); #else BOTAN_UNUSED(p); BOTAN_UNUSED(n); |