diff --git a/node/C25519.cpp b/node/C25519.cpp index 0bea59e9d..949d5bcf3 100644 --- a/node/C25519.cpp +++ b/node/C25519.cpp @@ -2696,7 +2696,7 @@ void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char for (i = 64;i < smlen;++i) playground[i] = sm[i]; //crypto_hash_sha512(hram,playground,smlen); - ZeroTier::SHA512::hash(hram,playground,(unsigned int)smlen); + ZeroTier::SHA512(hram,playground,(unsigned int)smlen); } ////////////////////////////////////////////////////////////////////////////// @@ -2716,11 +2716,11 @@ void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void unsigned char digest[64]; crypto_scalarmult(rawkey,mine.data,their.data); - SHA512::hash(digest,rawkey,32); + SHA512(digest,rawkey,32); for(unsigned int i=0,k=0;i(this),sizeof(Identity)); } + inline void zero() { memset(reinterpret_cast(this),0,sizeof(Identity)); } + inline Identity &operator=(const Identity &id) { memcpy(reinterpret_cast(this),&id,sizeof(Identity)); @@ -118,10 +120,10 @@ public: if (_hasPrivate) { switch(_type) { case C25519: - SHA512::hash(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN); + SHA512(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN); return true; case P384: - SHA512::hash(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE); + SHA512(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE); return true; } } @@ -139,10 +141,10 @@ public: if (_hasPrivate) { switch(_type) { case C25519: - SHA512::hash(sha,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN); + SHA512(sha,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN); return true; case P384: - SHA512::hash(sha,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE); + SHA512(sha,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE); return true; } } @@ -175,7 +177,7 @@ public: case P384: if (siglen < ZT_ECC384_SIGNATURE_SIZE) return 0; - SHA512::hash(h,data,len); + SHA512(h,data,len); ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig); return ZT_ECC384_SIGNATURE_SIZE; } @@ -200,7 +202,7 @@ public: case P384: if (siglen != ZT_ECC384_SIGNATURE_SIZE) return false; - SHA512::hash(h,data,len); + SHA512(h,data,len); return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig); } return false; @@ -227,12 +229,12 @@ public: return true; case P384: ECC384ECDH(id._k.t1.pub,_k.t1.priv,ecc384RawSecret); - SHA512::hash(h,ecc384RawSecret,sizeof(ecc384RawSecret)); + SHA512(h,ecc384RawSecret,sizeof(ecc384RawSecret)); unsigned int hi = 0; for(unsigned int i=0;i #include +#define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255 +#define ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES 255 + namespace ZeroTier { /** @@ -48,22 +53,139 @@ namespace ZeroTier { class Locator { public: - Locator() : - _signatureLength(0) {} + Locator() : _signatureLength(0) {} inline const std::vector &phy() const { return _physical; } inline const std::vector &virt() const { return _virtual; } + inline void add(const InetAddress &ip) + { + if (_physical.size() < ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES) + _physical.push_back(ip); + } + inline void add(const Identity &zt) + { + if (_virtual.size() < ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES) + _virtual.push_back(zt); + } + inline void finish(const Identity &id,const int64_t ts) + { + _ts = ts; + _id = id; + std::sort(_physical.begin(),_physical.end()); + _physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end()); + std::sort(_virtual.begin(),_virtual.end()); + _virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_virtual.end()); + } + inline bool sign(const Identity &signingId) { - std::sort(_physical.begin(),_physical.end()); - std::sort(_virtual.begin(),_virtual.end()); - _id = signingId; + if (!signingId.hasPrivate()) + return false; + if (signingId == _id) { + _signedBy.zero(); + } else { + _signedBy = signingId; + } + Buffer<65536> *tmp = new Buffer<65536>(); + try { + serialize(*tmp,true); + _signatureLength = signingId.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE); + delete tmp; + return (_signatureLength > 0); + } catch ( ... ) { + delete tmp; + return false; + } + } + + inline bool verify() const + { + if ((_signatureLength == 0)||(_signatureLength > sizeof(_signature))) + return false; + Buffer<16384> *tmp; + try { + tmp = new Buffer<16384>(); // 16384 would be huge + serialize(*tmp,true); + const bool ok = (_signedBy) ? _signedBy.verify(tmp->data(),tmp->size(),_signature,_signatureLength) : _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength); + delete tmp; + return ok; + } catch ( ... ) { + delete tmp; + return false; + } + } + + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append((uint8_t)0; // version/flags, currently 0 + b.append((uint64_t)_ts); + _id.serialise(b,false); + if (_signedBy) { + b.append((uint8_t)1); // number of signers + _signedBy.serialize(b,false); + } else { + b.append((uint8_t)0); // signer is _id + } + b.append((uint8_t)_physical.size()); + for(std::vector::const_iterator i(_physical.begin());i!=_physical.end();++i) + i->serialize(b); + b.append((uint8_t)_virtual.size()); + for(std::vector::const_iterator i(_virtual.begin());i!=_virtual.end();++i) + i->serialize(b,false); + if (!forSign) { + b.append((uint16_t)_signatureLength); + b.append(_signature,_signatureLength); + } + b.append((uint16_t)0); // length of additional fields, currently 0 + + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + + if (b[p++] != 0) + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; + _ts = (int64_t)b.template at(p); p += 8; + p += _id.deserialize(b,p); + const unsigned int signerCount = b[p++]; + if (signerCount > 1) + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + if (signerCount == 1) { + p += _signedBy.deserialize(b,p); + } else { + _signedBy.zero(); + } + const unsigned int physicalCount = b[p++]; + _physical.resize(physicalCount); + for(unsigned int i=0;i(p); p += 2; + if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + memcpy(_signature,b.field(p,_signatureLength),_signatureLength); + p += _signatureLength; + p += b.template at(p); p += 2; + if (p > b.size()) + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + + return (p - startAt); } private: int64_t _ts; Identity _id; + Identity _signedBy; // signed by _id if nil/zero std::vector _physical; std::vector _virtual; unsigned int _signatureLength; diff --git a/node/SHA512.cpp b/node/SHA512.cpp index d3c938afb..0e5dba5b1 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -14,17 +14,29 @@ Public domain. #include "SHA512.hpp" #include "Utils.hpp" +#if 0 + #ifdef __APPLE__ #include #define ZT_HAVE_NATIVE_SHA512 namespace ZeroTier { -void SHA512::hash(void *digest,const void *data,unsigned int len) + +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 @@ -32,327 +44,221 @@ void SHA512::hash(void *digest,const void *data,unsigned int len) #include #define ZT_HAVE_NATIVE_SHA512 namespace ZeroTier { -void SHA512::hash(void *digest,const void *data,unsigned int len) + +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 + #endif #ifndef ZT_HAVE_NATIVE_SHA512 namespace ZeroTier { -#define uint64 uint64_t +namespace { -#ifdef ZT_NO_TYPE_PUNNING - -static uint64 load_bigendian(const unsigned char *x) +static inline void sha512_encode(uint64_t input, uint8_t *output, uint32_t idx) { - return - (uint64) (x[7]) \ - | (((uint64) (x[6])) << 8) \ - | (((uint64) (x[5])) << 16) \ - | (((uint64) (x[4])) << 24) \ - | (((uint64) (x[3])) << 32) \ - | (((uint64) (x[2])) << 40) \ - | (((uint64) (x[1])) << 48) \ - | (((uint64) (x[0])) << 56) - ; + output[idx + 0] = (uint8_t)(input >> 56); + output[idx + 1] = (uint8_t)(input >> 48); + output[idx + 2] = (uint8_t)(input >> 40); + output[idx + 3] = (uint8_t)(input >> 32); + output[idx + 4] = (uint8_t)(input >> 24); + output[idx + 5] = (uint8_t)(input >> 16); + output[idx + 6] = (uint8_t)(input >> 8); + output[idx + 7] = (uint8_t)(input >> 0); +} +static inline void sha512_decode(uint64_t *output, uint8_t *input, uint32_t idx) +{ + *output = ((uint64_t)input[idx + 0] << 56) + | ((uint64_t)input[idx + 1] << 48) + | ((uint64_t)input[idx + 2] << 40) + | ((uint64_t)input[idx + 3] << 32) + | ((uint64_t)input[idx + 4] << 24) + | ((uint64_t)input[idx + 5] << 16) + | ((uint64_t)input[idx + 6] << 8) + | ((uint64_t)input[idx + 7] << 0); } -static void store_bigendian(unsigned char *x,uint64 u) -{ - x[7] = u; u >>= 8; - x[6] = u; u >>= 8; - x[5] = u; u >>= 8; - x[4] = u; u >>= 8; - x[3] = u; u >>= 8; - x[2] = u; u >>= 8; - x[1] = u; u >>= 8; - x[0] = u; -} +typedef struct sha512_ctx_tag { + uint32_t is_sha384; + uint8_t block[128]; + uint64_t len[2]; + uint64_t val[8]; + uint8_t *payload_addr; + uint64_t payload_len; +} sha512_ctx_t; -#else // !ZT_NO_TYPE_PUNNING +#define LSR(x,n) (x >> n) +#define ROR(x,n) (LSR(x,n) | (x << (64 - n))) -#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x))) -#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u))) +#define MA(x,y,z) ((x & y) | (z & (x | y))) +#define CH(x,y,z) (z ^ (x & (y ^ z))) +#define GAMMA0(x) (ROR(x, 1) ^ ROR(x, 8) ^ LSR(x, 7)) +#define GAMMA1(x) (ROR(x,19) ^ ROR(x,61) ^ LSR(x, 6)) +#define SIGMA0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39)) +#define SIGMA1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41)) -#endif // ZT_NO_TYPE_PUNNING +#define INIT_COMPRESSOR() uint64_t tmp0 = 0, tmp1 = 0 +#define COMPRESS( a, b, c, d, e, f, g, h, x, k) \ + tmp0 = h + SIGMA1(e) + CH(e,f,g) + k + x; \ + tmp1 = SIGMA0(a) + MA(a,b,c); d += tmp0; h = tmp0 + tmp1; -#define SHR(x,c) ((x) >> (c)) -#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c)))) +static const uint8_t sha512_padding[128] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -#define Ch(x,y,z) ((x & y) ^ (~x & z)) -#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) -#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) -#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) -#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7)) -#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6)) - -#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0; - -#define EXPAND \ - M(w0 ,w14,w9 ,w1 ) \ - M(w1 ,w15,w10,w2 ) \ - M(w2 ,w0 ,w11,w3 ) \ - M(w3 ,w1 ,w12,w4 ) \ - M(w4 ,w2 ,w13,w5 ) \ - M(w5 ,w3 ,w14,w6 ) \ - M(w6 ,w4 ,w15,w7 ) \ - M(w7 ,w5 ,w0 ,w8 ) \ - M(w8 ,w6 ,w1 ,w9 ) \ - M(w9 ,w7 ,w2 ,w10) \ - M(w10,w8 ,w3 ,w11) \ - M(w11,w9 ,w4 ,w12) \ - M(w12,w10,w5 ,w13) \ - M(w13,w11,w6 ,w14) \ - M(w14,w12,w7 ,w15) \ - M(w15,w13,w8 ,w0 ) - -#define F(w,k) \ - T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \ - T2 = Sigma0(a) + Maj(a,b,c); \ - h = g; \ - g = f; \ - f = e; \ - e = d + T1; \ - d = c; \ - c = b; \ - b = a; \ - a = T1 + T2; - -static inline int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen) -{ - uint64 state[8]; - uint64 a; - uint64 b; - uint64 c; - uint64 d; - uint64 e; - uint64 f; - uint64 g; - uint64 h; - uint64 T1; - uint64 T2; - - a = load_bigendian(statebytes + 0); state[0] = a; - b = load_bigendian(statebytes + 8); state[1] = b; - c = load_bigendian(statebytes + 16); state[2] = c; - d = load_bigendian(statebytes + 24); state[3] = d; - e = load_bigendian(statebytes + 32); state[4] = e; - f = load_bigendian(statebytes + 40); state[5] = f; - g = load_bigendian(statebytes + 48); state[6] = g; - h = load_bigendian(statebytes + 56); state[7] = h; - - while (inlen >= 128) { - uint64 w0 = load_bigendian(in + 0); - uint64 w1 = load_bigendian(in + 8); - uint64 w2 = load_bigendian(in + 16); - uint64 w3 = load_bigendian(in + 24); - uint64 w4 = load_bigendian(in + 32); - uint64 w5 = load_bigendian(in + 40); - uint64 w6 = load_bigendian(in + 48); - uint64 w7 = load_bigendian(in + 56); - uint64 w8 = load_bigendian(in + 64); - uint64 w9 = load_bigendian(in + 72); - uint64 w10 = load_bigendian(in + 80); - uint64 w11 = load_bigendian(in + 88); - uint64 w12 = load_bigendian(in + 96); - uint64 w13 = load_bigendian(in + 104); - uint64 w14 = load_bigendian(in + 112); - uint64 w15 = load_bigendian(in + 120); - - F(w0 ,0x428a2f98d728ae22ULL) - F(w1 ,0x7137449123ef65cdULL) - F(w2 ,0xb5c0fbcfec4d3b2fULL) - F(w3 ,0xe9b5dba58189dbbcULL) - F(w4 ,0x3956c25bf348b538ULL) - F(w5 ,0x59f111f1b605d019ULL) - F(w6 ,0x923f82a4af194f9bULL) - F(w7 ,0xab1c5ed5da6d8118ULL) - F(w8 ,0xd807aa98a3030242ULL) - F(w9 ,0x12835b0145706fbeULL) - F(w10,0x243185be4ee4b28cULL) - F(w11,0x550c7dc3d5ffb4e2ULL) - F(w12,0x72be5d74f27b896fULL) - F(w13,0x80deb1fe3b1696b1ULL) - F(w14,0x9bdc06a725c71235ULL) - F(w15,0xc19bf174cf692694ULL) - - EXPAND - - F(w0 ,0xe49b69c19ef14ad2ULL) - F(w1 ,0xefbe4786384f25e3ULL) - F(w2 ,0x0fc19dc68b8cd5b5ULL) - F(w3 ,0x240ca1cc77ac9c65ULL) - F(w4 ,0x2de92c6f592b0275ULL) - F(w5 ,0x4a7484aa6ea6e483ULL) - F(w6 ,0x5cb0a9dcbd41fbd4ULL) - F(w7 ,0x76f988da831153b5ULL) - F(w8 ,0x983e5152ee66dfabULL) - F(w9 ,0xa831c66d2db43210ULL) - F(w10,0xb00327c898fb213fULL) - F(w11,0xbf597fc7beef0ee4ULL) - F(w12,0xc6e00bf33da88fc2ULL) - F(w13,0xd5a79147930aa725ULL) - F(w14,0x06ca6351e003826fULL) - F(w15,0x142929670a0e6e70ULL) - - EXPAND - - F(w0 ,0x27b70a8546d22ffcULL) - F(w1 ,0x2e1b21385c26c926ULL) - F(w2 ,0x4d2c6dfc5ac42aedULL) - F(w3 ,0x53380d139d95b3dfULL) - F(w4 ,0x650a73548baf63deULL) - F(w5 ,0x766a0abb3c77b2a8ULL) - F(w6 ,0x81c2c92e47edaee6ULL) - F(w7 ,0x92722c851482353bULL) - F(w8 ,0xa2bfe8a14cf10364ULL) - F(w9 ,0xa81a664bbc423001ULL) - F(w10,0xc24b8b70d0f89791ULL) - F(w11,0xc76c51a30654be30ULL) - F(w12,0xd192e819d6ef5218ULL) - F(w13,0xd69906245565a910ULL) - F(w14,0xf40e35855771202aULL) - F(w15,0x106aa07032bbd1b8ULL) - - EXPAND - - F(w0 ,0x19a4c116b8d2d0c8ULL) - F(w1 ,0x1e376c085141ab53ULL) - F(w2 ,0x2748774cdf8eeb99ULL) - F(w3 ,0x34b0bcb5e19b48a8ULL) - F(w4 ,0x391c0cb3c5c95a63ULL) - F(w5 ,0x4ed8aa4ae3418acbULL) - F(w6 ,0x5b9cca4f7763e373ULL) - F(w7 ,0x682e6ff3d6b2b8a3ULL) - F(w8 ,0x748f82ee5defb2fcULL) - F(w9 ,0x78a5636f43172f60ULL) - F(w10,0x84c87814a1f0ab72ULL) - F(w11,0x8cc702081a6439ecULL) - F(w12,0x90befffa23631e28ULL) - F(w13,0xa4506cebde82bde9ULL) - F(w14,0xbef9a3f7b2c67915ULL) - F(w15,0xc67178f2e372532bULL) - - EXPAND - - F(w0 ,0xca273eceea26619cULL) - F(w1 ,0xd186b8c721c0c207ULL) - F(w2 ,0xeada7dd6cde0eb1eULL) - F(w3 ,0xf57d4f7fee6ed178ULL) - F(w4 ,0x06f067aa72176fbaULL) - F(w5 ,0x0a637dc5a2c898a6ULL) - F(w6 ,0x113f9804bef90daeULL) - F(w7 ,0x1b710b35131c471bULL) - F(w8 ,0x28db77f523047d84ULL) - F(w9 ,0x32caab7b40c72493ULL) - F(w10,0x3c9ebe0a15c9bebcULL) - F(w11,0x431d67c49c100d4cULL) - F(w12,0x4cc5d4becb3e42b6ULL) - F(w13,0x597f299cfc657e2aULL) - F(w14,0x5fcb6fab3ad6faecULL) - F(w15,0x6c44198c4a475817ULL) - - a += state[0]; - b += state[1]; - c += state[2]; - d += state[3]; - e += state[4]; - f += state[5]; - g += state[6]; - h += state[7]; - - state[0] = a; - state[1] = b; - state[2] = c; - state[3] = d; - state[4] = e; - state[5] = f; - state[6] = g; - state[7] = h; - - in += 128; - inlen -= 128; - } - - store_bigendian(statebytes + 0,state[0]); - store_bigendian(statebytes + 8,state[1]); - store_bigendian(statebytes + 16,state[2]); - store_bigendian(statebytes + 24,state[3]); - store_bigendian(statebytes + 32,state[4]); - store_bigendian(statebytes + 40,state[5]); - store_bigendian(statebytes + 48,state[6]); - store_bigendian(statebytes + 56,state[7]); - - return 0; -} - -#define blocks crypto_hashblocks - -static const unsigned char iv[64] = { - 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, - 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, - 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, - 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, - 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, - 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, - 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, - 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +static const uint64_t K[80] = { + 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL, + 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, + 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL, + 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL, + 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, + 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL, + 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL, + 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, + 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL, + 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL, + 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, + 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL, + 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL, + 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, + 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL, + 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL, + 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, + 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL, + 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL, + 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL }; -void SHA512::hash(void *digest,const void *data,unsigned int len) +static inline void sha512_memcpy(uint8_t *src, uint8_t *dst, uint32_t size) { - unsigned char h[64]; - unsigned char padded[256]; - int i; - uint64_t bytes = len; + uint32_t i = 0; + for (;i < size;i++) { *dst++ = *src++; } +} +static inline void sha512_memclr(uint8_t *dst, uint32_t size) +{ + uint32_t i = 0; + for (;i < size;i++) { *dst++ = 0; } +} - const unsigned char *in = (const unsigned char *)data; - unsigned int inlen = len; +static inline void sha512_init_512(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len) +{ + sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t)); + sha512_ctx->val[0] = 0x6A09E667F3BCC908ULL; + sha512_ctx->val[1] = 0xBB67AE8584CAA73BULL; + sha512_ctx->val[2] = 0x3C6EF372FE94F82BULL; + sha512_ctx->val[3] = 0xA54FF53A5F1D36F1ULL; + sha512_ctx->val[4] = 0x510E527FADE682D1ULL; + sha512_ctx->val[5] = 0x9B05688C2B3E6C1FULL; + sha512_ctx->val[6] = 0x1F83D9ABFB41BD6BULL; + sha512_ctx->val[7] = 0x5BE0CD19137E2179ULL; + sha512_ctx->is_sha384 = 0; + sha512_ctx->payload_addr = payload_addr; + sha512_ctx->payload_len = (uint64_t)payload_len; + sha512_ctx->len[0] = payload_len << 3; + sha512_ctx->len[1] = payload_len >> 61; +} - for (i = 0;i < 64;++i) h[i] = iv[i]; +static inline void sha512_init_384(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len) +{ + sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t)); + sha512_ctx->val[0] = 0xCBBB9D5DC1059ED8ULL; + sha512_ctx->val[1] = 0x629A292A367CD507ULL; + sha512_ctx->val[2] = 0x9159015A3070DD17ULL; + sha512_ctx->val[3] = 0x152FECD8F70E5939ULL; + sha512_ctx->val[4] = 0x67332667FFC00B31ULL; + sha512_ctx->val[5] = 0x8EB44A8768581511ULL; + sha512_ctx->val[6] = 0xDB0C2E0D64F98FA7ULL; + sha512_ctx->val[7] = 0x47B5481DBEFA4FA4ULL; + sha512_ctx->is_sha384 = 1; + sha512_ctx->payload_addr = payload_addr; + sha512_ctx->payload_len = (uint64_t)payload_len; + sha512_ctx->len[0] = payload_len << 3; + sha512_ctx->len[1] = payload_len >> 61; +} - blocks(h,in,inlen); - in += inlen; - inlen &= 127; - in -= inlen; - - for (i = 0;i < (int)inlen;++i) padded[i] = in[i]; - padded[inlen] = 0x80; - - if (inlen < 112) { - for (i = inlen + 1;i < 119;++i) padded[i] = 0; - padded[119] = (unsigned char)((bytes >> 61) & 0xff); - padded[120] = (unsigned char)((bytes >> 53) & 0xff); - padded[121] = (unsigned char)((bytes >> 45) & 0xff); - padded[122] = (unsigned char)((bytes >> 37) & 0xff); - padded[123] = (unsigned char)((bytes >> 29) & 0xff); - padded[124] = (unsigned char)((bytes >> 21) & 0xff); - padded[125] = (unsigned char)((bytes >> 13) & 0xff); - padded[126] = (unsigned char)((bytes >> 5) & 0xff); - padded[127] = (unsigned char)((bytes << 3) & 0xff); - blocks(h,padded,128); - } else { - for (i = inlen + 1;i < 247;++i) padded[i] = 0; - padded[247] = (unsigned char)((bytes >> 61) & 0xff); - padded[248] = (unsigned char)((bytes >> 53) & 0xff); - padded[249] = (unsigned char)((bytes >> 45) & 0xff); - padded[250] = (unsigned char)((bytes >> 37) & 0xff); - padded[251] = (unsigned char)((bytes >> 29) & 0xff); - padded[252] = (unsigned char)((bytes >> 21) & 0xff); - padded[253] = (unsigned char)((bytes >> 13) & 0xff); - padded[254] = (unsigned char)((bytes >> 5) & 0xff); - padded[255] = (unsigned char)((bytes << 3) & 0xff); - blocks(h,padded,256); +static inline void sha512_hash_factory(sha512_ctx_t *ctx, uint8_t data[128]) +{ + uint32_t i = 0; + uint64_t W[80]; + uint64_t v[8]; + INIT_COMPRESSOR(); + for(i = 0; i < 16; i++) { sha512_decode(&W[i], data, i << 3 ); } + for(; i < 80; i++) { W[i] = GAMMA1(W[i - 2]) + W[i - 7] + GAMMA0(W[i - 15]) + W[i - 16]; } + for (i = 0;i < 8; i++) { v[i] = ctx->val[i]; } + for(i = 0; i < 80;) { + COMPRESS(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], W[i], K[i] ); i++; + COMPRESS(v[7], v[0], v[1], v[2], v[3], v[4], v[5], v[6], W[i], K[i] ); i++; + COMPRESS(v[6], v[7], v[0], v[1], v[2], v[3], v[4], v[5], W[i], K[i] ); i++; + COMPRESS(v[5], v[6], v[7], v[0], v[1], v[2], v[3], v[4], W[i], K[i] ); i++; + COMPRESS(v[4], v[5], v[6], v[7], v[0], v[1], v[2], v[3], W[i], K[i] ); i++; + COMPRESS(v[3], v[4], v[5], v[6], v[7], v[0], v[1], v[2], W[i], K[i] ); i++; + COMPRESS(v[2], v[3], v[4], v[5], v[6], v[7], v[0], v[1], W[i], K[i] ); i++; + COMPRESS(v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[0], W[i], K[i] ); i++; } + for (i = 0; i < 8; i++) { ctx->val[i] += v[i]; } +} - for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[i]; +static inline void sha512_stage1(sha512_ctx_t *sha512_ctx) +{ + while (sha512_ctx->payload_len >= 128) { + sha512_hash_factory(sha512_ctx, sha512_ctx->payload_addr); + sha512_ctx->payload_addr += 128; + sha512_ctx->payload_len -= 128; + } +} + +static inline void sha512_stage2(sha512_ctx_t *sha512_ctx, uint8_t output[64]) +{ + uint32_t block_pos = sha512_ctx->payload_len; + uint32_t padding_bytes = 0; + uint8_t temp_data[128] = {0}; + uint8_t *temp_data_p = (uint8_t *)&temp_data[0]; + uint8_t len_be[16] = {0}; + uint8_t i = 0; + sha512_memcpy(sha512_ctx->payload_addr, temp_data_p, sha512_ctx->payload_len); + padding_bytes = 112 - block_pos; + temp_data_p += block_pos; + sha512_memcpy((uint8_t *)sha512_padding, temp_data_p, padding_bytes); + temp_data_p += padding_bytes; + sha512_encode(sha512_ctx->len[1], len_be, 0); + sha512_encode(sha512_ctx->len[0], len_be, 8); + sha512_memcpy(len_be, temp_data_p, 16); + sha512_hash_factory(sha512_ctx, temp_data); + for (i = 0; i < 6; i++) { sha512_encode(sha512_ctx->val[i], output, i * 8); } + for ( ;(i < 8) && (sha512_ctx->is_sha384 == 0); i++) { sha512_encode(sha512_ctx->val[i], output, i * 8); } +} + +} // anonymous namespace + +void SHA512(void *digest,const void *data,unsigned int len) +{ + sha512_ctx_t h; + sha512_init_512(&h,(uint8_t *)data,len); + sha512_stage1(&h); + sha512_stage2(&h,(uint8_t *)digest); +} + +void SHA384(void *digest,const void *data,unsigned int len) +{ + sha512_ctx_t h; + sha512_init_384(&h,(uint8_t *)data,len); + sha512_stage1(&h); + sha512_stage2(&h,(uint8_t *)digest); } } // namespace ZeroTier @@ -363,5 +269,5 @@ void SHA512::hash(void *digest,const void *data,unsigned int len) // This eliminates the need to link against a third party SHA512() from this code extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len) { - ZeroTier::SHA512::hash(digest,data,len); + ZeroTier::SHA512(digest,data,len); } diff --git a/node/SHA512.hpp b/node/SHA512.hpp index cb7b40a8b..1ede6cc9b 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -31,14 +31,9 @@ namespace ZeroTier { -/** - * SHA-512 digest algorithm - */ -class SHA512 -{ -public: - static void hash(void *digest,const void *data,unsigned int len); -}; +void SHA512(void *digest,const void *data,unsigned int len); + +void SHA384(void *digest,const void *data,unsigned int len); } // namespace ZeroTier diff --git a/node/Utils.hpp b/node/Utils.hpp index e06139468..1cb5ceb9c 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -242,8 +242,8 @@ public: */ static void getSecureRandom(void *buf,unsigned int bytes); - static int Utils::b32d(const char *encoded, uint8_t *result, int bufSize); - static int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize); + static int b32d(const char *encoded, uint8_t *result, int bufSize); + static int b32e(const uint8_t *data,int length,char *result,int bufSize); /** * Tokenize a string (alias for strtok_r or strtok_s depending on platform) diff --git a/selftest.cpp b/selftest.cpp index 4e46ab8fd..8ded0f310 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -105,6 +105,7 @@ static const unsigned char poly1305TV1Tag[16] = { 0xa6,0xf7,0x45,0x00,0x8f,0x81, static const char *sha512TV0Input = "supercalifragilisticexpealidocious"; static const unsigned char sha512TV0Digest[64] = { 0x18,0x2a,0x85,0x59,0x69,0xe5,0xd3,0xe6,0xcb,0xf6,0x05,0x24,0xad,0xf2,0x88,0xd1,0xbb,0xf2,0x52,0x92,0x81,0x24,0x31,0xf6,0xd2,0x52,0xf1,0xdb,0xc1,0xcb,0x44,0xdf,0x21,0x57,0x3d,0xe1,0xb0,0x6b,0x68,0x75,0x95,0x9f,0x3b,0x6f,0x87,0xb1,0x13,0x81,0xd0,0xbc,0x79,0x2c,0x43,0x3a,0x13,0x55,0x3c,0xe0,0x84,0xc2,0x92,0x55,0x31,0x1c }; +static const unsigned char sha384TV0Digest[48] = { 0x71,0xe7,0x71,0x79,0xae,0xc3,0xf3,0x5f,0x93,0xea,0xe2,0x1d,0xe3,0x3f,0x24,0x6d,0xed,0x2a,0x59,0xae,0x22,0x45,0x27,0x6c,0x12,0x57,0xf3,0xbe,0xe6,0xce,0xe2,0x73,0xd8,0xad,0xaa,0x9b,0x99,0xa4,0x8a,0x1b,0x7a,0xb9,0x5d,0xfb,0x9c,0x1a,0x1c,0xf6 }; struct C25519TestVector { @@ -220,7 +221,7 @@ static int testCrypto() bytes += 1234567.0; } uint64_t end = OSUtils::now(); - SHA512::hash(buf1,bb,1234567); + SHA512(buf1,bb,1234567); std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1024.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << std::endl; ::free((void *)bb); } @@ -272,18 +273,25 @@ static int testCrypto() bytes += 1234567.0; } uint64_t end = OSUtils::now(); - SHA512::hash(buf1,bb,1234567); + SHA512(buf1,bb,1234567); std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1024.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << std::endl; ::free((void *)bb); } std::cout << "[crypto] Testing SHA-512... "; std::cout.flush(); - SHA512::hash(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input)); + SHA512(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input)); if (memcmp(buf1,sha512TV0Digest,64)) { std::cout << "FAIL" << std::endl; return -1; } std::cout << "PASS" << std::endl; + std::cout << "[crypto] Testing SHA-384... "; std::cout.flush(); + SHA384(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input)); + if (memcmp(buf1,sha384TV0Digest,48)) { + std::cout << "FAIL" << std::endl; + return -1; + } + std::cout << "PASS" << std::endl; std::cout << "[crypto] Testing Poly1305... "; std::cout.flush(); Poly1305::compute(buf1,poly1305TV0Input,sizeof(poly1305TV0Input),poly1305TV0Key); diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index df3d89c22..081a468ee 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -127,7 +127,7 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute) const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH])); if ((metaHash.length() == ZT_SHA512_DIGEST_LEN)&&(OSUtils::readFile(binPath.c_str(),d.bin))) { std::array sha512; - SHA512::hash(sha512.data(),d.bin.data(),(unsigned int)d.bin.length()); + SHA512(sha512.data(),d.bin.data(),(unsigned int)d.bin.length()); if (!memcmp(sha512.data(),metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional std::array shakey; @@ -347,7 +347,7 @@ bool SoftwareUpdater::check(const int64_t now) try { // (1) Check the hash itself to make sure the image is basically okay uint8_t sha512[ZT_SHA512_DIGEST_LEN]; - SHA512::hash(sha512,_download.data(),(unsigned int)_download.length()); + SHA512(sha512,_download.data(),(unsigned int)_download.length()); char hexbuf[(ZT_SHA512_DIGEST_LEN * 2) + 2]; if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"") == Utils::hex(sha512,ZT_SHA512_DIGEST_LEN,hexbuf)) { // (2) Check signature by signing authority