From 55f4f9aaeb6d2794df79897eb1c7857bfc23650b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 4 Sep 2019 16:15:10 -0700 Subject: [PATCH] cleanup --- node/AES.hpp | 40 ++++++++++++------- node/Utils.cpp | 23 +++++------ selftest.cpp | 103 ++++++++++++++++++++++++++----------------------- 3 files changed, 88 insertions(+), 78 deletions(-) diff --git a/node/AES.hpp b/node/AES.hpp index bcb395cf4..5bd6f64ae 100644 --- a/node/AES.hpp +++ b/node/AES.hpp @@ -41,14 +41,14 @@ public: */ static const bool HW_ACCEL; - inline AES() {} - inline AES(const uint8_t key[32]) { this->init(key); } - inline ~AES() { Utils::burn(&_k,sizeof(_k)); } + ZT_ALWAYS_INLINE AES() {} + ZT_ALWAYS_INLINE AES(const uint8_t key[32]) { this->init(key); } + ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); } /** * Set (or re-set) this AES256 cipher's key */ - inline void init(const uint8_t key[32]) + ZT_ALWAYS_INLINE void init(const uint8_t key[32]) { #ifdef ZT_AES_AESNI if (likely(HW_ACCEL)) { @@ -66,7 +66,7 @@ public: * @param in Input block * @param out Output block (can be same as input) */ - inline void encrypt(const uint8_t in[16],uint8_t out[16]) const + ZT_ALWAYS_INLINE void encrypt(const uint8_t in[16],uint8_t out[16]) const { #ifdef ZT_AES_AESNI if (likely(HW_ACCEL)) { @@ -86,7 +86,7 @@ public: * @param len Length of input * @param out 128-bit authorization tag from GMAC */ - inline void gmac(const uint8_t iv[12],const void *in,const unsigned int len,uint8_t out[16]) const + ZT_ALWAYS_INLINE void gmac(const uint8_t iv[12],const void *in,const unsigned int len,uint8_t out[16]) const { #ifdef ZT_AES_AESNI if (likely(HW_ACCEL)) { @@ -110,7 +110,7 @@ public: * @param len Length of input * @param out Output plaintext or ciphertext */ - inline void ctr(const uint8_t iv[16],const void *in,unsigned int len,void *out) const + ZT_ALWAYS_INLINE void ctr(const uint8_t iv[16],const void *in,unsigned int len,void *out) const { #ifdef ZT_AES_AESNI if (likely(HW_ACCEL)) { @@ -173,7 +173,7 @@ public: * @param out Output buffer to receive ciphertext * @param tag Output buffer to receive 64-bit authentication tag */ - static inline void ztGmacCtrEncrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[12],const void *in,unsigned int len,void *out,uint8_t tag[8]) + static ZT_ALWAYS_INLINE void ztGmacCtrEncrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[12],const void *in,const unsigned int len,void *out,uint8_t tag[8]) { uint8_t ctrIv[16]; @@ -216,7 +216,7 @@ public: * @param tag Authentication tag supplied with message * @return True if authentication tags match and message appears authentic */ - static inline bool ztGmacCtrDecrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[12],const void *in,unsigned int len,void *out,const uint8_t tag[8]) + static ZT_ALWAYS_INLINE bool ztGmacCtrDecrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[12],const void *in,const unsigned int len,void *out,const uint8_t tag[8]) { uint8_t ctrIv[16],gmacOut[16]; @@ -248,7 +248,9 @@ public: } /** - * Use HMAC-SHA-384 as a PRF to generate four AES keys from one master + * Use KBKDF with HMAC-SHA-384 to derive four sub-keys for AES-GMAC-CTR from a single master key + * + * See section 5.1 at https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf * * @param masterKey Master 256-bit key * @param k1 GMAC key @@ -256,12 +258,20 @@ public: * @param k3 CTR IV masking (ECB encryption) key * @param k4 AES-CTR key */ - static inline void initGmacCtrKeys(const uint8_t masterKey[32],AES &k1,AES &k2,AES &k3,AES &k4) + static ZT_ALWAYS_INLINE void initGmacCtrKeys(const uint8_t masterKey[32],AES &k1,AES &k2,AES &k3,AES &k4) { - uint64_t kbuf[6]; - for(uint8_t kno=0;kno<4;++kno) { - HMACSHA384(masterKey,&kno,1,(uint8_t *)kbuf); - k1.init((const uint8_t *)kbuf); + uint8_t kbuf[48]; + uint8_t kbkdfMsg[16]; + kbkdfMsg[0] = 0; // key iterator, incremented for each key + for(unsigned int i=0;i<12;++i) + kbkdfMsg[i+1] = (uint8_t)("AES-GMAC-CTR"[i]); // KBKDF "label" indicating the use for these keys + kbkdfMsg[13] = 0; // 0x00 + kbkdfMsg[14] = 0; // KBKDF "context", just 0 as it's not used in this protocol + kbkdfMsg[15] = 32; // bits used in resulting key + while (kbkdfMsg[0] < 4) { + HMACSHA384(masterKey,&kbkdfMsg,sizeof(kbkdfMsg),kbuf); + k1.init(kbuf); + ++kbkdfMsg[0]; } } diff --git a/node/Utils.cpp b/node/Utils.cpp index 719e4066a..4c27a0ade 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -143,8 +143,8 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) { static Mutex globalLock; static bool initialized = false; - static uint64_t randomState[1024]; - static uint8_t randomBuf[65536]; + static uint64_t randomState[4]; + static uint8_t randomBuf[16384]; static unsigned long randomPtr = sizeof(randomBuf); #ifdef __WINDOWS__ static HCRYPTPROV cryptProvider = NULL; @@ -196,23 +196,18 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) for(unsigned int i=0;i= sizeof(randomBuf)) { - for(unsigned int k=0;k<1024;++k) { + randomPtr = 0; + + for(unsigned int k=0;k<4;++k) { if (++randomState[k]) break; } - uint8_t h[64]; - SHA512(h,randomState,sizeof(randomState)); + uint8_t h[48]; + HMACSHA384((const uint8_t *)randomState,randomBuf,sizeof(randomBuf),h); - if (AES::HW_ACCEL) { - AES c(h); - c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf); - } else { - Salsa20 c(h,h + 32); - c.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); - } - - randomPtr = 0; + AES c(h); + c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf); } ((uint8_t *)buf)[i] = randomBuf[randomPtr++]; } diff --git a/selftest.cpp b/selftest.cpp index f5b5c309e..fd103e714 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -179,57 +179,62 @@ static int testCrypto() { std::cout << "[crypto] Testing and benchmarking AES-256..." ZT_EOL_S << " AES-256 (test vectors): "; std::cout.flush(); - AES tv(AES_TEST_VECTOR_0_KEY); - tv.encrypt(AES_TEST_VECTOR_0_IN,(uint8_t *)buf1); - if (memcmp(buf1,AES_TEST_VECTOR_0_OUT,16) != 0) { - std::cout << "FAILED (test vector 0 encrypt)" ZT_EOL_S; - return -1; + { + AES tv(AES_TEST_VECTOR_0_KEY); + tv.encrypt(AES_TEST_VECTOR_0_IN,(uint8_t *)buf1); + if (memcmp(buf1,AES_TEST_VECTOR_0_OUT,16) != 0) { + std::cout << "FAILED (test vector 0 encrypt)" ZT_EOL_S; + return -1; + } + std::cout << "OK" ZT_EOL_S << " GMAC-AES-256 (test vectors): "; std::cout.flush(); + tv.init(AES_GMAC_VECTOR_0_KEY); + tv.gmac(AES_GMAC_VECTOR_0_IV,AES_GMAC_VECTOR_0_IN,sizeof(AES_GMAC_VECTOR_0_IN),(uint8_t *)buf2); + if (memcmp(buf2,AES_GMAC_VECTOR_0_OUT,16) != 0) { + std::cout << "FAILED (test vector 0) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; + return -1; + } + tv.init(AES_GMAC_VECTOR_1_KEY); + tv.gmac(AES_GMAC_VECTOR_1_IV,AES_GMAC_VECTOR_1_IN,sizeof(AES_GMAC_VECTOR_1_IN),(uint8_t *)buf2); + if (memcmp(buf2,AES_GMAC_VECTOR_1_OUT,16) != 0) { + std::cout << "FAILED (test vector 1) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; + return -1; + } + tv.init(AES_GMAC_VECTOR_2_KEY); + tv.gmac(AES_GMAC_VECTOR_2_IV,AES_GMAC_VECTOR_2_IN,sizeof(AES_GMAC_VECTOR_2_IN),(uint8_t *)buf2); + if (memcmp(buf2,AES_GMAC_VECTOR_2_OUT,16) != 0) { + std::cout << "FAILED (test vector 2) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; + return -1; + } + std::cout << "OK" ZT_EOL_S << " GMAC-AES-256 (benchmark): "; std::cout.flush(); + int64_t start = OSUtils::now(); + for(unsigned long i=0;i<200000;++i) { + tv.gmac((const uint8_t *)buf1,buf1,sizeof(buf1),(uint8_t *)buf1); + } + int64_t end = OSUtils::now(); + *dummy = hexbuf[0]; + std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; + std::cout << " AES-256-CTR (benchmark): "; std::cout.flush(); + start = OSUtils::now(); + for(unsigned long i=0;i<200000;++i) { + tv.ctr((const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2); + hexbuf[0] = buf2[0]; + } + end = OSUtils::now(); + *dummy = buf2[0]; + std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; } - std::cout << "OK" ZT_EOL_S << " GMAC-AES-256 (test vectors): "; std::cout.flush(); - tv.init(AES_GMAC_VECTOR_0_KEY); - tv.gmac(AES_GMAC_VECTOR_0_IV,AES_GMAC_VECTOR_0_IN,sizeof(AES_GMAC_VECTOR_0_IN),(uint8_t *)buf2); - if (memcmp(buf2,AES_GMAC_VECTOR_0_OUT,16) != 0) { - std::cout << "FAILED (test vector 0) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; - return -1; + { + std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush(); + AES k1,k2,k3,k4; + AES::initGmacCtrKeys(AES_TEST_VECTOR_0_KEY,k1,k2,k3,k4); + int64_t start = OSUtils::now(); + for(unsigned long i=0;i<200000;++i) { + AES::ztGmacCtrEncrypt(k1,k2,k3,k4,(const uint8_t *)hexbuf,buf1,sizeof(buf1),buf1,(uint8_t *)(hexbuf + 8)); + *dummy = buf1[0]; + } + int64_t end = OSUtils::now(); + std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; } - tv.init(AES_GMAC_VECTOR_1_KEY); - tv.gmac(AES_GMAC_VECTOR_1_IV,AES_GMAC_VECTOR_1_IN,sizeof(AES_GMAC_VECTOR_1_IN),(uint8_t *)buf2); - if (memcmp(buf2,AES_GMAC_VECTOR_1_OUT,16) != 0) { - std::cout << "FAILED (test vector 1) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; - return -1; - } - tv.init(AES_GMAC_VECTOR_2_KEY); - tv.gmac(AES_GMAC_VECTOR_2_IV,AES_GMAC_VECTOR_2_IN,sizeof(AES_GMAC_VECTOR_2_IN),(uint8_t *)buf2); - if (memcmp(buf2,AES_GMAC_VECTOR_2_OUT,16) != 0) { - std::cout << "FAILED (test vector 2) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; - return -1; - } - std::cout << "OK" ZT_EOL_S << " GMAC-AES-256 (benchmark): "; std::cout.flush(); - int64_t start = OSUtils::now(); - for(unsigned long i=0;i<200000;++i) { - tv.gmac((const uint8_t *)buf1,buf1,sizeof(buf1),(uint8_t *)buf1); - } - int64_t end = OSUtils::now(); - *dummy = hexbuf[0]; - std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; - std::cout << " AES-256-CTR (benchmark): "; std::cout.flush(); - start = OSUtils::now(); - for(unsigned long i=0;i<200000;++i) { - tv.ctr((const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2); - hexbuf[0] = buf2[0]; - } - end = OSUtils::now(); - *dummy = buf2[0]; - std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; - std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush(); - start = OSUtils::now(); - for(unsigned long i=0;i<200000;++i) { - AES::ztGmacCtrEncrypt(tv,tv,tv,tv,(const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2,(uint8_t *)(hexbuf + 8)); - hexbuf[0] = buf2[0]; - } - end = OSUtils::now(); - *dummy = buf2[0]; - std::cout << (((double)(200000 * sizeof(buf1)) / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second" ZT_EOL_S; } {