فهرست منبع

Add new crypto: SHA512 and C25519 -- not integrated yet.

Adam Ierymenko 12 سال پیش
والد
کامیت
77965af288
7فایلهای تغییر یافته به همراه830 افزوده شده و 25 حذف شده
  1. 345 0
      node/C25519.cpp
  2. 69 0
      node/C25519.hpp
  3. 2 0
      node/PacketDecoder.cpp
  4. 351 0
      node/SHA512.cpp
  5. 46 0
      node/SHA512.hpp
  6. 2 0
      objects.mk
  7. 15 25
      selftest.cpp

+ 345 - 0
node/C25519.cpp

@@ -0,0 +1,345 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013  ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Utils.hpp"
+#include "C25519.hpp"
+#include "SHA512.hpp"
+
+namespace ZeroTier {
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Code taken from NaCl by D. J. Bernstein and others
+
+/*
+Matthew Dempsky
+Public domain.
+Derived from public domain code by D. J. Bernstein.
+*/
+
+static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+  unsigned int j;
+  unsigned int u;
+  u = 0;
+  for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
+  u += a[31] + b[31]; out[31] = u;
+}
+
+static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+  unsigned int j;
+  unsigned int u;
+  u = 218;
+  for (j = 0;j < 31;++j) {
+    u += a[j] + 65280 - b[j];
+    out[j] = u & 255;
+    u >>= 8;
+  }
+  u += a[31] - b[31];
+  out[31] = u;
+}
+
+static void squeeze(unsigned int a[32])
+{
+  unsigned int j;
+  unsigned int u;
+  u = 0;
+  for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
+  u += a[31]; a[31] = u & 127;
+  u = 19 * (u >> 7);
+  for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
+  u += a[31]; a[31] = u;
+}
+
+static const unsigned int minusp[32] = {
+ 19, 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, 128
+} ;
+
+static void freeze(unsigned int a[32])
+{
+  unsigned int aorig[32];
+  unsigned int j;
+  unsigned int negative;
+
+  for (j = 0;j < 32;++j) aorig[j] = a[j];
+  add(a,a,minusp);
+  negative = -((a[31] >> 7) & 1);
+  for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
+}
+
+static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+  unsigned int i;
+  unsigned int j;
+  unsigned int u;
+
+  for (i = 0;i < 32;++i) {
+    u = 0;
+    for (j = 0;j <= i;++j) u += a[j] * b[i - j];
+    for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
+    out[i] = u;
+  }
+  squeeze(out);
+}
+
+static void mult121665(unsigned int out[32],const unsigned int a[32])
+{
+  unsigned int j;
+  unsigned int u;
+
+  u = 0;
+  for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
+  u += 121665 * a[31]; out[31] = u & 127;
+  u = 19 * (u >> 7);
+  for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
+  u += out[j]; out[j] = u;
+}
+
+static void square(unsigned int out[32],const unsigned int a[32])
+{
+  unsigned int i;
+  unsigned int j;
+  unsigned int u;
+
+  for (i = 0;i < 32;++i) {
+    u = 0;
+    for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
+    for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
+    u *= 2;
+    if ((i & 1) == 0) {
+      u += a[i / 2] * a[i / 2];
+      u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
+    }
+    out[i] = u;
+  }
+  squeeze(out);
+}
+
+static void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b)
+{
+  unsigned int j;
+  unsigned int t;
+  unsigned int bminus1;
+
+  bminus1 = b - 1;
+  for (j = 0;j < 64;++j) {
+    t = bminus1 & (r[j] ^ s[j]);
+    p[j] = s[j] ^ t;
+    q[j] = r[j] ^ t;
+  }
+}
+
+static void mainloop(unsigned int work[64],const unsigned char e[32])
+{
+  unsigned int xzm1[64];
+  unsigned int xzm[64];
+  unsigned int xzmb[64];
+  unsigned int xzm1b[64];
+  unsigned int xznb[64];
+  unsigned int xzn1b[64];
+  unsigned int a0[64];
+  unsigned int a1[64];
+  unsigned int b0[64];
+  unsigned int b1[64];
+  unsigned int c1[64];
+  unsigned int r[32];
+  unsigned int s[32];
+  unsigned int t[32];
+  unsigned int u[32];
+  //unsigned int i;
+  unsigned int j;
+  unsigned int b;
+  int pos;
+
+  for (j = 0;j < 32;++j) xzm1[j] = work[j];
+  xzm1[32] = 1;
+  for (j = 33;j < 64;++j) xzm1[j] = 0;
+
+  xzm[0] = 1;
+  for (j = 1;j < 64;++j) xzm[j] = 0;
+
+  for (pos = 254;pos >= 0;--pos) {
+    b = e[pos / 8] >> (pos & 7);
+    b &= 1;
+    select(xzmb,xzm1b,xzm,xzm1,b);
+    add(a0,xzmb,xzmb + 32);
+    sub(a0 + 32,xzmb,xzmb + 32);
+    add(a1,xzm1b,xzm1b + 32);
+    sub(a1 + 32,xzm1b,xzm1b + 32);
+    square(b0,a0);
+    square(b0 + 32,a0 + 32);
+    mult(b1,a1,a0 + 32);
+    mult(b1 + 32,a1 + 32,a0);
+    add(c1,b1,b1 + 32);
+    sub(c1 + 32,b1,b1 + 32);
+    square(r,c1 + 32);
+    sub(s,b0,b0 + 32);
+    mult121665(t,s);
+    add(u,t,b0);
+    mult(xznb,b0,b0 + 32);
+    mult(xznb + 32,s,u);
+    square(xzn1b,c1);
+    mult(xzn1b + 32,r,work);
+    select(xzm,xzm1,xznb,xzn1b,b);
+  }
+
+  for (j = 0;j < 64;++j) work[j] = xzm[j];
+}
+
+static void recip(unsigned int out[32],const unsigned int z[32])
+{
+  unsigned int z2[32];
+  unsigned int z9[32];
+  unsigned int z11[32];
+  unsigned int z2_5_0[32];
+  unsigned int z2_10_0[32];
+  unsigned int z2_20_0[32];
+  unsigned int z2_50_0[32];
+  unsigned int z2_100_0[32];
+  unsigned int t0[32];
+  unsigned int t1[32];
+  int i;
+
+  /* 2 */ square(z2,z);
+  /* 4 */ square(t1,z2);
+  /* 8 */ square(t0,t1);
+  /* 9 */ mult(z9,t0,z);
+  /* 11 */ mult(z11,z9,z2);
+  /* 22 */ square(t0,z11);
+  /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9);
+
+  /* 2^6 - 2^1 */ square(t0,z2_5_0);
+  /* 2^7 - 2^2 */ square(t1,t0);
+  /* 2^8 - 2^3 */ square(t0,t1);
+  /* 2^9 - 2^4 */ square(t1,t0);
+  /* 2^10 - 2^5 */ square(t0,t1);
+  /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0);
+
+  /* 2^11 - 2^1 */ square(t0,z2_10_0);
+  /* 2^12 - 2^2 */ square(t1,t0);
+  /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); }
+  /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0);
+
+  /* 2^21 - 2^1 */ square(t0,z2_20_0);
+  /* 2^22 - 2^2 */ square(t1,t0);
+  /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); }
+  /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0);
+
+  /* 2^41 - 2^1 */ square(t1,t0);
+  /* 2^42 - 2^2 */ square(t0,t1);
+  /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); }
+  /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0);
+
+  /* 2^51 - 2^1 */ square(t0,z2_50_0);
+  /* 2^52 - 2^2 */ square(t1,t0);
+  /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
+  /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0);
+
+  /* 2^101 - 2^1 */ square(t1,z2_100_0);
+  /* 2^102 - 2^2 */ square(t0,t1);
+  /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); }
+  /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0);
+
+  /* 2^201 - 2^1 */ square(t0,t1);
+  /* 2^202 - 2^2 */ square(t1,t0);
+  /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
+  /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0);
+
+  /* 2^251 - 2^1 */ square(t1,t0);
+  /* 2^252 - 2^2 */ square(t0,t1);
+  /* 2^253 - 2^3 */ square(t1,t0);
+  /* 2^254 - 2^4 */ square(t0,t1);
+  /* 2^255 - 2^5 */ square(t1,t0);
+  /* 2^255 - 21 */ mult(out,t1,z11);
+}
+
+static int crypto_scalarmult(unsigned char *q,
+  const unsigned char *n,
+  const unsigned char *p)
+{
+  unsigned int work[96];
+  unsigned char e[32];
+  unsigned int i;
+  for (i = 0;i < 32;++i) e[i] = n[i];
+  e[0] &= 248;
+  e[31] &= 127;
+  e[31] |= 64;
+  for (i = 0;i < 32;++i) work[i] = p[i];
+  mainloop(work,e);
+  recip(work + 32,work + 32);
+  mult(work + 64,work,work + 32);
+  freeze(work + 64);
+  for (i = 0;i < 32;++i) q[i] = work[64 + i];
+  return 0;
+}
+
+static const unsigned char base[32] = {9};
+
+static int crypto_scalarmult_base(unsigned char *q,
+  const unsigned char *n)
+{
+  return crypto_scalarmult(q,n,base);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+C25519::Pair C25519::generate()
+{
+	Pair kp;
+	Utils::getSecureRandom(kp.priv.data,kp.priv.size());
+
+	// First 32 bytes of pub and priv are the keys for C25519 key
+	// agreement. This generates the public portion from the private.
+	crypto_scalarmult_base(kp.pub.data,kp.priv.data);
+
+	return kp;
+}
+
+void C25519::agree(const C25519::Pair &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
+{
+	unsigned char rawkey[32];
+	unsigned char digest[64];
+
+	crypto_scalarmult(rawkey,mine.priv.data,their.data);
+	SHA512::hash(digest,rawkey,32);
+	for(unsigned int i=0,k=0;i<keylen;) {
+		if (k == 64) {
+			k = 0;
+			SHA512::hash(digest,digest,64);
+		}
+		((unsigned char *)keybuf)[i++] = digest[k++];
+	}
+}
+
+} // namespace ZeroTier

+ 69 - 0
node/C25519.hpp

@@ -0,0 +1,69 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013  ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef _ZT_C25519_HPP
+#define _ZT_C25519_HPP
+
+#include "Array.hpp"
+
+namespace ZeroTier {
+
+/**
+ * C25519 elliptic curve key agreement and signing
+ */
+class C25519
+{
+public:
+	typedef Array<unsigned char,64> Public; // crypto key, signing key
+	typedef Array<unsigned char,96> Private; // crypto key, signing key (64 bytes)
+	typedef struct {
+		Public pub;
+		Private priv;
+	} Pair;
+
+	/**
+	 * Generate a C25519 elliptic curve key pair
+	 */
+	static Pair generate();
+
+	/**
+	 * Perform C25519 ECC key agreement
+	 *
+	 * Actual key bytes are generated from one or more SHA-512 digests of
+	 * the raw result of key agreement.
+	 *
+	 * @param mine My key pair including secret
+	 * @param their Their public key
+	 * @param keybuf Buffer to fill
+	 * @param keylen Number of key bytes to generate
+	 */
+	static void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen);
+};
+
+} // namespace ZeroTier
+
+#endif

+ 2 - 0
node/PacketDecoder.cpp

@@ -25,6 +25,8 @@
  * LLC. Start here: http://www.zerotier.com/
  */
 
+#include "../version.h"
+
 #include "Constants.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Topology.hpp"

+ 351 - 0
node/SHA512.cpp

@@ -0,0 +1,351 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013  ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SHA512.hpp"
+
+namespace ZeroTier {
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Code taken from NaCl by D. J. Bernstein and others
+// Public domain
+
+/*
+20080913
+D. J. Bernstein
+Public domain.
+*/
+
+#define uint64 uint64_t
+
+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;
+}
+
+#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;
+
+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
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void SHA512::hash(void *digest,const void *data,unsigned int len)
+{
+  unsigned char h[64];
+  unsigned char padded[256];
+  int i;
+  uint64_t bytes = len;
+
+  const unsigned char *in = (const unsigned char *)data;
+  unsigned int inlen = len;
+
+  for (i = 0;i < 64;++i) h[i] = iv[i];
+
+  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 < 64;++i) ((unsigned char *)digest)[i] = h[i];
+}
+
+} // namespace ZeroTier

+ 46 - 0
node/SHA512.hpp

@@ -0,0 +1,46 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013  ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef _ZT_SHA512_HPP
+#define _ZT_SHA512_HPP
+
+#define ZT_SHA512_DIGEST_LEN 64
+
+namespace ZeroTier {
+
+/**
+ * SHA-512 digest algorithm
+ */
+class SHA512
+{
+public:
+	static void hash(void *digest,const void *data,unsigned int len);
+};
+
+} // namespace ZeroTier
+
+#endif

+ 2 - 0
objects.mk

@@ -2,6 +2,7 @@ OBJS=\
 	ext/kissdb/kissdb.o \
 	ext/lz4/lz4hc.o \
 	ext/lz4/lz4.o \
+	node/C25519.o \
 	node/Defaults.o \
 	node/Demarc.o \
 	node/EllipticCurveKeyPair.o \
@@ -19,6 +20,7 @@ OBJS=\
 	node/Peer.o \
 	node/Salsa20.o \
 	node/Service.o \
+	node/SHA512.o \
 	node/Switch.o \
 	node/SysEnv.o \
 	node/Topology.o \

+ 15 - 25
selftest.cpp

@@ -50,8 +50,9 @@
 #include "node/Condition.hpp"
 #include "node/NodeConfig.hpp"
 #include "node/Dictionary.hpp"
-#include "node/RateLimiter.hpp"
 #include "node/EthernetTap.hpp"
+#include "node/SHA512.hpp"
+#include "node/C25519.hpp"
 
 #include <openssl/rand.h>
 
@@ -93,10 +94,6 @@ static void _initLibCrypto()
 
 static unsigned char fuzzbuf[1048576];
 
-static const char *hmacShaTV0Key = "key";
-static const char *hmacShaTV0Msg = "The quick brown fox jumps over the lazy dog";
-static const unsigned char hmacShaTV0Mac[32] = { 0xf7,0xbc,0x83,0xf4,0x30,0x53,0x84,0x24,0xb1,0x32,0x98,0xe6,0xaa,0x6f,0xb1,0x43,0xef,0x4d,0x59,0xa1,0x49,0x46,0x17,0x59,0x97,0x47,0x9d,0xbc,0x2d,0x1a,0x3c,0xd8 };
-
 static const unsigned char s20TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c };
 static const unsigned char s20TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 };
 static const unsigned char s20TV0Ks[64] = { 0x5e,0x5e,0x71,0xf9,0x01,0x99,0x34,0x03,0x04,0xab,0xb2,0x2a,0x37,0xb6,0x62,0x5b,0xf8,0x83,0xfb,0x89,0xce,0x3b,0x21,0xf5,0x4a,0x10,0xb8,0x10,0x66,0xef,0x87,0xda,0x30,0xb7,0x76,0x99,0xaa,0x73,0x79,0xda,0x59,0x5c,0x77,0xdd,0x59,0x54,0x2d,0xa2,0x08,0xe5,0x95,0x4f,0x89,0xe4,0x0e,0xb7,0xaa,0x80,0xa8,0x4a,0x61,0x76,0x66,0x3f };
@@ -106,29 +103,22 @@ static int testCrypto()
 	unsigned char buf1[16384];
 	unsigned char buf2[sizeof(buf1)],buf3[sizeof(buf1)];
 
-	//Utils::getSecureRandom(buf1,1024);
-	//std::cout << "[crypto] getSecureRandom() -> " << Utils::hex(buf1,1024) << std::endl;
-
-	std::cout << "[crypto] Testing ECDSA... "; std::cout.flush();
-	for(unsigned int k=0;k<64;++k) {
-		EllipticCurveKeyPair kp;
-		kp.generate();
-		for(int i=0;i<32;++i)
-			buf1[i] = (unsigned char)rand();
-		std::string sig = kp.sign(buf1);
-		if (!EllipticCurveKeyPair::verify(buf1,kp.pub(),sig.data(),sig.length())) {
+	std::cout << "[crypto] Testing C25519 ECC key agreement... "; std::cout.flush();
+	for(unsigned int i=0;i<100;++i) {
+		C25519::Pair p1 = C25519::generate();
+		C25519::Pair p2 = C25519::generate();
+		C25519::Pair p3 = C25519::generate();
+		C25519::agree(p1,p2.pub,buf1,64);
+		C25519::agree(p2,p1.pub,buf2,64);
+		C25519::agree(p3,p1.pub,buf3,64);
+		if (memcmp(buf1,buf2,64)) {
 			std::cout << "FAIL" << std::endl;
 			return -1;
 		}
-	}
-	std::cout << "PASS" << std::endl;
-
-	std::cout << "[crypto] Testing HMAC-SHA256... "; std::cout.flush();
-	memset(buf1,0,sizeof(buf1));
-	HMAC::sha256(hmacShaTV0Key,strlen(hmacShaTV0Key),hmacShaTV0Msg,strlen(hmacShaTV0Msg),buf1);
-	if (memcmp(buf1,hmacShaTV0Mac,32)) {
-		std::cout << "FAIL (test vector 0) (" << Utils::hex(buf1,32) << ")" << std::endl;
-		return -1;
+		if (!memcmp(buf2,buf3,64)) {
+			std::cout << "FAIL (2)" << std::endl;
+			return -1;
+		}
 	}
 	std::cout << "PASS" << std::endl;