From 52f7f6e6cf2c2370450101faea8072b8f1da2657 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 23 Aug 2019 20:20:32 -0700 Subject: [PATCH] Fully implement the packet encryption/decryption algorithms. --- node/AES.hpp | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++- selftest.cpp | 16 +++++-- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/node/AES.hpp b/node/AES.hpp index cf081a20c..9741b391d 100644 --- a/node/AES.hpp +++ b/node/AES.hpp @@ -90,7 +90,7 @@ public: #endif } - inline void ctr(const uint8_t iv[16],const void *in,const unsigned int len,void *out) const + 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)) { @@ -98,6 +98,120 @@ public: return; } #endif + + uint64_t ctr[2],cenc[2]; + memcpy(ctr,iv,16); + uint64_t bctr = Utils::ntoh(ctr[1]); + + const uint8_t *i = (const uint8_t *)in; + uint8_t *o = (uint8_t *)out; + while (len >= 16) { + _encryptSW((const uint8_t *)ctr,(uint8_t *)cenc); + ctr[1] = Utils::hton(++bctr); + for(unsigned int k=0;k<16;++k) + *(o++) = *(i++) ^ ((uint8_t *)cenc)[k]; + len -= 16; + } + + if (len) { + _encryptSW((const uint8_t *)ctr,(uint8_t *)cenc); + for(unsigned int k=0;k> 24); + gmacIv[9] = (uint8_t)(len >> 16); + gmacIv[10] = (uint8_t)(len >> 8); + gmacIv[11] = (uint8_t)len; + gmac(gmacIv,in,len,ctrIv); + + // (2) The first 64 bits of GMAC output are the auth tag. Create + // a secret synthetic AES256-CTR IV by encrypting these and the + // original supplied IV. +#ifdef ZT_NO_TYPE_PUNNING + for(unsigned int i=0;i<8;++i) tag[i] = ctrIv[i]; + for(unsigned int i=0;i<8;++i) ctrIv[i+8] = iv[i]; +#else + *((uint64_t *)tag) = *((const uint64_t *)ctrIv); + *((uint64_t *)(ctrIv + 8)) = *((const uint64_t *)iv); +#endif + encrypt(ctrIv,ctrIv); + + // (3) Encrypt input using AES256-CTR + ctr(ctrIv,in,len,out); + } + + /** + * Decrypt a message encrypted with AES-256-GMAC-CTR and check its authenticity + * + * @param iv 64-bit message IV + * @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 + */ + inline bool ztGmacCtrDecrypt(const uint8_t iv[8],const void *in,unsigned int len,void *out,const uint8_t tag[8]) + { + uint8_t ctrIv[16],gmacOut[16],gmacIv[12]; + + // (1) Re-create the original secret synthetic AES256-CTR IV. +#ifdef ZT_NO_TYPE_PUNNING + for(unsigned int i=0;i<8;++i) ctrIv[i] = tag[i]; + for(unsigned int i=0;i<8;++i) ctrIv[i+8] = iv[i]; +#else + *((uint64_t *)ctrIv) = *((const uint8_t *)tag); + *((uint64_t *)(ctrIv + 8)) = *((const uint64_t *)iv); +#endif + encrypt(ctrIv,ctrIv); + + // (2) Decrypt input using AES256-CTR + ctr(ctrIv,in,len,out); + + // (3) Compute AES256-GMAC(out) using the re-created 96-bit + // GMAC IV built from the message IV and the message size. +#ifdef ZT_NO_TYPE_PUNNING + for(unsigned int i=0;i<8;++i) gmacIv[i] = iv[i]; +#else + *((uint64_t *)gmacIv) = *((const uint64_t *)iv); +#endif + gmacIv[8] = (uint8_t)(len >> 24); + gmacIv[9] = (uint8_t)(len >> 16); + gmacIv[10] = (uint8_t)(len >> 8); + gmacIv[11] = (uint8_t)len; + gmac(gmacIv,out,len,gmacOut); + + // (4) Compare first 64 bits of GMAC output with tag. +#ifdef ZT_NO_TYPE_PUNNING + return Utils::secureEq(gmacOut,tag,8); +#else + return (*((const uint64_t *)gmacOut) == *((const uint64_t *)tag)); +#endif } private: @@ -561,11 +675,13 @@ private: __m128i h2 = _k.ni.hhh; __m128i h3 = _k.ni.hh; __m128i h4 = _k.ni.h; + __m128i y = _mm_setzero_si128(); const __m128i *ab = (const __m128i *)in; unsigned int blocks = len / 16; unsigned int pblocks = blocks - (blocks % 4); unsigned int rem = len % 16; + for (unsigned int i=0;i