New crypto integrated -- going to be testing new identity address generation algo a bit more before finalizing.

This commit is contained in:
Adam Ierymenko 2013-09-16 13:57:57 -04:00
parent ceb024ab03
commit e376c6f6a9
12 changed files with 84 additions and 115 deletions

View File

@ -13,7 +13,7 @@ STRIP=strip
#STRIP=echo
CXXFLAGS=$(CFLAGS) -fno-rtti
LIBS=-lcrypto -lm
LIBS=-lm
include objects.mk

View File

@ -49,8 +49,6 @@
#include <signal.h>
#endif
#include <openssl/rand.h>
#include "node/Constants.hpp"
#include "node/Defaults.hpp"
#include "node/Utils.hpp"
@ -58,36 +56,6 @@
using namespace ZeroTier;
// ---------------------------------------------------------------------------
// Override libcrypto default RAND_ with Utils::getSecureRandom(), which uses
// a system strong random source. This is because OpenSSL libcrypto's default
// RAND_ implementation uses uninitialized memory as one of its entropy
// sources, which plays havoc with all kinds of debuggers and auditing tools.
static void _zeroTier_rand_cleanup() {}
static void _zeroTier_rand_add(const void *buf, int num, double add_entropy) {}
static int _zeroTier_rand_status() { return 1; }
static void _zeroTier_rand_seed(const void *buf, int num) {}
static int _zeroTier_rand_bytes(unsigned char *buf, int num)
{
Utils::getSecureRandom(buf,num);
return 1;
}
static RAND_METHOD _zeroTierRandMethod = {
_zeroTier_rand_seed,
_zeroTier_rand_bytes,
_zeroTier_rand_cleanup,
_zeroTier_rand_add,
_zeroTier_rand_bytes,
_zeroTier_rand_status
};
static void _initLibCrypto()
{
RAND_set_rand_method(&_zeroTierRandMethod);
}
// ---------------------------------------------------------------------------
static Node *node = (Node *)0;
static void printHelp(const char *cn,FILE *out)
@ -145,8 +113,6 @@ int main(int argc,char **argv)
SetConsoleCtrlHandler(&_handlerRoutine,TRUE);
#endif
_initLibCrypto();
const char *homeDir = (const char *)0;
for(int i=1;i<argc;++i) {
if (argv[i][0] == '-') {

View File

@ -52,6 +52,7 @@ static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap()
// Nothing special about a supernode... except that they are
// designated as such.
#if 0
// cthulhu.zerotier.com - New York, New York, USA
addrs.clear();
if (!id.fromString("271ee006a0:1:AgGXs3I+9CWrEmGMxc50x3E+trwtaa2ZMXDU6ezz92fFJXzlhRKGUY/uAToHDdH9XiLxtcA+kUQAZdC4Dy2xtqXxjw==:QgH5Nlx4oWEGVrwhNocqem+3VNd4qzt7RLrmuvqZvKPRS9R70LJYJQLlKZj0ri55Pzg+Mlwy4a4nAgfnRAWA+TW6R0EjSmq72MG585XGNfWBVk3LxMvxlNWErnVNFr2BQS9yzVp4pRjPLdCW4RB3dwEHBUgJ78rwMxQ6IghVCl8CjkDapg=="))
@ -72,6 +73,7 @@ static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap()
throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("198.211.127.172",ZT_DEFAULT_UDP_PORT));
sn[id] = addrs;
#endif
return sn;
}

View File

@ -31,6 +31,7 @@
#include <stdint.h>
#include "Identity.hpp"
#include "SHA512.hpp"
namespace ZeroTier {
@ -76,7 +77,7 @@ std::string Identity::toString(bool includePrivate) const
r.append(Utils::hex(_signature.data,_signature.size()));
if ((_privateKey)&&(includePrivate)) {
r.push_back(':');
r.append(Utils::hex(_privateKey.data,_privateKey.size()));
r.append(Utils::hex(_privateKey->data,_privateKey->size()));
}
return r;
@ -129,8 +130,8 @@ bool Identity::fromString(const char *str)
// These are fixed parameters and can't be changed without a new
// identity type.
#define ZT_IDENTITY_DERIVEADDRESS_DIGESTS 540672
#define ZT_IDENTITY_DERIVEADDRESS_ROUNDS 4
#define ZT_IDENTITY_DERIVEADDRESS_DIGESTS 2048
#define ZT_IDENTITY_DERIVEADDRESS_ROUNDS 8
Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
{

View File

@ -39,6 +39,8 @@
#include "C25519.hpp"
#include "Buffer.hpp"
#define ZT_IDENTITY_MAX_BINARY_SERIALIZED_LENGTH (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN)
namespace ZeroTier {
/**
@ -148,6 +150,36 @@ public:
*/
inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); }
/**
* Sign a message with this identity (private key required)
*
* @param data Data to sign
* @param len Length of data
*/
inline C25519::Signature sign(const void *data,unsigned int len) const
throw(std::runtime_error)
{
if (_privateKey)
return C25519::sign(*_privateKey,_publicKey,data,len);
throw std::runtime_error("sign() requires a private key");
}
/**
* Verify a message signature against this identity
*
* @param data Data to check
* @param len Length of data
* @param signature Signature bytes
* @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const
{
if (siglen != ZT_C25519_SIGNATURE_LEN)
return false;
return C25519::verify(_publicKey,data,len,signature);
}
/**
* Shortcut method to perform key agreement with another identity
*
@ -193,8 +225,8 @@ public:
b.append(_publicKey.data,_publicKey.size());
b.append(_signature.data,_signature.size());
if ((_privateKey)&&(includePrivate)) {
b.append((unsigned char)_privateKey.size());
b.append(_privateKey.data,_privateKey.size());
b.append((unsigned char)_privateKey->size());
b.append(_privateKey->data,_privateKey->size());
} else b.append((unsigned char)0);
}
@ -225,15 +257,15 @@ public:
if (b[p++] != IDENTITY_TYPE_C25519)
throw std::invalid_argument("Identity: deserialize(): unsupported identity type");
memcpy(_publicKey.data,field(p,_publicKey.size()),_publicKey.size());
memcpy(_publicKey.data,b.field(p,_publicKey.size()),_publicKey.size());
p += _publicKey.size();
memcpy(_signature.data,field(p,_signature.size()),_signature.size());
memcpy(_signature.data,b.field(p,_signature.size()),_signature.size());
p += _signature.size();
unsigned int privateKeyLength = b[p++];
if ((privateKeyLength)&&(privateKeyLength == ZT_C25519_PRIVATE_KEY_LEN)) {
_privateKey = new C25519::Private();
memcpy(_privateKey->data,field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
}

View File

@ -31,10 +31,9 @@
#include <stdint.h>
#include <string.h>
#include <openssl/sha.h>
#include <utility>
#include <algorithm>
#include <stdexcept>
#include <map>
#include <set>
#include <vector>
@ -51,6 +50,7 @@
#include "BloomFilter.hpp"
#include "Identity.hpp"
#include "CMWC4096.hpp"
#include "C25519.hpp"
// Maximum sample size to pick during choice of multicast propagation peers
#define ZT_MULTICAST_PICK_MAX_SAMPLE_SIZE (ZT_MULTICAST_PROPAGATION_BREADTH * 8)
@ -92,13 +92,20 @@ public:
* @param etherType 16-bit ethernet type
* @param data Ethernet frame data
* @param len Length of frame
* @return ECDSA signature
* @return Signature of packet data and attributes
* @throws std::runtime_error Cannot sign, e.g. identity has no private key
*/
static inline std::string signMulticastPacket(const Identity &id,uint64_t nwid,const MAC &from,const MulticastGroup &to,unsigned int etherType,const void *data,unsigned int len)
static inline C25519::Signature signMulticastPacket(const Identity &id,uint64_t nwid,const MAC &from,const MulticastGroup &to,unsigned int etherType,const void *data,unsigned int len)
throw(std::runtime_error)
{
unsigned char digest[32];
_hashMulticastPacketForSig(nwid,from,to,etherType,data,len,digest);
return id.sign(digest);
char tmp[65536];
*((uint64_t *)tmp) = Utils::hton(nwid);
memcpy(tmp + 8,from.data,6);
memcpy(tmp + 14,to.mac().data,6);
*((uint32_t *)(tmp + 20)) = Utils::hton(to.adi());
*((uint16_t *)(tmp + 24)) = Utils::hton((uint16_t)etherType);
memcpy(tmp + 26,data,std::min((unsigned int)(sizeof(tmp) - 26),len)); // min() is a sanity check here, no packet is that big
return id.sign(tmp,len + 26);
}
/**
@ -111,15 +118,20 @@ public:
* @param etherType 16-bit ethernet type
* @param data Ethernet frame data
* @param len Length of frame
* @param signature ECDSA signature
* @param signature Signature
* @param siglen Length of signature in bytes
* @return ECDSA signature
* @return True if signature verification was successful
*/
static bool verifyMulticastPacket(const Identity &id,uint64_t nwid,const MAC &from,const MulticastGroup &to,unsigned int etherType,const void *data,unsigned int len,const void *signature,unsigned int siglen)
{
unsigned char digest[32];
_hashMulticastPacketForSig(nwid,from,to,etherType,data,len,digest);
return id.verifySignature(digest,signature,siglen);
char tmp[65536];
*((uint64_t *)tmp) = Utils::hton(nwid);
memcpy(tmp + 8,from.data,6);
memcpy(tmp + 14,to.mac().data,6);
*((uint32_t *)(tmp + 20)) = Utils::hton(to.adi());
*((uint16_t *)(tmp + 24)) = Utils::hton((uint16_t)etherType);
memcpy(tmp + 26,data,std::min((unsigned int)(sizeof(tmp) - 26),len)); // min() is a sanity check here, no packet is that big
return id.verify(tmp,len + 26,signature,siglen);
}
/**
@ -349,29 +361,6 @@ private:
}
};
static inline void _hashMulticastPacketForSig(uint64_t nwid,const MAC &from,const MulticastGroup &to,unsigned int etherType,const void *data,unsigned int len,unsigned char *digest)
throw()
{
unsigned char zero = 0;
SHA256_CTX sha;
SHA256_Init(&sha);
uint64_t _nwid = Utils::hton(nwid);
SHA256_Update(&sha,(unsigned char *)&_nwid,sizeof(_nwid));
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)from.data,6);
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)to.mac().data,6);
SHA256_Update(&sha,&zero,1);
uint32_t _adi = Utils::hton(to.adi());
SHA256_Update(&sha,(unsigned char *)&_adi,sizeof(_adi));
SHA256_Update(&sha,&zero,1);
uint16_t _etype = Utils::hton((uint16_t)etherType);
SHA256_Update(&sha,(unsigned char *)&_etype,sizeof(_etype));
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)data,len);
SHA256_Final(digest,&sha);
}
// ring buffer: [0] - CRC, [1] - timestamp
uint64_t _multicastHistory[ZT_MULTICAST_DEDUP_HISTORY_LENGTH][2];
volatile unsigned int _multicastHistoryPtr;

View File

@ -30,8 +30,6 @@
#include <stdlib.h>
#include <math.h>
#include <openssl/sha.h>
#include "RuntimeEnvironment.hpp"
#include "NodeConfig.hpp"
#include "Network.hpp"

View File

@ -66,6 +66,7 @@
#include "Mutex.hpp"
#include "Multicaster.hpp"
#include "CMWC4096.hpp"
#include "SHA512.hpp"
#include "Service.hpp"
#ifdef __WINDOWS__
@ -128,10 +129,11 @@ Node::LocalClient::LocalClient(const char *authToken,void (*resultHandler)(void
// If socket fails to bind, there's a big problem like missing IPv4 stack
if (sock) {
SHA256_CTX sha;
SHA256_Init(&sha);
SHA256_Update(&sha,authToken,strlen(authToken));
SHA256_Final(impl->key,&sha);
{
unsigned int csk[64];
SHA512::hash(csk,authToken,strlen(authToken));
memcpy(impl->key,csk,32);
}
impl->sock = sock;
impl->resultHandler = resultHandler;

View File

@ -69,7 +69,7 @@ NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken)
{
{
unsigned int csk[64];
SHA512::hash(authToken,strlen(authToken));
SHA512::hash(csk,authToken,strlen(authToken));
memcpy(_controlSocketKey,csk,32);
}

View File

@ -42,7 +42,6 @@
#include "Demarc.hpp"
#include "RuntimeEnvironment.hpp"
#include "InetAddress.hpp"
#include "EllipticCurveKey.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
@ -54,7 +53,7 @@
*/
#define ZT_PEER_MAX_SERIALIZED_LENGTH ( \
64 + \
IDENTITY_MAX_BINARY_SERIALIZED_LENGTH + \
ZT_IDENTITY_MAX_BINARY_SERIALIZED_LENGTH + \
( ( \
(sizeof(uint64_t) * 4) + \
sizeof(uint16_t) + \

View File

@ -135,11 +135,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
if (!np)
return;
std::string signature(Multicaster::signMulticastPacket(_r->identity,network->id(),from,mg,etherType,data.data(),data.size()));
if (!signature.length()) {
TRACE("failure signing multicast message!");
return;
}
C25519::Signature signature(Multicaster::signMulticastPacket(_r->identity,network->id(),from,mg,etherType,data.data(),data.size()));
Packet outpTmpl(propPeers[0]->address(),_r->identity.address(),Packet::VERB_MULTICAST_FRAME);
outpTmpl.append((uint8_t)0);
@ -152,9 +148,9 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
outpTmpl.append((uint8_t)0); // 0 hops
outpTmpl.append((uint16_t)etherType);
outpTmpl.append((uint16_t)data.size());
outpTmpl.append((uint16_t)signature.length());
outpTmpl.append((uint16_t)signature.size());
outpTmpl.append(data.data(),data.size());
outpTmpl.append(signature.data(),(unsigned int)signature.length());
outpTmpl.append(signature.data,(unsigned int)signature.size());
outpTmpl.compress();
send(outpTmpl,true);
for(unsigned int i=1;i<np;++i) {

View File

@ -38,13 +38,10 @@
#include "node/Constants.hpp"
#include "node/RuntimeEnvironment.hpp"
#include "node/InetAddress.hpp"
#include "node/EllipticCurveKey.hpp"
#include "node/EllipticCurveKeyPair.hpp"
#include "node/Utils.hpp"
#include "node/Identity.hpp"
#include "node/Packet.hpp"
#include "node/Salsa20.hpp"
#include "node/HMAC.hpp"
#include "node/MAC.hpp"
#include "node/Peer.hpp"
#include "node/Condition.hpp"
@ -322,9 +319,9 @@ static int testPacket()
return -1;
}
a.hmacSet(hmacKey);
if (!a.hmacVerify(hmacKey)) {
std::cout << "FAIL (hmacVerify)" << std::endl;
a.macSet(hmacKey);
if (!a.macVerify(hmacKey)) {
std::cout << "FAIL (macVerify)" << std::endl;
return -1;
}
@ -334,19 +331,6 @@ static int testPacket()
static int testOther()
{
std::cout << "[other] Testing Base64 encode/decode... "; std::cout.flush();
for(unsigned int k=0;k<1000;++k) {
unsigned int flen = (rand() % 8194) + 1;
for(unsigned int i=0;i<flen;++i)
fuzzbuf[i] = (unsigned char)(rand() & 0xff);
std::string dec = Utils::base64Decode(Utils::base64Encode(fuzzbuf,flen));
if ((dec.length() != flen)||(memcmp(dec.data(),fuzzbuf,dec.length()))) {
std::cout << "FAILED!" << std::endl;
return -1;
}
}
std::cout << "PASS" << std::endl;
std::cout << "[other] Testing hex encode/decode... "; std::cout.flush();
for(unsigned int k=0;k<1000;++k) {
unsigned int flen = (rand() % 8194) + 1;
@ -365,7 +349,7 @@ static int testOther()
std::cout << "[other] Testing command bus encode/decode... "; std::cout.flush();
try {
static char key[32] = { 0 };
for(unsigned int k=0;k<1000;++k) {
for(unsigned int k=0;k<100;++k) {
std::vector<std::string> original;
for(unsigned int i=0,j=rand() % 256,l=(rand() % 1024)+1;i<j;++i)
original.push_back(std::string(l,'x'));
@ -395,7 +379,7 @@ static int testOther()
std::cout << "PASS" << std::endl;
std::cout << "[other] Testing Dictionary... "; std::cout.flush();
for(int k=0;k<10000;++k) {
for(int k=0;k<1000;++k) {
Dictionary a,b;
int nk = rand() % 32;
for(int q=0;q<nk;++q) {