From 5cea8da664533dbfbfa89608d03500dcee0c5cfb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 5 Sep 2019 12:03:11 -0700 Subject: [PATCH] Optimization and naming cleanup --- node/AES.hpp | 86 +++++++++++++++++++++++++++++++++++++--------------- selftest.cpp | 5 ++- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/node/AES.hpp b/node/AES.hpp index 278dc34d5..beb6f110e 100644 --- a/node/AES.hpp +++ b/node/AES.hpp @@ -151,7 +151,7 @@ public: } /** - * Perform AES-GMAC-CTR encryption + * Perform AES-GMAC-SIV encryption * * This is an AES mode built from GMAC and AES-CTR that is similar to the * various SIV (synthetic IV) modes for AES and is resistant to nonce @@ -167,34 +167,52 @@ public: * @param k2 GMAC auth tag masking (ECB encryption) key * @param k3 CTR IV masking (ECB encryption) key * @param k4 AES-CTR key - * @param iv 96-bit message IV + * @param iv 64-bit packet IV + * @param direction Direction byte * @param in Message plaintext * @param len Length of plaintext * @param out Output buffer to receive ciphertext * @param tag Output buffer to receive 64-bit authentication tag */ - 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]) + static ZT_ALWAYS_INLINE void gmacSivEncrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t direction,const void *in,const unsigned int len,void *out,uint8_t tag[8]) { +#ifdef __GNUC__ + uint8_t __attribute__ ((aligned (16))) miv[12]; + uint8_t __attribute__ ((aligned (16))) ctrIv[16]; +#else + uint8_t miv[12]; uint8_t ctrIv[16]; +#endif - // Compute AES[k2](GMAC[k1](iv,plaintext)) - k1.gmac(iv,in,len,ctrIv); + // Extend packet IV to 96-bit message IV using direction byte and message length +#ifndef __GNUC__ + for(unsigned int i=0;i<8;++i) miv[i] = iv[i]; +#else + *((uint64_t *)miv) = *((const uint64_t *)iv); +#endif + miv[8] = direction; + miv[9] = (uint8_t)(len >> 16); + miv[10] = (uint8_t)(len >> 8); + miv[11] = (uint8_t)len; + + // Compute AES[k2](GMAC[k1](miv,plaintext)) + k1.gmac(miv,in,len,ctrIv); k2.encrypt(ctrIv,ctrIv); // ECB mode encrypt step is because GMAC is not a PRF // Auth tag for packet is first 64 bits of AES(GMAC) (rest is discarded) -#ifdef ZT_NO_TYPE_PUNNING +#ifndef __GNUC__ for(unsigned int i=0;i<8;++i) tag[i] = ctrIv[i]; #else *((uint64_t *)tag) = *((uint64_t *)ctrIv); #endif - // Create synthetic CTR IV -#ifdef ZT_NO_TYPE_PUNNING - for(unsigned int i=0;i<4;++i) ctrIv[i+8] = iv[i]; - for(unsigned int i=4;i<8;++i) ctrIv[i+8] = iv[i] ^ iv[i+4]; + // Create synthetic CTR IV from keyed hash of tag and message IV +#ifndef __GNUC__ + for(unsigned int i=0;i<4;++i) ctrIv[i+8] = miv[i]; + for(unsigned int i=4;i<8;++i) ctrIv[i+8] = miv[i] ^ miv[i+4]; #else - ((uint32_t *)ctrIv)[2] = ((const uint32_t *)iv)[0]; - ((uint32_t *)ctrIv)[3] = ((const uint32_t *)iv)[1] ^ ((const uint32_t *)iv)[2]; + ((uint32_t *)ctrIv)[2] = ((const uint32_t *)miv)[0]; + ((uint32_t *)ctrIv)[3] = ((const uint32_t *)miv)[1] ^ ((const uint32_t *)miv)[2]; #endif k3.encrypt(ctrIv,ctrIv); @@ -203,32 +221,52 @@ public: } /** - * Decrypt a message encrypted with AES-GMAC-CTR and check its authenticity + * Decrypt a message encrypted with AES-GMAC-SIV and check its authenticity * * @param k1 GMAC key * @param k2 GMAC auth tag masking (ECB encryption) key * @param k3 CTR IV masking (ECB encryption) key * @param k4 AES-CTR key - * @param iv 96-bit message IV + * @param iv 64-bit message IV + * @param direction Direction byte * @param in Message ciphertext * @param len Length of ciphertext * @param out Output buffer to receive plaintext * @param tag Authentication tag supplied with message * @return True if authentication tags match and message appears authentic */ - 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]) + static ZT_ALWAYS_INLINE bool gmacSivDecrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t direction,const void *in,const unsigned int len,void *out,const uint8_t tag[8]) { - uint8_t ctrIv[16],gmacOut[16]; +#ifdef __GNUC__ + uint8_t __attribute__ ((aligned (16))) miv[12]; + uint8_t __attribute__ ((aligned (16))) ctrIv[16]; + uint8_t __attribute__ ((aligned (16))) gmacOut[16]; +#else + uint8_t miv[12]; + uint8_t ctrIv[16]; + uint8_t gmacOut[16]; +#endif + + // Extend packet IV to 96-bit message IV using direction byte and message length +#ifndef __GNUC__ + for(unsigned int i=0;i<8;++i) miv[i] = iv[i]; +#else + *((uint64_t *)miv) = *((const uint64_t *)iv); +#endif + miv[8] = direction; + miv[9] = (uint8_t)(len >> 16); + miv[10] = (uint8_t)(len >> 8); + miv[11] = (uint8_t)len; // Recover synthetic and secret CTR IV from auth tag and packet IV -#ifdef ZT_NO_TYPE_PUNNING +#ifndef __GNUC__ for(unsigned int i=0;i<8;++i) ctrIv[i] = tag[i]; - for(unsigned int i=0;i<4;++i) ctrIv[i+8] = iv[i]; - for(unsigned int i=4;i<8;++i) ctrIv[i+8] = iv[i] ^ iv[i+4]; + for(unsigned int i=0;i<4;++i) ctrIv[i+8] = miv[i]; + for(unsigned int i=4;i<8;++i) ctrIv[i+8] = miv[i] ^ miv[i+4]; #else *((uint64_t *)ctrIv) = *((const uint64_t *)tag); - ((uint32_t *)ctrIv)[2] = ((const uint32_t *)iv)[0]; - ((uint32_t *)ctrIv)[3] = ((const uint32_t *)iv)[1] ^ ((const uint32_t *)iv)[2]; + ((uint32_t *)ctrIv)[2] = ((const uint32_t *)miv)[0]; + ((uint32_t *)ctrIv)[3] = ((const uint32_t *)miv)[1] ^ ((const uint32_t *)miv)[2]; #endif k3.encrypt(ctrIv,ctrIv); @@ -236,11 +274,11 @@ public: k4.ctr(ctrIv,in,len,out); // Compute AES[k2](GMAC[k1](iv,plaintext)) - k1.gmac(iv,out,len,gmacOut); + k1.gmac(miv,out,len,gmacOut); k2.encrypt(gmacOut,gmacOut); // Check that packet's auth tag matches first 64 bits of AES(GMAC) -#ifdef ZT_NO_TYPE_PUNNING +#ifndef __GNUC__ return Utils::secureEq(gmacOut,tag,8); #else return (*((const uint64_t *)gmacOut) == *((const uint64_t *)tag)); @@ -248,7 +286,7 @@ public: } /** - * Use KBKDF with HMAC-SHA-384 to derive four sub-keys for AES-GMAC-CTR from a single master key + * Use KBKDF with HMAC-SHA-384 to derive four sub-keys for AES-GMAC-SIV from a single master key * * See section 5.1 at https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf * diff --git a/selftest.cpp b/selftest.cpp index 484a1713e..590354778 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -167,8 +167,7 @@ static const uint8_t AES_GMAC_VECTOR_2_OUT[16] = { 0x67,0x39,0x4f,0x00,0x04,0x28 static int testCrypto() { - static unsigned char buf1[16384]; - static unsigned char buf2[sizeof(buf1)],buf3[sizeof(buf1)]; + static uint8_t buf1[16384],buf2[16384],buf3[16384]; static char hexbuf[1024]; volatile unsigned char *dummy = (volatile unsigned char *)&(buf1[100]); @@ -228,7 +227,7 @@ static int testCrypto() AES::initGmacCtrKeys(AES_TEST_VECTOR_0_KEY,k1,k2,k3,k4); int64_t start = OSUtils::now(); for(unsigned long i=0;i<500000;++i) { - AES::ztGmacCtrEncrypt(k1,k2,k3,k4,(const uint8_t *)hexbuf,buf1,ZT_DEFAULT_MTU,buf1,(uint8_t *)(hexbuf + 8)); + AES::gmacSivEncrypt(k1,k2,k3,k4,(const uint8_t *)hexbuf,0,buf1,ZT_DEFAULT_MTU,buf1,(uint8_t *)(hexbuf + 8)); *dummy = buf1[0]; } int64_t end = OSUtils::now();