summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/C25519.cpp10
-rw-r--r--node/C25519.hpp33
-rw-r--r--node/EllipticCurveKey.hpp114
-rw-r--r--node/EllipticCurveKeyPair.cpp369
-rw-r--r--node/EllipticCurveKeyPair.hpp130
-rw-r--r--node/HMAC.cpp81
-rw-r--r--node/HMAC.hpp55
-rw-r--r--node/Identity.cpp182
-rw-r--r--node/Identity.hpp218
9 files changed, 123 insertions, 1069 deletions
diff --git a/node/C25519.cpp b/node/C25519.cpp
index 82ba7884..eab7d110 100644
--- a/node/C25519.cpp
+++ b/node/C25519.cpp
@@ -2311,13 +2311,13 @@ C25519::Pair C25519::generate()
return kp;
}
-void C25519::agree(const C25519::Pair &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
+void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
throw()
{
unsigned char rawkey[32];
unsigned char digest[64];
- crypto_scalarmult(rawkey,mine.priv.data,their.data);
+ crypto_scalarmult(rawkey,mine.data,their.data);
SHA512::hash(digest,rawkey,32);
for(unsigned int i=0,k=0;i<keylen;) {
if (k == 64) {
@@ -2328,7 +2328,7 @@ void C25519::agree(const C25519::Pair &mine,const C25519::Public &their,void *ke
}
}
-void C25519::sign(const C25519::Pair &mine,const void *msg,unsigned int len,void *signature)
+void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature)
throw()
{
sc25519 sck, scs, scsk;
@@ -2343,7 +2343,7 @@ void C25519::sign(const C25519::Pair &mine,const void *msg,unsigned int len,void
SHA512::hash(digest,msg,len);
- SHA512::hash(extsk,mine.priv.data + 32,32);
+ SHA512::hash(extsk,myPrivate.data + 32,32);
extsk[0] &= 248;
extsk[31] &= 127;
extsk[31] |= 64;
@@ -2365,7 +2365,7 @@ void C25519::sign(const C25519::Pair &mine,const void *msg,unsigned int len,void
for(unsigned int i=0;i<32;i++)
sig[i] = r[i];
- get_hram(hram,sig,mine.pub.data + 32,sig,96);
+ get_hram(hram,sig,myPublic.data + 32,sig,96);
sc25519_from64bytes(&scs, hram);
sc25519_from32bytes(&scsk, extsk);
diff --git a/node/C25519.hpp b/node/C25519.hpp
index cf6bd60e..9ce098ca 100644
--- a/node/C25519.hpp
+++ b/node/C25519.hpp
@@ -77,13 +77,18 @@ public:
* 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 mine My private key
* @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)
+ static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen)
throw();
+ static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen)
+ throw()
+ {
+ agree(mine.priv,their,keybuf,keylen);
+ }
/**
* Sign a message with a sender's key pair
@@ -98,27 +103,41 @@ public:
* produces a signature of fixed 96-byte length based on the hash of an
* arbitrary-length message.
*
- * @param Key pair to sign with
+ * @param myPrivate My private key
+ * @param myPublic My public key
* @param msg Message to sign
* @param len Length of message in bytes
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length
*/
- static void sign(const Pair &mine,const void *msg,unsigned int len,void *signature)
+ static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature)
throw();
+ static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature)
+ throw()
+ {
+ sign(mine.priv,mine.pub,msg,len,signature);
+ }
/**
* Sign a message with a sender's key pair
*
- * @param Key pair to sign with
+ * @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 Signature sign(const Pair &mine,const void *msg,unsigned int len)
+ static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len)
+ throw()
+ {
+ Signature sig;
+ sign(myPrivate,myPublic,msg,len,sig.data);
+ return sig;
+ }
+ static inline Signature sign(const Pair &mine,const void *msg,unsigned int len)
throw()
{
Signature sig;
- sign(mine,msg,len,sig.data);
+ sign(mine.priv,mine.pub,msg,len,sig.data);
return sig;
}
diff --git a/node/EllipticCurveKey.hpp b/node/EllipticCurveKey.hpp
deleted file mode 100644
index c3439c62..00000000
--- a/node/EllipticCurveKey.hpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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_ELLIPTICCURVEKEY_H
-#define _ZT_ELLIPTICCURVEKEY_H
-
-#include <string>
-#include <algorithm>
-#include <stdexcept>
-#include <string.h>
-#include "Utils.hpp"
-
-/**
- * Key type ID for identifying our use of NIST-P-521
- *
- * If in the future other types of keys are supported (post-quantum crypto?)
- * then we'll need a key type 2, etc. When keys are stored in the database
- * they are prefixed by this key type ID byte.
- */
-#define ZT_KEY_TYPE 1
-
-#define ZT_EC_OPENSSL_CURVE NID_secp521r1
-#define ZT_EC_CURVE_NAME "NIST-P-521"
-#define ZT_EC_PRIME_BYTES 66
-#define ZT_EC_PUBLIC_KEY_BYTES (ZT_EC_PRIME_BYTES + 1)
-#define ZT_EC_PRIVATE_KEY_BYTES ZT_EC_PRIME_BYTES
-#define ZT_EC_MAX_BYTES ZT_EC_PUBLIC_KEY_BYTES
-
-namespace ZeroTier {
-
-class EllipticCurveKeyPair;
-
-/**
- * An elliptic curve public or private key
- */
-class EllipticCurveKey
-{
- friend class EllipticCurveKeyPair;
-
-public:
- EllipticCurveKey()
- throw() :
- _bytes(0)
- {
- memset(_key,0,sizeof(_key));
- }
-
- EllipticCurveKey(const void *data,unsigned int len)
- throw(std::out_of_range)
- {
- set(data,len);
- }
-
- EllipticCurveKey(const std::string &data)
- throw(std::out_of_range)
- {
- set(data.data(),(unsigned int)data.length());
- }
-
- inline void set(const void *data,unsigned int len)
- throw(std::out_of_range)
- {
- if (len <= ZT_EC_MAX_BYTES) {
- _bytes = len;
- memcpy(_key,data,len);
- } else throw std::out_of_range("key too large");
- }
-
- inline const unsigned char *data() const throw() { return _key; }
- inline unsigned int size() const throw() { return _bytes; }
- inline std::string toHex() const throw() { return Utils::hex(_key,_bytes); }
-
- inline unsigned char operator[](const unsigned int i) const throw() { return _key[i]; }
-
- inline bool operator==(const EllipticCurveKey &k) const throw() { return ((_bytes == k._bytes)&&(!memcmp(_key,k._key,_bytes))); }
- inline bool operator<(const EllipticCurveKey &k) const throw() { return std::lexicographical_compare(_key,&_key[_bytes],k._key,&k._key[k._bytes]); }
- inline bool operator!=(const EllipticCurveKey &k) const throw() { return !(*this == k); }
- inline bool operator>(const EllipticCurveKey &k) const throw() { return (k < *this); }
- inline bool operator<=(const EllipticCurveKey &k) const throw() { return !(k < *this); }
- inline bool operator>=(const EllipticCurveKey &k) const throw() { return !(*this < k); }
-
-private:
- unsigned int _bytes;
- unsigned char _key[ZT_EC_MAX_BYTES];
-};
-
-} // namespace ZeroTier
-
-#endif
-
diff --git a/node/EllipticCurveKeyPair.cpp b/node/EllipticCurveKeyPair.cpp
deleted file mode 100644
index dd95d9a7..00000000
--- a/node/EllipticCurveKeyPair.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "Constants.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <Windows.h>
-#endif
-
-#include <openssl/bn.h>
-#include <openssl/obj_mac.h>
-#include <openssl/rand.h>
-#include <openssl/ec.h>
-#include <openssl/ecdh.h>
-#include <openssl/ecdsa.h>
-#include <openssl/sha.h>
-
-#include "EllipticCurveKey.hpp"
-#include "EllipticCurveKeyPair.hpp"
-
-namespace ZeroTier {
-
-class _EC_Group
-{
-public:
- _EC_Group()
- {
- g = EC_GROUP_new_by_curve_name(ZT_EC_OPENSSL_CURVE);
- }
- ~_EC_Group() {}
- EC_GROUP *g;
-};
-static _EC_Group ZT_EC_GROUP;
-
-/**
- * Key derivation function
- *
- * TODO:
- * If/when we document the protocol, this will have to be documented as
- * well. It's a fairly standard KDF that uses SHA-256 to transform the
- * raw EC key. It's generally considered good crypto practice to do this
- * to eliminate the possibility of leaking information from EC exchange to
- * downstream algorithms.
- *
- * In our code it is used to produce a two 32-bit keys. One key is used
- * for Salsa20 and the other for HMAC-SHA-256. They are generated together
- * as a single 64-bit key.
- */
-static void *_zt_EC_KDF(const void *in,size_t inlen,void *out,size_t *outlen)
-{
- SHA256_CTX sha;
- unsigned char dig[SHA256_DIGEST_LENGTH];
-
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)in,inlen);
- SHA256_Final(dig,&sha);
- for(unsigned long i=0,k=0;i<(unsigned long)*outlen;) {
- if (k == SHA256_DIGEST_LENGTH) {
- k = 0;
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)in,inlen);
- SHA256_Update(&sha,dig,SHA256_DIGEST_LENGTH);
- SHA256_Final(dig,&sha);
- }
- ((unsigned char *)out)[i++] = dig[k++];
- }
-
- return out;
-}
-
-EllipticCurveKeyPair::EllipticCurveKeyPair() :
- _pub(),
- _priv(),
- _internal_key((void *)0)
-{
-}
-
-EllipticCurveKeyPair::EllipticCurveKeyPair(const EllipticCurveKeyPair &pair) :
- _pub(pair._pub),
- _priv(pair._priv),
- _internal_key((void *)0)
-{
-}
-
-EllipticCurveKeyPair::EllipticCurveKeyPair(const EllipticCurveKey &pubk,const EllipticCurveKey &privk) :
- _pub(pubk),
- _priv(privk),
- _internal_key((void *)0)
-{
-}
-
-EllipticCurveKeyPair::~EllipticCurveKeyPair()
-{
- if (_internal_key)
- EC_KEY_free((EC_KEY *)_internal_key);
-}
-
-const EllipticCurveKeyPair &EllipticCurveKeyPair::operator=(const EllipticCurveKeyPair &pair)
-{
- if (_internal_key)
- EC_KEY_free((EC_KEY *)_internal_key);
- _pub = pair._pub;
- _priv = pair._priv;
- _internal_key = (void *)0;
- return *this;
-}
-
-bool EllipticCurveKeyPair::generate()
-{
- EC_KEY *key;
- int len;
-
- key = EC_KEY_new();
- if (!key) return false;
-
- if (!EC_KEY_set_group(key,ZT_EC_GROUP.g)) {
- EC_KEY_free(key);
- return false;
- }
-
- if (!EC_KEY_generate_key(key)) {
- EC_KEY_free(key);
- return false;
- }
-
- memset(_priv._key,0,sizeof(_priv._key));
- len = (int)BN_num_bytes(EC_KEY_get0_private_key(key));
- if ((len > ZT_EC_PRIME_BYTES)||(len < 0)) {
- EC_KEY_free(key);
- return false;
- }
- BN_bn2bin(EC_KEY_get0_private_key(key),&(_priv._key[ZT_EC_PRIME_BYTES - len]));
- _priv._bytes = ZT_EC_PRIME_BYTES;
-
- memset(_pub._key,0,sizeof(_pub._key));
- len = (int)EC_POINT_point2oct(ZT_EC_GROUP.g,EC_KEY_get0_public_key(key),POINT_CONVERSION_COMPRESSED,_pub._key,sizeof(_pub._key),0);
- if (len != ZT_EC_PUBLIC_KEY_BYTES) {
- EC_KEY_free(key);
- return false;
- }
- _pub._bytes = ZT_EC_PUBLIC_KEY_BYTES;
-
- if (_internal_key)
- EC_KEY_free((EC_KEY *)_internal_key);
- _internal_key = key;
-
- return true;
-}
-
-bool EllipticCurveKeyPair::agree(const EllipticCurveKey &theirPublicKey,unsigned char *agreedUponKey,unsigned int agreedUponKeyLength) const
-{
- if (theirPublicKey._bytes != ZT_EC_PUBLIC_KEY_BYTES)
- return false;
-
- if (!_internal_key) {
- if (!(const_cast <EllipticCurveKeyPair *> (this))->initInternalKey())
- return false;
- }
-
- EC_POINT *pub = EC_POINT_new(ZT_EC_GROUP.g);
- if (!pub)
- return false;
- EC_POINT_oct2point(ZT_EC_GROUP.g,pub,theirPublicKey._key,ZT_EC_PUBLIC_KEY_BYTES,0);
-
- int i = ECDH_compute_key(agreedUponKey,agreedUponKeyLength,pub,(EC_KEY *)_internal_key,&_zt_EC_KDF);
- EC_POINT_free(pub);
-
- return (i == (int)agreedUponKeyLength);
-}
-
-std::string EllipticCurveKeyPair::sign(const void *sha256) const
-{
- unsigned char buf[256];
- std::string sigbin;
-
- if (!_internal_key) {
- if (!(const_cast <EllipticCurveKeyPair *> (this))->initInternalKey())
- return std::string();
- }
-
- ECDSA_SIG *sig = ECDSA_do_sign((const unsigned char *)sha256,SHA256_DIGEST_LENGTH,(EC_KEY *)_internal_key);
- if (!sig)
- return std::string();
-
- int rlen = BN_num_bytes(sig->r);
- if ((rlen > 255)||(rlen <= 0)) {
- ECDSA_SIG_free(sig);
- return std::string();
- }
- sigbin.push_back((char)rlen);
- BN_bn2bin(sig->r,buf);
- sigbin.append((const char *)buf,rlen);
-
- int slen = BN_num_bytes(sig->s);
- if ((slen > 255)||(slen <= 0)) {
- ECDSA_SIG_free(sig);
- return std::string();
- }
- sigbin.push_back((char)slen);
- BN_bn2bin(sig->s,buf);
- sigbin.append((const char *)buf,slen);
-
- ECDSA_SIG_free(sig);
-
- return sigbin;
-}
-
-std::string EllipticCurveKeyPair::sign(const void *data,unsigned int len) const
-{
- SHA256_CTX sha;
- unsigned char dig[SHA256_DIGEST_LENGTH];
-
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)data,len);
- SHA256_Final(dig,&sha);
-
- return sign(dig);
-}
-
-bool EllipticCurveKeyPair::verify(const void *sha256,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen)
-{
- bool result = false;
- ECDSA_SIG *sig = (ECDSA_SIG *)0;
- EC_POINT *pub = (EC_POINT *)0;
- EC_KEY *key = (EC_KEY *)0;
- int rlen,slen;
-
- if (!siglen)
- goto verify_sig_return;
- rlen = ((const unsigned char *)sigbytes)[0];
- if (!rlen)
- goto verify_sig_return;
- if (siglen < (unsigned int)(rlen + 2))
- goto verify_sig_return;
- slen = ((const unsigned char *)sigbytes)[rlen + 1];
- if (!slen)
- goto verify_sig_return;
- if (siglen < (unsigned int)(rlen + slen + 2))
- goto verify_sig_return;
-
- sig = ECDSA_SIG_new();
- if (!sig)
- goto verify_sig_return;
-
- BN_bin2bn((const unsigned char *)sigbytes + 1,rlen,sig->r);
- BN_bin2bn((const unsigned char *)sigbytes + (1 + rlen + 1),slen,sig->s);
-
- pub = EC_POINT_new(ZT_EC_GROUP.g);
- if (!pub)
- goto verify_sig_return;
- EC_POINT_oct2point(ZT_EC_GROUP.g,pub,pk._key,ZT_EC_PUBLIC_KEY_BYTES,0);
-
- key = EC_KEY_new();
- if (!key)
- goto verify_sig_return;
- if (!EC_KEY_set_group(key,ZT_EC_GROUP.g))
- goto verify_sig_return;
- EC_KEY_set_public_key(key,pub);
-
- result = (ECDSA_do_verify((const unsigned char *)sha256,SHA256_DIGEST_LENGTH,sig,key) == 1);
-
-verify_sig_return:
- if (key)
- EC_KEY_free(key);
- if (pub)
- EC_POINT_free(pub);
- if (sig)
- ECDSA_SIG_free(sig);
-
- return result;
-}
-
-bool EllipticCurveKeyPair::verify(const void *data,unsigned int len,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen)
-{
- SHA256_CTX sha;
- unsigned char dig[SHA256_DIGEST_LENGTH];
-
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)data,len);
- SHA256_Final(dig,&sha);
-
- return verify(dig,pk,sigbytes,siglen);
-}
-
-bool EllipticCurveKeyPair::initInternalKey()
-{
- EC_KEY *key;
- EC_POINT *kxy;
- BIGNUM *pn;
-
- if (_priv._bytes != ZT_EC_PRIME_BYTES) return false;
- if (_pub._bytes != ZT_EC_PUBLIC_KEY_BYTES) return false;
-
- key = EC_KEY_new();
- if (!key) return false;
-
- if (!EC_KEY_set_group(key,ZT_EC_GROUP.g)) {
- EC_KEY_free(key);
- return false;
- }
-
- pn = BN_new();
- if (!pn) {
- EC_KEY_free(key);
- return false;
- }
- if (!BN_bin2bn(_priv._key,ZT_EC_PRIME_BYTES,pn)) {
- BN_free(pn);
- EC_KEY_free(key);
- return false;
- }
- if (!EC_KEY_set_private_key(key,pn)) {
- BN_free(pn);
- EC_KEY_free(key);
- return false;
- }
- BN_free(pn);
-
- kxy = EC_POINT_new(ZT_EC_GROUP.g);
- if (!kxy) {
- EC_KEY_free(key);
- return false;
- }
- EC_POINT_oct2point(ZT_EC_GROUP.g,kxy,_pub._key,ZT_EC_PUBLIC_KEY_BYTES,0);
- if (!EC_KEY_set_public_key(key,kxy)) {
- EC_POINT_free(kxy);
- EC_KEY_free(key);
- return false;
- }
- EC_POINT_free(kxy);
-
- if (_internal_key)
- EC_KEY_free((EC_KEY *)_internal_key);
- _internal_key = key;
-
- return true;
-}
-
-} // namespace ZeroTier
-
diff --git a/node/EllipticCurveKeyPair.hpp b/node/EllipticCurveKeyPair.hpp
deleted file mode 100644
index dbe08cc9..00000000
--- a/node/EllipticCurveKeyPair.hpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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_ELLIPTICCURVEKEYPAIR_HPP
-#define _ZT_ELLIPTICCURVEKEYPAIR_HPP
-
-#include <string>
-#include "EllipticCurveKey.hpp"
-
-namespace ZeroTier {
-
-/**
- * An elliptic curve key pair supporting generation and key agreement
- *
- * This is basically OpenSSL libcrypto glue.
- */
-class EllipticCurveKeyPair
-{
-public:
- EllipticCurveKeyPair();
- EllipticCurveKeyPair(const EllipticCurveKeyPair &pair);
- EllipticCurveKeyPair(const EllipticCurveKey &pubk,const EllipticCurveKey &privk);
- ~EllipticCurveKeyPair();
-
- const EllipticCurveKeyPair &operator=(const EllipticCurveKeyPair &pair);
-
- /**
- * Fill this structure with a newly generated public/private key pair
- *
- * @return True if key generation is successful
- */
- bool generate();
-
- /**
- * Perform elliptic curve key agreement
- *
- * @param theirPublicKey Remote side's public key
- * @param agreedUponKey Buffer to fill with agreed-upon symmetric key
- * @param agreedUponKeyLength Number of bytes to generate
- * @return True if key agreement is successful
- */
- bool agree(const EllipticCurveKey &theirPublicKey,unsigned char *agreedUponKey,unsigned int agreedUponKeyLength) const;
-
- /**
- * Sign a SHA256 hash
- *
- * @param sha256 Pointer to 256-bit / 32-byte SHA hash to sign
- * @return ECDSA signature (r and s in binary format, each prefixed by an 8-bit size)
- */
- std::string sign(const void *sha256) const;
-
- /**
- * Sign something with this pair's private key, computing its hash first
- *
- * @param data Data to hash and sign
- * @param len Length of data
- * @return Signature bytes
- */
- std::string sign(const void *data,unsigned int len) const;
-
- /**
- * Verify a signature
- *
- * @param sha256 Pointer to 256-bit / 32-byte SHA hash to verify
- * @param pk Public key to verify against
- * @param sigbytes Signature bytes
- * @param siglen Length of signature
- */
- static bool verify(const void *sha256,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen);
-
- /**
- * Verify a signature
- *
- * @param data Data to verify
- * @param len Length of data
- * @param pk Public key to verify against
- * @param sigbytes Signature bytes
- * @param siglen Length of signature
- */
- static bool verify(const void *data,unsigned int len,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen);
-
- inline bool operator==(const EllipticCurveKeyPair &kp) const
- throw()
- {
- return ((_pub == kp._pub)&&(_priv == kp._priv));
- }
- inline bool operator!=(const EllipticCurveKeyPair &kp) const
- throw()
- {
- return ((_pub != kp._pub)||(_priv != kp._priv));
- }
-
- inline const EllipticCurveKey &pub() const throw() { return _pub; }
- inline const EllipticCurveKey &priv() const throw() { return _priv; }
-
-private:
- bool initInternalKey();
-
- EllipticCurveKey _pub;
- EllipticCurveKey _priv;
- void *_internal_key;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/node/HMAC.cpp b/node/HMAC.cpp
deleted file mode 100644
index d8a756a9..00000000
--- a/node/HMAC.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 "HMAC.hpp"
-
-#include <openssl/sha.h>
-
-namespace ZeroTier {
-
-void HMAC::sha256(const void *key,unsigned int klen,const void *message,unsigned int len,void *mac)
- throw()
-{
- union {
- uint64_t q[12];
- uint8_t b[96];
- } key2,opad,ipad;
- SHA256_CTX sha;
-
- if (klen == 32) { // this is what we use, so handle this quickly
- key2.q[0] = ((const uint64_t *)key)[0];
- key2.q[1] = ((const uint64_t *)key)[1];
- key2.q[2] = ((const uint64_t *)key)[2];
- key2.q[3] = ((const uint64_t *)key)[3];
- key2.q[4] = 0ULL;
- key2.q[5] = 0ULL;
- key2.q[6] = 0ULL;
- key2.q[7] = 0ULL;
- } else { // for correctness and testing against test vectors
- if (klen > 64) {
- SHA256_Init(&sha);
- SHA256_Update(&sha,key,klen);
- SHA256_Final(key2.b,&sha);
- klen = 32;
- } else {
- for(unsigned int i=0;i<klen;++i)
- key2.b[i] = ((const uint8_t *)key)[i];
- }
- while (klen < 64)
- key2.b[klen++] = (uint8_t)0;
- }
-
- for(unsigned int i=0;i<8;++i)
- opad.q[i] = 0x5c5c5c5c5c5c5c5cULL ^ key2.q[i];
- for(unsigned int i=0;i<8;++i)
- ipad.q[i] = 0x3636363636363636ULL ^ key2.q[i];
-
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)ipad.b,64);
- SHA256_Update(&sha,(const unsigned char *)message,len);
- SHA256_Final((unsigned char *)(opad.b + 64),&sha);
-
- SHA256_Init(&sha);
- SHA256_Update(&sha,opad.b,96);
- SHA256_Final((unsigned char *)mac,&sha);
-}
-
-} // namespace ZeroTier
diff --git a/node/HMAC.hpp b/node/HMAC.hpp
deleted file mode 100644
index f48c33c1..00000000
--- a/node/HMAC.hpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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_HMAC_HPP
-#define _ZT_HMAC_HPP
-
-#include <stdint.h>
-
-namespace ZeroTier {
-
-/**
- * HMAC authenticator functions
- */
-class HMAC
-{
-public:
- /**
- * Compute HMAC-SHA256
- *
- * @param key Key bytes
- * @param klen Length of key
- * @param len Length of message
- * @param mac Buffer to receive 32-byte MAC
- */
- static void sha256(const void *key,unsigned int klen,const void *message,unsigned int len,void *mac)
- throw();
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/node/Identity.cpp b/node/Identity.cpp
index 391b436e..18f59cce 100644
--- a/node/Identity.cpp
+++ b/node/Identity.cpp
@@ -30,130 +30,60 @@
#include <string.h>
#include <stdint.h>
-#include <openssl/sha.h>
-
#include "Identity.hpp"
-#include "Salsa20.hpp"
-#include "HMAC.hpp"
-#include "Utils.hpp"
namespace ZeroTier {
void Identity::generate()
{
- delete [] _keyPair;
-
- // Generate key pair and derive address
+ C25519::Pair kp;
do {
- _keyPair = new EllipticCurveKeyPair();
- _keyPair->generate();
- _address = deriveAddress(_keyPair->pub().data(),_keyPair->pub().size());
+ kp = C25519::generate();
+ _address = deriveAddress(kp.pub.data,kp.pub.size());
} while (_address.isReserved());
- _publicKey = _keyPair->pub();
-
- // Sign address, key type, and public key with private key (with a zero
- // byte between each field). Including this extra data means simply editing
- // the address of an identity will be detected as its signature will be
- // invalid. Of course, deep verification of address/key relationship is
- // required to cover the more elaborate address claim jump attempt case.
- unsigned char atmp[ZT_ADDRESS_LENGTH];
- _address.copyTo(atmp,ZT_ADDRESS_LENGTH);
- SHA256_CTX sha;
- unsigned char dig[32];
- unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
- SHA256_Init(&sha);
- SHA256_Update(&sha,atmp,ZT_ADDRESS_LENGTH);
- SHA256_Update(&sha,&zero,1);
- SHA256_Update(&sha,&idtype,1);
- SHA256_Update(&sha,&zero,1);
- SHA256_Update(&sha,_publicKey.data(),_publicKey.size());
- SHA256_Update(&sha,&zero,1);
- SHA256_Final(dig,&sha);
- _signature = _keyPair->sign(dig);
+
+ _publicKey = kp.pub;
+ if (!_privateKey)
+ _privateKey = new C25519::Private();
+ *_privateKey = kp.priv;
+
+ unsigned char tmp[ZT_ADDRESS_LENGTH + ZT_C25519_PUBLIC_KEY_LEN];
+ _address.copyTo(tmp,ZT_ADDRESS_LENGTH);
+ memcpy(tmp + ZT_ADDRESS_LENGTH,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
+ _signature = C25519::sign(kp,tmp,sizeof(tmp));
}
bool Identity::locallyValidate(bool doAddressDerivationCheck) const
{
- unsigned char atmp[ZT_ADDRESS_LENGTH];
- _address.copyTo(atmp,ZT_ADDRESS_LENGTH);
- SHA256_CTX sha;
- unsigned char dig[32];
- unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
- SHA256_Init(&sha);
- SHA256_Update(&sha,atmp,ZT_ADDRESS_LENGTH);
- SHA256_Update(&sha,&zero,1);
- SHA256_Update(&sha,&idtype,1);
- SHA256_Update(&sha,&zero,1);
- SHA256_Update(&sha,_publicKey.data(),_publicKey.size());
- SHA256_Update(&sha,&zero,1);
- SHA256_Final(dig,&sha);
-
- return ((EllipticCurveKeyPair::verify(dig,_publicKey,_signature.data(),(unsigned int)_signature.length()))&&((!doAddressDerivationCheck)||(deriveAddress(_publicKey.data(),_publicKey.size()) == _address)));
+ unsigned char tmp[ZT_ADDRESS_LENGTH + ZT_C25519_PUBLIC_KEY_LEN];
+ _address.copyTo(tmp,ZT_ADDRESS_LENGTH);
+ memcpy(tmp + ZT_ADDRESS_LENGTH,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
+ if (!C25519::verify(_publicKey,tmp,sizeof(tmp),_signature))
+ return false;
+ if ((doAddressDerivationCheck)&&(deriveAddress(_publicKey.data,_publicKey.size()) != _address))
+ return false;
+ return true;
}
std::string Identity::toString(bool includePrivate) const
{
std::string r;
+
r.append(_address.toString());
- r.append(":1:"); // 1 == IDENTITY_TYPE_NIST_P_521
- r.append(Utils::base64Encode(_publicKey.data(),_publicKey.size()));
- r.push_back(':');
- r.append(Utils::base64Encode(_signature.data(),(unsigned int)_signature.length()));
- if ((includePrivate)&&(_keyPair)) {
- r.push_back(':');
- r.append(Utils::base64Encode(_keyPair->priv().data(),_keyPair->priv().size()));
- }
+ r.append(":2:"); // 2 == IDENTITY_TYPE_C25519
+
return r;
}
bool Identity::fromString(const char *str)
{
- delete _keyPair;
- _keyPair = (EllipticCurveKeyPair *)0;
-
- std::vector<std::string> fields(Utils::split(Utils::trim(std::string(str)).c_str(),":","",""));
-
- if (fields.size() < 4)
- return false;
-
- if (fields[1] != "1")
- return false; // version mismatch
-
- std::string b(Utils::unhex(fields[0]));
- if (b.length() != ZT_ADDRESS_LENGTH)
- return false;
- _address.setTo(b.data(),ZT_ADDRESS_LENGTH);
-
- b = Utils::base64Decode(fields[2]);
- if ((!b.length())||(b.length() > ZT_EC_MAX_BYTES))
- return false;
- _publicKey.set(b.data(),(unsigned int)b.length());
-
- _signature = Utils::base64Decode(fields[3]);
- if (!_signature.length())
- return false;
-
- if (fields.size() >= 5) {
- b = Utils::base64Decode(fields[4]);
- if ((!b.length())||(b.length() > ZT_EC_MAX_BYTES))
- return false;
- _keyPair = new EllipticCurveKeyPair(_publicKey,EllipticCurveKey(b.data(),(unsigned int)b.length()));
- }
-
- return true;
}
-// These are core protocol 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_MEMORY 33554432
Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
{
- unsigned char dig[32];
- Salsa20 s20a,s20b;
- SHA256_CTX sha;
-
/*
* Sequential memory-hard algorithm wedding address to public key
*
@@ -164,64 +94,28 @@ Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
* that creates a costly 1:~1 mapping from key to address, hence this odd
* algorithm.
*
- * This is designed not to be parallelizable and to be resistant to
- * implementation on things like GPUs with tiny-memory nodes and poor
- * branching capability. Toward that end it throws branching and a large
- * memory buffer into the mix. It can only be efficiently computed by a
- * single core with at least ~32MB RAM.
- *
* Search for "sequential memory hard algorithm" for academic references
* to similar concepts.
- *
- * Right now this takes ~1700ms on a 2.4ghz Intel Core i5. If this could
- * be reduced to 1ms per derivation, it would take about 34 years to search
- * the entire 40-bit address space for an average of ~17 years to generate
- * a key colliding with a known existing address.
*/
- // Initial starting digest
- SHA256_Init(&sha);
- SHA256_Update(&sha,(const unsigned char *)keyBytes,keyLen); // key
- SHA256_Final(dig,&sha);
-
- s20a.init(dig,256,"ZeroTier");
-
- unsigned char *ram = new unsigned char[ZT_IDENTITY_DERIVEADDRESS_MEMORY];
+ unsigned char finalDigest[ZT_SHA512_DIGEST_LEN];
+ unsigned char *digests = new unsigned char[ZT_SHA512_DIGEST_LEN * ZT_IDENTITY_DERIVEADDRESS_DIGESTS];
- // Encrypt and digest a large memory buffer for several rounds
- for(unsigned long i=0;i<ZT_IDENTITY_DERIVEADDRESS_MEMORY;++i)
- ram[i] = (unsigned char)(i & 0xff) ^ dig[i & 31];
- for(unsigned long r=0;r<ZT_IDENTITY_DERIVEADDRESS_ROUNDS;++r) {
- SHA256_Init(&sha);
-
- SHA256_Update(&sha,(const unsigned char *)keyBytes,keyLen);
- SHA256_Update(&sha,dig,32);
-
- for(unsigned long i=0;i<ZT_IDENTITY_DERIVEADDRESS_MEMORY;++i) {
- if (ram[i] == 17) // Forces a branch to be required
- ram[i] ^= dig[i & 31];
- }
- s20b.init(dig,256,"ZeroTier");
- s20a.encrypt(ram,ram,ZT_IDENTITY_DERIVEADDRESS_MEMORY);
- s20b.encrypt(ram,ram,ZT_IDENTITY_DERIVEADDRESS_MEMORY);
- SHA256_Update(&sha,ram,ZT_IDENTITY_DERIVEADDRESS_MEMORY);
-
- SHA256_Final(dig,&sha);
- }
+ SHA512::hash(finalDigest,keyBytes,keyLen);
+ for(unsigned int i=0;i<(unsigned int)sizeof(digests);++i)
+ digests[i] = ((const unsigned char *)keyBytes)[i % keyLen];
- // Final digest, executed for twice our number of rounds
- SHA256_Init(&sha);
- for(unsigned long r=0;r<(ZT_IDENTITY_DERIVEADDRESS_ROUNDS * 2);++r) {
- SHA256_Update(&sha,(const unsigned char *)keyBytes,keyLen);
- SHA256_Update(&sha,ram,ZT_IDENTITY_DERIVEADDRESS_ROUNDS);
- SHA256_Update(&sha,dig,32);
- SHA256_Update(&sha,(const unsigned char *)keyBytes,keyLen);
+ for(unsigned int r=0;r<ZT_IDENTITY_DERIVEADDRESS_ROUNDS;++r) {
+ for(unsigned int i=0;i<(ZT_SHA512_DIGEST_LEN * ZT_IDENTITY_DERIVEADDRESS_DIGESTS);++i)
+ digests[i] ^= finalDigest[i % ZT_SHA512_DIGEST_LEN];
+ for(unsigned int d=0;d<ZT_IDENTITY_DERIVEADDRESS_DIGESTS;++d)
+ SHA512::hash(digests + (ZT_SHA512_DIGEST_LEN * d),digests,ZT_SHA512_DIGEST_LEN * ZT_IDENTITY_DERIVEADDRESS_DIGESTS);
+ SHA512::hash(finalDigest,digests,ZT_SHA512_DIGEST_LEN * ZT_IDENTITY_DERIVEADDRESS_DIGESTS);
}
- SHA256_Final(dig,&sha);
- delete [] ram;
+ delete [] digests;
- return Address(dig,ZT_ADDRESS_LENGTH); // first 5 bytes of dig[]
+ return Address(finalDigest,ZT_ADDRESS_LENGTH); // first 5 bytes of dig[]
}
} // namespace ZeroTier
diff --git a/node/Identity.hpp b/node/Identity.hpp
index 22e60fde..de4ad2a0 100644
--- a/node/Identity.hpp
+++ b/node/Identity.hpp
@@ -32,18 +32,13 @@
#include <stdlib.h>
#include <string>
-#include "EllipticCurveKey.hpp"
-#include "EllipticCurveKeyPair.hpp"
+#include "Constants.hpp"
#include "Array.hpp"
#include "Utils.hpp"
#include "Address.hpp"
+#include "C25519.hpp"
#include "Buffer.hpp"
-/**
- * Maximum length for a serialized identity
- */
-#define IDENTITY_MAX_BINARY_SERIALIZED_LENGTH ((ZT_EC_MAX_BYTES * 2) + 256)
-
namespace ZeroTier {
/**
@@ -55,22 +50,6 @@ namespace ZeroTier {
* The address derivation algorithm makes it computationally very expensive to
* search for a different public key that duplicates an existing address. (See
* code for deriveAddress() for this algorithm.)
- *
- * After derivation, the address must be checked against isReserved(). If the
- * address is reserved, generation is repeated until a valid address results.
- *
- * Serialization of an identity:
- *
- * <[5] address> - 40-bit ZeroTier network address
- * <[1] type> - Identity type ID (rest is type-dependent)
- * <[1] key length> - Length of public key
- * <[n] public key> - Elliptic curve public key
- * <[1] sig length> - Length of ECDSA self-signature
- * <[n] signature> - ECDSA signature of first four fields
- * [<[1] key length>] - [Optional] Length of private key
- * [<[n] private key>] - [Optional] Private key
- *
- * Local storage of an identity also requires storage of its private key.
*/
class Identity
{
@@ -80,28 +59,26 @@ public:
*/
enum Type
{
- /* Elliptic curve NIST-P-521 and ECDSA signature */
- IDENTITY_TYPE_NIST_P_521 = 1
- /* We won't need another identity type until quantum computers with
- * tens of thousands of qubits are a reality. */
+ IDENTITY_TYPE_NIST_P_521 = 1, // OBSOLETE -- only present in some early alpha versions
+ IDENTITY_TYPE_C25519 = 2
};
Identity() :
- _keyPair((EllipticCurveKeyPair *)0)
+ _privateKey((C25519::Private *)0)
{
}
Identity(const Identity &id) :
- _keyPair((id._keyPair) ? new EllipticCurveKeyPair(*id._keyPair) : (EllipticCurveKeyPair *)0),
- _publicKey(id._publicKey),
_address(id._address),
- _signature(id._signature)
+ _publicKey(id._publicKey),
+ _signature(id._signature),
+ _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0)
{
}
Identity(const char *str)
throw(std::invalid_argument) :
- _keyPair((EllipticCurveKeyPair *)0)
+ _privateKey((C25519::Private *)0)
{
if (!fromString(str))
throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str);
@@ -109,7 +86,7 @@ public:
Identity(const std::string &str)
throw(std::invalid_argument) :
- _keyPair((EllipticCurveKeyPair *)0)
+ _privateKey((C25519::Private *)0)
{
if (!fromString(str))
throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str);
@@ -118,35 +95,36 @@ public:
template<unsigned int C>
Identity(const Buffer<C> &b,unsigned int startAt = 0)
throw(std::out_of_range,std::invalid_argument) :
- _keyPair((EllipticCurveKeyPair *)0)
+ _privateKey((C25519::Private *)0)
{
deserialize(b,startAt);
}
~Identity()
{
- delete _keyPair;
+ delete _privateKey;
}
inline Identity &operator=(const Identity &id)
{
- _keyPair = (id._keyPair) ? new EllipticCurveKeyPair(*id._keyPair) : (EllipticCurveKeyPair *)0;
- _publicKey = id._publicKey;
_address = id._address;
+ _publicKey = id._publicKey;
_signature = id._signature;
+ if (id._privateKey) {
+ if (!_privateKey)
+ _privateKey = new C25519::Private();
+ *_privateKey = *(id._privateKey);
+ } else {
+ delete _privateKey;
+ _privateKey = (C25519::Private *)0;
+ }
return *this;
}
/**
* Generate a new identity (address, key pair)
- *
- * This is a somewhat time consuming operation by design, as the address
- * is derived from the key using a purposefully expensive many-round
- * hash/encrypt/hash operation. This took about two seconds on a 2.4ghz
- * Intel Core i5 in 2013.
- *
- * In the very unlikely event that a reserved address is created, generate
- * will automatically run again.
+ *
+ * This is a time consuming operation.
*/
void generate();
@@ -166,19 +144,14 @@ public:
bool locallyValidate(bool doAddressDerivationCheck) const;
/**
- * @return Private key pair or NULL if not included with this identity
+ * @return True if this identity contains a private key
*/
- inline const EllipticCurveKeyPair *privateKeyPair() const throw() { return _keyPair; }
-
- /**
- * @return True if this identity has its private portion
- */
- inline bool hasPrivate() const throw() { return (_keyPair != (EllipticCurveKeyPair *)0); }
+ inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); }
/**
* Shortcut method to perform key agreement with another identity
*
- * This identity must have its private portion.
+ * This identity must have a private key. (Check hasPrivate())
*
* @param id Identity to agree with
* @param key Result parameter to fill with key bytes
@@ -187,75 +160,17 @@ public:
*/
inline bool agree(const Identity &id,void *key,unsigned int klen) const
{
- if ((id)&&(_keyPair))
- return _keyPair->agree(id._publicKey,(unsigned char *)key,klen);
+ if (_privateKey) {
+ C25519::agree(*_privateKey,id._publicKey,key,klen);
+ return true;
+ }
return false;
}
/**
- * Sign a hash with this identity's private key
- *
- * @param sha256 32-byte hash to sign
- * @return ECDSA signature or empty string on failure or if identity has no private portion
- */
- inline std::string sign(const void *sha256) const
- {
- if (_keyPair)
- return _keyPair->sign(sha256);
- return std::string();
- }
-
- /**
- * Sign a block of data with this identity's private key
- *
- * This is a shortcut to SHA-256 hashing then signing.
- *
- * @param sha256 32-byte hash to sign
- * @return ECDSA signature or empty string on failure or if identity has no private portion
- */
- inline std::string sign(const void *data,unsigned int len) const
- {
- if (_keyPair)
- return _keyPair->sign(data,len);
- return std::string();
- }
-
- /**
- * Verify something signed with this identity's public key
- *
- * @param sha256 32-byte hash to verify
- * @param sigbytes Signature bytes
- * @param siglen Length of signature
- * @return True if signature is valid
- */
- inline bool verifySignature(const void *sha256,const void *sigbytes,unsigned int siglen) const
- {
- return EllipticCurveKeyPair::verify(sha256,_publicKey,sigbytes,siglen);
- }
-
- /**
- * Verify something signed with this identity's public key
- *
- * @param data Data to verify
- * @param len Length of data to verify
- * @param sigbytes Signature bytes
- * @param siglen Length of signature
- * @return True if signature is valid
- */
- inline bool verifySignature(const void *data,unsigned int len,const void *sigbytes,unsigned int siglen) const
- {
- return EllipticCurveKeyPair::verify(data,len,_publicKey,sigbytes,siglen);
- }
-
- /**
- * @return Public key (available in all identities)
- */
- inline const EllipticCurveKey &publicKey() const throw() { return _publicKey; }
-
- /**
* @return Identity type
*/
- inline Type type() const throw() { return IDENTITY_TYPE_NIST_P_521; }
+ inline Type type() const throw() { return IDENTITY_TYPE_C25519; }
/**
* @return This identity's address
@@ -274,14 +189,12 @@ public:
throw(std::out_of_range)
{
_address.appendTo(b);
- b.append((unsigned char)IDENTITY_TYPE_NIST_P_521);
- b.append((unsigned char)(_publicKey.size() & 0xff));
- b.append(_publicKey.data(),_publicKey.size());
- b.append((unsigned char)(_signature.length() & 0xff));
- b.append(_signature);
- if ((includePrivate)&&(_keyPair)) {
- b.append((unsigned char)(_keyPair->priv().size() & 0xff));
- b.append(_keyPair->priv().data(),_keyPair->priv().size());
+ b.append((unsigned char)IDENTITY_TYPE_C25519);
+ 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());
} else b.append((unsigned char)0);
}
@@ -301,33 +214,27 @@ public:
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
throw(std::out_of_range,std::invalid_argument)
{
- delete _keyPair;
- _keyPair = (EllipticCurveKeyPair *)0;
+ delete _privateKey;
+ _privateKey = (C25519::Private *)0;
unsigned int p = startAt;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
- if (b[p++] != IDENTITY_TYPE_NIST_P_521)
+ if (b[p++] != IDENTITY_TYPE_C25519)
throw std::invalid_argument("Identity: deserialize(): unsupported identity type");
- unsigned int publicKeyLength = b[p++];
- if (!publicKeyLength)
- throw std::invalid_argument("Identity: deserialize(): no public key");
- _publicKey.set(b.field(p,publicKeyLength),publicKeyLength);
- p += publicKeyLength;
-
- unsigned int signatureLength = b[p++];
- if (!signatureLength)
- throw std::invalid_argument("Identity: deserialize(): no signature");
- _signature.assign((const char *)b.field(p,signatureLength),signatureLength);
- p += signatureLength;
+ memcpy(_publicKey.data,field(p,_publicKey.size()),_publicKey.size());
+ p += _publicKey.size();
+ memcpy(_signature.data,field(p,_signature.size()),_signature.size());
+ p += _signature.size();
unsigned int privateKeyLength = b[p++];
- if (privateKeyLength) {
- _keyPair = new EllipticCurveKeyPair(_publicKey,EllipticCurveKey(b.field(p,privateKeyLength),privateKeyLength));
- p += privateKeyLength;
+ 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);
+ p += ZT_C25519_PRIVATE_KEY_LEN;
}
return (p - startAt);
@@ -356,27 +263,10 @@ public:
/**
* @return True if this identity contains something
*/
- inline operator bool() const throw() { return (_publicKey.size() != 0); }
+ inline operator bool() const throw() { return (_address); }
- inline bool operator==(const Identity &id) const
- throw()
- {
- if (_address == id._address) {
- if ((_keyPair)&&(id._keyPair))
- return (*_keyPair == *id._keyPair);
- return (_publicKey == id._publicKey);
- }
- return false;
- }
- inline bool operator<(const Identity &id) const
- throw()
- {
- if (_address < id._address)
- return true;
- else if (_address == id._address)
- return (_publicKey < id._publicKey);
- return false;
- }
+ inline bool operator==(const Identity &id) const throw() { return ((_address == id._address)&&(_publicKey == id._publicKey)); }
+ inline bool operator<(const Identity &id) const throw() { return ((_address < id._address)||((_address == id._address)&&(_publicKey < id._publicKey))); }
inline bool operator!=(const Identity &id) const throw() { return !(*this == id); }
inline bool operator>(const Identity &id) const throw() { return (id < *this); }
inline bool operator<=(const Identity &id) const throw() { return !(id < *this); }
@@ -386,10 +276,10 @@ private:
// Compute an address from public key bytes
static Address deriveAddress(const void *keyBytes,unsigned int keyLen);
- EllipticCurveKeyPair *_keyPair;
- EllipticCurveKey _publicKey;
Address _address;
- std::string _signature;
+ C25519::Public _publicKey;
+ C25519::Signature _signature;
+ C25519::Private *_privateKey;
};
} // namespace ZeroTier