ecc-ecdh.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /* ecc-ecdh.c - Elliptic Curve Diffie-Hellman key agreement
  2. * Copyright (C) 2019 g10 Code GmbH
  3. *
  4. * This file is part of Libgcrypt.
  5. *
  6. * Libgcrypt is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as
  8. * published by the Free Software Foundation; either version 2.1 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * Libgcrypt is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, see <https://www.gnu.org/licenses/>.
  18. * SPDX-License-Identifier: LGPL-2.1+
  19. */
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include "g10lib.h"
  26. #include "mpi.h"
  27. #include "cipher.h"
  28. #include "context.h"
  29. #include "ec-context.h"
  30. #include "ecc-common.h"
  31. #define ECC_CURVE25519_BYTES 32
  32. #define ECC_CURVE448_BYTES 56
  33. static gpg_err_code_t
  34. prepare_ec (mpi_ec_t *r_ec, const char *name)
  35. {
  36. int flags = 0;
  37. if (!strcmp (name, "Curve25519"))
  38. flags = PUBKEY_FLAG_DJB_TWEAK;
  39. return _gcry_mpi_ec_internal_new (r_ec, &flags, "ecc_mul_point", NULL, name);
  40. }
  41. unsigned int
  42. _gcry_ecc_get_algo_keylen (int curveid)
  43. {
  44. unsigned int len = 0;
  45. if (curveid == GCRY_ECC_CURVE25519)
  46. len = ECC_CURVE25519_BYTES;
  47. else if (curveid == GCRY_ECC_CURVE448)
  48. len = ECC_CURVE448_BYTES;
  49. return len;
  50. }
  51. /* For Curve25519 and X448, we need to mask the bits and enable the MSB. */
  52. static void
  53. ecc_tweak_bits (unsigned char *seckey, size_t seckey_len)
  54. {
  55. if (seckey_len == 32)
  56. {
  57. seckey[0] &= 0xf8;
  58. seckey[31] &= 0x7f;
  59. seckey[31] |= 0x40;
  60. }
  61. else
  62. {
  63. seckey[0] &= 0xfc;
  64. seckey[55] |= 0x80;
  65. }
  66. }
  67. gpg_err_code_t
  68. _gcry_ecc_curve_keypair (const char *curve,
  69. unsigned char *pubkey, size_t pubkey_len,
  70. unsigned char *seckey, size_t seckey_len)
  71. {
  72. gpg_err_code_t err;
  73. unsigned int nbits;
  74. unsigned int nbytes;
  75. gcry_mpi_t mpi_k = NULL;
  76. mpi_ec_t ec = NULL;
  77. mpi_point_struct Q = { NULL, NULL, NULL };
  78. gcry_mpi_t x;
  79. unsigned int len;
  80. unsigned char *buf;
  81. err = prepare_ec (&ec, curve);
  82. if (err)
  83. return err;
  84. nbits = ec->nbits;
  85. nbytes = (nbits + 7)/8;
  86. if (seckey_len != nbytes)
  87. return GPG_ERR_INV_ARG;
  88. if (ec->model == MPI_EC_WEIERSTRASS)
  89. {
  90. if (pubkey_len != 1 + 2*nbytes)
  91. return GPG_ERR_INV_ARG;
  92. do
  93. {
  94. mpi_free (mpi_k);
  95. mpi_k = mpi_new (nbytes*8);
  96. _gcry_randomize (seckey, nbytes, GCRY_STRONG_RANDOM);
  97. _gcry_mpi_set_buffer (mpi_k, seckey, nbytes, 0);
  98. }
  99. while (mpi_cmp (mpi_k, ec->n) >= 0);
  100. }
  101. else if (ec->model == MPI_EC_MONTGOMERY)
  102. {
  103. if (pubkey_len != nbytes)
  104. return GPG_ERR_INV_ARG;
  105. _gcry_randomize (seckey, nbytes, GCRY_STRONG_RANDOM);
  106. /* Existing ECC applications with libgcrypt (like gpg-agent in
  107. GnuPG) assumes that scalar is tweaked at key generation time.
  108. For the possible use case where generated key with this routine
  109. may be used with those, we put compatibile behavior here. */
  110. ecc_tweak_bits (seckey, nbytes);
  111. mpi_k = _gcry_mpi_set_opaque_copy (NULL, seckey, nbytes*8);
  112. }
  113. else
  114. return GPG_ERR_UNKNOWN_CURVE;
  115. x = mpi_new (nbits);
  116. point_init (&Q);
  117. _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec);
  118. if (ec->model == MPI_EC_WEIERSTRASS)
  119. {
  120. gcry_mpi_t y = mpi_new (nbits);
  121. gcry_mpi_t negative = mpi_new (nbits);
  122. _gcry_mpi_ec_get_affine (x, y, &Q, ec);
  123. /* For the backward compatibility, we check if it's a
  124. "compliant key". */
  125. mpi_sub (negative, ec->p, y);
  126. if (mpi_cmp (negative, y) < 0) /* p - y < p */
  127. {
  128. mpi_free (y);
  129. y = negative;
  130. mpi_sub (mpi_k, ec->n, mpi_k);
  131. buf = _gcry_mpi_get_buffer (mpi_k, 0, &len, NULL);
  132. memset (seckey, 0, nbytes - len);
  133. memcpy (seckey + nbytes - len, buf, len);
  134. }
  135. else /* p - y >= p */
  136. mpi_free (negative);
  137. buf = _gcry_ecc_ec2os_buf (x, y, ec->p, &len);
  138. if (!buf)
  139. {
  140. err = gpg_err_code_from_syserror ();
  141. mpi_free (y);
  142. }
  143. else
  144. {
  145. if (len != 1 + 2*nbytes)
  146. {
  147. err = GPG_ERR_INV_ARG;
  148. mpi_free (y);
  149. }
  150. else
  151. {
  152. /* (x,y) in SEC1 point encoding. */
  153. memcpy (pubkey, buf, len);
  154. xfree (buf);
  155. mpi_free (y);
  156. }
  157. }
  158. }
  159. else /* MPI_EC_MONTGOMERY */
  160. {
  161. _gcry_mpi_ec_get_affine (x, NULL, &Q, ec);
  162. buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL);
  163. if (!buf)
  164. err = gpg_err_code_from_syserror ();
  165. else
  166. {
  167. memcpy (pubkey, buf, nbytes);
  168. xfree (buf);
  169. }
  170. }
  171. mpi_free (x);
  172. point_free (&Q);
  173. mpi_free (mpi_k);
  174. _gcry_mpi_ec_free (ec);
  175. return err;
  176. }
  177. gpg_err_code_t
  178. _gcry_ecc_curve_mul_point (const char *curve,
  179. unsigned char *result, size_t result_len,
  180. const unsigned char *scalar, size_t scalar_len,
  181. const unsigned char *point, size_t point_len)
  182. {
  183. unsigned int nbits;
  184. unsigned int nbytes;
  185. gpg_err_code_t err;
  186. gcry_mpi_t mpi_k = NULL;
  187. mpi_ec_t ec = NULL;
  188. mpi_point_struct Q = { NULL, NULL, NULL };
  189. gcry_mpi_t x = NULL;
  190. unsigned int len;
  191. unsigned char *buf;
  192. err = prepare_ec (&ec, curve);
  193. if (err)
  194. return err;
  195. nbits = ec->nbits;
  196. nbytes = (nbits + 7)/8;
  197. if (ec->model == MPI_EC_WEIERSTRASS)
  198. {
  199. if (scalar_len != nbytes
  200. || result_len != 1 + 2*nbytes
  201. || point_len != 1 + 2*nbytes)
  202. {
  203. err = GPG_ERR_INV_ARG;
  204. goto leave;
  205. }
  206. mpi_k = mpi_new (nbytes*8);
  207. _gcry_mpi_set_buffer (mpi_k, scalar, nbytes, 0);
  208. }
  209. else if (ec->model == MPI_EC_MONTGOMERY)
  210. {
  211. if (scalar_len != nbytes
  212. || result_len != nbytes
  213. || point_len != nbytes)
  214. {
  215. err = GPG_ERR_INV_ARG;
  216. goto leave;
  217. }
  218. mpi_k = _gcry_mpi_set_opaque_copy (NULL, scalar, nbytes*8);
  219. }
  220. else
  221. {
  222. err = GPG_ERR_UNKNOWN_CURVE;
  223. goto leave;
  224. }
  225. point_init (&Q);
  226. if (point)
  227. {
  228. gcry_mpi_t mpi_u = _gcry_mpi_set_opaque_copy (NULL, point, point_len*8);
  229. mpi_point_struct P;
  230. point_init (&P);
  231. if (ec->model == MPI_EC_WEIERSTRASS)
  232. err = _gcry_ecc_sec_decodepoint (mpi_u, ec, &P);
  233. else /* MPI_EC_MONTGOMERY */
  234. err = _gcry_ecc_mont_decodepoint (mpi_u, ec, &P);
  235. mpi_free (mpi_u);
  236. if (err)
  237. goto leave;
  238. _gcry_mpi_ec_mul_point (&Q, mpi_k, &P, ec);
  239. point_free (&P);
  240. }
  241. else
  242. _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec);
  243. x = mpi_new (nbits);
  244. if (ec->model == MPI_EC_WEIERSTRASS)
  245. {
  246. gcry_mpi_t y = mpi_new (nbits);
  247. _gcry_mpi_ec_get_affine (x, y, &Q, ec);
  248. buf = _gcry_ecc_ec2os_buf (x, y, ec->p, &len);
  249. if (!buf)
  250. {
  251. err = gpg_err_code_from_syserror ();
  252. mpi_free (y);
  253. }
  254. else
  255. {
  256. if (len != 1 + 2*nbytes)
  257. {
  258. err = GPG_ERR_INV_ARG;
  259. mpi_free (y);
  260. }
  261. else
  262. {
  263. /* (x,y) in SEC1 point encoding. */
  264. memcpy (result, buf, len);
  265. xfree (buf);
  266. mpi_free (y);
  267. }
  268. }
  269. }
  270. else /* MPI_EC_MONTGOMERY */
  271. {
  272. _gcry_mpi_ec_get_affine (x, NULL, &Q, ec);
  273. buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL);
  274. if (!buf)
  275. err = gpg_err_code_from_syserror ();
  276. else
  277. {
  278. if (len != nbytes)
  279. err = GPG_ERR_INV_ARG;
  280. else
  281. {
  282. /* x in little endian. */
  283. memcpy (result, buf, nbytes);
  284. xfree (buf);
  285. }
  286. }
  287. }
  288. mpi_free (x);
  289. leave:
  290. point_free (&Q);
  291. mpi_free (mpi_k);
  292. _gcry_mpi_ec_free (ec);
  293. return err;
  294. }
  295. gpg_err_code_t
  296. _gcry_ecc_mul_point (int curveid, unsigned char *result,
  297. const unsigned char *scalar, const unsigned char *point)
  298. {
  299. const char *curve;
  300. size_t pubkey_len, seckey_len;
  301. if (curveid == GCRY_ECC_CURVE25519)
  302. {
  303. curve = "Curve25519";
  304. pubkey_len = seckey_len = 32;
  305. }
  306. else if (curveid == GCRY_ECC_CURVE448)
  307. {
  308. curve = "X448";
  309. pubkey_len = seckey_len = 56;
  310. }
  311. else
  312. return gpg_error (GPG_ERR_UNKNOWN_CURVE);
  313. return _gcry_ecc_curve_mul_point (curve, result, pubkey_len,
  314. scalar, seckey_len,
  315. point, pubkey_len);
  316. }