diff --git a/node/C25519.cpp b/node/C25519.cpp index 535cc135d..8c6f5bcb2 100644 --- a/node/C25519.cpp +++ b/node/C25519.cpp @@ -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 - 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 diff --git a/node/ECC384.cpp b/node/ECC384.cpp index 465385982..34279419c 100644 --- a/node/ECC384.cpp +++ b/node/ECC384.cpp @@ -116,7 +116,7 @@ typedef struct EccPoint #define Curve_G_24 { \ {0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, 0x188DA80EB03090F6ull}, \ {0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, 0x07192B95FFC8DA78ull}} - + #define Curve_G_32 { \ {0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull}, \ {0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull}} @@ -189,7 +189,7 @@ static inline uint vli_numBits(uint64_t *p_vli) { uint i; uint64_t l_digit; - + uint l_numDigits = vli_numDigits(p_vli); if(l_numDigits == 0) { @@ -201,7 +201,7 @@ static inline uint vli_numBits(uint64_t *p_vli) { l_digit >>= 1; } - + return ((l_numDigits - 1) * 64 + i); } @@ -244,7 +244,7 @@ static inline uint64_t vli_lshift(uint64_t *p_result, uint64_t *p_in, uint p_shi p_result[i] = (l_temp << p_shift) | l_carry; l_carry = l_temp >> (64 - p_shift); } - + return l_carry; } @@ -253,7 +253,7 @@ static inline void vli_rshift1(uint64_t *p_vli) { uint64_t *l_end = p_vli; uint64_t l_carry = 0; - + p_vli += NUM_ECC_DIGITS; while(p_vli-- > l_end) { @@ -304,9 +304,9 @@ static inline void vli_mult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_ri { uint128_t r01 = 0; uint64_t r2 = 0; - + uint i, k; - + /* Compute each digit of p_result in sequence, maintaining the carries. */ for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) { @@ -321,7 +321,7 @@ static inline void vli_mult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_ri r01 = (r01 >> 64) | (((uint128_t)r2) << 64); r2 = 0; } - + p_result[NUM_ECC_DIGITS*2 - 1] = (uint64_t)r01; } @@ -330,7 +330,7 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left) { uint128_t r01 = 0; uint64_t r2 = 0; - + uint i, k; for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) { @@ -350,7 +350,7 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left) r01 = (r01 >> 64) | (((uint128_t)r2) << 64); r2 = 0; } - + p_result[NUM_ECC_DIGITS*2 - 1] = (uint64_t)r01; } @@ -359,27 +359,27 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left) static inline uint128_t mul_64_64(uint64_t p_left, uint64_t p_right) { uint128_t l_result; - + uint64_t a0 = p_left & 0xffffffffull; uint64_t a1 = p_left >> 32; uint64_t b0 = p_right & 0xffffffffull; uint64_t b1 = p_right >> 32; - + uint64_t m0 = a0 * b0; uint64_t m1 = a0 * b1; uint64_t m2 = a1 * b0; uint64_t m3 = a1 * b1; - + m2 += (m0 >> 32); m2 += m1; if(m2 < m1) { // overflow m3 += 0x100000000ull; } - + l_result.m_low = (m0 & 0xffffffffull) | (m2 << 32); l_result.m_high = m3 + (m2 >> 32); - + return l_result; } @@ -395,9 +395,9 @@ static inline void vli_mult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_ri { uint128_t r01 = {0, 0}; uint64_t r2 = 0; - + uint i, k; - + /* Compute each digit of p_result in sequence, maintaining the carries. */ for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) { @@ -413,7 +413,7 @@ static inline void vli_mult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_ri r01.m_high = r2; r2 = 0; } - + p_result[NUM_ECC_DIGITS*2 - 1] = r01.m_low; } @@ -421,7 +421,7 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left) { uint128_t r01 = {0, 0}; uint64_t r2 = 0; - + uint i, k; for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) { @@ -443,7 +443,7 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left) r01.m_high = r2; r2 = 0; } - + p_result[NUM_ECC_DIGITS*2 - 1] = r01.m_low; } @@ -480,33 +480,33 @@ static void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) { uint64_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - + vli_set(p_result, p_product); - + l_tmp[0] = p_product[2]; l_tmp[1] = (p_product[3] & 0x1FFFFFFFFull) | (p_product[2] << 33); l_carry = vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = (p_product[2] >> 31) | (p_product[3] << 33); l_tmp[1] = (p_product[3] >> 31) | ((p_product[2] & 0xFFFFFFFF80000000ull) << 2); l_carry += vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = (p_product[2] >> 62) | (p_product[3] << 2); l_tmp[1] = (p_product[3] >> 62) | ((p_product[2] & 0xC000000000000000ull) >> 29) | (p_product[3] << 35); l_carry += vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = (p_product[3] >> 29); l_tmp[1] = ((p_product[3] & 0xFFFFFFFFE0000000ull) << 4); l_carry += vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = (p_product[3] >> 60); l_tmp[1] = (p_product[3] & 0xFFFFFFFE00000000ull); l_carry += vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = 0; l_tmp[1] = ((p_product[3] & 0xF000000000000000ull) >> 27); l_carry += vli_add(p_result, p_result, l_tmp); - + while(l_carry || vli_cmp(curve_p, p_result) != 1) { l_carry -= vli_sub(p_result, p_result, curve_p); @@ -521,21 +521,21 @@ static void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) { uint64_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - + vli_set(p_result, p_product); - + vli_set(l_tmp, &p_product[3]); l_carry = vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = 0; l_tmp[1] = p_product[3]; l_tmp[2] = p_product[4]; l_carry += vli_add(p_result, p_result, l_tmp); - + l_tmp[0] = l_tmp[1] = p_product[5]; l_tmp[2] = 0; l_carry += vli_add(p_result, p_result, l_tmp); - + while(l_carry || vli_cmp(curve_p, p_result) != 1) { l_carry -= vli_sub(p_result, p_result, curve_p); @@ -550,10 +550,10 @@ static void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) { uint64_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - + /* t */ vli_set(p_result, p_product); - + /* s1 */ l_tmp[0] = 0; l_tmp[1] = p_product[5] & 0xffffffff00000000ull; @@ -561,56 +561,56 @@ static void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) l_tmp[3] = p_product[7]; l_carry = vli_lshift(l_tmp, l_tmp, 1); l_carry += vli_add(p_result, p_result, l_tmp); - + /* s2 */ l_tmp[1] = p_product[6] << 32; l_tmp[2] = (p_product[6] >> 32) | (p_product[7] << 32); l_tmp[3] = p_product[7] >> 32; l_carry += vli_lshift(l_tmp, l_tmp, 1); l_carry += vli_add(p_result, p_result, l_tmp); - + /* s3 */ l_tmp[0] = p_product[4]; l_tmp[1] = p_product[5] & 0xffffffff; l_tmp[2] = 0; l_tmp[3] = p_product[7]; l_carry += vli_add(p_result, p_result, l_tmp); - + /* s4 */ l_tmp[0] = (p_product[4] >> 32) | (p_product[5] << 32); l_tmp[1] = (p_product[5] >> 32) | (p_product[6] & 0xffffffff00000000ull); l_tmp[2] = p_product[7]; l_tmp[3] = (p_product[6] >> 32) | (p_product[4] << 32); l_carry += vli_add(p_result, p_result, l_tmp); - + /* d1 */ l_tmp[0] = (p_product[5] >> 32) | (p_product[6] << 32); l_tmp[1] = (p_product[6] >> 32); l_tmp[2] = 0; l_tmp[3] = (p_product[4] & 0xffffffff) | (p_product[5] << 32); l_carry -= vli_sub(p_result, p_result, l_tmp); - + /* d2 */ l_tmp[0] = p_product[6]; l_tmp[1] = p_product[7]; l_tmp[2] = 0; l_tmp[3] = (p_product[4] >> 32) | (p_product[5] & 0xffffffff00000000ull); l_carry -= vli_sub(p_result, p_result, l_tmp); - + /* d3 */ l_tmp[0] = (p_product[6] >> 32) | (p_product[7] << 32); l_tmp[1] = (p_product[7] >> 32) | (p_product[4] << 32); l_tmp[2] = (p_product[4] >> 32) | (p_product[5] << 32); l_tmp[3] = (p_product[6] << 32); l_carry -= vli_sub(p_result, p_result, l_tmp); - + /* d4 */ l_tmp[0] = p_product[7]; l_tmp[1] = p_product[4] & 0xffffffff00000000ull; l_tmp[2] = p_product[5]; l_tmp[3] = p_product[6] & 0xffffffff00000000ull; l_carry -= vli_sub(p_result, p_result, l_tmp); - + if(l_carry < 0) { do @@ -633,7 +633,7 @@ static inline void omega_mult(uint64_t *p_result, uint64_t *p_right) { uint64_t l_tmp[NUM_ECC_DIGITS]; uint64_t l_carry, l_diff; - + /* Multiply by (2^128 + 2^96 - 2^32 + 1). */ vli_set(p_result, p_right); /* 1 */ l_carry = vli_lshift(l_tmp, p_right, 32); @@ -662,17 +662,17 @@ static inline void omega_mult(uint64_t *p_result, uint64_t *p_right) static inline void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) { uint64_t l_tmp[2*NUM_ECC_DIGITS]; - + while(!vli_isZero(p_product + NUM_ECC_DIGITS)) /* While c1 != 0 */ { uint64_t l_carry = 0; uint i; - + vli_clear(l_tmp); vli_clear(l_tmp + NUM_ECC_DIGITS); omega_mult(l_tmp, p_product + NUM_ECC_DIGITS); /* tmp = w * c1 */ vli_clear(p_product + NUM_ECC_DIGITS); /* p = c0 */ - + /* (c1, c0) = c0 + w * c1 */ for(i=0; i 0) { vli_sub(p_product, p_product, curve_p); @@ -719,7 +719,7 @@ static inline void vli_modInv(uint64_t *p_result, uint64_t *p_input, uint64_t *p uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; uint64_t l_carry; int l_cmpResult; - + if(vli_isZero(p_input)) { vli_clear(p_result); @@ -731,7 +731,7 @@ static inline void vli_modInv(uint64_t *p_result, uint64_t *p_input, uint64_t *p vli_clear(u); u[0] = 1; vli_clear(v); - + while((l_cmpResult = vli_cmp(a, b)) != 0) { l_carry = 0; @@ -800,7 +800,7 @@ static inline void vli_modInv(uint64_t *p_result, uint64_t *p_input, uint64_t *p } } } - + vli_set(p_result, u); } @@ -822,23 +822,23 @@ static inline void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t /* t1 = X, t2 = Y, t3 = Z */ uint64_t t4[NUM_ECC_DIGITS]; uint64_t t5[NUM_ECC_DIGITS]; - + if(vli_isZero(Z1)) { return; } - + vli_modSquare_fast(t4, Y1); /* t4 = y1^2 */ vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */ vli_modSquare_fast(t4, t4); /* t4 = y1^4 */ vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */ vli_modSquare_fast(Z1, Z1); /* t3 = z1^2 */ - + vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */ vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */ vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */ vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */ - + vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */ vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */ if(vli_testBit(X1, 0)) @@ -852,14 +852,14 @@ static inline void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t vli_rshift1(X1); } /* t1 = 3/2*(x1^2 - z1^4) = B */ - + vli_modSquare_fast(Z1, X1); /* t3 = B^2 */ vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */ vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */ vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */ vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */ vli_modSub(t4, X1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */ - + vli_set(X1, Z1); vli_set(Z1, Y1); vli_set(Y1, t4); @@ -880,10 +880,10 @@ static inline void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z) static inline void XYcZ_initial_double(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2, uint64_t *p_initialZ) { uint64_t z[NUM_ECC_DIGITS]; - + vli_set(X2, X1); vli_set(Y2, Y1); - + vli_clear(z); z[0] = 1; if(p_initialZ) @@ -892,9 +892,9 @@ static inline void XYcZ_initial_double(uint64_t *X1, uint64_t *Y1, uint64_t *X2, } apply_z(X1, Y1, z); - + EccPoint_double_jacobian(X1, Y1, z); - + apply_z(X2, Y2, z); } @@ -906,14 +906,14 @@ static inline void XYcZ_add(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t * { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ uint64_t t5[NUM_ECC_DIGITS]; - + vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ vli_modSquare_fast(t5, Y2); /* t5 = (y2 - y1)^2 = D */ - + vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */ vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */ vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */ @@ -921,7 +921,7 @@ static inline void XYcZ_add(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t * vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */ vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */ vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ - + vli_set(X2, t5); } @@ -935,7 +935,7 @@ static inline void XYcZ_addC(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t uint64_t t5[NUM_ECC_DIGITS]; uint64_t t6[NUM_ECC_DIGITS]; uint64_t t7[NUM_ECC_DIGITS]; - + vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ @@ -948,17 +948,17 @@ static inline void XYcZ_addC(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */ vli_modSquare_fast(X2, Y2); /* t3 = (y2 - y1)^2 */ vli_modSub(X2, X2, t6, curve_p); /* t3 = x3 */ - + vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */ vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */ vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ - + vli_modSquare_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */ vli_modSub(t7, t7, t6, curve_p); /* t7 = x3' */ vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */ vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */ vli_modSub(Y1, t6, Y1, curve_p); /* t2 = y3' */ - + vli_set(X1, t7); } @@ -968,9 +968,9 @@ static inline void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint64_t uint64_t Rx[2][NUM_ECC_DIGITS]; uint64_t Ry[2][NUM_ECC_DIGITS]; uint64_t z[NUM_ECC_DIGITS]; - + int i, nb; - + vli_set(Rx[1], p_point->x); vli_set(Ry[1], p_point->y); @@ -985,7 +985,7 @@ static inline void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint64_t nb = !vli_testBit(p_scalar, 0); XYcZ_addC(Rx[1-nb], Ry[1-nb], Rx[nb], Ry[nb]); - + /* Find final 1/Z value. */ vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */ vli_modMult_fast(z, z, Ry[1-nb]); /* Yb * (X1 - X0) */ @@ -996,9 +996,9 @@ static inline void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint64_t /* End 1/Z calculation */ XYcZ_add(Rx[nb], Ry[nb], Rx[1-nb], Ry[1-nb]); - + apply_z(Rx[0], Ry[0], z); - + vli_set(p_result->x, Rx[0]); vli_set(p_result->y, Ry[0]); } @@ -1037,7 +1037,7 @@ static inline void mod_sqrt(uint64_t a[NUM_ECC_DIGITS]) unsigned i; uint64_t p1[NUM_ECC_DIGITS] = {1}; uint64_t l_result[NUM_ECC_DIGITS] = {1}; - + /* Since curve_p == 3 (mod 4) for all supported curves, we can compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */ vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */ @@ -1056,14 +1056,14 @@ static inline void ecc_point_decompress(EccPoint *p_point, const uint8_t p_compr { uint64_t _3[NUM_ECC_DIGITS] = {3}; /* -a = 3 */ ecc_bytes2native(p_point->x, p_compressed+1); - + vli_modSquare_fast(p_point->y, p_point->x); /* y = x^2 */ vli_modSub(p_point->y, p_point->y, _3, curve_p); /* y = x^2 - 3 */ vli_modMult_fast(p_point->y, p_point->y, p_point->x); /* y = x^3 - 3x */ vli_modAdd(p_point->y, p_point->y, curve_b, curve_p); /* y = x^3 - 3x + b */ - + mod_sqrt(p_point->y); - + if((p_point->y[0] & 0x01) != (p_compressed[0] & 0x01)) { vli_sub(p_point->y, curve_p, p_point->y); @@ -1075,7 +1075,7 @@ static inline int ecc_make_key(uint8_t p_publicKey[ECC_BYTES+1], uint8_t p_priva uint64_t l_private[NUM_ECC_DIGITS]; EccPoint l_public; unsigned l_tries = 0; - + do { if(!getRandomNumber(l_private) || (l_tries++ >= MAX_TRIES)) @@ -1086,7 +1086,7 @@ static inline int ecc_make_key(uint8_t p_publicKey[ECC_BYTES+1], uint8_t p_priva { continue; } - + /* Make sure the private key is in the range [1, n-1]. For the supported curves, n is always large enough that we only need to subtract once at most. */ if(vli_cmp(curve_n, l_private) != 1) @@ -1096,7 +1096,7 @@ static inline int ecc_make_key(uint8_t p_publicKey[ECC_BYTES+1], uint8_t p_priva EccPoint_mult(&l_public, &curve_G, l_private, NULL); } while(EccPoint_isZero(&l_public)); - + ecc_native2bytes(p_privateKey, l_private); ecc_native2bytes(p_publicKey + 1, l_public.x); p_publicKey[0] = 2 + (l_public.y[0] & 0x01); @@ -1108,20 +1108,20 @@ static inline int ecdh_shared_secret(const uint8_t p_publicKey[ECC_BYTES+1], con EccPoint l_public; uint64_t l_private[NUM_ECC_DIGITS]; uint64_t l_random[NUM_ECC_DIGITS]; - + if(!getRandomNumber(l_random)) { return 0; } - + ecc_point_decompress(&l_public, p_publicKey); ecc_bytes2native(l_private, p_privateKey); - + EccPoint l_product; EccPoint_mult(&l_product, &l_public, l_private, l_random); - + ecc_native2bytes(p_secret, l_product.x); - + return !EccPoint_isZero(&l_product); } @@ -1135,7 +1135,7 @@ static inline void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p uint l_digitShift, l_bitShift; uint l_productBits; uint l_modBits = vli_numBits(p_mod); - + vli_mult(l_product, p_left, p_right); l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS); if(l_productBits) @@ -1146,13 +1146,13 @@ static inline void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p { l_productBits = vli_numBits(l_product); } - + if(l_productBits < l_modBits) { /* l_product < p_mod. */ vli_set(p_result, l_product); return; } - + /* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest power of two possible while still resulting in a number less than p_left. */ vli_clear(l_modMultiple); @@ -1186,7 +1186,7 @@ static inline void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p vli_rshift1(l_modMultiple + NUM_ECC_DIGITS); vli_rshift1(l_modMultiple); l_modMultiple[NUM_ECC_DIGITS-1] |= l_carry; - + --l_productBits; } vli_set(p_result, l_product); @@ -1204,7 +1204,7 @@ static inline int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_ uint64_t l_s[NUM_ECC_DIGITS]; EccPoint p; unsigned l_tries = 0; - + do { if(!getRandomNumber(k) || (l_tries++ >= MAX_TRIES)) @@ -1215,15 +1215,15 @@ static inline int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_ { continue; } - + if(vli_cmp(curve_n, k) != 1) { vli_sub(k, k, curve_n); } - + /* tmp = k * G */ EccPoint_mult(&p, &curve_G, k, NULL); - + /* r = x1 (mod n) */ if(vli_cmp(curve_n, p.x) != 1) { @@ -1232,7 +1232,7 @@ static inline int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_ } while(vli_isZero(p.x)); ecc_native2bytes(p_signature, p.x); - + ecc_bytes2native(l_tmp, p_privateKey); vli_modMult(l_s, p.x, l_tmp, curve_n); /* s = r*d */ ecc_bytes2native(l_tmp, p_hash); @@ -1240,7 +1240,7 @@ static inline int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_ vli_modInv(k, k, curve_n); /* k = 1 / k */ vli_modMult(l_s, l_s, k, curve_n); /* s = (e + r*d) / k */ ecc_native2bytes(p_signature + ECC_BYTES, l_s); - + return 1; } @@ -1254,18 +1254,18 @@ static inline int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uin uint64_t tx[NUM_ECC_DIGITS]; uint64_t ty[NUM_ECC_DIGITS]; uint64_t tz[NUM_ECC_DIGITS]; - + uint64_t l_r[NUM_ECC_DIGITS], l_s[NUM_ECC_DIGITS]; - + ecc_point_decompress(&l_public, p_publicKey); ecc_bytes2native(l_r, p_signature); ecc_bytes2native(l_s, p_signature + ECC_BYTES); - + if(vli_isZero(l_r) || vli_isZero(l_s)) { /* r, s must not be 0. */ return 0; } - + if(vli_cmp(curve_n, l_r) != 1 || vli_cmp(curve_n, l_s) != 1) { /* r, s must be < n. */ return 0; @@ -1276,7 +1276,7 @@ static inline int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uin ecc_bytes2native(u1, p_hash); vli_modMult(u1, u1, z, curve_n); /* u1 = e/s */ vli_modMult(u2, l_r, z, curve_n); /* u2 = r/s */ - + /* Calculate l_sum = G + Q. */ vli_set(l_sum.x, l_public.x); vli_set(l_sum.y, l_public.y); @@ -1286,11 +1286,11 @@ static inline int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uin XYcZ_add(tx, ty, l_sum.x, l_sum.y); vli_modInv(z, z, curve_p); /* Z = 1/Z */ apply_z(l_sum.x, l_sum.y, z); - + /* Use Shamir's trick to calculate u1*G + u2*Q */ EccPoint *l_points[4] = {NULL, &curve_G, &l_public, &l_sum}; uint l_numBits = umax(vli_numBits(u1), vli_numBits(u2)); - + EccPoint *l_point = l_points[(!!vli_testBit(u1, l_numBits-1)) | ((!!vli_testBit(u2, l_numBits-1)) << 1)]; vli_set(rx, l_point->x); vli_set(ry, l_point->y); @@ -1301,7 +1301,7 @@ static inline int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uin for(i = l_numBits - 2; i >= 0; --i) { EccPoint_double_jacobian(rx, ry, z); - + int l_index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1); EccPoint *l_point = l_points[l_index]; if(l_point) @@ -1317,7 +1317,7 @@ static inline int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES+1], const uin vli_modInv(z, z, curve_p); /* Z = 1/Z */ apply_z(rx, ry, z); - + /* v = x1 (mod n) */ if(vli_cmp(curve_n, rx) != 1) { diff --git a/node/Identity.cpp b/node/Identity.cpp index d60d436e5..050ad6ff9 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -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; diff --git a/node/Identity.hpp b/node/Identity.hpp index 9b24e27e3..028e818f8 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -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(this),0,sizeof(Identity)); } @@ -78,6 +78,9 @@ public: inline ~Identity() { Utils::burn(reinterpret_cast(this),sizeof(Identity)); } + /** + * Set identity to NIL value (all zero) + */ inline void zero() { Utils::burn(reinterpret_cast(this),sizeof(Identity)); } inline Identity &operator=(const Identity &id) @@ -95,7 +98,7 @@ public: * Generate a new identity (address, key pair) * * This is a time consuming operation. - * + * * @param t Type of identity to generate */ void generate(const Type t); @@ -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; } } @@ -159,7 +141,7 @@ public: * * The signature buffer should be large enough for the largest * signature, which is currently 96 bytes. - * + * * @param data Data to sign * @param len Length of data * @param sig Buffer to receive signature @@ -168,25 +150,33 @@ 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; } - + /** * Verify a message signature against this identity * @@ -200,18 +190,20 @@ 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; } return false; } - + /** * Shortcut method to perform key agreement with another identity * @@ -219,34 +211,43 @@ 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;iidentity.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); diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index c733792a3..0da707520 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -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) diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index d25c67dbd..d7099aca4 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -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 } diff --git a/node/Peer.cpp b/node/Peer.cpp index 919193b3a..a9e1dbff5 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -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; } diff --git a/node/Root.hpp b/node/Root.hpp index 0b6b4f231..a1028c9bb 100644 --- a/node/Root.hpp +++ b/node/Root.hpp @@ -40,18 +40,18 @@ namespace ZeroTier { /** * A root entry pointing to a node capable of global identity lookup and indirect transit - * + * * Root entries point to DNS records that contain TXT entries that decode to Locator objects * pointing to actual root nodes. A default root identity and static addresses can also be * provided as fallback if DNS is not available. - * + * * Note that root identities can change if DNS returns a different result, but that DNS entries * are authenticated using their own signature scheme. This allows a root DNS name to serve * up different roots based on factors like location or relative load of different roots. - * + * * It's also possible to create a root with no DNS and no DNS validator public key. This root * will be a static entry pointing to a single root identity and set of physical addresses. - * + * * This object is thread-safe and may be concurrently accessed and updated. */ class Root @@ -62,7 +62,7 @@ public: /** * Create a new root entry - * + * * @param dn DNS name * @param dnspk DNS public key for record validation * @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key) @@ -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 v4a,v6a; + Mutex::Lock l(_lock); + const std::vector *const av = (_lastFetchedLocator) ? &(_lastFetchedLocator.phy()) : &_defaultAddresses; + for(std::vector::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 _defaultAddresses; diff --git a/node/SHA512.cpp b/node/SHA512.cpp index e79efc674..7a81d55a2 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -14,49 +14,6 @@ Public domain. #include "SHA512.hpp" #include "Utils.hpp" -#ifdef __APPLE__ -#include -#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(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(digest),&ctx); -} -} -#endif - -#ifdef ZT_USE_LIBCRYPTO -#include -#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(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(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); } diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 418a85b5b..1e37fffe7 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -27,12 +27,61 @@ #ifndef ZT_SHA512_HPP #define ZT_SHA512_HPP +#include "Constants.hpp" + +#ifdef __APPLE__ +#include +#endif + +#ifdef ZT_USE_LIBCRYPTO +#include +#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(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(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(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(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 diff --git a/node/Trace.hpp b/node/Trace.hpp index b8feefe56..31c29d4a6 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -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 diff --git a/node/Utils.cpp b/node/Utils.cpp index 5ce530ca7..001c9d1f2 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -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= 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= 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) { @@ -379,7 +371,7 @@ unsigned int Utils::b64d(const char *in,unsigned char *out,unsigned int outlen) break; case 1: out[j++] |= (c >> 4) & 0x3; - out[j] = (c & 0xf) << 4; + out[j] = (c & 0xf) << 4; break; case 2: out[j++] |= (c >> 2) & 0xf; diff --git a/selftest.cpp b/selftest.cpp index 43664ba35..1d6db9dbf 100644 --- a/selftest.cpp +++ b/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;kp2 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