aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2016-03-30 15:37:41 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2016-05-13 10:22:54 +0200
commit6bec172eb95e195847bb6dd6d4e62ada79c98c6d (patch)
tree741f48e6f1aeaa04652605d732a6ee8ae4b248ae
parentcd2be4419e9d8c6445fecc877b50198dc918a81f (diff)
Add ctaes-based constant time AES implementation
-rw-r--r--src/Makefile.am4
-rw-r--r--src/crypto/aes.cpp73
-rw-r--r--src/crypto/aes.h66
-rw-r--r--src/test/crypto_tests.cpp56
4 files changed, 198 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3c056386fa..0ab0d66ac2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -225,6 +225,8 @@ libbitcoin_wallet_a_SOURCES = \
crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
+ crypto/aes.cpp \
+ crypto/aes.h \
crypto/common.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
@@ -434,7 +436,7 @@ CLEANFILES += zmq/*.gcda zmq/*.gcno
DISTCLEANFILES = obj/build.h
-EXTRA_DIST = leveldb
+EXTRA_DIST = leveldb crypto/ctaes
clean-local:
-$(MAKE) -C leveldb clean
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
new file mode 100644
index 0000000000..035abd75bd
--- /dev/null
+++ b/src/crypto/aes.cpp
@@ -0,0 +1,73 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "aes.h"
+#include "crypto/common.h"
+
+#include <assert.h>
+#include <string.h>
+
+extern "C" {
+#include "crypto/ctaes/ctaes.c"
+}
+
+AES128Encrypt::AES128Encrypt(const unsigned char key[16])
+{
+ AES128_init(&ctx, key);
+}
+
+AES128Encrypt::~AES128Encrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES128Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
+{
+ AES128_encrypt(&ctx, 1, ciphertext, plaintext);
+}
+
+AES128Decrypt::AES128Decrypt(const unsigned char key[16])
+{
+ AES128_init(&ctx, key);
+}
+
+AES128Decrypt::~AES128Decrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES128Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
+{
+ AES128_decrypt(&ctx, 1, plaintext, ciphertext);
+}
+
+AES256Encrypt::AES256Encrypt(const unsigned char key[32])
+{
+ AES256_init(&ctx, key);
+}
+
+AES256Encrypt::~AES256Encrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES256Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
+{
+ AES256_encrypt(&ctx, 1, ciphertext, plaintext);
+}
+
+AES256Decrypt::AES256Decrypt(const unsigned char key[32])
+{
+ AES256_init(&ctx, key);
+}
+
+AES256Decrypt::~AES256Decrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES256Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
+{
+ AES256_decrypt(&ctx, 1, plaintext, ciphertext);
+}
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
new file mode 100644
index 0000000000..4bf17a33ea
--- /dev/null
+++ b/src/crypto/aes.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+// C++ wrapper around ctaes, a constant-time AES implementation
+
+#ifndef BITCOIN_CRYPTO_AES_H
+#define BITCOIN_CRYPTO_AES_H
+
+extern "C" {
+#include "crypto/ctaes/ctaes.h"
+}
+
+static const int AES_BLOCKSIZE = 16;
+static const int AES128_KEYSIZE = 16;
+static const int AES256_KEYSIZE = 32;
+
+/** An encryption class for AES-128. */
+class AES128Encrypt
+{
+private:
+ AES128_ctx ctx;
+
+public:
+ AES128Encrypt(const unsigned char key[16]);
+ ~AES128Encrypt();
+ void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
+};
+
+/** A decryption class for AES-128. */
+class AES128Decrypt
+{
+private:
+ AES128_ctx ctx;
+
+public:
+ AES128Decrypt(const unsigned char key[16]);
+ ~AES128Decrypt();
+ void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
+};
+
+/** An encryption class for AES-256. */
+class AES256Encrypt
+{
+private:
+ AES256_ctx ctx;
+
+public:
+ AES256Encrypt(const unsigned char key[32]);
+ ~AES256Encrypt();
+ void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
+};
+
+/** A decryption class for AES-256. */
+class AES256Decrypt
+{
+private:
+ AES256_ctx ctx;
+
+public:
+ AES256Decrypt(const unsigned char key[32]);
+ ~AES256Decrypt();
+ void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
+};
+
+#endif // BITCOIN_CRYPTO_AES_H
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 0b46d718d1..3fc9855d6a 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "crypto/aes.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
@@ -63,6 +64,45 @@ void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const s
TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
}
+void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> buf, buf2;
+
+ assert(key.size() == 16);
+ assert(in.size() == 16);
+ assert(correctout.size() == 16);
+ AES128Encrypt enc(&key[0]);
+ buf.resize(correctout.size());
+ buf2.resize(correctout.size());
+ enc.Encrypt(&buf[0], &in[0]);
+ BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));
+ AES128Decrypt dec(&key[0]);
+ dec.Decrypt(&buf2[0], &buf[0]);
+ BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));
+}
+
+void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> buf;
+
+ assert(key.size() == 32);
+ assert(in.size() == 16);
+ assert(correctout.size() == 16);
+ AES256Encrypt enc(&key[0]);
+ buf.resize(correctout.size());
+ enc.Encrypt(&buf[0], &in[0]);
+ BOOST_CHECK(buf == correctout);
+ AES256Decrypt dec(&key[0]);
+ dec.Decrypt(&buf[0], &buf[0]);
+ BOOST_CHECK(buf == in);
+}
+
std::string LongTestString(void) {
std::string ret;
for (int i=0; i<200000; i++) {
@@ -248,4 +288,20 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
}
+BOOST_AUTO_TEST_CASE(aes_testvectors) {
+ // AES test vectors from FIPS 197.
+ TestAES128("000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a");
+ TestAES256("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089");
+
+ // AES-ECB test vectors from NIST sp800-38a.
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7");
+}
+
BOOST_AUTO_TEST_SUITE_END()