Finish up ECC384 identity generation.

This commit is contained in:
Adam Ierymenko 2019-08-07 23:50:47 -05:00
parent 14c8564893
commit 3c590994db
No known key found for this signature in database
GPG Key ID: 1657198823E52A61
2 changed files with 98 additions and 105 deletions

View File

@ -37,8 +37,7 @@
namespace ZeroTier {
//////////////////////////////////////////////////////////////////////////////
// This is the memory-hard hash used for type 0 identities' addresses
namespace {
// These can't be changed without a new identity type. They define the
// parameters of the hashcash hashing/searching algorithm.
@ -46,7 +45,7 @@ namespace ZeroTier {
#define ZT_IDENTITY_GEN_MEMORY 2097152
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
static void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
{
// Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes);
@ -96,73 +95,132 @@ struct _Identity_generate_cond
char *genmem;
};
//////////////////////////////////////////////////////////////////////////////
// This is a memory-hard momentum-like hash used for type 1 addresses
//////////////////////////////////////////////////////////////////////////////
} // anonymous namespace
void Identity::generate(const Type t)
{
uint8_t digest[64];
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
switch(t) {
case C25519: {
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
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;
delete [] genmem;
} break;
case P384: {
do {
ECC384GenerateKey(_k.t1.pub,_k.t1.priv);
// TODO
SHA512(digest,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
_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;
}
delete [] genmem;
}
bool Identity::locallyValidate() const
{
if (_address.isReserved())
return false;
switch(_type) {
case C25519: {
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_k.t0.pub.data,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]));
} break;
case P384: {
return true;
} break;
uint8_t digest[64];
char *genmem = nullptr;
try {
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;
}
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]));
} catch ( ... ) {
if (genmem) delete [] genmem;
return false;
}
}
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
uint8_t h[48];
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);
return ZT_C25519_SIGNATURE_LEN;
case P384:
if (siglen < ZT_ECC384_SIGNATURE_SIZE)
return 0;
SHA384(h,data,len);
ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
return 0;
}
bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
case C25519:
return C25519::verify(_k.t0.pub,data,len,sig,siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len);
return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig);
}
break;
}
return false;
}
bool Identity::agree(const Identity &id,void *key,unsigned int klen) const
{
uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE];
uint8_t h[48];
if (_hasPrivate) {
switch(_type) {
case C25519:
C25519::agree(_k.t0.priv,id._k.t0.pub,key,klen);
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++];
}
return true;
}
}
return false;
}
@ -186,7 +244,6 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
*p = (char)0;
return buf;
}
case P384: {
char *p = buf;
Utils::hex10(_address.toInt(),p);

View File

@ -163,29 +163,7 @@ public:
* @param siglen Length of buffer
* @return Number of bytes actually written to sig or 0 on error
*/
inline unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
uint8_t h[48];
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);
return ZT_C25519_SIGNATURE_LEN;
case P384:
if (siglen < ZT_ECC384_SIGNATURE_SIZE)
return 0;
SHA384(h,data,len);
ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
return 0;
}
unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const;
/**
* Verify a message signature against this identity
@ -196,23 +174,7 @@ public:
* @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
case C25519:
return C25519::verify(_k.t0.pub,data,len,sig,siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len);
return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig);
}
}
return false;
}
bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const;
/**
* Shortcut method to perform key agreement with another identity
@ -224,33 +186,7 @@ public:
* @param klen Length of key in bytes
* @return Was agreement successful?
*/
inline bool agree(const Identity &id,void *key,unsigned int klen) const
{
uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE];
uint8_t h[48];
if (_hasPrivate) {
switch(_type) {
case C25519:
C25519::agree(_k.t0.priv,id._k.t0.pub,key,klen);
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++];
}
return true;
}
}
return false;
}
bool agree(const Identity &id,void *key,unsigned int klen) const;
/**
* @return This identity's address