EllipticCurveKeyPair.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include <iostream>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <openssl/bn.h>
  32. #include <openssl/obj_mac.h>
  33. #include <openssl/rand.h>
  34. #include <openssl/ec.h>
  35. #include <openssl/ecdh.h>
  36. #include <openssl/ecdsa.h>
  37. #include <openssl/sha.h>
  38. #include "EllipticCurveKey.hpp"
  39. #include "EllipticCurveKeyPair.hpp"
  40. namespace ZeroTier {
  41. class _EC_Group
  42. {
  43. public:
  44. _EC_Group()
  45. {
  46. g = EC_GROUP_new_by_curve_name(ZT_EC_OPENSSL_CURVE);
  47. }
  48. ~_EC_Group() {}
  49. EC_GROUP *g;
  50. };
  51. static _EC_Group ZT_EC_GROUP;
  52. /**
  53. * Key derivation function
  54. *
  55. * TODO:
  56. * If/when we document the protocol, this will have to be documented as
  57. * well. It's a fairly standard KDF that uses SHA-256 to transform the
  58. * raw EC key. It's generally considered good crypto practice to do this
  59. * to eliminate the possibility of leaking information from EC exchange to
  60. * downstream algorithms.
  61. *
  62. * In our code it is used to produce a two 32-bit keys. One key is used
  63. * for Salsa20 and the other for HMAC-SHA-256. They are generated together
  64. * as a single 64-bit key.
  65. */
  66. static void *_zt_EC_KDF(const void *in,size_t inlen,void *out,size_t *outlen)
  67. {
  68. SHA256_CTX sha;
  69. unsigned char dig[SHA256_DIGEST_LENGTH];
  70. SHA256_Init(&sha);
  71. SHA256_Update(&sha,(const unsigned char *)in,inlen);
  72. SHA256_Final(dig,&sha);
  73. for(unsigned long i=0,k=0;i<(unsigned long)*outlen;) {
  74. if (k == SHA256_DIGEST_LENGTH) {
  75. k = 0;
  76. SHA256_Init(&sha);
  77. SHA256_Update(&sha,(const unsigned char *)in,inlen);
  78. SHA256_Update(&sha,dig,SHA256_DIGEST_LENGTH);
  79. SHA256_Final(dig,&sha);
  80. }
  81. ((unsigned char *)out)[i++] = dig[k++];
  82. }
  83. return out;
  84. }
  85. EllipticCurveKeyPair::EllipticCurveKeyPair() :
  86. _pub(),
  87. _priv(),
  88. _internal_key((void *)0)
  89. {
  90. }
  91. EllipticCurveKeyPair::EllipticCurveKeyPair(const EllipticCurveKeyPair &pair) :
  92. _pub(pair._pub),
  93. _priv(pair._priv),
  94. _internal_key((void *)0)
  95. {
  96. }
  97. EllipticCurveKeyPair::EllipticCurveKeyPair(const EllipticCurveKey &pubk,const EllipticCurveKey &privk) :
  98. _pub(pubk),
  99. _priv(privk),
  100. _internal_key((void *)0)
  101. {
  102. }
  103. EllipticCurveKeyPair::~EllipticCurveKeyPair()
  104. {
  105. if (_internal_key)
  106. EC_KEY_free((EC_KEY *)_internal_key);
  107. }
  108. const EllipticCurveKeyPair &EllipticCurveKeyPair::operator=(const EllipticCurveKeyPair &pair)
  109. {
  110. if (_internal_key)
  111. EC_KEY_free((EC_KEY *)_internal_key);
  112. _pub = pair._pub;
  113. _priv = pair._priv;
  114. _internal_key = (void *)0;
  115. return *this;
  116. }
  117. bool EllipticCurveKeyPair::generate()
  118. {
  119. unsigned char tmp[16384];
  120. EC_KEY *key;
  121. int len;
  122. // Make sure OpenSSL libcrypto has sufficient randomness (on most
  123. // platforms it auto-seeds, so this is a sanity check).
  124. if (!RAND_status()) {
  125. #if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
  126. FILE *rf = fopen("/dev/urandom","r");
  127. if (rf) {
  128. fread(tmp,sizeof(tmp),1,rf);
  129. fclose(rf);
  130. } else {
  131. fprintf(stderr,"FATAL: could not open /dev/urandom\n");
  132. exit(-1);
  133. }
  134. RAND_seed(tmp,sizeof(tmp));
  135. #else
  136. #ifdef _WIN32
  137. error need win32;
  138. #else
  139. error;
  140. #endif
  141. #endif
  142. }
  143. key = EC_KEY_new();
  144. if (!key) return false;
  145. if (!EC_KEY_set_group(key,ZT_EC_GROUP.g)) {
  146. EC_KEY_free(key);
  147. return false;
  148. }
  149. if (!EC_KEY_generate_key(key)) {
  150. EC_KEY_free(key);
  151. return false;
  152. }
  153. memset(_priv._key,0,sizeof(_priv._key));
  154. len = BN_num_bytes(EC_KEY_get0_private_key(key));
  155. if ((len > ZT_EC_PRIME_BYTES)||(len < 0)) {
  156. EC_KEY_free(key);
  157. return false;
  158. }
  159. BN_bn2bin(EC_KEY_get0_private_key(key),&(_priv._key[ZT_EC_PRIME_BYTES - len]));
  160. _priv._bytes = ZT_EC_PRIME_BYTES;
  161. memset(_pub._key,0,sizeof(_pub._key));
  162. len = EC_POINT_point2oct(ZT_EC_GROUP.g,EC_KEY_get0_public_key(key),POINT_CONVERSION_COMPRESSED,_pub._key,sizeof(_pub._key),0);
  163. if (len != ZT_EC_PUBLIC_KEY_BYTES) {
  164. EC_KEY_free(key);
  165. return false;
  166. }
  167. _pub._bytes = ZT_EC_PUBLIC_KEY_BYTES;
  168. if (_internal_key)
  169. EC_KEY_free((EC_KEY *)_internal_key);
  170. _internal_key = key;
  171. return true;
  172. }
  173. bool EllipticCurveKeyPair::agree(const EllipticCurveKey &theirPublicKey,unsigned char *agreedUponKey,unsigned int agreedUponKeyLength) const
  174. {
  175. if (theirPublicKey._bytes != ZT_EC_PUBLIC_KEY_BYTES)
  176. return false;
  177. if (!_internal_key) {
  178. if (!(const_cast <EllipticCurveKeyPair *> (this))->initInternalKey())
  179. return false;
  180. }
  181. EC_POINT *pub = EC_POINT_new(ZT_EC_GROUP.g);
  182. if (!pub)
  183. return false;
  184. EC_POINT_oct2point(ZT_EC_GROUP.g,pub,theirPublicKey._key,ZT_EC_PUBLIC_KEY_BYTES,0);
  185. int i = ECDH_compute_key(agreedUponKey,agreedUponKeyLength,pub,(EC_KEY *)_internal_key,&_zt_EC_KDF);
  186. EC_POINT_free(pub);
  187. return (i == (int)agreedUponKeyLength);
  188. }
  189. std::string EllipticCurveKeyPair::sign(const void *sha256) const
  190. {
  191. unsigned char buf[256];
  192. std::string sigbin;
  193. if (!_internal_key) {
  194. if (!(const_cast <EllipticCurveKeyPair *> (this))->initInternalKey())
  195. return std::string();
  196. }
  197. ECDSA_SIG *sig = ECDSA_do_sign((const unsigned char *)sha256,SHA256_DIGEST_LENGTH,(EC_KEY *)_internal_key);
  198. if (!sig)
  199. return std::string();
  200. int rlen = BN_num_bytes(sig->r);
  201. if ((rlen > 255)||(rlen <= 0)) {
  202. ECDSA_SIG_free(sig);
  203. return std::string();
  204. }
  205. sigbin.push_back((char)rlen);
  206. BN_bn2bin(sig->r,buf);
  207. sigbin.append((const char *)buf,rlen);
  208. int slen = BN_num_bytes(sig->s);
  209. if ((slen > 255)||(slen <= 0)) {
  210. ECDSA_SIG_free(sig);
  211. return std::string();
  212. }
  213. sigbin.push_back((char)slen);
  214. BN_bn2bin(sig->s,buf);
  215. sigbin.append((const char *)buf,slen);
  216. ECDSA_SIG_free(sig);
  217. return sigbin;
  218. }
  219. std::string EllipticCurveKeyPair::sign(const void *data,unsigned int len) const
  220. {
  221. SHA256_CTX sha;
  222. unsigned char dig[SHA256_DIGEST_LENGTH];
  223. SHA256_Init(&sha);
  224. SHA256_Update(&sha,(const unsigned char *)data,len);
  225. SHA256_Final(dig,&sha);
  226. return sign(dig);
  227. }
  228. bool EllipticCurveKeyPair::verify(const void *sha256,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen)
  229. {
  230. bool result = false;
  231. ECDSA_SIG *sig = (ECDSA_SIG *)0;
  232. EC_POINT *pub = (EC_POINT *)0;
  233. EC_KEY *key = (EC_KEY *)0;
  234. int rlen,slen;
  235. if (!siglen)
  236. goto verify_sig_return;
  237. rlen = ((const unsigned char *)sigbytes)[0];
  238. if (!rlen)
  239. goto verify_sig_return;
  240. if (siglen < (unsigned int)(rlen + 2))
  241. goto verify_sig_return;
  242. slen = ((const unsigned char *)sigbytes)[rlen + 1];
  243. if (!slen)
  244. goto verify_sig_return;
  245. if (siglen < (unsigned int)(rlen + slen + 2))
  246. goto verify_sig_return;
  247. sig = ECDSA_SIG_new();
  248. if (!sig)
  249. goto verify_sig_return;
  250. BN_bin2bn((const unsigned char *)sigbytes + 1,rlen,sig->r);
  251. BN_bin2bn((const unsigned char *)sigbytes + (1 + rlen + 1),slen,sig->s);
  252. pub = EC_POINT_new(ZT_EC_GROUP.g);
  253. if (!pub)
  254. goto verify_sig_return;
  255. EC_POINT_oct2point(ZT_EC_GROUP.g,pub,pk._key,ZT_EC_PUBLIC_KEY_BYTES,0);
  256. key = EC_KEY_new();
  257. if (!key)
  258. goto verify_sig_return;
  259. if (!EC_KEY_set_group(key,ZT_EC_GROUP.g))
  260. goto verify_sig_return;
  261. EC_KEY_set_public_key(key,pub);
  262. result = (ECDSA_do_verify((const unsigned char *)sha256,SHA256_DIGEST_LENGTH,sig,key) == 1);
  263. verify_sig_return:
  264. if (key)
  265. EC_KEY_free(key);
  266. if (pub)
  267. EC_POINT_free(pub);
  268. if (sig)
  269. ECDSA_SIG_free(sig);
  270. return result;
  271. }
  272. bool EllipticCurveKeyPair::verify(const void *data,unsigned int len,const EllipticCurveKey &pk,const void *sigbytes,unsigned int siglen)
  273. {
  274. SHA256_CTX sha;
  275. unsigned char dig[SHA256_DIGEST_LENGTH];
  276. SHA256_Init(&sha);
  277. SHA256_Update(&sha,(const unsigned char *)data,len);
  278. SHA256_Final(dig,&sha);
  279. return verify(dig,pk,sigbytes,siglen);
  280. }
  281. bool EllipticCurveKeyPair::initInternalKey()
  282. {
  283. EC_KEY *key;
  284. EC_POINT *kxy;
  285. BIGNUM *pn;
  286. if (_priv._bytes != ZT_EC_PRIME_BYTES) return false;
  287. if (_pub._bytes != ZT_EC_PUBLIC_KEY_BYTES) return false;
  288. key = EC_KEY_new();
  289. if (!key) return false;
  290. if (!EC_KEY_set_group(key,ZT_EC_GROUP.g)) {
  291. EC_KEY_free(key);
  292. return false;
  293. }
  294. pn = BN_new();
  295. if (!pn) {
  296. EC_KEY_free(key);
  297. return false;
  298. }
  299. if (!BN_bin2bn(_priv._key,ZT_EC_PRIME_BYTES,pn)) {
  300. BN_free(pn);
  301. EC_KEY_free(key);
  302. return false;
  303. }
  304. if (!EC_KEY_set_private_key(key,pn)) {
  305. BN_free(pn);
  306. EC_KEY_free(key);
  307. return false;
  308. }
  309. BN_free(pn);
  310. kxy = EC_POINT_new(ZT_EC_GROUP.g);
  311. if (!kxy) {
  312. EC_KEY_free(key);
  313. return false;
  314. }
  315. EC_POINT_oct2point(ZT_EC_GROUP.g,kxy,_pub._key,ZT_EC_PUBLIC_KEY_BYTES,0);
  316. if (!EC_KEY_set_public_key(key,kxy)) {
  317. EC_POINT_free(kxy);
  318. EC_KEY_free(key);
  319. return false;
  320. }
  321. EC_POINT_free(kxy);
  322. if (_internal_key)
  323. EC_KEY_free((EC_KEY *)_internal_key);
  324. _internal_key = key;
  325. return true;
  326. }
  327. } // namespace ZeroTier