mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 04:53:44 +02:00
Crypto work, packet work
This commit is contained in:
parent
83d723eb79
commit
3a21fdc304
5 changed files with 110 additions and 66 deletions
71
node/AES.hpp
71
node/AES.hpp
|
@ -155,6 +155,77 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt with AES256-GCM-DDS
|
||||||
|
*
|
||||||
|
* DDS stands for Data Dependent Scramble and refers to our scheme for nonce
|
||||||
|
* duplication resistance.
|
||||||
|
*
|
||||||
|
* @param iv IV (usually random)
|
||||||
|
* @param in Input plaintext
|
||||||
|
* @param inlen Length of plaintext
|
||||||
|
* @param assoc Associated data that won't be encrypted
|
||||||
|
* @param assoclen Length of associated data
|
||||||
|
* @param out Output ciphertext buffer (must be at least inlen in size)
|
||||||
|
* @param combinedTag Buffer to receive 128-bit encrypted combined IV and MAC
|
||||||
|
*/
|
||||||
|
inline void gcmDdsEncrypt(const uint64_t iv,const void *in,unsigned int inlen,const void *assoc,unsigned int assoclen,void *out,uint64_t combinedTag[2])
|
||||||
|
{
|
||||||
|
// Make 12-byte GCM IV (use combinedTag as tmp buffer)
|
||||||
|
combinedTag[0] = iv;
|
||||||
|
((uint8_t *)combinedTag)[8] = (uint8_t)(inlen >> 16);
|
||||||
|
((uint8_t *)combinedTag)[9] = (uint8_t)(inlen >> 8);
|
||||||
|
((uint8_t *)combinedTag)[10] = (uint8_t)inlen;
|
||||||
|
((uint8_t *)combinedTag)[11] = (uint8_t)assoclen;
|
||||||
|
|
||||||
|
// Encrypt data and store 64-bit tag/MAC code in second 64 bits of combinedTag.
|
||||||
|
gcmEncrypt((const uint8_t *)combinedTag,in,inlen,assoc,assoclen,out,((uint8_t *)&(combinedTag[1])),8);
|
||||||
|
|
||||||
|
// Encrypt combinedTag once to get scramble key
|
||||||
|
encrypt((const uint8_t *)combinedTag,(uint8_t *)combinedTag);
|
||||||
|
|
||||||
|
// Scramble ciphertext
|
||||||
|
scramble((const uint8_t *)combinedTag,out,inlen,out);
|
||||||
|
|
||||||
|
// Encrypt combinedTag again to get masked tag to include with message
|
||||||
|
encrypt((const uint8_t *)combinedTag,(uint8_t *)combinedTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt with AES256-GCM-DDS
|
||||||
|
*
|
||||||
|
* @param combinedTag Encrypted combined tag
|
||||||
|
* @param in Input ciphertext
|
||||||
|
* @param inlen Length of ciphertext
|
||||||
|
* @param assoc Associated data that wasn't encrypted
|
||||||
|
* @param assoclen Length of associated data
|
||||||
|
* @param out Output plaintext buffer (must be at least inlen in size)
|
||||||
|
* @return True if GCM authentication check succeeded (if false, discard packet)
|
||||||
|
*/
|
||||||
|
inline bool gcmDdsDecrypt(const uint64_t combinedTag[2],const void *in,unsigned int inlen,const void *assoc,unsigned int assoclen,void *out)
|
||||||
|
{
|
||||||
|
uint64_t tmp[2],gcmIv[2];
|
||||||
|
|
||||||
|
// Decrypt combinedTag to get scramble key
|
||||||
|
decrypt((const uint8_t *)combinedTag,(uint8_t *)tmp);
|
||||||
|
|
||||||
|
// Unscramble ciphertext
|
||||||
|
unscramble((const uint8_t *)tmp,in,inlen,out);
|
||||||
|
|
||||||
|
// Decrypt combinedTag again to get original IV and AES-GCM MAC
|
||||||
|
decrypt((const uint8_t *)tmp,(uint8_t *)tmp);
|
||||||
|
|
||||||
|
// Make 12-byte GCM IV
|
||||||
|
gcmIv[0] = tmp[0];
|
||||||
|
((uint8_t *)gcmIv)[8] = (uint8_t)(inlen >> 16);
|
||||||
|
((uint8_t *)gcmIv)[9] = (uint8_t)(inlen >> 8);
|
||||||
|
((uint8_t *)gcmIv)[10] = (uint8_t)inlen;
|
||||||
|
((uint8_t *)gcmIv)[11] = (uint8_t)assoclen;
|
||||||
|
|
||||||
|
// Perform GCM decryption and authentication
|
||||||
|
return gcmDecrypt((const uint8_t *)gcmIv,out,inlen,assoc,assoclen,out,(const uint8_t *)&(tmp[1]),8);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint32_t Te0[256];
|
static const uint32_t Te0[256];
|
||||||
static const uint32_t Te1[256];
|
static const uint32_t Te1[256];
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace ZeroTier {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a NIST P-384 key pair
|
* Generate a NIST P-384 key pair
|
||||||
*
|
*
|
||||||
* @param pub Buffer to receive point compressed public key
|
* @param pub Buffer to receive point compressed public key
|
||||||
* @param priv Buffer to receiver private key
|
* @param priv Buffer to receiver private key
|
||||||
*/
|
*/
|
||||||
|
@ -71,10 +71,10 @@ void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_EC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a hash with a NIST P-384 private key
|
* Sign a hash with a NIST P-384 private key
|
||||||
*
|
*
|
||||||
* The hash must be 48 bytes in size and is typically the first 48 bytes
|
* The hash must be 48 bytes in size. If it's longer only the first 48
|
||||||
* of a SHA512 hash or something similar. Extra bytes of course are ignored.
|
* bytes are used.
|
||||||
*
|
*
|
||||||
* @param priv Private key
|
* @param priv Private key
|
||||||
* @param hash 48-byte hash
|
* @param hash 48-byte hash
|
||||||
* @param sig Buffer to receive signature
|
* @param sig Buffer to receive signature
|
||||||
|
@ -83,7 +83,7 @@ void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify a signature
|
* Verify a signature
|
||||||
*
|
*
|
||||||
* @param pub Public key
|
* @param pub Public key
|
||||||
* @param hash 48-byte hash (usually first 48 bytes of SHA512(msg))
|
* @param hash 48-byte hash (usually first 48 bytes of SHA512(msg))
|
||||||
* @param sig Signature to check
|
* @param sig Signature to check
|
||||||
|
@ -93,10 +93,10 @@ bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform ECDH key agreement
|
* Perform ECDH key agreement
|
||||||
*
|
*
|
||||||
* The secret generated here is the raw 48-byte result of ECDH.
|
* The secret generated here is the raw 48-byte result of ECDH.
|
||||||
* It's typically hashed prior to use.
|
* It's typically hashed prior to use.
|
||||||
*
|
*
|
||||||
* @param theirPub Remote public key
|
* @param theirPub Remote public key
|
||||||
* @param ourPriv Local private key
|
* @param ourPriv Local private key
|
||||||
* @param secret Buffer to receive 48-byte secret
|
* @param secret Buffer to receive 48-byte secret
|
||||||
|
|
|
@ -218,31 +218,36 @@ public:
|
||||||
uint8_t rawkey[128];
|
uint8_t rawkey[128];
|
||||||
uint8_t h[64];
|
uint8_t h[64];
|
||||||
if (_hasPrivate) {
|
if (_hasPrivate) {
|
||||||
switch(_type) {
|
if (_type == C25519) {
|
||||||
|
if ((id._type == C25519)||(id._type == P384)) {
|
||||||
case C25519:
|
// If we are a C25519 key we can agree with another C25519 key or with only the
|
||||||
|
// C25519 portion of a type 1 P-384 key.
|
||||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||||
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
|
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
|
||||||
memcpy(key,h,32);
|
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
case P384:
|
} else if (_type == P384) {
|
||||||
if (id._type == P384) {
|
if (id._type == P384) {
|
||||||
// Perform key agreement over both curves for the same reason that C25519 public
|
// Perform key agreement over both curves for the same reason that C25519 public
|
||||||
// keys are included in P-384 signature inputs: to bind the keys together so
|
// keys are included in P-384 signature inputs: to bind the keys together so
|
||||||
// that a type 1 identity with the same C25519 public key (and therefore address)
|
// that a type 1 identity with the same C25519 public key (and therefore address)
|
||||||
// but a different P-384 key will not work.
|
// but a different P-384 key will not work.
|
||||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||||
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
|
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
|
||||||
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
|
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
|
||||||
for(unsigned int i=0;i<32;++i)
|
for(unsigned int i=0;i<32;++i)
|
||||||
key[i] = h[i];
|
key[i] = h[i];
|
||||||
for(unsigned int i=0;i<16;++i)
|
for(unsigned int i=0;i<16;++i)
|
||||||
key[i] ^= h[32+i];
|
key[i] ^= h[32+i];
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (id._type == C25519) {
|
||||||
return false;
|
// If the other identity is a C25519 identity we can agree using only that type.
|
||||||
|
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||||
|
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
|
||||||
|
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include "NetworkController.hpp"
|
#include "NetworkController.hpp"
|
||||||
#include "SelfAwareness.hpp"
|
#include "SelfAwareness.hpp"
|
||||||
#include "Salsa20.hpp"
|
#include "Salsa20.hpp"
|
||||||
#include "SHA512.hpp"
|
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "CertificateOfMembership.hpp"
|
#include "CertificateOfMembership.hpp"
|
||||||
#include "Capability.hpp"
|
#include "Capability.hpp"
|
||||||
|
@ -377,38 +376,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
||||||
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
|
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
|
||||||
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
|
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
|
||||||
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
|
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
|
||||||
|
_path->address().serialize(outp);
|
||||||
if (protoVersion >= 5) {
|
|
||||||
_path->address().serialize(outp);
|
|
||||||
} else {
|
|
||||||
/* LEGACY COMPATIBILITY HACK:
|
|
||||||
*
|
|
||||||
* For a while now (since 1.0.3), ZeroTier has recognized changes in
|
|
||||||
* its network environment empirically by examining its external network
|
|
||||||
* address as reported by trusted peers. In versions prior to 1.1.0
|
|
||||||
* (protocol version < 5), they did this by saving a snapshot of this
|
|
||||||
* information (in SelfAwareness.hpp) keyed by reporting device ID and
|
|
||||||
* address type.
|
|
||||||
*
|
|
||||||
* This causes problems when clustering is combined with symmetric NAT.
|
|
||||||
* Symmetric NAT remaps ports, so different endpoints in a cluster will
|
|
||||||
* report back different exterior addresses. Since the old code keys
|
|
||||||
* this by device ID and not sending physical address and compares the
|
|
||||||
* entire address including port, it constantly thinks its external
|
|
||||||
* surface is changing and resets connections when talking to a cluster.
|
|
||||||
*
|
|
||||||
* In new code we key by sending physical address and device and we also
|
|
||||||
* take the more conservative position of only interpreting changes in
|
|
||||||
* IP address (neglecting port) as a change in network topology that
|
|
||||||
* necessitates a reset. But we can make older clients work here by
|
|
||||||
* nulling out the port field. Since this info is only used for empirical
|
|
||||||
* detection of link changes, it doesn't break anything else.
|
|
||||||
*/
|
|
||||||
InetAddress tmpa(_path->address());
|
|
||||||
tmpa.setPort(0);
|
|
||||||
tmpa.serialize(outp);
|
|
||||||
}
|
|
||||||
|
|
||||||
outp.armor(peer->key(),true);
|
outp.armor(peer->key(),true);
|
||||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||||
|
|
||||||
|
|
|
@ -455,7 +455,7 @@ public:
|
||||||
* <[8] timestamp for determining latency>
|
* <[8] timestamp for determining latency>
|
||||||
* <[...] binary serialized identity (see Identity)>
|
* <[...] binary serialized identity (see Identity)>
|
||||||
* <[...] physical destination address of packet>
|
* <[...] physical destination address of packet>
|
||||||
*
|
*
|
||||||
* HELLO is sent in the clear as it is how peers share their identity
|
* HELLO is sent in the clear as it is how peers share their identity
|
||||||
* public keys.
|
* public keys.
|
||||||
*
|
*
|
||||||
|
@ -724,7 +724,7 @@ public:
|
||||||
*
|
*
|
||||||
* Flags:
|
* Flags:
|
||||||
* 0x01 - COM is attached (DEPRECATED)
|
* 0x01 - COM is attached (DEPRECATED)
|
||||||
*
|
*
|
||||||
* More than one OK response can occur if the response is broken up across
|
* More than one OK response can occur if the response is broken up across
|
||||||
* multiple packets or if querying a clustered node.
|
* multiple packets or if querying a clustered node.
|
||||||
*
|
*
|
||||||
|
@ -759,7 +759,7 @@ public:
|
||||||
* 0x02 - Implicit gather limit field is present (DEPRECATED)
|
* 0x02 - Implicit gather limit field is present (DEPRECATED)
|
||||||
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
|
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
|
||||||
* 0x08 - Explicit recipient list included for P2P/HS replication
|
* 0x08 - Explicit recipient list included for P2P/HS replication
|
||||||
*
|
*
|
||||||
* Explicit recipient lists are used for peer to peer or hub and spoke
|
* Explicit recipient lists are used for peer to peer or hub and spoke
|
||||||
* replication.
|
* replication.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue