mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
AES-GMAC-CTR tweaks, self test tweaks, debian typo fix.
This commit is contained in:
parent
e29c2d0260
commit
185e90c40f
5 changed files with 57 additions and 24 deletions
2
debian/control
vendored
2
debian/control
vendored
|
@ -11,7 +11,7 @@ Homepage: https://www.zerotier.com/
|
||||||
Package: zerotier-one
|
Package: zerotier-one
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6
|
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
|
Description: ZeroTier network virtualization service
|
||||||
ZeroTier One lets you join ZeroTier virtual networks and
|
ZeroTier One lets you join ZeroTier virtual networks and
|
||||||
have them appear as tun/tap ports on your system. See
|
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
|
* This is an AES mode built from GMAC and AES-CTR that is similar to the
|
||||||
* yield a mode similar to AES256-GCM-SIV that is resistant to accidental
|
* various SIV (synthetic IV) modes for AES and is resistant to nonce
|
||||||
* message IV duplication. This is good because ZeroTier is stateless and
|
* re-use. It's specifically tweaked for ZeroTier's packet structure with
|
||||||
* uses a small (64-bit) IV to reduce bandwidth overhead.
|
* 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 iv 96-bit message IV
|
||||||
* @param in Message plaintext
|
* @param in Message plaintext
|
||||||
* @param len Length of plaintext
|
* @param len Length of plaintext
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
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];
|
uint8_t ctrIv[16];
|
||||||
|
|
||||||
gmac(iv,in,len,ctrIv);
|
// Compute AES[k1](GMAC[k1](iv,plaintext))
|
||||||
encrypt(ctrIv,ctrIv);
|
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];
|
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=4;i<8;++i) ctrIv[i] ^= iv[i - 4];
|
||||||
for(unsigned int i=8;i<16;++i) ctrIv[i] = iv[i - 4];
|
for(unsigned int i=8;i<16;++i) ctrIv[i] = iv[i - 4];
|
||||||
encrypt(ctrIv,ctrIv);
|
k1.encrypt(ctrIv,ctrIv);
|
||||||
ctr(ctrIv,in,len,out);
|
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 iv 96-bit message IV
|
||||||
* @param in Message ciphertext
|
* @param in Message ciphertext
|
||||||
* @param len Length of ciphertext
|
* @param len Length of ciphertext
|
||||||
|
@ -188,20 +207,25 @@ 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
|
||||||
*/
|
*/
|
||||||
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];
|
uint8_t ctrIv[16],gmacOut[16];
|
||||||
|
|
||||||
for(unsigned int i=0;i<8;++i) ctrIv[i] = tag[i];
|
// 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] ^= iv[i - 4];
|
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];
|
for(unsigned int i=8;i<16;++i) ctrIv[i] = iv[i - 4];
|
||||||
encrypt(ctrIv,ctrIv);
|
k1.encrypt(ctrIv,ctrIv);
|
||||||
ctr(ctrIv,in,len,out);
|
k2.encrypt(ctrIv,ctrIv);
|
||||||
|
|
||||||
gmac(iv,out,len,gmacOut);
|
// Decrypt with AES[k2]-CTR
|
||||||
encrypt(gmacOut,gmacOut);
|
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
|
#ifdef ZT_NO_TYPE_PUNNING
|
||||||
return Utils::secureEq(gmacOut,tag,8);
|
return Utils::secureEq(gmacOut,tag,8);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -935,11 +935,19 @@ bool Packet::uncompress()
|
||||||
|
|
||||||
uint64_t Packet::nextPacketId()
|
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 uint64_t ctr = 0;
|
||||||
static Mutex lock;
|
static Mutex lock;
|
||||||
lock.lock();
|
lock.lock();
|
||||||
while (ctr == 0)
|
while (ctr == 0) {
|
||||||
Utils::getSecureRandom(&ctr,sizeof(ctr));
|
Utils::getSecureRandom(&ctr,sizeof(ctr));
|
||||||
|
ctr <<= 32;
|
||||||
|
ctr |= ((uint64_t)time(nullptr)) & 0x00000000ffffffffULL;
|
||||||
|
}
|
||||||
const uint64_t i = ctr++;
|
const uint64_t i = ctr++;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -316,8 +316,9 @@ static void handlePacket(const int v4s,const int v6s,const InetAddress *const ip
|
||||||
switch(pkt.verb()) {
|
switch(pkt.verb()) {
|
||||||
case Packet::VERB_HELLO:
|
case Packet::VERB_HELLO:
|
||||||
try {
|
try {
|
||||||
if ((now - peer->lastHello) > 1000) {
|
if ((now - peer->lastHello) > 500) {
|
||||||
peer->lastHello = now;
|
peer->lastHello = now;
|
||||||
|
|
||||||
peer->vProto = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
|
peer->vProto = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
|
||||||
peer->vMajor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
|
peer->vMajor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
|
||||||
peer->vMinor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MINOR_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:
|
case Packet::VERB_ECHO:
|
||||||
try {
|
try {
|
||||||
if ((now - peer->lastEcho) > 1000) {
|
if ((now - peer->lastEcho) > 500) {
|
||||||
peer->lastEcho = now;
|
peer->lastEcho = now;
|
||||||
|
|
||||||
Packet outp(source,s_self.address(),Packet::VERB_OK);
|
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();
|
std::cout << " AES-256-GMAC-CTR (benchmark): "; std::cout.flush();
|
||||||
start = OSUtils::now();
|
start = OSUtils::now();
|
||||||
for(unsigned long i=0;i<200000;++i) {
|
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];
|
hexbuf[0] = buf2[0];
|
||||||
}
|
}
|
||||||
end = OSUtils::now();
|
end = OSUtils::now();
|
||||||
|
|
Loading…
Add table
Reference in a new issue