AES integrated on send side.

This commit is contained in:
Adam Ierymenko 2020-08-21 14:23:31 -07:00
parent 3fd8efe642
commit 2ac49d99dd
15 changed files with 446 additions and 427 deletions

View file

@ -1,367 +1,274 @@
// Code taken from NaCl by D. J. Bernstein and others
// Public domain
/*
20080913
D. J. Bernstein
Public domain.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
// This code is public domain, taken from a PD crypto source file on GitHub.
#include "SHA512.hpp"
#include "Utils.hpp"
#ifdef __APPLE__
#include <CommonCrypto/CommonDigest.h>
#define ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
void SHA512::hash(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);
}
}
#endif
#ifdef ZT_USE_LIBCRYPTO
#include <openssl/sha.h>
#define ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
void SHA512::hash(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);
}
}
#endif
#ifndef ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
namespace {
#define uint64 uint64_t
#ifdef ZT_NO_TYPE_PUNNING
static uint64 load_bigendian(const unsigned char *x)
{
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)
;
}
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;
}
#else // !ZT_NO_TYPE_PUNNING
#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x)))
#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u)))
#endif // ZT_NO_TYPE_PUNNING
#define SHR(x,c) ((x) >> (c))
#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
#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
struct sha512_state {
uint64_t length,state[8];
unsigned long curlen;
uint8_t buf[128];
};
void SHA512::hash(void *digest,const void *data,unsigned int len)
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
};
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y,x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y))))
#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y))))
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) ((x)>>(n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
{
unsigned char h[64];
unsigned char padded[256];
uint64_t S[8], W[80], t0, t1;
int i;
uint64_t bytes = len;
const unsigned char *in = (const unsigned char *)data;
unsigned int inlen = len;
for (i = 0; i < 8; i++)
S[i] = md->state[i];
for (i = 0; i < 16; i++)
LOAD64H(W[i], buf + (8*i));
for (i = 16; i < 80; i++)
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
for (i = 0;i < 64;++i) h[i] = iv[i];
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
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);
for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
}
for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[i];
for (i = 0; i < 8; i++)
md->state[i] = md->state[i] + S[i];
}
} // namespace ZeroTier
static ZT_INLINE void sha384_init(sha512_state *const md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = 0xcbbb9d5dc1059ed8ULL;
md->state[1] = 0x629a292a367cd507ULL;
md->state[2] = 0x9159015a3070dd17ULL;
md->state[3] = 0x152fecd8f70e5939ULL;
md->state[4] = 0x67332667ffc00b31ULL;
md->state[5] = 0x8eb44a8768581511ULL;
md->state[6] = 0xdb0c2e0d64f98fa7ULL;
md->state[7] = 0x47b5481dbefa4fa4ULL;
}
static ZT_INLINE void sha512_init(sha512_state *const md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = 0x6a09e667f3bcc908ULL;
md->state[1] = 0xbb67ae8584caa73bULL;
md->state[2] = 0x3c6ef372fe94f82bULL;
md->state[3] = 0xa54ff53a5f1d36f1ULL;
md->state[4] = 0x510e527fade682d1ULL;
md->state[5] = 0x9b05688c2b3e6c1fULL;
md->state[6] = 0x1f83d9abfb41bd6bULL;
md->state[7] = 0x5be0cd19137e2179ULL;
}
static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen)
{
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md,(uint8_t *)in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
unsigned long n = std::min(inlen,(128 - md->curlen));
Utils::copy(md->buf + md->curlen,in,n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
sha512_compress(md,md->buf);
md->length += 8*128;
md->curlen = 0;
}
}
}
}
static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
{
int i;
md->length += md->curlen * 8ULL;
md->buf[md->curlen++] = (uint8_t)0x80;
if (md->curlen > 112) {
while (md->curlen < 128) {
md->buf[md->curlen++] = (uint8_t)0;
}
sha512_compress(md, md->buf);
md->curlen = 0;
}
while (md->curlen < 120) {
md->buf[md->curlen++] = (uint8_t)0;
}
STORE64H(md->length, md->buf+120);
sha512_compress(md, md->buf);
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
}
}
} // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len)
{
sha512_state state;
sha512_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,(uint8_t *)digest);
}
void SHA384(void *digest,const void *data,unsigned int len)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
}
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data0,(unsigned long)len0);
sha512_process(&state,(uint8_t *)data1,(unsigned long)len1);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
}
#endif // !ZT_HAVE_NATIVE_SHA512
// Internally re-export to included C code, which includes some fast crypto code ported in on some platforms.
// 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)
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48])
{
ZeroTier::SHA512::hash(digest,data,len);
uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg)
const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key);
const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8);
const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16);
const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24);
const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32);
const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40);
const uint64_t ipad = 0x3636363636363636ULL;
kInPadded[0] = k0 ^ ipad;
kInPadded[1] = k1 ^ ipad;
kInPadded[2] = k2 ^ ipad;
kInPadded[3] = k3 ^ ipad;
kInPadded[4] = k4 ^ ipad;
kInPadded[5] = k5 ^ ipad;
kInPadded[6] = ipad;
kInPadded[7] = ipad;
kInPadded[8] = ipad;
kInPadded[9] = ipad;
kInPadded[10] = ipad;
kInPadded[11] = ipad;
kInPadded[12] = ipad;
kInPadded[13] = ipad;
kInPadded[14] = ipad;
kInPadded[15] = ipad;
const uint64_t opad = 0x5c5c5c5c5c5c5c5cULL;
outer[0] = k0 ^ opad;
outer[1] = k1 ^ opad;
outer[2] = k2 ^ opad;
outer[3] = k3 ^ opad;
outer[4] = k4 ^ opad;
outer[5] = k5 ^ opad;
outer[6] = opad;
outer[7] = opad;
outer[8] = opad;
outer[9] = opad;
outer[10] = opad;
outer[11] = opad;
outer[12] = opad;
outer[13] = opad;
outer[14] = opad;
outer[15] = opad;
// H(output padded key | H(input padded key | msg))
SHA384(reinterpret_cast<uint8_t *>(outer) + 128,kInPadded,128,msg,msglen);
SHA384(mac,outer,176);
}
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{
uint8_t kbkdfMsg[13];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[6] = (uint8_t)label;
kbkdfMsg[7] = 0;
kbkdfMsg[8] = (uint8_t)context;
// Output key length: 384 bits (as 32-bit big-endian value)
kbkdfMsg[9] = 0;
kbkdfMsg[10] = 0;
kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out);
}
} // namespace ZeroTier