Fully implement the packet encryption/decryption algorithms.

This commit is contained in:
Adam Ierymenko 2019-08-23 20:20:32 -07:00
parent 9fd5ec673b
commit 52f7f6e6cf
No known key found for this signature in database
GPG Key ID: 1657198823E52A61
2 changed files with 132 additions and 4 deletions

View File

@ -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<len;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
}
}
/**
* Perform AES-256-GMAC-CTR encryption
*
* This mode combines the two standard modes AES256-GMAC and AES256-CTR to
* yield a mode similar to AES256-GCM-SIV that is resistant to accidental
* message IV duplication.
*
* @param iv 64-bit message IV
* @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
*/
inline void ztGmacCtrEncrypt(const uint8_t iv[8],const void *in,unsigned int len,void *out,uint8_t tag[8])
{
uint8_t ctrIv[16],gmacIv[12];
// (1) Compute AES256-GMAC(in) using a 96-bit IV constructed from
// the 64-bit supplied 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,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<pblocks;i+=4) {
__m128i d1 = _mm_loadu_si128(ab + i + 0);
__m128i d2 = _mm_loadu_si128(ab + i + 1);
@ -574,8 +690,10 @@ private:
y = _mm_xor_si128(y,d1);
y = _mult4xor_aesni(h1,h2,h3,h4,y,d2,d3,d4);
}
for (unsigned int i=pblocks;i<blocks;++i)
y = _ghash_aesni(_k.ni.h,y,_mm_loadu_si128(ab + i));
if (rem) {
__m128i last = _mm_setzero_si128();
memcpy(&last,ab + blocks,rem);

View File

@ -153,6 +153,11 @@ static const uint8_t AES_GMAC_VECTOR_0_IV[12] = { 0x2f, 0x9a, 0xd0, 0x12, 0xad,
static const uint8_t AES_GMAC_VECTOR_0_IN[16] = { 0xdb, 0x98, 0xd9, 0x0d, 0x1b, 0x69, 0x5c, 0xdb, 0x74, 0x7a, 0x34, 0x3f, 0xbb, 0xc9, 0xf1, 0x41 };
static const uint8_t AES_GMAC_VECTOR_0_OUT[16] = { 0xef, 0x06, 0xd5, 0x4d, 0xfd, 0x00, 0x02, 0x1d, 0x75, 0x27, 0xdf, 0xf2, 0x6f, 0xc9, 0xd4, 0x84 };
static const uint8_t AES_GMAC_VECTOR_1_KEY[32] = { 0x83,0xC0,0x93,0xB5,0x8D,0xE7,0xFF,0xE1,0xC0,0xDA,0x92,0x6A,0xC4,0x3F,0xB3,0x60,0x9A,0xC1,0xC8,0x0F,0xEE,0x1B,0x62,0x44,0x97,0xEF,0x94,0x2E,0x2F,0x79,0xA8,0x23 };
static const uint8_t AES_GMAC_VECTOR_1_IV[12] = { 0x7C,0xFD,0xE9,0xF9,0xE3,0x37,0x24,0xC6,0x89,0x32,0xD6,0x12 };
static const uint8_t AES_GMAC_VECTOR_1_IN[81] = { 0x84,0xC5,0xD5,0x13,0xD2,0xAA,0xF6,0xE5,0xBB,0xD2,0x72,0x77,0x88,0xE5,0x23,0x00,0x89,0x32,0xD6,0x12,0x7C,0xFD,0xE9,0xF9,0xE3,0x37,0x24,0xC6,0x08,0x00,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x00,0x05 };
static const uint8_t AES_GMAC_VECTOR_1_OUT[16] = { 0x6E,0xE1,0x60,0xE8,0xFA,0xEC,0xA4,0xB3,0x6C,0x86,0xB2,0x34,0x92,0x0C,0xA9,0x75 };
//////////////////////////////////////////////////////////////////////////////
static int testCrypto()
@ -182,6 +187,12 @@ static int testCrypto()
std::cout << "FAILED (test vector 0)" 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 *)hexbuf);
if (memcmp(hexbuf,AES_GMAC_VECTOR_1_OUT,16) != 0) {
std::cout << "FAILED (test vector 1)" 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) {
@ -200,11 +211,10 @@ static int testCrypto()
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 << " GMAC-AES-256 and AES-256-CTR (benchmark): "; std::cout.flush();
std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush();
start = OSUtils::now();
for(unsigned long i=0;i<200000;++i) {
tv.gmac(AES_GMAC_VECTOR_0_IV,buf1,sizeof(buf1),(uint8_t *)hexbuf);
tv.ctr((const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2);
tv.ztGmacCtrEncrypt((const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2,(uint8_t *)(hexbuf + 8));
hexbuf[0] = buf2[0];
}
end = OSUtils::now();