mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 04:53:44 +02:00
type 1 (P-384) identities
This commit is contained in:
parent
6e771607c0
commit
83d723eb79
15 changed files with 467 additions and 591 deletions
|
@ -2395,23 +2395,12 @@ static inline void get_hram(unsigned char *hram, const unsigned char *sm, const
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
|
||||
void C25519::agree(const uint8_t mine[ZT_C25519_PRIVATE_KEY_LEN],const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],uint8_t rawkey[32])
|
||||
{
|
||||
unsigned char rawkey[32];
|
||||
unsigned char digest[64];
|
||||
|
||||
crypto_scalarmult(rawkey,mine.data,their.data);
|
||||
SHA512(digest,rawkey,32);
|
||||
for(unsigned int i=0,k=0;i<keylen;) {
|
||||
if (k == 64) {
|
||||
k = 0;
|
||||
SHA512(digest,digest,64);
|
||||
}
|
||||
((unsigned char *)keybuf)[i++] = digest[k++];
|
||||
}
|
||||
crypto_scalarmult(rawkey,mine,their);
|
||||
}
|
||||
|
||||
void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature)
|
||||
void C25519::sign(const uint8_t myPrivate[ZT_C25519_PRIVATE_KEY_LEN],const uint8_t myPublic[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,void *signature)
|
||||
{
|
||||
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
|
||||
SHA512(digest,msg,len);
|
||||
|
@ -2425,7 +2414,7 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
|
|||
unsigned char hram[crypto_hash_sha512_BYTES];
|
||||
unsigned char *sig = (unsigned char *)signature;
|
||||
|
||||
SHA512(extsk,myPrivate.data + 32,32);
|
||||
SHA512(extsk,myPrivate + 32,32);
|
||||
extsk[0] &= 248;
|
||||
extsk[31] &= 127;
|
||||
extsk[31] |= 64;
|
||||
|
@ -2446,7 +2435,7 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
|
|||
for(unsigned int i=0;i<32;i++)
|
||||
sig[i] = r[i];
|
||||
|
||||
get_hram(hram,sig,myPublic.data + 32,sig,96);
|
||||
get_hram(hram,sig,myPublic + 32,sig,96);
|
||||
|
||||
sc25519_from64bytes(&scs, hram);
|
||||
sc25519_from32bytes(&scsk, extsk);
|
||||
|
@ -2459,7 +2448,7 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
|
|||
sig[32 + i] = s[i];
|
||||
}
|
||||
|
||||
bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature,const unsigned int siglen)
|
||||
bool C25519::verify(const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,const void *signature,const unsigned int siglen)
|
||||
{
|
||||
if (siglen < 64) return false;
|
||||
|
||||
|
@ -2482,10 +2471,10 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len
|
|||
unsigned char hram[crypto_hash_sha512_BYTES];
|
||||
unsigned char m[96];
|
||||
|
||||
if (ge25519_unpackneg_vartime(&get1,their.data + 32))
|
||||
if (ge25519_unpackneg_vartime(&get1,their + 32))
|
||||
return false;
|
||||
|
||||
get_hram(hram,sig,their.data + 32,m,96);
|
||||
get_hram(hram,sig,their + 32,m,96);
|
||||
|
||||
sc25519_from64bytes(&schram, hram);
|
||||
|
||||
|
@ -2497,14 +2486,14 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len
|
|||
return Utils::secureEq(sig,t2,32);
|
||||
}
|
||||
|
||||
void C25519::_calcPubDH(C25519::Pair &kp)
|
||||
void C25519::_calcPubDH(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
|
||||
{
|
||||
// First 32 bytes of pub and priv are the keys for ECDH key
|
||||
// agreement. This generates the public portion from the private.
|
||||
crypto_scalarmult_base(kp.pub.data,kp.priv.data);
|
||||
crypto_scalarmult_base(pub,priv);
|
||||
}
|
||||
|
||||
void C25519::_calcPubED(C25519::Pair &kp)
|
||||
void C25519::_calcPubED(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
|
||||
{
|
||||
unsigned char extsk[64];
|
||||
sc25519 scsk;
|
||||
|
@ -2512,13 +2501,14 @@ void C25519::_calcPubED(C25519::Pair &kp)
|
|||
|
||||
// Second 32 bytes of pub and priv are the keys for ed25519
|
||||
// signing and verification.
|
||||
SHA512(extsk,kp.priv.data + 32,32);
|
||||
SHA512(extsk,priv + 32,32);
|
||||
extsk[0] &= 248;
|
||||
extsk[31] &= 127;
|
||||
extsk[31] |= 64;
|
||||
sc25519_from32bytes(&scsk,extsk);
|
||||
ge25519_scalarmult_base(&gepk,&scsk);
|
||||
ge25519_pack(kp.pub.data + 32,&gepk);
|
||||
ge25519_pack(pub + 32,&gepk);
|
||||
|
||||
// In NaCl, the public key is crammed into the next 32 bytes
|
||||
// of the private key for signing since both keys are required
|
||||
// to sign. In this version we just get it from kp.pub, so we
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace ZeroTier {
|
|||
#define ZT_C25519_PUBLIC_KEY_LEN 64
|
||||
#define ZT_C25519_PRIVATE_KEY_LEN 64
|
||||
#define ZT_C25519_SIGNATURE_LEN 96
|
||||
#define ZT_C25519_SHARED_KEY_LEN 32
|
||||
|
||||
/**
|
||||
* A combined Curve25519 ECDH and Ed25519 signature engine
|
||||
|
@ -41,21 +42,14 @@ namespace ZeroTier {
|
|||
class C25519
|
||||
{
|
||||
public:
|
||||
struct Public { uint8_t data[ZT_C25519_PUBLIC_KEY_LEN]; };
|
||||
struct Private { uint8_t data[ZT_C25519_PRIVATE_KEY_LEN]; };
|
||||
struct Signature { uint8_t data[ZT_C25519_SIGNATURE_LEN]; };
|
||||
struct Pair { Public pub; Private priv; };
|
||||
|
||||
/**
|
||||
* Generate a C25519 elliptic curve key pair
|
||||
*/
|
||||
static inline Pair generate()
|
||||
static inline void generate(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
|
||||
{
|
||||
Pair kp;
|
||||
Utils::getSecureRandom(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_calcPubDH(kp);
|
||||
_calcPubED(kp);
|
||||
return kp;
|
||||
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_calcPubDH(pub,priv);
|
||||
_calcPubED(pub,priv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,18 +66,15 @@ public:
|
|||
* @tparam F Type of 'cond'
|
||||
*/
|
||||
template<typename F>
|
||||
static inline Pair generateSatisfying(F cond)
|
||||
static inline void generateSatisfying(F cond,uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
|
||||
{
|
||||
Pair kp;
|
||||
void *const priv = (void *)kp.priv.data;
|
||||
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
|
||||
_calcPubED(pub,priv); // do Ed25519 key -- bytes 32-63 of pub and priv
|
||||
do {
|
||||
++(((uint64_t *)priv)[1]);
|
||||
--(((uint64_t *)priv)[2]);
|
||||
_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
|
||||
} while (!cond(kp));
|
||||
return kp;
|
||||
_calcPubDH(pub,priv); // keep regenerating bytes 0-31 until satisfied
|
||||
} while (!cond(pub));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,10 +85,9 @@ public:
|
|||
*
|
||||
* @param mine My private key
|
||||
* @param their Their public key
|
||||
* @param keybuf Buffer to fill
|
||||
* @param keylen Number of key bytes to generate
|
||||
* @param rawkey Buffer to receive raw (not hashed) agreed upon key
|
||||
*/
|
||||
static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen);
|
||||
static void agree(const uint8_t mine[ZT_C25519_PRIVATE_KEY_LEN],const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],uint8_t rawkey[32]);
|
||||
|
||||
/**
|
||||
* Sign a message with a sender's key pair
|
||||
|
@ -118,34 +108,7 @@ public:
|
|||
* @param len Length of message in bytes
|
||||
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length
|
||||
*/
|
||||
static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature);
|
||||
|
||||
/**
|
||||
* Sign a message with a sender's key pair
|
||||
*
|
||||
* Note that this generates a 96-byte signature that contains an extra 32 bytes
|
||||
* of hash data. This data is included for historical reasons and is optional. The
|
||||
* verify function here will take the first 64 bytes only (normal ed25519 signature)
|
||||
* or a 96-byte length signature with the extra input hash data.
|
||||
*
|
||||
* @param myPrivate My private key
|
||||
* @param myPublic My public key
|
||||
* @param msg Message to sign
|
||||
* @param len Length of message in bytes
|
||||
* @return Signature
|
||||
*/
|
||||
static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len)
|
||||
{
|
||||
Signature sig;
|
||||
sign(myPrivate,myPublic,msg,len,sig.data);
|
||||
return sig;
|
||||
}
|
||||
static inline Signature sign(const Pair &mine,const void *msg,unsigned int len)
|
||||
{
|
||||
Signature sig;
|
||||
sign(mine.priv,mine.pub,msg,len,sig.data);
|
||||
return sig;
|
||||
}
|
||||
static void sign(const uint8_t myPrivate[ZT_C25519_PRIVATE_KEY_LEN],const uint8_t myPublic[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,void *signature);
|
||||
|
||||
/**
|
||||
* Verify a message's signature
|
||||
|
@ -157,27 +120,16 @@ public:
|
|||
* @param siglen Length of signature in bytes
|
||||
* @return True if signature is valid and the message is authentic and unmodified
|
||||
*/
|
||||
static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature,const unsigned int siglen);
|
||||
|
||||
/**
|
||||
* Verify a message's signature
|
||||
*
|
||||
* @param their Public key to verify against
|
||||
* @param msg Message to verify signature integrity against
|
||||
* @param len Length of message in bytes
|
||||
* @param signature 96-byte signature
|
||||
* @return True if signature is valid and the message is authentic and unmodified
|
||||
*/
|
||||
static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) { return verify(their,msg,len,signature.data,96); }
|
||||
static bool verify(const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,const void *signature,const unsigned int siglen);
|
||||
|
||||
private:
|
||||
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
|
||||
// this is the ECDH key
|
||||
static void _calcPubDH(Pair &kp);
|
||||
static void _calcPubDH(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN]);
|
||||
|
||||
// derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
|
||||
// this is the Ed25519 sign/verify key
|
||||
static void _calcPubED(Pair &kp);
|
||||
static void _calcPubED(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN]);
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -40,7 +40,8 @@ namespace ZeroTier {
|
|||
namespace {
|
||||
|
||||
// These can't be changed without a new identity type. They define the
|
||||
// parameters of the hashcash hashing/searching algorithm.
|
||||
// parameters of the hashcash hashing/searching algorithm for type 0
|
||||
// identities.
|
||||
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
|
||||
#define ZT_IDENTITY_GEN_MEMORY 2097152
|
||||
|
||||
|
@ -86,9 +87,9 @@ struct _Identity_generate_cond
|
|||
{
|
||||
inline _Identity_generate_cond() {}
|
||||
inline _Identity_generate_cond(unsigned char *sb,char *gm) : digest(sb),genmem(gm) {}
|
||||
inline bool operator()(const C25519::Pair &kp) const
|
||||
inline bool operator()(const uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN]) const
|
||||
{
|
||||
_computeMemoryHardHash(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
_computeMemoryHardHash(pub,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
|
||||
}
|
||||
unsigned char *digest;
|
||||
|
@ -100,71 +101,44 @@ struct _Identity_generate_cond
|
|||
void Identity::generate(const Type t)
|
||||
{
|
||||
uint8_t digest[64];
|
||||
|
||||
_type = t;
|
||||
_hasPrivate = true;
|
||||
|
||||
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
switch(t) {
|
||||
case C25519: {
|
||||
C25519::Pair kp;
|
||||
do {
|
||||
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
|
||||
} while (_address.isReserved());
|
||||
memcpy(_k.t0.pub.data,kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(_k.t0.priv.data,kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_type = C25519;
|
||||
_hasPrivate = true;
|
||||
} break;
|
||||
case P384: {
|
||||
do {
|
||||
ECC384GenerateKey(_k.t1.pub,_k.t1.priv);
|
||||
_computeMemoryHardHash(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,digest,genmem);
|
||||
if (digest[0] >= ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)
|
||||
continue;
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH);
|
||||
} while (_address.isReserved());
|
||||
_type = P384;
|
||||
_hasPrivate = true;
|
||||
} break;
|
||||
}
|
||||
do {
|
||||
C25519::generateSatisfying(_Identity_generate_cond(digest,genmem),_pub.c25519,_priv.c25519);
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
|
||||
} while (_address.isReserved());
|
||||
delete [] genmem;
|
||||
|
||||
if (t == P384)
|
||||
ECC384GenerateKey(_pub.p384,_priv.p384);
|
||||
}
|
||||
|
||||
bool Identity::locallyValidate() const
|
||||
{
|
||||
if (_address.isReserved())
|
||||
return false;
|
||||
uint8_t digest[64];
|
||||
|
||||
char *genmem = nullptr;
|
||||
try {
|
||||
uint8_t digest[64];
|
||||
genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
_computeMemoryHardHash(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
break;
|
||||
case P384:
|
||||
_computeMemoryHardHash(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,digest,genmem);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
_computeMemoryHardHash(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
delete [] genmem;
|
||||
unsigned char addrb[5];
|
||||
_address.copyTo(addrb,5);
|
||||
return (
|
||||
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
|
||||
(digest[59] == addrb[0])&&
|
||||
(digest[60] == addrb[1])&&
|
||||
(digest[61] == addrb[2])&&
|
||||
(digest[62] == addrb[3])&&
|
||||
(digest[63] == addrb[4]));
|
||||
return ((_address == Address(digest + 59,ZT_ADDRESS_LENGTH))&&(!_address.isReserved())&&(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN));
|
||||
} catch ( ... ) {
|
||||
if (genmem) delete [] genmem;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
|
||||
{
|
||||
switch(_type) {
|
||||
|
||||
case C25519: {
|
||||
char *p = buf;
|
||||
Utils::hex10(_address.toInt(),p);
|
||||
|
@ -172,16 +146,17 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
|
|||
*(p++) = ':';
|
||||
*(p++) = '0';
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,p);
|
||||
Utils::hex(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,p);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN,p);
|
||||
Utils::hex(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN,p);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
|
||||
}
|
||||
*p = (char)0;
|
||||
return buf;
|
||||
} break;
|
||||
|
||||
case P384: {
|
||||
char *p = buf;
|
||||
Utils::hex10(_address.toInt(),p);
|
||||
|
@ -189,38 +164,43 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
|
|||
*(p++) = ':';
|
||||
*(p++) = '1';
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,p);
|
||||
p += ZT_ECC384_PUBLIC_KEY_SIZE * 2;
|
||||
int el = Utils::b32e((const uint8_t *)(&_pub),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,p,(unsigned int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
|
||||
if (el <= 0) return nullptr;
|
||||
p += el;
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE,p);
|
||||
p += ZT_ECC384_PRIVATE_KEY_SIZE * 2;
|
||||
el = Utils::b32e((const uint8_t *)(&_pub),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,p,(unsigned int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
|
||||
if (el <= 0) return nullptr;
|
||||
p += el;
|
||||
}
|
||||
*p = (char)0;
|
||||
return buf;
|
||||
} break;
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Identity::fromString(const char *str)
|
||||
{
|
||||
_hasPrivate = false;
|
||||
|
||||
if (!str) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
|
||||
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||
if (!Utils::scopy(tmp,sizeof(tmp),str)) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasPrivate = false;
|
||||
|
||||
int fno = 0;
|
||||
char *saveptr = (char *)0;
|
||||
for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) {
|
||||
for(char *f=Utils::stok(tmp,":",&saveptr);((f)&&(fno < 4));f=Utils::stok((char *)0,":",&saveptr)) {
|
||||
switch(fno++) {
|
||||
|
||||
case 0:
|
||||
_address = Address(Utils::hexStrToU64(f));
|
||||
if (_address.isReserved()) {
|
||||
|
@ -228,6 +208,7 @@ bool Identity::fromString(const char *str)
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if ((f[0] == '0')&&(!f[1])) {
|
||||
_type = C25519;
|
||||
|
@ -238,47 +219,56 @@ bool Identity::fromString(const char *str)
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch(_type) {
|
||||
|
||||
case C25519:
|
||||
if (Utils::unhex(f,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
|
||||
if (Utils::unhex(f,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case P384:
|
||||
if (Utils::unhex(f,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) != ZT_ECC384_PUBLIC_KEY_SIZE) {
|
||||
if (Utils::b32d(f,(uint8_t *)(&_pub),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE) != (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
if (Utils::unhex(f,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
if (Utils::unhex(f,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE) != ZT_ECC384_PRIVATE_KEY_SIZE) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
if (strlen(f) > 1) {
|
||||
switch(_type) {
|
||||
|
||||
case C25519:
|
||||
if (Utils::unhex(f,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case P384:
|
||||
if (Utils::b32d(f,(uint8_t *)(&_priv),ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE) != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE)) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_address.zero();
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fno < 3) {
|
||||
_address.zero();
|
||||
return false;
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "SHA512.hpp"
|
||||
#include "ECC384.hpp"
|
||||
|
||||
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
|
||||
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 512
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -60,8 +60,8 @@ public:
|
|||
*/
|
||||
enum Type
|
||||
{
|
||||
C25519 = ZT_CRYPTO_ALG_C25519, // Type 0 -- Curve25519 and Ed25519 (1.0 and 2.0, default)
|
||||
P384 = ZT_CRYPTO_ALG_P384 // Type 1 -- NIST P-384 ECDH and ECDSA (2.0+ only)
|
||||
C25519 = ZT_CRYPTO_ALG_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default)
|
||||
P384 = ZT_CRYPTO_ALG_P384 // Type 1 -- NIST P-384 with linked Curve25519 and Ed25519 secondaries (2.x+)
|
||||
};
|
||||
|
||||
inline Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
|
||||
|
@ -78,6 +78,9 @@ public:
|
|||
|
||||
inline ~Identity() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
|
||||
|
||||
/**
|
||||
* Set identity to NIL value (all zero)
|
||||
*/
|
||||
inline void zero() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
|
||||
|
||||
inline Identity &operator=(const Identity &id)
|
||||
|
@ -123,31 +126,10 @@ public:
|
|||
if (_hasPrivate) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
SHA512(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
SHA512(sha,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
return true;
|
||||
case P384:
|
||||
SHA512(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the SHA512 hash of our public key
|
||||
*
|
||||
* @param sha Buffer to receive hash bytes
|
||||
* @return True on success, false if identity is empty or invalid
|
||||
*/
|
||||
inline bool sha512PublicKey(void *sha) const
|
||||
{
|
||||
if (_hasPrivate) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
SHA512(sha,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
return true;
|
||||
case P384:
|
||||
SHA512(sha,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
SHA512(sha,&_priv,ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -168,20 +150,28 @@ public:
|
|||
*/
|
||||
inline unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
||||
{
|
||||
uint8_t h[48];
|
||||
uint8_t h[48 + ZT_C25519_PUBLIC_KEY_LEN];
|
||||
if (!_hasPrivate)
|
||||
return 0;
|
||||
switch(_type) {
|
||||
|
||||
case C25519:
|
||||
if (siglen < ZT_C25519_SIGNATURE_LEN)
|
||||
return 0;
|
||||
C25519::sign(_k.t0.priv,_k.t0.pub,data,len,sig);
|
||||
C25519::sign(_priv.c25519,_pub.c25519,data,len,sig);
|
||||
return ZT_C25519_SIGNATURE_LEN;
|
||||
|
||||
case P384:
|
||||
if (siglen < ZT_ECC384_SIGNATURE_SIZE)
|
||||
return 0;
|
||||
// Include C25519 public key in input for P-384 signature so the two keys are "bound
|
||||
// together" and cannot be decoupled in the same identity. An identity can have the
|
||||
// same C25519 key but a different P-384 key and have the same address, but this
|
||||
// means its signatures and key agreements will be different.
|
||||
SHA384(h,data,len);
|
||||
ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig);
|
||||
memcpy(h + 48,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
SHA384(h,h,48 + ZT_C25519_PUBLIC_KEY_LEN);
|
||||
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
|
||||
return ZT_ECC384_SIGNATURE_SIZE;
|
||||
}
|
||||
return 0;
|
||||
|
@ -200,12 +190,14 @@ public:
|
|||
{
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return C25519::verify(_k.t0.pub,data,len,sig,siglen);
|
||||
return C25519::verify(_pub.c25519,data,len,sig,siglen);
|
||||
case P384:
|
||||
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
|
||||
uint8_t h[48];
|
||||
uint8_t h[48 + ZT_C25519_PUBLIC_KEY_LEN];
|
||||
SHA384(h,data,len);
|
||||
return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig);
|
||||
memcpy(h + 48,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
SHA384(h,h,48 + ZT_C25519_PUBLIC_KEY_LEN);
|
||||
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -219,29 +211,38 @@ public:
|
|||
*
|
||||
* @param id Identity to agree with
|
||||
* @param key Result parameter to fill with key bytes
|
||||
* @param klen Length of key in bytes
|
||||
* @return Was agreement successful?
|
||||
*/
|
||||
inline bool agree(const Identity &id,void *key,unsigned int klen) const
|
||||
inline bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const
|
||||
{
|
||||
uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE];
|
||||
uint8_t h[48];
|
||||
uint8_t rawkey[128];
|
||||
uint8_t h[64];
|
||||
if (_hasPrivate) {
|
||||
switch(_type) {
|
||||
|
||||
case C25519:
|
||||
C25519::agree(_k.t0.priv,id._k.t0.pub,key,klen);
|
||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
|
||||
memcpy(key,h,32);
|
||||
return true;
|
||||
|
||||
case P384:
|
||||
ECC384ECDH(id._k.t1.pub,_k.t1.priv,ecc384RawSecret);
|
||||
SHA384(h,ecc384RawSecret,sizeof(ecc384RawSecret));
|
||||
for(unsigned int i=0,hi=0;i<klen;++i) {
|
||||
if (hi == 48) {
|
||||
hi = 0;
|
||||
SHA384(h,h,48);
|
||||
}
|
||||
((uint8_t *)key)[i] = h[hi++];
|
||||
if (id._type == P384) {
|
||||
// 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
|
||||
// that a type 1 identity with the same C25519 public key (and therefore address)
|
||||
// but a different P-384 key will not work.
|
||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||
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);
|
||||
for(unsigned int i=0;i<32;++i)
|
||||
key[i] = h[i];
|
||||
for(unsigned int i=0;i<16;++i)
|
||||
key[i] ^= h[32+i];
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -267,10 +268,10 @@ public:
|
|||
|
||||
case C25519:
|
||||
b.append((uint8_t)C25519);
|
||||
b.append(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
b.append((uint8_t)ZT_C25519_PRIVATE_KEY_LEN);
|
||||
b.append(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
} else {
|
||||
b.append((uint8_t)0);
|
||||
}
|
||||
|
@ -278,10 +279,12 @@ public:
|
|||
|
||||
case P384:
|
||||
b.append((uint8_t)P384);
|
||||
b.append(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
b.append(_pub.p384,ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
b.append((uint8_t)ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
b.append(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
b.append((uint8_t)(ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE));
|
||||
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
b.append(_priv.p384,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
} else {
|
||||
b.append((uint8_t)0);
|
||||
}
|
||||
|
@ -312,37 +315,38 @@ public:
|
|||
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
p += ZT_ADDRESS_LENGTH;
|
||||
|
||||
_type = (Type)b[p++];
|
||||
switch(_type) {
|
||||
switch((_type = (Type)b[p++])) {
|
||||
|
||||
case C25519:
|
||||
memcpy(_k.t0.pub.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN;
|
||||
pkl = (unsigned int)b[p++];
|
||||
if (pkl) {
|
||||
if (pkl != ZT_C25519_PRIVATE_KEY_LEN)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_hasPrivate = true;
|
||||
memcpy(_k.t0.priv.data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
|
||||
memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN;
|
||||
} else {
|
||||
memset(_k.t0.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_hasPrivate = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case P384:
|
||||
memcpy(_k.t0.pub.data,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN;
|
||||
memcpy(_pub.p384,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
p += ZT_ECC384_PUBLIC_KEY_SIZE;
|
||||
pkl = (unsigned int)b[p++];
|
||||
if (pkl) {
|
||||
if (pkl != ZT_ECC384_PRIVATE_KEY_SIZE)
|
||||
if (pkl != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_hasPrivate = true;
|
||||
memcpy(_k.t1.priv,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN;
|
||||
memcpy(_priv.p384,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
p += ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||
} else {
|
||||
memset(_k.t1.priv,0,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
_hasPrivate = false;
|
||||
}
|
||||
break;
|
||||
|
@ -385,9 +389,9 @@ public:
|
|||
if ((_address == id._address)&&(_type == id._type)) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) == 0);
|
||||
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) == 0);
|
||||
case P384:
|
||||
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) == 0);
|
||||
return (memcmp(&_pub,&id._pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE) == 0);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -404,9 +408,9 @@ public:
|
|||
if (_type == id._type) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) < 0);
|
||||
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) < 0);
|
||||
case P384:
|
||||
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) < 0);
|
||||
return (memcmp(&_pub,&id._pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE) < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,18 +425,16 @@ public:
|
|||
|
||||
private:
|
||||
Address _address;
|
||||
union {
|
||||
struct {
|
||||
C25519::Public pub;
|
||||
C25519::Private priv;
|
||||
} t0;
|
||||
struct {
|
||||
uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
|
||||
uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE];
|
||||
} t1;
|
||||
} _k;
|
||||
Type _type;
|
||||
bool _hasPrivate;
|
||||
ZT_PACKED_STRUCT(struct { // don't re-order these
|
||||
uint8_t c25519[ZT_C25519_PRIVATE_KEY_LEN];
|
||||
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
|
||||
}) _priv;
|
||||
ZT_PACKED_STRUCT(struct { // don't re-order these
|
||||
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN];
|
||||
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE];
|
||||
}) _pub;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -295,7 +295,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
|||
return true;
|
||||
|
||||
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
|
||||
if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
|
||||
if (RR->identity.agree(id,key)) {
|
||||
if (dearmor(key)) { // ensure packet is authentic, otherwise drop
|
||||
RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision");
|
||||
Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
|
||||
|
|
|
@ -110,6 +110,8 @@ struct InetAddress : public sockaddr_storage
|
|||
inline InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
|
||||
inline InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
|
||||
|
||||
inline void clear() { memset(this,0,sizeof(InetAddress)); }
|
||||
|
||||
inline InetAddress &operator=(const InetAddress &a)
|
||||
{
|
||||
if (&a != this)
|
||||
|
|
|
@ -213,9 +213,8 @@ namespace ZeroTier {
|
|||
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
|
||||
* without locks.
|
||||
*/
|
||||
class NetworkConfig
|
||||
struct NetworkConfig
|
||||
{
|
||||
public:
|
||||
inline NetworkConfig() :
|
||||
networkId(0),
|
||||
timestamp(0),
|
||||
|
@ -278,7 +277,7 @@ public:
|
|||
interference with lwIP's TCP congestion algorithm. Compression is also disabled
|
||||
for some NAS builds due to the usage of low-performance processors in certain
|
||||
older and budget models. */
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
|||
_lastAggregateStatsReport(0),
|
||||
_lastAggregateAllocation(0)
|
||||
{
|
||||
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
|
||||
if (!myIdentity.agree(peerIdentity,_key))
|
||||
throw ZT_EXCEPTION_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @return DNS name for this root (or empty string if none)
|
||||
* @return DNS name for this root or empty string if static entry with no DNS
|
||||
*/
|
||||
inline const Str dnsName() const
|
||||
{
|
||||
|
@ -138,7 +138,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Latest locator
|
||||
* @return Latest locator or NIL locator object if none
|
||||
*/
|
||||
inline Locator locator() const
|
||||
{
|
||||
|
@ -147,7 +147,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Timestamp of latest retrieved locator
|
||||
* @return Timestamp of latest retrieved locator or 0 if none
|
||||
*/
|
||||
inline int64_t locatorTimestamp() const
|
||||
{
|
||||
|
@ -155,22 +155,6 @@ public:
|
|||
return _lastFetchedLocator.timestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick a random physical address
|
||||
*
|
||||
* @return Physical address or InetAddress::NIL if none are available
|
||||
*/
|
||||
inline const InetAddress randomPhysicalAddress() const
|
||||
{
|
||||
Mutex::Lock l(_lock);
|
||||
if (_lastFetchedLocator.phy().empty()) {
|
||||
if (_defaultAddresses.empty())
|
||||
return InetAddress::NIL;
|
||||
return _defaultAddresses[(unsigned long)Utils::random() % (unsigned long)_defaultAddresses.size()];
|
||||
}
|
||||
return _lastFetchedLocator.phy()[(unsigned long)Utils::random() % (unsigned long)_lastFetchedLocator.phy().size()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update locator, returning true if new locator is valid and newer than existing
|
||||
*/
|
||||
|
@ -197,7 +181,7 @@ public:
|
|||
if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE)
|
||||
return false;
|
||||
Locator loc;
|
||||
if (!loc.decodeTxtRecords(start,end,_dnsPublicKey))
|
||||
if (!loc.decodeTxtRecords(start,end,_dnsPublicKey)) // also does verify()
|
||||
return false;
|
||||
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
|
||||
_lastFetchedLocator = loc;
|
||||
|
@ -208,6 +192,41 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick random IPv4 and IPv6 addresses for this root
|
||||
*
|
||||
* @param v4 Filled with V4 address or NIL if none found
|
||||
* @param v6 Filled with V6 address or NIL if none found
|
||||
*/
|
||||
inline void pickPhysical(InetAddress &v4,InetAddress &v6) const
|
||||
{
|
||||
v4.clear();
|
||||
v6.clear();
|
||||
std::vector<const InetAddress *> v4a,v6a;
|
||||
Mutex::Lock l(_lock);
|
||||
const std::vector<InetAddress> *const av = (_lastFetchedLocator) ? &(_lastFetchedLocator.phy()) : &_defaultAddresses;
|
||||
for(std::vector<InetAddress>::const_iterator i(av->begin());i!=av->end();++i) {
|
||||
switch(i->ss_family) {
|
||||
case AF_INET:
|
||||
v4a.push_back(&(*i));
|
||||
break;
|
||||
case AF_INET6:
|
||||
v6a.push_back(&(*i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (v4a.size() == 1) {
|
||||
v4 = *v4a[0];
|
||||
} else if (v4a.size() > 1) {
|
||||
v4 = *v4a[(unsigned long)Utils::random() % (unsigned long)v4a.size()];
|
||||
}
|
||||
if (v6a.size() == 1) {
|
||||
v6 = *v6a[0];
|
||||
} else if (v6a.size() > 1) {
|
||||
v6 = *v6a[(unsigned long)Utils::random() % (unsigned long)v6a.size()];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Identity _defaultIdentity;
|
||||
std::vector<InetAddress> _defaultAddresses;
|
||||
|
|
|
@ -14,49 +14,6 @@ Public domain.
|
|||
#include "SHA512.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#define ZT_HAVE_NATIVE_SHA512
|
||||
namespace ZeroTier {
|
||||
void SHA512(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
CC_SHA512_CTX ctx;
|
||||
CC_SHA512_Init(&ctx);
|
||||
CC_SHA512_Update(&ctx,data,len);
|
||||
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
void SHA384(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
CC_SHA512_CTX ctx;
|
||||
CC_SHA384_Init(&ctx);
|
||||
CC_SHA384_Update(&ctx,data,len);
|
||||
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ZT_USE_LIBCRYPTO
|
||||
#include <openssl/sha.h>
|
||||
#define ZT_HAVE_NATIVE_SHA512
|
||||
namespace ZeroTier {
|
||||
void SHA512(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx,data,len);
|
||||
SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
void SHA384(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
SHA512_CTX ctx;
|
||||
SHA384_Init(&ctx);
|
||||
SHA384_Update(&ctx,data,len);
|
||||
SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If a platform-native SHA512 isn't available we use this 64-bit C version.
|
||||
#ifndef ZT_HAVE_NATIVE_SHA512
|
||||
|
||||
namespace ZeroTier {
|
||||
|
@ -255,6 +212,3 @@ void SHA384(void *digest,const void *data,unsigned int len)
|
|||
} // namespace ZeroTier
|
||||
|
||||
#endif // !ZT_HAVE_NATIVE_SHA512
|
||||
|
||||
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len) { ZeroTier::SHA512(digest,data,len); }
|
||||
extern "C" void ZT_sha384internal(void *digest,const void *data,unsigned int len) { ZeroTier::SHA384(digest,data,len); }
|
||||
|
|
|
@ -27,12 +27,61 @@
|
|||
#ifndef ZT_SHA512_HPP
|
||||
#define ZT_SHA512_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#endif
|
||||
|
||||
#ifdef ZT_USE_LIBCRYPTO
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#define ZT_SHA512_DIGEST_LEN 64
|
||||
#define ZT_SHA384_DIGEST_LEN 48
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define ZT_HAVE_NATIVE_SHA512 1
|
||||
static inline void SHA512(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
CC_SHA512_CTX ctx;
|
||||
CC_SHA512_Init(&ctx);
|
||||
CC_SHA512_Update(&ctx,data,len);
|
||||
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
static inline void SHA384(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
CC_SHA512_CTX ctx;
|
||||
CC_SHA384_Init(&ctx);
|
||||
CC_SHA384_Update(&ctx,data,len);
|
||||
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ZT_USE_LIBCRYPTO
|
||||
#define ZT_HAVE_NATIVE_SHA512 1
|
||||
static inline void SHA512(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx,data,len);
|
||||
SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
static inline void SHA384(void *digest,const void *data,unsigned int len)
|
||||
{
|
||||
SHA512_CTX ctx;
|
||||
SHA384_Init(&ctx);
|
||||
SHA384_Update(&ctx,data,len);
|
||||
SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZT_HAVE_NATIVE_SHA512
|
||||
void SHA512(void *digest,const void *data,unsigned int len);
|
||||
void SHA384(void *digest,const void *data,unsigned int len);
|
||||
#endif
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
|
|
|
@ -51,13 +51,13 @@ class Identity;
|
|||
class Peer;
|
||||
class Path;
|
||||
class Network;
|
||||
class NetworkConfig;
|
||||
class MAC;
|
||||
class CertificateOfMembership;
|
||||
class CertificateOfOwnership;
|
||||
class Revocation;
|
||||
class Tag;
|
||||
class Capability;
|
||||
struct NetworkConfig;
|
||||
|
||||
/**
|
||||
* Remote tracing and trace logging handler
|
||||
|
|
|
@ -154,9 +154,14 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
{
|
||||
static Mutex globalLock;
|
||||
static Salsa20 s20;
|
||||
static bool s20Initialized = false;
|
||||
static uint8_t randomBuf[65536];
|
||||
static bool initialized = false;
|
||||
static uint8_t randomBuf[131072];
|
||||
static unsigned int randomPtr = sizeof(randomBuf);
|
||||
#ifdef __WINDOWS__
|
||||
static HCRYPTPROV cryptProvider = NULL;
|
||||
#else
|
||||
static int devURandomFd = -1;
|
||||
#endif
|
||||
|
||||
Mutex::Lock _l(globalLock);
|
||||
|
||||
|
@ -167,8 +172,9 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
* 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 (!s20Initialized) {
|
||||
s20Initialized = true;
|
||||
if (unlikely(!initialized)) {
|
||||
initialized = true;
|
||||
|
||||
uint64_t s20Key[4];
|
||||
s20Key[0] = (uint64_t)time(nullptr);
|
||||
#ifdef __WINDOWS__
|
||||
|
@ -179,60 +185,46 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
|
||||
s20Key[3] = (uint64_t)&s20; // address of s20
|
||||
s20.init(s20Key,s20Key);
|
||||
|
||||
#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);
|
||||
}
|
||||
#else
|
||||
devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
||||
if (devURandomFd < 0) {
|
||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
static HCRYPTPROV cryptProvider = NULL;
|
||||
|
||||
for(unsigned int i=0;i<bytes;++i) {
|
||||
if (randomPtr >= sizeof(randomBuf)) {
|
||||
if (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 (unlikely(randomPtr >= sizeof(randomBuf))) {
|
||||
randomPtr = 0;
|
||||
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) {
|
||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
||||
exit(1);
|
||||
}
|
||||
randomPtr = 0;
|
||||
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf));
|
||||
s20.init(randomBuf,randomBuf);
|
||||
}
|
||||
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
|
||||
}
|
||||
|
||||
#else // not __WINDOWS__
|
||||
|
||||
static int devURandomFd = -1;
|
||||
|
||||
if (devURandomFd < 0) {
|
||||
devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
||||
if (devURandomFd < 0) {
|
||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i=0;i<bytes;++i) {
|
||||
if (randomPtr >= sizeof(randomBuf)) {
|
||||
for(;;) {
|
||||
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
|
||||
::close(devURandomFd);
|
||||
devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
||||
if (devURandomFd < 0) {
|
||||
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
} else break;
|
||||
}
|
||||
if (unlikely(randomPtr >= sizeof(randomBuf))) {
|
||||
randomPtr = 0;
|
||||
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);
|
||||
}
|
||||
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf));
|
||||
s20.init(randomBuf,randomBuf);
|
||||
}
|
||||
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
|
||||
}
|
||||
|
@ -265,7 +257,7 @@ int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
|
|||
}
|
||||
int index = 0x1F & (buffer >> (bitsLeft - 5));
|
||||
bitsLeft -= 5;
|
||||
result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
|
||||
result[count++] = "abcdefghijklmnopqrstuvwxyZ234567"[index];
|
||||
}
|
||||
}
|
||||
if (count < bufSize) {
|
||||
|
|
173
selftest.cpp
173
selftest.cpp
|
@ -386,7 +386,41 @@ static int testCrypto()
|
|||
::free((void *)bb);
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Testing ECC384 (NIST P-384)..." ZT_EOL_S;
|
||||
std::cout << "[crypto] Testing C25519 and Ed25519... "; std::cout.flush();
|
||||
for(int k=0;k<ZT_NUM_C25519_TEST_VECTORS;++k) {
|
||||
uint8_t pub1[ZT_C25519_PUBLIC_KEY_LEN],pub2[ZT_C25519_PUBLIC_KEY_LEN],priv1[ZT_C25519_PRIVATE_KEY_LEN],priv2[ZT_C25519_PRIVATE_KEY_LEN];
|
||||
memcpy(pub1,C25519_TEST_VECTORS[k].pub1,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(priv1,C25519_TEST_VECTORS[k].priv1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
memcpy(pub2,C25519_TEST_VECTORS[k].pub2,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(priv2,C25519_TEST_VECTORS[k].priv2,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
uint8_t ag1[32],ag2[32];
|
||||
C25519::agree(priv1,pub2,ag1);
|
||||
C25519::agree(priv2,pub1,ag2);
|
||||
if (memcmp(ag1,ag2,32) != 0) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
uint8_t ag1h[64];
|
||||
SHA512(ag1h,ag1,32);
|
||||
if (memcmp(ag1h,C25519_TEST_VECTORS[k].agreement,64) != 0) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
uint8_t sig1[ZT_C25519_SIGNATURE_LEN],sig2[ZT_C25519_SIGNATURE_LEN];
|
||||
C25519::sign(priv1,pub1,ag1h,64,sig1);
|
||||
C25519::sign(priv2,pub2,ag1h,64,sig2);
|
||||
if (memcmp(sig1,C25519_TEST_VECTORS[k].agreementSignedBy1,64) != 0) {
|
||||
std::cout << "FAIL (3)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(sig2,C25519_TEST_VECTORS[k].agreementSignedBy2,64) != 0) {
|
||||
std::cout << "FAIL (4)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing NIST P-384..." ZT_EOL_S;
|
||||
{
|
||||
uint8_t p384pub[ZT_ECC384_PUBLIC_KEY_SIZE],p384priv[ZT_ECC384_PRIVATE_KEY_SIZE],p384sig[ZT_ECC384_SIGNATURE_SIZE],p384hash[ZT_ECC384_SIGNATURE_HASH_SIZE];
|
||||
char p384hex[256];
|
||||
|
@ -432,116 +466,6 @@ static int testCrypto()
|
|||
std::cout << "[crypto] ECDSA Test Vector: PASS" ZT_EOL_S;
|
||||
}
|
||||
|
||||
std::cout << "[crypto] Testing C25519 and Ed25519 against test vectors... "; std::cout.flush();
|
||||
for(int k=0;k<ZT_NUM_C25519_TEST_VECTORS;++k) {
|
||||
C25519::Pair p1,p2;
|
||||
memcpy(p1.pub.data,C25519_TEST_VECTORS[k].pub1,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(p1.priv.data,C25519_TEST_VECTORS[k].priv1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
memcpy(p2.pub.data,C25519_TEST_VECTORS[k].pub2,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(p2.priv.data,C25519_TEST_VECTORS[k].priv2,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
C25519::agree(p1.priv,p2.pub,buf1,64);
|
||||
C25519::agree(p2.priv,p1.pub,buf2,64);
|
||||
if (memcmp(buf1,buf2,64)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(buf1,C25519_TEST_VECTORS[k].agreement,64)) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
C25519::Signature sig1 = C25519::sign(p1,buf1,64);
|
||||
if (memcmp(sig1.data,C25519_TEST_VECTORS[k].agreementSignedBy1,64)) {
|
||||
std::cout << "FAIL (3)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
C25519::Signature sig2 = C25519::sign(p2,buf1,64);
|
||||
if (memcmp(sig2.data,C25519_TEST_VECTORS[k].agreementSignedBy2,64)) {
|
||||
std::cout << "FAIL (4)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing C25519 ECC key agreement... "; std::cout.flush();
|
||||
for(unsigned int i=0;i<100;++i) {
|
||||
memset(buf1,64,sizeof(buf1));
|
||||
memset(buf2,64,sizeof(buf2));
|
||||
memset(buf3,64,sizeof(buf3));
|
||||
C25519::Pair p1 = C25519::generate();
|
||||
C25519::Pair p2 = C25519::generate();
|
||||
C25519::Pair p3 = C25519::generate();
|
||||
C25519::agree(p1.priv,p2.pub,buf1,64);
|
||||
C25519::agree(p2.priv,p1.pub,buf2,64);
|
||||
C25519::agree(p3.priv,p1.pub,buf3,64);
|
||||
// p1<>p2 should equal p1<>p2
|
||||
if (memcmp(buf1,buf2,64)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
// p2<>p1 should not equal p3<>p1
|
||||
if (!memcmp(buf2,buf3,64)) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Benchmarking C25519 ECC key agreement... "; std::cout.flush();
|
||||
C25519::Pair bp[8];
|
||||
for(int k=0;k<8;++k)
|
||||
bp[k] = C25519::generate();
|
||||
uint64_t st = OSUtils::now();
|
||||
for(unsigned int k=0;k<50;++k) {
|
||||
C25519::agree(bp[~k & 7].priv,bp[k & 7].pub,buf1,64);
|
||||
}
|
||||
uint64_t et = OSUtils::now();
|
||||
std::cout << ((double)(et - st) / 50.0) << "ms per agreement." ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Testing Ed25519 ECC signatures... "; std::cout.flush();
|
||||
C25519::Pair didntSign = C25519::generate();
|
||||
for(unsigned int i=0;i<10;++i) {
|
||||
C25519::Pair p1 = C25519::generate();
|
||||
for(unsigned int k=0;k<sizeof(buf1);++k)
|
||||
buf1[k] = (unsigned char)rand();
|
||||
C25519::Signature sig = C25519::sign(p1,buf1,sizeof(buf1));
|
||||
if (!C25519::verify(p1.pub,buf1,sizeof(buf1),sig)) {
|
||||
std::cout << "FAIL (1)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
++buf1[17];
|
||||
if (C25519::verify(p1.pub,buf1,sizeof(buf1),sig)) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
--buf1[17];
|
||||
if (!C25519::verify(p1.pub,buf1,sizeof(buf1),sig)) {
|
||||
std::cout << "FAIL (3)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
if (C25519::verify(didntSign.pub,buf1,sizeof(buf1),sig)) {
|
||||
std::cout << "FAIL (2)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
for(unsigned int k=0;k<64;++k) {
|
||||
C25519::Signature sig2(sig);
|
||||
sig2.data[rand() % ZT_C25519_SIGNATURE_LEN] ^= (unsigned char)(1 << (rand() & 7));
|
||||
if (C25519::verify(p1.pub,buf1,sizeof(buf1),sig2)) {
|
||||
std::cout << "FAIL (5)" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
|
||||
std::cout << "[crypto] Benchmarking Ed25519 ECC signatures... "; std::cout.flush();
|
||||
st = OSUtils::now();
|
||||
for(int k=0;k<1000;++k) {
|
||||
C25519::Signature sig;
|
||||
C25519::sign(didntSign.priv,didntSign.pub,buf1,sizeof(buf1),sig.data);
|
||||
}
|
||||
et = OSUtils::now();
|
||||
std::cout << ((double)(et - st) / 50.0) << "ms per signature." ZT_EOL_S;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -577,18 +501,21 @@ static int testIdentity()
|
|||
}
|
||||
std::cout << "PASS (i.e. it failed)" ZT_EOL_S;
|
||||
|
||||
for(unsigned int k=0;k<4;++k) {
|
||||
std::cout << "[identity] Generate identity... "; std::cout.flush();
|
||||
uint64_t genstart = OSUtils::now();
|
||||
id.generate(Identity::C25519);
|
||||
uint64_t genend = OSUtils::now();
|
||||
std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true,buf2) << ZT_EOL_S;
|
||||
std::cout << "[identity] Locally validate identity: ";
|
||||
if (id.locallyValidate()) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
static const Identity::Type idtypes[2] = { Identity::C25519,Identity::P384 };
|
||||
for(unsigned int ti=0;ti<2;++ti) {
|
||||
for(unsigned int k=0;k<2;++k) {
|
||||
std::cout << "[identity] Generate identity (type " << (int)idtypes[ti] << ")... "; std::cout.flush();
|
||||
uint64_t genstart = OSUtils::now();
|
||||
id.generate(idtypes[ti]);
|
||||
uint64_t genend = OSUtils::now();
|
||||
std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true,buf2) << ZT_EOL_S;
|
||||
std::cout << "[identity] Locally validate identity: ";
|
||||
if (id.locallyValidate()) {
|
||||
std::cout << "PASS" ZT_EOL_S;
|
||||
} else {
|
||||
std::cout << "FAIL" ZT_EOL_S;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue