This commit is contained in:
Adam Ierymenko 2019-09-04 16:15:10 -07:00
parent 82b7e1dbcb
commit 55f4f9aaeb
No known key found for this signature in database
GPG Key ID: C8877CF2D7A5D7F3
3 changed files with 88 additions and 78 deletions

View File

@ -41,14 +41,14 @@ public:
*/ */
static const bool HW_ACCEL; static const bool HW_ACCEL;
inline AES() {} ZT_ALWAYS_INLINE AES() {}
inline AES(const uint8_t key[32]) { this->init(key); } ZT_ALWAYS_INLINE AES(const uint8_t key[32]) { this->init(key); }
inline ~AES() { Utils::burn(&_k,sizeof(_k)); } ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); }
/** /**
* Set (or re-set) this AES256 cipher's key * 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 #ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) { if (likely(HW_ACCEL)) {
@ -66,7 +66,7 @@ public:
* @param in Input block * @param in Input block
* @param out Output block (can be same as input) * @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 #ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) { if (likely(HW_ACCEL)) {
@ -86,7 +86,7 @@ public:
* @param len Length of input * @param len Length of input
* @param out 128-bit authorization tag from GMAC * @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 #ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) { if (likely(HW_ACCEL)) {
@ -110,7 +110,7 @@ public:
* @param len Length of input * @param len Length of input
* @param out Output plaintext or ciphertext * @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 #ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) { if (likely(HW_ACCEL)) {
@ -173,7 +173,7 @@ public:
* @param out Output buffer to receive ciphertext * @param out Output buffer to receive ciphertext
* @param tag Output buffer to receive 64-bit authentication tag * @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]; uint8_t ctrIv[16];
@ -216,7 +216,7 @@ public:
* @param tag Authentication tag supplied with message * @param tag Authentication tag supplied with message
* @return True if authentication tags match and message appears authentic * @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]; 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 masterKey Master 256-bit key
* @param k1 GMAC key * @param k1 GMAC key
@ -256,12 +258,20 @@ public:
* @param k3 CTR IV masking (ECB encryption) key * @param k3 CTR IV masking (ECB encryption) key
* @param k4 AES-CTR 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]; uint8_t kbuf[48];
for(uint8_t kno=0;kno<4;++kno) { uint8_t kbkdfMsg[16];
HMACSHA384(masterKey,&kno,1,(uint8_t *)kbuf); kbkdfMsg[0] = 0; // key iterator, incremented for each key
k1.init((const uint8_t *)kbuf); 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];
} }
} }

View File

@ -143,8 +143,8 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
{ {
static Mutex globalLock; static Mutex globalLock;
static bool initialized = false; static bool initialized = false;
static uint64_t randomState[1024]; static uint64_t randomState[4];
static uint8_t randomBuf[65536]; static uint8_t randomBuf[16384];
static unsigned long randomPtr = sizeof(randomBuf); static unsigned long randomPtr = sizeof(randomBuf);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
static HCRYPTPROV cryptProvider = NULL; static HCRYPTPROV cryptProvider = NULL;
@ -196,23 +196,18 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
for(unsigned int i=0;i<bytes;++i) { for(unsigned int i=0;i<bytes;++i) {
if (randomPtr >= sizeof(randomBuf)) { if (randomPtr >= sizeof(randomBuf)) {
for(unsigned int k=0;k<1024;++k) { randomPtr = 0;
for(unsigned int k=0;k<4;++k) {
if (++randomState[k]) if (++randomState[k])
break; break;
} }
uint8_t h[64]; uint8_t h[48];
SHA512(h,randomState,sizeof(randomState)); HMACSHA384((const uint8_t *)randomState,randomBuf,sizeof(randomBuf),h);
if (AES::HW_ACCEL) { AES c(h);
AES c(h); c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf);
c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf);
} else {
Salsa20 c(h,h + 32);
c.crypt12(randomBuf,randomBuf,sizeof(randomBuf));
}
randomPtr = 0;
} }
((uint8_t *)buf)[i] = randomBuf[randomPtr++]; ((uint8_t *)buf)[i] = randomBuf[randomPtr++];
} }

View File

@ -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(); 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); AES tv(AES_TEST_VECTOR_0_KEY);
if (memcmp(buf1,AES_TEST_VECTOR_0_OUT,16) != 0) { tv.encrypt(AES_TEST_VECTOR_0_IN,(uint8_t *)buf1);
std::cout << "FAILED (test vector 0 encrypt)" ZT_EOL_S; if (memcmp(buf1,AES_TEST_VECTOR_0_OUT,16) != 0) {
return -1; 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); std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush();
tv.gmac(AES_GMAC_VECTOR_0_IV,AES_GMAC_VECTOR_0_IN,sizeof(AES_GMAC_VECTOR_0_IN),(uint8_t *)buf2); AES k1,k2,k3,k4;
if (memcmp(buf2,AES_GMAC_VECTOR_0_OUT,16) != 0) { AES::initGmacCtrKeys(AES_TEST_VECTOR_0_KEY,k1,k2,k3,k4);
std::cout << "FAILED (test vector 0) (" << Utils::hex(buf2,16,hexbuf) << ")" ZT_EOL_S; int64_t start = OSUtils::now();
return -1; 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;
} }
{ {