aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-01-03 19:56:04 -0500
committerJack Lloyd <[email protected]>2016-01-03 19:56:04 -0500
commit77b8eb8a4ed5f5b63710afd85766e8f30d0bd2d9 (patch)
treed17fcc018b990faaedc523dc6025ca655dcd4805 /src
parent9ec5243e2dc8fba1d024269f1a756af7df0421b8 (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.
Diffstat (limited to 'src')
-rw-r--r--src/build-data/buildh.in6
-rw-r--r--src/lib/block/aes_ssse3/aes_ssse3.cpp33
-rw-r--r--src/lib/utils/ct_utils.h41
3 files changed, 62 insertions, 18 deletions
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);