diff options
| author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-09-16 09:20:59 -0400 |
|---|---|---|
| committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-09-16 09:20:59 -0400 |
| commit | 3b2d98e7dcf4102f855006cc9f5d5000d8df0223 (patch) | |
| tree | c8353385dfd88e467a40c5013da5101b20a2978b /node | |
| parent | 02f336918547b93b4c03d608eafdf62de5d0a786 (diff) | |
| download | infinitytier-3b2d98e7dcf4102f855006cc9f5d5000d8df0223.tar.gz infinitytier-3b2d98e7dcf4102f855006cc9f5d5000d8df0223.zip | |
Integrating new crypto -- work in progress, wont build yet.
Diffstat (limited to 'node')
| -rw-r--r-- | node/C25519.cpp | 10 | ||||
| -rw-r--r-- | node/C25519.hpp | 33 | ||||
| -rw-r--r-- | node/EllipticCurveKey.hpp | 114 | ||||
| -rw-r--r-- | node/EllipticCurveKeyPair.cpp | 369 | ||||
| -rw-r--r-- | node/EllipticCurveKeyPair.hpp | 130 | ||||
| -rw-r--r-- | node/HMAC.cpp | 81 | ||||
| -rw-r--r-- | node/HMAC.hpp | 55 | ||||
| -rw-r--r-- | node/Identity.cpp | 182 | ||||
| -rw-r--r-- | node/Identity.hpp | 218 |
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 |
