mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-04 08:21:03 +00:00
cleanup and docs
This commit is contained in:
parent
171d661b84
commit
274b2682d6
26
node/AES.hpp
26
node/AES.hpp
@ -153,11 +153,19 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Perform AES-GMAC-SIV encryption
|
* Perform AES-GMAC-SIV encryption
|
||||||
*
|
*
|
||||||
* This is an AES mode built from GMAC and AES-CTR that is similar to the
|
* This is basically AES-CMAC-SIV but with GMAC in place of CMAC after
|
||||||
* various SIV (synthetic IV) modes for AES and is resistant to nonce
|
* GMAC is run through AES as a keyed hash to make it behave like a
|
||||||
* re-use. It's specifically tweaked for ZeroTier's packet structure with
|
* proper PRF.
|
||||||
* a 64-bit IV (extended to 96 bits by including packet size and other info)
|
*
|
||||||
* and a 64-bit auth tag.
|
* See: https://github.com/miscreant/meta/wiki/AES-SIV
|
||||||
|
*
|
||||||
|
* The advantage is that this can be described in terms of FIPS and NSA
|
||||||
|
* ceritifable primitives that are present in FIPS-compliant crypto
|
||||||
|
* modules.
|
||||||
|
*
|
||||||
|
* The extra AES-ECB (keyed hash) encryption of the AES-CTR IV prior
|
||||||
|
* to use makes the IV itself a secret. This is not strictly necessary
|
||||||
|
* but comes at little cost.
|
||||||
*
|
*
|
||||||
* @param k1 GMAC key
|
* @param k1 GMAC key
|
||||||
* @param k2 GMAC auth tag keyed hash key
|
* @param k2 GMAC auth tag keyed hash key
|
||||||
@ -180,7 +188,7 @@ public:
|
|||||||
uint8_t ctrIv[16];
|
uint8_t ctrIv[16];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Extend packet IV to 96-bit message IV using direction byte and message length
|
// GMAC IV is 64-bit packet IV followed by other packet attributes to extend to 96 bits
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
for(unsigned int i=0;i<8;++i) miv[i] = iv[i];
|
for(unsigned int i=0;i<8;++i) miv[i] = iv[i];
|
||||||
#else
|
#else
|
||||||
@ -191,18 +199,16 @@ public:
|
|||||||
miv[10] = (uint8_t)(len >> 8);
|
miv[10] = (uint8_t)(len >> 8);
|
||||||
miv[11] = (uint8_t)len;
|
miv[11] = (uint8_t)len;
|
||||||
|
|
||||||
// Compute AES[k2](GMAC[k1](miv,plaintext))
|
// Compute auth TAG: AES-ECB[k2](GMAC[k1](miv,plaintext))[0:8]
|
||||||
k1.gmac(miv,in,len,ctrIv);
|
k1.gmac(miv,in,len,ctrIv);
|
||||||
k2.encrypt(ctrIv,ctrIv); // ECB mode encrypt step is because GMAC is not a PRF
|
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
|
#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) tag[i] = ctrIv[i];
|
||||||
#else
|
#else
|
||||||
*((uint64_t *)tag) = *((uint64_t *)ctrIv);
|
*((uint64_t *)tag) = *((uint64_t *)ctrIv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create synthetic CTR IV from keyed hash of tag and message IV
|
// Create synthetic CTR IV: AES-ECB[k3](TAG | MIV[0:4] | (MIV[4:8] XOR MIV[8:12]))
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
for(unsigned int i=0;i<4;++i) ctrIv[i+8] = miv[i];
|
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];
|
for(unsigned int i=4;i<8;++i) ctrIv[i+8] = miv[i] ^ miv[i+4];
|
||||||
|
@ -146,69 +146,62 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||||||
static uint64_t randomState[4];
|
static uint64_t randomState[4];
|
||||||
static uint8_t randomBuf[16384];
|
static uint8_t randomBuf[16384];
|
||||||
static unsigned long randomPtr = sizeof(randomBuf);
|
static unsigned long randomPtr = sizeof(randomBuf);
|
||||||
#ifdef __WINDOWS__
|
|
||||||
static HCRYPTPROV cryptProvider = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Mutex::Lock _l(globalLock);
|
Mutex::Lock gl(globalLock);
|
||||||
|
|
||||||
/* Just for posterity we Salsa20 encrypt the result of whatever system
|
|
||||||
* CSPRNG we use. There have been several bugs at the OS or OS distribution
|
|
||||||
* level in the past that resulted in systematically weak or predictable
|
|
||||||
* keys due to random seeding problems. This mitigates that by grabbing
|
|
||||||
* a bit of extra entropy and further randomizing the result,and comes
|
|
||||||
* at almost no cost and with no real downside if the random source is
|
|
||||||
* good. */
|
|
||||||
if (unlikely(!initialized)) {
|
|
||||||
#ifdef __WINDOWS__
|
|
||||||
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomState),(BYTE *)randomState)) {
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) {
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
|
||||||
if (devURandomFd < 0) {
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if ((int)::read(devURandomFd,randomState,sizeof(randomState)) != (int)sizeof(randomState)) {
|
|
||||||
::close(devURandomFd);
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
|
|
||||||
::close(devURandomFd);
|
|
||||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
close(devURandomFd);
|
|
||||||
#endif
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned int i=0;i<bytes;++i) {
|
for(unsigned int i=0;i<bytes;++i) {
|
||||||
if (randomPtr >= sizeof(randomBuf)) {
|
if (randomPtr >= sizeof(randomBuf)) {
|
||||||
randomPtr = 0;
|
randomPtr = 0;
|
||||||
|
|
||||||
for(unsigned int k=0;k<4;++k) {
|
if (unlikely(!initialized)) {
|
||||||
if (++randomState[k])
|
initialized = true;
|
||||||
break;
|
#ifdef __WINDOWS__
|
||||||
|
HCRYPTPROV cryptProvider = NULL;
|
||||||
|
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomState),(BYTE *)randomState)) {
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) {
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
CryptReleaseContext(cryptProvider,0);
|
||||||
|
#else
|
||||||
|
int devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
||||||
|
if (devURandomFd < 0) {
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((int)::read(devURandomFd,randomState,sizeof(randomState)) != (int)sizeof(randomState)) {
|
||||||
|
::close(devURandomFd);
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
|
||||||
|
::close(devURandomFd);
|
||||||
|
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(devURandomFd);
|
||||||
|
#endif
|
||||||
|
randomState[0] ^= (uint64_t)time(nullptr);
|
||||||
|
randomState[1] ^= (uint64_t)((uintptr_t)buf); // XOR in some other entropy just in case the system random source is wonky
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t h[48];
|
uint8_t h[48];
|
||||||
|
for(unsigned int k=0;k<4;++k) {
|
||||||
|
if (++randomState[k] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
HMACSHA384((const uint8_t *)randomState,randomBuf,sizeof(randomBuf),h);
|
HMACSHA384((const uint8_t *)randomState,randomBuf,sizeof(randomBuf),h);
|
||||||
|
|
||||||
AES c(h);
|
AES c(h);
|
||||||
c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf);
|
c.ctr(h + 32,randomBuf,sizeof(randomBuf),randomBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
|
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user