mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-24 04:55:40 +00:00
Fully implement the packet encryption/decryption algorithms.
This commit is contained in:
parent
9fd5ec673b
commit
52f7f6e6cf
120
node/AES.hpp
120
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<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);
|
||||
|
16
selftest.cpp
16
selftest.cpp
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user