• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2020, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/ec.h>
16 
17 #include <openssl/digest.h>
18 #include <openssl/err.h>
19 #include <openssl/nid.h>
20 #include <openssl/type_check.h>
21 
22 #include <assert.h>
23 
24 #include "internal.h"
25 #include "../fipsmodule/bn/internal.h"
26 #include "../fipsmodule/ec/internal.h"
27 #include "../internal.h"
28 
29 
30 // This file implements hash-to-curve, as described in
31 // draft-irtf-cfrg-hash-to-curve-07.
32 //
33 // This hash-to-curve implementation is written generically with the
34 // expectation that we will eventually wish to support other curves. If it
35 // becomes a performance bottleneck, some possible optimizations by
36 // specializing it to the curve:
37 //
38 // - Rather than using a generic |felem_exp|, specialize the exponentation to
39 //   c2 with a faster addition chain.
40 //
41 // - |felem_mul| and |felem_sqr| are indirect calls to generic Montgomery
42 //   code. Given the few curves, we could specialize
43 //   |map_to_curve_simple_swu|. But doing this reasonably without duplicating
44 //   code in C is difficult. (C++ templates would be useful here.)
45 //
46 // - P-521's Z and c2 have small power-of-two absolute values. We could save
47 //   two multiplications in SSWU. (Other curves have reasonable values of Z
48 //   and inconvenient c2.) This is unlikely to be worthwhile without C++
49 //   templates to make specializing more convenient.
50 
51 // expand_message_xmd implements the operation described in section 5.3.1 of
52 // draft-irtf-cfrg-hash-to-curve-07. It returns one on success and zero on
53 // allocation failure or if |out_len| was too large.
expand_message_xmd(const EVP_MD * md,uint8_t * out,size_t out_len,const uint8_t * msg,size_t msg_len,const uint8_t * dst,size_t dst_len)54 static int expand_message_xmd(const EVP_MD *md, uint8_t *out, size_t out_len,
55                               const uint8_t *msg, size_t msg_len,
56                               const uint8_t *dst, size_t dst_len) {
57   int ret = 0;
58   const size_t block_size = EVP_MD_block_size(md);
59   const size_t md_size = EVP_MD_size(md);
60   EVP_MD_CTX ctx;
61   EVP_MD_CTX_init(&ctx);
62 
63   // Long DSTs are hashed down to size. See section 5.3.3.
64   OPENSSL_STATIC_ASSERT(EVP_MAX_MD_SIZE < 256, "hashed DST still too large");
65   uint8_t dst_buf[EVP_MAX_MD_SIZE];
66   if (dst_len >= 256) {
67     static const char kPrefix[] = "H2C-OVERSIZE-DST-";
68     if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
69         !EVP_DigestUpdate(&ctx, kPrefix, sizeof(kPrefix) - 1) ||
70         !EVP_DigestUpdate(&ctx, dst, dst_len) ||
71         !EVP_DigestFinal_ex(&ctx, dst_buf, NULL)) {
72       goto err;
73     }
74     dst = dst_buf;
75     dst_len = md_size;
76   }
77   uint8_t dst_len_u8 = (uint8_t)dst_len;
78 
79   // Compute b_0.
80   static const uint8_t kZeros[EVP_MAX_MD_BLOCK_SIZE] = {0};
81   // If |out_len| exceeds 16 bits then |i| will wrap below causing an error to
82   // be returned. This depends on the static assert above.
83   uint8_t l_i_b_str_zero[3] = {out_len >> 8, out_len, 0};
84   uint8_t b_0[EVP_MAX_MD_SIZE];
85   if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
86       !EVP_DigestUpdate(&ctx, kZeros, block_size) ||
87       !EVP_DigestUpdate(&ctx, msg, msg_len) ||
88       !EVP_DigestUpdate(&ctx, l_i_b_str_zero, sizeof(l_i_b_str_zero)) ||
89       !EVP_DigestUpdate(&ctx, dst, dst_len) ||
90       !EVP_DigestUpdate(&ctx, &dst_len_u8, 1) ||
91       !EVP_DigestFinal_ex(&ctx, b_0, NULL)) {
92     goto err;
93   }
94 
95   uint8_t b_i[EVP_MAX_MD_SIZE];
96   uint8_t i = 1;
97   while (out_len > 0) {
98     if (i == 0) {
99       // Input was too large.
100       OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
101       goto err;
102     }
103     if (i > 1) {
104       for (size_t j = 0; j < md_size; j++) {
105         b_i[j] ^= b_0[j];
106       }
107     } else {
108       OPENSSL_memcpy(b_i, b_0, md_size);
109     }
110 
111     if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
112         !EVP_DigestUpdate(&ctx, b_i, md_size) ||
113         !EVP_DigestUpdate(&ctx, &i, 1) ||
114         !EVP_DigestUpdate(&ctx, dst, dst_len) ||
115         !EVP_DigestUpdate(&ctx, &dst_len_u8, 1) ||
116         !EVP_DigestFinal_ex(&ctx, b_i, NULL)) {
117       goto err;
118     }
119 
120     size_t todo = out_len >= md_size ? md_size : out_len;
121     OPENSSL_memcpy(out, b_i, todo);
122     out += todo;
123     out_len -= todo;
124     i++;
125   }
126 
127   ret = 1;
128 
129 err:
130   EVP_MD_CTX_cleanup(&ctx);
131   return ret;
132 }
133 
134 // num_bytes_to_derive determines the number of bytes to derive when hashing to
135 // a number modulo |modulus|. See the hash_to_field operation defined in
136 // section 5.2 of draft-irtf-cfrg-hash-to-curve-07.
num_bytes_to_derive(size_t * out,const BIGNUM * modulus,unsigned k)137 static int num_bytes_to_derive(size_t *out, const BIGNUM *modulus, unsigned k) {
138   size_t bits = BN_num_bits(modulus);
139   size_t L = (bits + k + 7) / 8;
140   // We require 2^(8*L) < 2^(2*bits - 2) <= n^2 so to fit in bounds for
141   // |felem_reduce| and |ec_scalar_reduce|. All defined hash-to-curve suites
142   // define |k| to be well under this bound. (|k| is usually around half of
143   // |p_bits|.)
144   if (L * 8 >= 2 * bits - 2 ||
145       L > 2 * EC_MAX_BYTES) {
146     assert(0);
147     OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
148     return 0;
149   }
150 
151   *out = L;
152   return 1;
153 }
154 
155 // big_endian_to_words decodes |in| as a big-endian integer and writes the
156 // result to |out|. |num_words| must be large enough to contain the output.
big_endian_to_words(BN_ULONG * out,size_t num_words,const uint8_t * in,size_t len)157 static void big_endian_to_words(BN_ULONG *out, size_t num_words,
158                                 const uint8_t *in, size_t len) {
159   assert(len <= num_words * sizeof(BN_ULONG));
160   // Ensure any excess bytes are zeroed.
161   OPENSSL_memset(out, 0, num_words * sizeof(BN_ULONG));
162   uint8_t *out_u8 = (uint8_t *)out;
163   for (size_t i = 0; i < len; i++) {
164     out_u8[len - 1 - i] = in[i];
165   }
166 }
167 
168 // hash_to_field implements the operation described in section 5.2
169 // of draft-irtf-cfrg-hash-to-curve-07, with count = 2. |k| is the security
170 // factor.
hash_to_field2(const EC_GROUP * group,const EVP_MD * md,EC_FELEM * out1,EC_FELEM * out2,const uint8_t * dst,size_t dst_len,unsigned k,const uint8_t * msg,size_t msg_len)171 static int hash_to_field2(const EC_GROUP *group, const EVP_MD *md,
172                           EC_FELEM *out1, EC_FELEM *out2, const uint8_t *dst,
173                           size_t dst_len, unsigned k, const uint8_t *msg,
174                           size_t msg_len) {
175   size_t L;
176   uint8_t buf[4 * EC_MAX_BYTES];
177   if (!num_bytes_to_derive(&L, &group->field, k) ||
178       !expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len)) {
179     return 0;
180   }
181   BN_ULONG words[2 * EC_MAX_WORDS];
182   size_t num_words = 2 * group->field.width;
183   big_endian_to_words(words, num_words, buf, L);
184   group->meth->felem_reduce(group, out1, words, num_words);
185   big_endian_to_words(words, num_words, buf + L, L);
186   group->meth->felem_reduce(group, out2, words, num_words);
187   return 1;
188 }
189 
190 // hash_to_scalar behaves like |hash_to_field2| but returns a value modulo the
191 // group order rather than a field element. |k| is the security factor.
hash_to_scalar(const EC_GROUP * group,const EVP_MD * md,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,unsigned k,const uint8_t * msg,size_t msg_len)192 static int hash_to_scalar(const EC_GROUP *group, const EVP_MD *md,
193                           EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
194                           unsigned k, const uint8_t *msg, size_t msg_len) {
195   size_t L;
196   uint8_t buf[EC_MAX_BYTES * 2];
197   if (!num_bytes_to_derive(&L, &group->order, k) ||
198       !expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len)) {
199     return 0;
200   }
201 
202   BN_ULONG words[2 * EC_MAX_WORDS];
203   size_t num_words = 2 * group->order.width;
204   big_endian_to_words(words, num_words, buf, L);
205   ec_scalar_reduce(group, out, words, num_words);
206   return 1;
207 }
208 
mul_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)209 static inline void mul_A(const EC_GROUP *group, EC_FELEM *out,
210                          const EC_FELEM *in) {
211   assert(group->a_is_minus3);
212   EC_FELEM tmp;
213   ec_felem_add(group, &tmp, in, in);      // tmp = 2*in
214   ec_felem_add(group, &tmp, &tmp, &tmp);  // tmp = 4*in
215   ec_felem_sub(group, out, in, &tmp);     // out = -3*in
216 }
217 
mul_minus_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)218 static inline void mul_minus_A(const EC_GROUP *group, EC_FELEM *out,
219                                const EC_FELEM *in) {
220   assert(group->a_is_minus3);
221   EC_FELEM tmp;
222   ec_felem_add(group, &tmp, in, in);   // tmp = 2*in
223   ec_felem_add(group, out, &tmp, in);  // out = 3*in
224 }
225 
226 // sgn0_le implements the operation described in section 4.1.2 of
227 // draft-irtf-cfrg-hash-to-curve-07.
sgn0_le(const EC_GROUP * group,const EC_FELEM * a)228 static BN_ULONG sgn0_le(const EC_GROUP *group, const EC_FELEM *a) {
229   uint8_t buf[EC_MAX_BYTES];
230   size_t len;
231   ec_felem_to_bytes(group, buf, &len, a);
232   return buf[len - 1] & 1;
233 }
234 
235 // map_to_curve_simple_swu implements the operation described in section 6.6.2
236 // of draft-irtf-cfrg-hash-to-curve-07, using the optimization in appendix
237 // D.2.1. It returns one on success and zero on error.
map_to_curve_simple_swu(const EC_GROUP * group,const EC_FELEM * Z,const BN_ULONG * c1,size_t num_c1,const EC_FELEM * c2,EC_RAW_POINT * out,const EC_FELEM * u)238 static int map_to_curve_simple_swu(const EC_GROUP *group, const EC_FELEM *Z,
239                                    const BN_ULONG *c1, size_t num_c1,
240                                    const EC_FELEM *c2, EC_RAW_POINT *out,
241                                    const EC_FELEM *u) {
242   void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
243                           const EC_FELEM *b) = group->meth->felem_mul;
244   void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
245       group->meth->felem_sqr;
246 
247   // This function requires the prime be 3 mod 4, and that A = -3.
248   if (group->field.width == 0 || (group->field.d[0] & 3) != 3 ||
249       !group->a_is_minus3) {
250     OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
251     return 0;
252   }
253 
254   EC_FELEM tv1, tv2, tv3, tv4, xd, x1n, x2n, tmp, gxd, gx1, y1, y2;
255   felem_sqr(group, &tv1, u);                         // tv1 = u^2
256   felem_mul(group, &tv3, Z, &tv1);                   // tv3 = Z * tv1
257   felem_sqr(group, &tv2, &tv3);                      // tv2 = tv3^2
258   ec_felem_add(group, &xd, &tv2, &tv3);              // xd = tv2 + tv3
259   ec_felem_add(group, &x1n, &xd, &group->one);       // x1n = xd + 1
260   felem_mul(group, &x1n, &x1n, &group->b);           // x1n = x1n * B
261   mul_minus_A(group, &xd, &xd);                      // xd = -A * xd
262   BN_ULONG e1 = ec_felem_non_zero_mask(group, &xd);  // e1 = xd == 0 [flipped]
263   mul_A(group, &tmp, Z);
264   ec_felem_select(group, &xd, e1, &xd, &tmp);  // xd = CMOV(xd, Z * A, e1)
265   felem_sqr(group, &tv2, &xd);                 // tv2 = xd^2
266   felem_mul(group, &gxd, &tv2, &xd);           // gxd = tv2 * xd = xd^3
267   mul_A(group, &tv2, &tv2);                    // tv2 = A * tv2
268   felem_sqr(group, &gx1, &x1n);                // gx1 = x1n^2
269   ec_felem_add(group, &gx1, &gx1, &tv2);       // gx1 = gx1 + tv2
270   felem_mul(group, &gx1, &gx1, &x1n);          // gx1 = gx1 * x1n
271   felem_mul(group, &tv2, &group->b, &gxd);     // tv2 = B * gxd
272   ec_felem_add(group, &gx1, &gx1, &tv2);       // gx1 = gx1 + tv2
273   felem_sqr(group, &tv4, &gxd);                // tv4 = gxd^2
274   felem_mul(group, &tv2, &gx1, &gxd);          // tv2 = gx1 * gxd
275   felem_mul(group, &tv4, &tv4, &tv2);          // tv4 = tv4 * tv2
276   group->meth->felem_exp(group, &y1, &tv4, c1, num_c1);  // y1 = tv4^c1
277   felem_mul(group, &y1, &y1, &tv2);                      // y1 = y1 * tv2
278   felem_mul(group, &x2n, &tv3, &x1n);                    // x2n = tv3 * x1n
279   felem_mul(group, &y2, &y1, c2);                        // y2 = y1 * c2
280   felem_mul(group, &y2, &y2, &tv1);                      // y2 = y2 * tv1
281   felem_mul(group, &y2, &y2, u);                         // y2 = y2 * u
282   felem_sqr(group, &tv2, &y1);                           // tv2 = y1^2
283   felem_mul(group, &tv2, &tv2, &gxd);                    // tv2 = tv2 * gxd
284   ec_felem_sub(group, &tv3, &tv2, &gx1);
285   BN_ULONG e2 =
286       ec_felem_non_zero_mask(group, &tv3);       // e2 = tv2 == gx1 [flipped]
287   ec_felem_select(group, &x1n, e2, &x2n, &x1n);  // xn = CMOV(x2n, x1n, e2)
288   ec_felem_select(group, &y1, e2, &y2, &y1);     // y = CMOV(y2, y1, e2)
289   BN_ULONG sgn0_u = sgn0_le(group, u);
290   BN_ULONG sgn0_y = sgn0_le(group, &y1);
291   BN_ULONG e3 = sgn0_u ^ sgn0_y;
292   e3 = ((BN_ULONG)0) - e3;  // e3 = sgn0(u) == sgn0(y) [flipped]
293   ec_felem_neg(group, &y2, &y1);
294   ec_felem_select(group, &y1, e3, &y2, &y1);  // y = CMOV(-y, y, e3)
295 
296   // Appendix D.1 describes how to convert (x1n, xd, y1, 1) to Jacobian
297   // coordinates. Note yd = 1. Also note that gxd computed above is xd^3.
298   felem_mul(group, &out->X, &x1n, &xd);     // X = xn * xd
299   felem_mul(group, &out->Y, &y1, &gxd);     // Y = yn * gxd = yn * xd^3
300   out->Z = xd;                              // Z = xd
301   return 1;
302 }
303 
hash_to_curve(const EC_GROUP * group,const EVP_MD * md,const EC_FELEM * Z,const EC_FELEM * c2,unsigned k,EC_RAW_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)304 static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
305                          const EC_FELEM *Z, const EC_FELEM *c2, unsigned k,
306                          EC_RAW_POINT *out, const uint8_t *dst, size_t dst_len,
307                          const uint8_t *msg, size_t msg_len) {
308   EC_FELEM u0, u1;
309   if (!hash_to_field2(group, md, &u0, &u1, dst, dst_len, k, msg, msg_len)) {
310     return 0;
311   }
312 
313   // Compute |c1| = (p - 3) / 4.
314   BN_ULONG c1[EC_MAX_WORDS];
315   size_t num_c1 = group->field.width;
316   if (!bn_copy_words(c1, num_c1, &group->field)) {
317     return 0;
318   }
319   bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
320 
321   EC_RAW_POINT Q0, Q1;
322   if (!map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q0, &u0) ||
323       !map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q1, &u1)) {
324     return 0;
325   }
326 
327   group->meth->add(group, out, &Q0, &Q1);  // R = Q0 + Q1
328   // All our curves have cofactor one, so |clear_cofactor| is a no-op.
329   return 1;
330 }
331 
felem_from_u8(const EC_GROUP * group,EC_FELEM * out,uint8_t a)332 static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
333   uint8_t bytes[EC_MAX_BYTES] = {0};
334   size_t len = BN_num_bytes(&group->field);
335   bytes[len - 1] = a;
336   return ec_felem_from_bytes(group, out, bytes, len);
337 }
338 
ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(const EC_GROUP * group,EC_RAW_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)339 int ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
340     const EC_GROUP *group, EC_RAW_POINT *out, const uint8_t *dst,
341     size_t dst_len, const uint8_t *msg, size_t msg_len) {
342   // See section 8.3 of draft-irtf-cfrg-hash-to-curve-07.
343   if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
344     OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
345     return 0;
346   }
347 
348   // kSqrt1728 was computed as follows in python3:
349   //
350   // p = 2**384 - 2**128 - 2**96 + 2**32 - 1
351   // z3 = 12**3
352   // c2 = pow(z3, (p+1)//4, p)
353   // assert z3 == pow(c2, 2, p)
354   // ", ".join("0x%02x" % b for b in c2.to_bytes(384//8, 'big')
355 
356   static const uint8_t kSqrt1728[] = {
357       0x01, 0x98, 0x77, 0xcc, 0x10, 0x41, 0xb7, 0x55, 0x57, 0x43, 0xc0, 0xae,
358       0x2e, 0x3a, 0x3e, 0x61, 0xfb, 0x2a, 0xaa, 0x2e, 0x0e, 0x87, 0xea, 0x55,
359       0x7a, 0x56, 0x3d, 0x8b, 0x59, 0x8a, 0x09, 0x40, 0xd0, 0xa6, 0x97, 0xa9,
360       0xe0, 0xb9, 0xe9, 0x2c, 0xfa, 0xa3, 0x14, 0xf5, 0x83, 0xc9, 0xd0, 0x66
361   };
362 
363   // Z = -12, c2 = sqrt(1728)
364   EC_FELEM Z, c2;
365   if (!felem_from_u8(group, &Z, 12) ||
366       !ec_felem_from_bytes(group, &c2, kSqrt1728, sizeof(kSqrt1728))) {
367     return 0;
368   }
369   ec_felem_neg(group, &Z, &Z);
370 
371   return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/192, out, dst,
372                        dst_len, msg, msg_len);
373 }
374 
ec_hash_to_scalar_p384_xmd_sha512_draft07(const EC_GROUP * group,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)375 int ec_hash_to_scalar_p384_xmd_sha512_draft07(
376     const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
377     const uint8_t *msg, size_t msg_len) {
378   if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
379     OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
380     return 0;
381   }
382 
383   return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/192, msg,
384                         msg_len);
385 }
386