mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-20 17:00:49 +00:00
AES-GMAC-CTR tweaks, self test tweaks, debian typo fix.
This commit is contained in:
parent
e29c2d0260
commit
185e90c40f
2
debian/control
vendored
2
debian/control
vendored
@ -11,7 +11,7 @@ Homepage: https://www.zerotier.com/
|
||||
Package: zerotier-one
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6
|
||||
apt-caHomepage: https://www.zerotier.com/
|
||||
Homepage: https://www.zerotier.com/
|
||||
Description: ZeroTier network virtualization service
|
||||
ZeroTier One lets you join ZeroTier virtual networks and
|
||||
have them appear as tun/tap ports on your system. See
|
||||
|
62
node/AES.hpp
62
node/AES.hpp
@ -150,37 +150,56 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform AES-256-GMAC-CTR encryption
|
||||
* Perform AES-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. This is good because ZeroTier is stateless and
|
||||
* uses a small (64-bit) IV to reduce bandwidth overhead.
|
||||
* This is an AES mode built from GMAC and AES-CTR that is similar to the
|
||||
* various SIV (synthetic IV) modes for AES and is resistant to nonce
|
||||
* re-use. It's specifically tweaked for ZeroTier's packet structure with
|
||||
* a 64-bit IV (extended to 96 bits by including packet size and other info)
|
||||
* and a 64-bit auth tag.
|
||||
*
|
||||
* The use of separate keys for MAC and encrypt is precautionary. It
|
||||
* ensures that the CTR IV (and CTR output) are always secrets regardless
|
||||
* of what an attacker might do with accumulated IVs and auth tags.
|
||||
*
|
||||
* @param k1 MAC key
|
||||
* @param k2 Encryption key
|
||||
* @param iv 96-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[12],const void *in,unsigned int len,void *out,uint8_t tag[8]) const
|
||||
static inline void ztGmacCtrEncrypt(const AES &k1,const AES &k2,const uint8_t iv[12],const void *in,unsigned int len,void *out,uint8_t tag[8])
|
||||
{
|
||||
uint8_t ctrIv[16];
|
||||
|
||||
gmac(iv,in,len,ctrIv);
|
||||
encrypt(ctrIv,ctrIv);
|
||||
// Compute AES[k1](GMAC[k1](iv,plaintext))
|
||||
k1.gmac(iv,in,len,ctrIv);
|
||||
k1.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
|
||||
for(unsigned int i=0;i<8;++i) tag[i] = ctrIv[i];
|
||||
#else
|
||||
*((uint64_t *)tag) = *((uint64_t *)ctrIv);
|
||||
#endif
|
||||
|
||||
// Synthetic CTR IV is AES[k2](AES[k1]( tag[0..4] | tag[4..8]^iv[0..4] | iv[4..12] ))
|
||||
for(unsigned int i=4;i<8;++i) ctrIv[i] ^= iv[i - 4];
|
||||
for(unsigned int i=8;i<16;++i) ctrIv[i] = iv[i - 4];
|
||||
encrypt(ctrIv,ctrIv);
|
||||
ctr(ctrIv,in,len,out);
|
||||
k1.encrypt(ctrIv,ctrIv);
|
||||
k2.encrypt(ctrIv,ctrIv); // ECB mode encrypt here makes CTR IV itself a secret and mixes bits
|
||||
|
||||
// Encrypt with AES[k2]-CTR
|
||||
k2.ctr(ctrIv,in,len,out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a message encrypted with AES-256-GMAC-CTR and check its authenticity
|
||||
* Decrypt a message encrypted with AES-GMAC-CTR and check its authenticity
|
||||
*
|
||||
* @param k1 MAC key
|
||||
* @param k2 Encryption key
|
||||
* @param iv 96-bit message IV
|
||||
* @param in Message ciphertext
|
||||
* @param len Length of ciphertext
|
||||
@ -188,20 +207,25 @@ public:
|
||||
* @param tag Authentication tag supplied with message
|
||||
* @return True if authentication tags match and message appears authentic
|
||||
*/
|
||||
inline bool ztGmacCtrDecrypt(const uint8_t iv[12],const void *in,unsigned int len,void *out,const uint8_t tag[8]) const
|
||||
static inline bool ztGmacCtrDecrypt(const AES &k1,const AES &k2,const uint8_t iv[12],const void *in,unsigned int len,void *out,const uint8_t tag[8])
|
||||
{
|
||||
uint8_t ctrIv[16],gmacOut[16];
|
||||
|
||||
for(unsigned int i=0;i<8;++i) ctrIv[i] = tag[i];
|
||||
|
||||
for(unsigned int i=4;i<8;++i) ctrIv[i] ^= iv[i - 4];
|
||||
// Recover synthetic and secret CTR IV from auth tag and packet IV
|
||||
for(unsigned int i=0;i<4;++i) ctrIv[i] = tag[i];
|
||||
for(unsigned int i=4;i<8;++i) ctrIv[i] = tag[i] ^ iv[i - 4];
|
||||
for(unsigned int i=8;i<16;++i) ctrIv[i] = iv[i - 4];
|
||||
encrypt(ctrIv,ctrIv);
|
||||
ctr(ctrIv,in,len,out);
|
||||
k1.encrypt(ctrIv,ctrIv);
|
||||
k2.encrypt(ctrIv,ctrIv);
|
||||
|
||||
gmac(iv,out,len,gmacOut);
|
||||
encrypt(gmacOut,gmacOut);
|
||||
// Decrypt with AES[k2]-CTR
|
||||
k2.ctr(ctrIv,in,len,out);
|
||||
|
||||
// Compute AES[k1](GMAC[k1](iv,plaintext))
|
||||
k1.gmac(iv,out,len,gmacOut);
|
||||
k1.encrypt(gmacOut,gmacOut);
|
||||
|
||||
// Check that packet's auth tag matches first 64 bits of AES(GMAC)
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
return Utils::secureEq(gmacOut,tag,8);
|
||||
#else
|
||||
|
@ -935,11 +935,19 @@ bool Packet::uncompress()
|
||||
|
||||
uint64_t Packet::nextPacketId()
|
||||
{
|
||||
// The packet ID which is also the packet's nonce/IV can be sequential but
|
||||
// it should never repeat. This scheme minimizes the chance of nonce
|
||||
// repetition if (as will usually be the case) the clock is relatively
|
||||
// accurate.
|
||||
|
||||
static uint64_t ctr = 0;
|
||||
static Mutex lock;
|
||||
lock.lock();
|
||||
while (ctr == 0)
|
||||
while (ctr == 0) {
|
||||
Utils::getSecureRandom(&ctr,sizeof(ctr));
|
||||
ctr <<= 32;
|
||||
ctr |= ((uint64_t)time(nullptr)) & 0x00000000ffffffffULL;
|
||||
}
|
||||
const uint64_t i = ctr++;
|
||||
lock.unlock();
|
||||
return i;
|
||||
|
@ -316,8 +316,9 @@ static void handlePacket(const int v4s,const int v6s,const InetAddress *const ip
|
||||
switch(pkt.verb()) {
|
||||
case Packet::VERB_HELLO:
|
||||
try {
|
||||
if ((now - peer->lastHello) > 1000) {
|
||||
if ((now - peer->lastHello) > 500) {
|
||||
peer->lastHello = now;
|
||||
|
||||
peer->vProto = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
|
||||
peer->vMajor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
|
||||
peer->vMinor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
|
||||
@ -354,7 +355,7 @@ static void handlePacket(const int v4s,const int v6s,const InetAddress *const ip
|
||||
|
||||
case Packet::VERB_ECHO:
|
||||
try {
|
||||
if ((now - peer->lastEcho) > 1000) {
|
||||
if ((now - peer->lastEcho) > 500) {
|
||||
peer->lastEcho = now;
|
||||
|
||||
Packet outp(source,s_self.address(),Packet::VERB_OK);
|
||||
|
@ -224,7 +224,7 @@ static int testCrypto()
|
||||
std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush();
|
||||
start = OSUtils::now();
|
||||
for(unsigned long i=0;i<200000;++i) {
|
||||
tv.ztGmacCtrEncrypt((const uint8_t *)hexbuf,buf1,sizeof(buf1),buf2,(uint8_t *)(hexbuf + 8));
|
||||
AES::ztGmacCtrEncrypt(tv,tv,(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