/src/libgcrypt/cipher/ecc-eddsa.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* ecc-eddsa.c - Elliptic Curve EdDSA signatures |
2 | | * Copyright (C) 2013, 2014 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 |
17 | | * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include <config.h> |
21 | | #include <stdio.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | #include <errno.h> |
25 | | |
26 | | #include "g10lib.h" |
27 | | #include "mpi.h" |
28 | | #include "cipher.h" |
29 | | #include "context.h" |
30 | | #include "ec-context.h" |
31 | | #include "ecc-common.h" |
32 | | |
33 | | |
34 | | |
35 | | void |
36 | | reverse_buffer (unsigned char *buffer, unsigned int length) |
37 | 0 | { |
38 | 0 | unsigned int tmp, i; |
39 | |
|
40 | 0 | for (i=0; i < length/2; i++) |
41 | 0 | { |
42 | 0 | tmp = buffer[i]; |
43 | 0 | buffer[i] = buffer[length-1-i]; |
44 | 0 | buffer[length-1-i] = tmp; |
45 | 0 | } |
46 | 0 | } |
47 | | |
48 | | |
49 | | /* Helper to scan a hex string. */ |
50 | | static gcry_mpi_t |
51 | | scanval (const char *string) |
52 | 0 | { |
53 | 0 | gpg_err_code_t rc; |
54 | 0 | gcry_mpi_t val; |
55 | |
|
56 | 0 | rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); |
57 | 0 | if (rc) |
58 | 0 | log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); |
59 | 0 | return val; |
60 | 0 | } |
61 | | |
62 | | |
63 | | |
64 | | /* Encode MPI using the EdDSA scheme. MINLEN specifies the required |
65 | | length of the buffer in bytes. On success 0 is returned an a |
66 | | malloced buffer with the encoded point is stored at R_BUFFER; the |
67 | | length of this buffer is stored at R_BUFLEN. */ |
68 | | static gpg_err_code_t |
69 | | eddsa_encodempi (gcry_mpi_t mpi, unsigned int nbits, |
70 | | unsigned char **r_buffer, unsigned int *r_buflen) |
71 | 0 | { |
72 | 0 | unsigned char *rawmpi; |
73 | 0 | unsigned int rawmpilen; |
74 | 0 | unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; |
75 | |
|
76 | 0 | rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL); |
77 | 0 | if (!rawmpi) |
78 | 0 | return gpg_err_code_from_syserror (); |
79 | | |
80 | 0 | *r_buffer = rawmpi; |
81 | 0 | *r_buflen = rawmpilen; |
82 | 0 | return 0; |
83 | 0 | } |
84 | | |
85 | | |
86 | | /* Encode (X,Y) using the EdDSA scheme. NBITS is the number of bits |
87 | | of the field of the curve. If WITH_PREFIX is set the returned |
88 | | buffer is prefixed with a 0x40 byte. On success 0 is returned and |
89 | | a malloced buffer with the encoded point is stored at R_BUFFER; the |
90 | | length of this buffer is stored at R_BUFLEN. */ |
91 | | static gpg_err_code_t |
92 | | eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int nbits, |
93 | | int with_prefix, |
94 | | unsigned char **r_buffer, unsigned int *r_buflen) |
95 | 0 | { |
96 | 0 | unsigned char *rawmpi; |
97 | 0 | unsigned int rawmpilen; |
98 | 0 | int off = with_prefix? 1:0; |
99 | 0 | unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; |
100 | |
|
101 | 0 | rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL); |
102 | 0 | if (!rawmpi) |
103 | 0 | return gpg_err_code_from_syserror (); |
104 | 0 | if (mpi_test_bit (x, 0) && rawmpilen) |
105 | 0 | rawmpi[off + rawmpilen - 1] |= 0x80; /* Set sign bit. */ |
106 | 0 | if (off) |
107 | 0 | rawmpi[0] = 0x40; |
108 | |
|
109 | 0 | *r_buffer = rawmpi; |
110 | 0 | *r_buflen = rawmpilen + off; |
111 | 0 | return 0; |
112 | 0 | } |
113 | | |
114 | | /* Encode POINT using the EdDSA scheme. X and Y are either scratch |
115 | | variables supplied by the caller or NULL. CTX is the usual |
116 | | context. If WITH_PREFIX is set the returned buffer is prefixed |
117 | | with a 0x40 byte. On success 0 is returned and a malloced buffer |
118 | | with the encoded point is stored at R_BUFFER; the length of this |
119 | | buffer is stored at R_BUFLEN. */ |
120 | | gpg_err_code_t |
121 | | _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec, |
122 | | gcry_mpi_t x_in, gcry_mpi_t y_in, |
123 | | int with_prefix, |
124 | | unsigned char **r_buffer, unsigned int *r_buflen) |
125 | 0 | { |
126 | 0 | gpg_err_code_t rc; |
127 | 0 | gcry_mpi_t x, y; |
128 | |
|
129 | 0 | x = x_in? x_in : mpi_new (0); |
130 | 0 | y = y_in? y_in : mpi_new (0); |
131 | |
|
132 | 0 | if (_gcry_mpi_ec_get_affine (x, y, point, ec)) |
133 | 0 | { |
134 | 0 | log_error ("eddsa_encodepoint: Failed to get affine coordinates\n"); |
135 | 0 | rc = GPG_ERR_INTERNAL; |
136 | 0 | } |
137 | 0 | else |
138 | 0 | rc = eddsa_encode_x_y (x, y, ec->nbits, with_prefix, r_buffer, r_buflen); |
139 | |
|
140 | 0 | if (!x_in) |
141 | 0 | mpi_free (x); |
142 | 0 | if (!y_in) |
143 | 0 | mpi_free (y); |
144 | 0 | return rc; |
145 | 0 | } |
146 | | |
147 | | |
148 | | /* Make sure that the opaque MPI VALUE is in compact EdDSA format. |
149 | | This function updates MPI if needed. */ |
150 | | gpg_err_code_t |
151 | | _gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, unsigned int nbits) |
152 | 0 | { |
153 | 0 | gpg_err_code_t rc; |
154 | 0 | const unsigned char *buf; |
155 | 0 | unsigned int rawmpilen; |
156 | 0 | gcry_mpi_t x, y; |
157 | 0 | unsigned char *enc; |
158 | 0 | unsigned int enclen; |
159 | |
|
160 | 0 | if (!mpi_is_opaque (value)) |
161 | 0 | return GPG_ERR_INV_OBJ; |
162 | 0 | buf = mpi_get_opaque (value, &rawmpilen); |
163 | 0 | if (!buf) |
164 | 0 | return GPG_ERR_INV_OBJ; |
165 | 0 | rawmpilen = (rawmpilen + 7)/8; |
166 | |
|
167 | 0 | if (rawmpilen > 1 && (rawmpilen%2)) |
168 | 0 | { |
169 | 0 | if (buf[0] == 0x04) |
170 | 0 | { |
171 | | /* Buffer is in SEC1 uncompressed format. Extract y and |
172 | | compress. */ |
173 | 0 | rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, |
174 | 0 | buf+1, (rawmpilen-1)/2, NULL); |
175 | 0 | if (rc) |
176 | 0 | return rc; |
177 | 0 | rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, |
178 | 0 | buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL); |
179 | 0 | if (rc) |
180 | 0 | { |
181 | 0 | mpi_free (x); |
182 | 0 | return rc; |
183 | 0 | } |
184 | | |
185 | 0 | rc = eddsa_encode_x_y (x, y, nbits, 0, &enc, &enclen); |
186 | 0 | mpi_free (x); |
187 | 0 | mpi_free (y); |
188 | 0 | if (rc) |
189 | 0 | return rc; |
190 | | |
191 | 0 | mpi_set_opaque (value, enc, 8*enclen); |
192 | 0 | } |
193 | 0 | else if (buf[0] == 0x40) |
194 | 0 | { |
195 | | /* Buffer is compressed but with our SEC1 alike compression |
196 | | indicator. Remove that byte. FIXME: We should write and |
197 | | use a function to manipulate an opaque MPI in place. */ |
198 | 0 | if (!_gcry_mpi_set_opaque_copy (value, buf + 1, (rawmpilen - 1)*8)) |
199 | 0 | return gpg_err_code_from_syserror (); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | | |
207 | | static gpg_err_code_t |
208 | | ecc_ed448_recover_x (gcry_mpi_t x, gcry_mpi_t y, int x_0, mpi_ec_t ec) |
209 | 0 | { |
210 | 0 | gpg_err_code_t rc = 0; |
211 | 0 | gcry_mpi_t u, v, u3, v3, t; |
212 | 0 | static gcry_mpi_t p34; /* Hard coded (P-3)/4 */ |
213 | |
|
214 | 0 | if (mpi_cmp (y, ec->p) >= 0) |
215 | 0 | rc = GPG_ERR_INV_OBJ; |
216 | |
|
217 | 0 | if (!p34) |
218 | 0 | p34 = scanval ("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" |
219 | 0 | "BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); |
220 | |
|
221 | 0 | u = mpi_new (0); |
222 | 0 | v = mpi_new (0); |
223 | 0 | u3 = mpi_new (0); |
224 | 0 | v3 = mpi_new (0); |
225 | 0 | t = mpi_new (0); |
226 | | |
227 | | /* Compute u and v */ |
228 | | /* u = y^2 */ |
229 | 0 | mpi_mulm (u, y, y, ec->p); |
230 | | /* v = b*y^2 */ |
231 | 0 | mpi_mulm (v, ec->b, u, ec->p); |
232 | | /* u = y^2-1 */ |
233 | 0 | mpi_sub_ui (u, u, 1); |
234 | | /* v = b*y^2-1 */ |
235 | 0 | mpi_sub_ui (v, v, 1); |
236 | | |
237 | | /* Compute sqrt(u/v) */ |
238 | | /* u3 = u^3 */ |
239 | 0 | mpi_powm (u3, u, mpi_const (MPI_C_THREE), ec->p); |
240 | 0 | mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); |
241 | | /* t = u^4 * u * v3 = u^5 * v^3 */ |
242 | 0 | mpi_powm (t, u, mpi_const (MPI_C_FOUR), ec->p); |
243 | 0 | mpi_mulm (t, t, u, ec->p); |
244 | 0 | mpi_mulm (t, t, v3, ec->p); |
245 | | /* t = t^((p-3)/4) = (u^5 * v^3)^((p-3)/4) */ |
246 | 0 | mpi_powm (t, t, p34, ec->p); |
247 | | /* x = t * u^3 * v = (u^3 * v) * (u^5 * v^3)^((p-3)/4) */ |
248 | 0 | mpi_mulm (t, t, u3, ec->p); |
249 | 0 | mpi_mulm (x, t, v, ec->p); |
250 | | |
251 | | /* t = v * x^2 */ |
252 | 0 | mpi_mulm (t, x, x, ec->p); |
253 | 0 | mpi_mulm (t, t, v, ec->p); |
254 | |
|
255 | 0 | if (mpi_cmp (t, u) != 0) |
256 | 0 | rc = GPG_ERR_INV_OBJ; |
257 | 0 | else |
258 | 0 | { |
259 | 0 | if (!mpi_cmp_ui (x, 0) && x_0) |
260 | 0 | rc = GPG_ERR_INV_OBJ; |
261 | | |
262 | | /* Choose the desired square root according to parity */ |
263 | 0 | if (mpi_test_bit (x, 0) != !!x_0) |
264 | 0 | mpi_sub (x, ec->p, x); |
265 | 0 | } |
266 | |
|
267 | 0 | mpi_free (t); |
268 | 0 | mpi_free (u3); |
269 | 0 | mpi_free (v3); |
270 | 0 | mpi_free (v); |
271 | 0 | mpi_free (u); |
272 | |
|
273 | 0 | return rc; |
274 | 0 | } |
275 | | |
276 | | |
277 | | /* Recover X from Y and SIGN (which actually is a parity bit). */ |
278 | | gpg_err_code_t |
279 | | _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) |
280 | 0 | { |
281 | 0 | gpg_err_code_t rc = 0; |
282 | 0 | gcry_mpi_t u, v, v3, t; |
283 | 0 | static gcry_mpi_t p58, seven; |
284 | | |
285 | | /* |
286 | | * This routine is actually curve specific. Now, only supports |
287 | | * Ed25519 and Ed448. |
288 | | */ |
289 | |
|
290 | 0 | if (ec->dialect != ECC_DIALECT_ED25519) |
291 | | /* For now, it's only Ed448. */ |
292 | 0 | return ecc_ed448_recover_x (x, y, sign, ec); |
293 | | |
294 | | /* It's Ed25519. */ |
295 | | |
296 | 0 | if (!p58) |
297 | 0 | p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" |
298 | 0 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD"); |
299 | 0 | if (!seven) |
300 | 0 | seven = mpi_set_ui (NULL, 7); |
301 | |
|
302 | 0 | u = mpi_new (0); |
303 | 0 | v = mpi_new (0); |
304 | 0 | v3 = mpi_new (0); |
305 | 0 | t = mpi_new (0); |
306 | | |
307 | | /* Compute u and v */ |
308 | | /* u = y^2 */ |
309 | 0 | mpi_mulm (u, y, y, ec->p); |
310 | | /* v = b*y^2 */ |
311 | 0 | mpi_mulm (v, ec->b, u, ec->p); |
312 | | /* u = y^2-1 */ |
313 | 0 | mpi_sub_ui (u, u, 1); |
314 | | /* v = b*y^2+1 */ |
315 | 0 | mpi_add_ui (v, v, 1); |
316 | | |
317 | | /* Compute sqrt(u/v) */ |
318 | | /* v3 = v^3 */ |
319 | 0 | mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); |
320 | | /* t = v3 * v3 * u * v = u * v^7 */ |
321 | 0 | mpi_powm (t, v, seven, ec->p); |
322 | 0 | mpi_mulm (t, t, u, ec->p); |
323 | | /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8) */ |
324 | 0 | mpi_powm (t, t, p58, ec->p); |
325 | | /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */ |
326 | 0 | mpi_mulm (t, t, u, ec->p); |
327 | 0 | mpi_mulm (x, t, v3, ec->p); |
328 | | |
329 | | /* Adjust if needed. */ |
330 | | /* t = v * x^2 */ |
331 | 0 | mpi_mulm (t, x, x, ec->p); |
332 | 0 | mpi_mulm (t, t, v, ec->p); |
333 | | /* -t == u ? x = x * sqrt(-1) */ |
334 | 0 | mpi_sub (t, ec->p, t); |
335 | 0 | if (!mpi_cmp (t, u)) |
336 | 0 | { |
337 | 0 | static gcry_mpi_t m1; /* Fixme: this is not thread-safe. */ |
338 | 0 | if (!m1) |
339 | 0 | m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7" |
340 | 0 | "2F431806AD2FE478C4EE1B274A0EA0B0"); |
341 | 0 | mpi_mulm (x, x, m1, ec->p); |
342 | | /* t = v * x^2 */ |
343 | 0 | mpi_mulm (t, x, x, ec->p); |
344 | 0 | mpi_mulm (t, t, v, ec->p); |
345 | | /* -t == u ? x = x * sqrt(-1) */ |
346 | 0 | mpi_sub (t, ec->p, t); |
347 | 0 | if (!mpi_cmp (t, u)) |
348 | 0 | rc = GPG_ERR_INV_OBJ; |
349 | 0 | } |
350 | | |
351 | | /* Choose the desired square root according to parity */ |
352 | 0 | if (mpi_test_bit (x, 0) != !!sign) |
353 | 0 | mpi_sub (x, ec->p, x); |
354 | |
|
355 | 0 | mpi_free (t); |
356 | 0 | mpi_free (v3); |
357 | 0 | mpi_free (v); |
358 | 0 | mpi_free (u); |
359 | |
|
360 | 0 | return rc; |
361 | 0 | } |
362 | | |
363 | | |
364 | | /* Decode the EdDSA style encoded PK and set it into RESULT. CTX is |
365 | | the usual curve context. If R_ENCPK is not NULL, the encoded PK is |
366 | | stored at that address; this is a new copy to be released by the |
367 | | caller. In contrast to the supplied PK, this is not an MPI and |
368 | | thus guaranteed to be properly padded. R_ENCPKLEN receives the |
369 | | length of that encoded key. */ |
370 | | gpg_err_code_t |
371 | | _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result, |
372 | | unsigned char **r_encpk, unsigned int *r_encpklen) |
373 | 0 | { |
374 | 0 | gpg_err_code_t rc; |
375 | 0 | unsigned char *rawmpi; |
376 | 0 | unsigned int rawmpilen; |
377 | 0 | int sign; |
378 | |
|
379 | 0 | if (mpi_is_opaque (pk)) |
380 | 0 | { |
381 | 0 | const unsigned char *buf; |
382 | 0 | unsigned int len; |
383 | |
|
384 | 0 | len = (ctx->nbits%8) == 0 ? (ctx->nbits/8 + 1): (ctx->nbits+7)/8; |
385 | |
|
386 | 0 | buf = mpi_get_opaque (pk, &rawmpilen); |
387 | 0 | if (!buf) |
388 | 0 | return GPG_ERR_INV_OBJ; |
389 | 0 | rawmpilen = (rawmpilen + 7)/8; |
390 | |
|
391 | 0 | if (!(rawmpilen == len |
392 | 0 | || rawmpilen == len + 1 |
393 | 0 | || rawmpilen == len * 2 + 1)) |
394 | 0 | return GPG_ERR_INV_OBJ; |
395 | | |
396 | | /* Handle compression prefixes. The size of the buffer will be |
397 | | odd in this case. */ |
398 | 0 | if (rawmpilen > 1 && (rawmpilen == len + 1 || rawmpilen == len * 2 + 1)) |
399 | 0 | { |
400 | | /* First check whether the public key has been given in |
401 | | standard uncompressed format (SEC1). No need to recover |
402 | | x in this case. */ |
403 | 0 | if (buf[0] == 0x04) |
404 | 0 | { |
405 | 0 | gcry_mpi_t x, y; |
406 | |
|
407 | 0 | rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, |
408 | 0 | buf+1, (rawmpilen-1)/2, NULL); |
409 | 0 | if (rc) |
410 | 0 | return rc; |
411 | 0 | rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, |
412 | 0 | buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2,NULL); |
413 | 0 | if (rc) |
414 | 0 | { |
415 | 0 | mpi_free (x); |
416 | 0 | return rc; |
417 | 0 | } |
418 | | |
419 | 0 | if (r_encpk) |
420 | 0 | { |
421 | 0 | rc = eddsa_encode_x_y (x, y, ctx->nbits, 0, |
422 | 0 | r_encpk, r_encpklen); |
423 | 0 | if (rc) |
424 | 0 | { |
425 | 0 | mpi_free (x); |
426 | 0 | mpi_free (y); |
427 | 0 | return rc; |
428 | 0 | } |
429 | 0 | } |
430 | 0 | mpi_snatch (result->x, x); |
431 | 0 | mpi_snatch (result->y, y); |
432 | 0 | mpi_set_ui (result->z, 1); |
433 | 0 | return 0; |
434 | 0 | } |
435 | | |
436 | | /* Check whether the public key has been prefixed with a 0x40 |
437 | | byte to explicitly indicate compressed format using a SEC1 |
438 | | alike prefix byte. This is a Libgcrypt extension. */ |
439 | 0 | if (buf[0] == 0x40) |
440 | 0 | { |
441 | 0 | rawmpilen--; |
442 | 0 | buf++; |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | | /* EdDSA compressed point. */ |
447 | 0 | rawmpi = xtrymalloc (rawmpilen); |
448 | 0 | if (!rawmpi) |
449 | 0 | return gpg_err_code_from_syserror (); |
450 | 0 | memcpy (rawmpi, buf, rawmpilen); |
451 | 0 | reverse_buffer (rawmpi, rawmpilen); |
452 | 0 | } |
453 | 0 | else |
454 | 0 | { |
455 | | /* Note: Without using an opaque MPI it is not reliable possible |
456 | | to find out whether the public key has been given in |
457 | | uncompressed format. Thus we expect native EdDSA format. */ |
458 | 0 | rawmpi = _gcry_mpi_get_buffer (pk, (ctx->nbits+7)/8, &rawmpilen, NULL); |
459 | 0 | if (!rawmpi) |
460 | 0 | return gpg_err_code_from_syserror (); |
461 | 0 | } |
462 | | |
463 | 0 | if (rawmpilen) |
464 | 0 | { |
465 | 0 | sign = !!(rawmpi[0] & 0x80); |
466 | 0 | rawmpi[0] &= 0x7f; |
467 | 0 | } |
468 | 0 | else |
469 | 0 | sign = 0; |
470 | 0 | _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0); |
471 | 0 | if (r_encpk) |
472 | 0 | { |
473 | | /* Revert to little endian. */ |
474 | 0 | if (sign && rawmpilen) |
475 | 0 | rawmpi[0] |= 0x80; |
476 | 0 | reverse_buffer (rawmpi, rawmpilen); |
477 | 0 | *r_encpk = rawmpi; |
478 | 0 | if (r_encpklen) |
479 | 0 | *r_encpklen = rawmpilen; |
480 | 0 | } |
481 | 0 | else |
482 | 0 | xfree (rawmpi); |
483 | |
|
484 | 0 | rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx); |
485 | 0 | mpi_set_ui (result->z, 1); |
486 | |
|
487 | 0 | return rc; |
488 | 0 | } |
489 | | |
490 | | |
491 | | /* Compute the A value as used by EdDSA. The caller needs to provide |
492 | | the context EC and the actual secret D as an MPI. The function |
493 | | returns a newly allocated 64 byte buffer at r_digest; the first 32 |
494 | | bytes represent the A value. NULL is returned on error and NULL |
495 | | stored at R_DIGEST. */ |
496 | | gpg_err_code_t |
497 | | _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec) |
498 | 0 | { |
499 | 0 | gpg_err_code_t rc; |
500 | 0 | unsigned char *rawmpi = NULL; |
501 | 0 | unsigned int rawmpilen; |
502 | 0 | unsigned char *digest; |
503 | 0 | int hashalgo, b, digestlen; |
504 | 0 | gcry_buffer_t hvec[2]; |
505 | |
|
506 | 0 | *r_digest = NULL; |
507 | |
|
508 | 0 | b = (ec->nbits+7)/8; |
509 | | |
510 | | /* |
511 | | * Choice of hashalgo is curve specific. |
512 | | * For now, it's determine by the bit size of the field. |
513 | | */ |
514 | 0 | if (ec->nbits == 255) |
515 | 0 | { |
516 | 0 | hashalgo = GCRY_MD_SHA512; |
517 | 0 | digestlen = 64; |
518 | 0 | } |
519 | 0 | else if (ec->nbits == 448) |
520 | 0 | { |
521 | 0 | b++; |
522 | 0 | hashalgo = GCRY_MD_SHAKE256; |
523 | 0 | digestlen = 2 * b; |
524 | 0 | } |
525 | 0 | else |
526 | 0 | return GPG_ERR_NOT_IMPLEMENTED; |
527 | | |
528 | | /* Note that we clear DIGEST so we can use it as input to left pad |
529 | | the key with zeroes for hashing. */ |
530 | 0 | digest = xtrycalloc_secure (2, b); |
531 | 0 | if (!digest) |
532 | 0 | return gpg_err_code_from_syserror (); |
533 | | |
534 | 0 | rawmpi = _gcry_mpi_get_buffer (ec->d, 0, &rawmpilen, NULL); |
535 | 0 | if (!rawmpi) |
536 | 0 | { |
537 | 0 | xfree (digest); |
538 | 0 | return gpg_err_code_from_syserror (); |
539 | 0 | } |
540 | | |
541 | 0 | memset (hvec, 0, sizeof hvec); |
542 | |
|
543 | 0 | hvec[0].data = digest; |
544 | 0 | hvec[0].len = (hashalgo == GCRY_MD_SHA512 && b > rawmpilen) |
545 | 0 | ? b - rawmpilen : 0; |
546 | 0 | hvec[1].data = rawmpi; |
547 | 0 | hvec[1].len = rawmpilen; |
548 | 0 | rc = _gcry_md_hash_buffers_extract (hashalgo, 0, digest, digestlen, hvec, 2); |
549 | |
|
550 | 0 | xfree (rawmpi); |
551 | 0 | if (rc) |
552 | 0 | { |
553 | 0 | xfree (digest); |
554 | 0 | return rc; |
555 | 0 | } |
556 | | |
557 | | /* Compute the A value. */ |
558 | 0 | reverse_buffer (digest, b); /* Only the first half of the hash. */ |
559 | | |
560 | | /* Field specific handling of clearing/setting bits. */ |
561 | 0 | if (ec->nbits == 255) |
562 | 0 | { |
563 | 0 | digest[0] = (digest[0] & 0x7f) | 0x40; |
564 | 0 | digest[31] &= 0xf8; |
565 | 0 | } |
566 | 0 | else |
567 | 0 | { |
568 | 0 | digest[0] = 0; |
569 | 0 | digest[1] |= 0x80; |
570 | 0 | digest[56] &= 0xfc; |
571 | 0 | } |
572 | |
|
573 | 0 | *r_digest = digest; |
574 | 0 | return 0; |
575 | 0 | } |
576 | | |
577 | | |
578 | | /** |
579 | | * _gcry_ecc_eddsa_genkey - EdDSA version of the key generation. |
580 | | * |
581 | | * @ec: Elliptic curve computation context. |
582 | | * @flags: Flags controlling aspects of the creation. |
583 | | * |
584 | | * Return: An error code. |
585 | | * |
586 | | * The only @flags bit used by this function is %PUBKEY_FLAG_TRANSIENT |
587 | | * to use a faster RNG. |
588 | | */ |
589 | | gpg_err_code_t |
590 | | _gcry_ecc_eddsa_genkey (mpi_ec_t ec, int flags) |
591 | 0 | { |
592 | 0 | gpg_err_code_t rc; |
593 | 0 | int b; |
594 | 0 | gcry_mpi_t a, x, y; |
595 | 0 | mpi_point_struct Q; |
596 | 0 | gcry_random_level_t random_level; |
597 | 0 | char *dbuf; |
598 | 0 | size_t dlen; |
599 | 0 | unsigned char *hash_d = NULL; |
600 | |
|
601 | 0 | if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) |
602 | 0 | random_level = GCRY_STRONG_RANDOM; |
603 | 0 | else |
604 | 0 | random_level = GCRY_VERY_STRONG_RANDOM; |
605 | |
|
606 | 0 | b = (ec->nbits+7)/8; |
607 | |
|
608 | 0 | if (ec->nbits == 255) |
609 | 0 | ; |
610 | 0 | else if (ec->nbits == 448) |
611 | 0 | b++; |
612 | 0 | else |
613 | 0 | return GPG_ERR_NOT_IMPLEMENTED; |
614 | | |
615 | 0 | dlen = b; |
616 | |
|
617 | 0 | a = mpi_snew (0); |
618 | 0 | x = mpi_new (0); |
619 | 0 | y = mpi_new (0); |
620 | | |
621 | | /* Generate a secret. */ |
622 | 0 | dbuf = _gcry_random_bytes_secure (dlen, random_level); |
623 | 0 | ec->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); |
624 | 0 | rc = _gcry_ecc_eddsa_compute_h_d (&hash_d, ec); |
625 | 0 | if (rc) |
626 | 0 | goto leave; |
627 | | |
628 | 0 | _gcry_mpi_set_buffer (a, hash_d, b, 0); |
629 | 0 | xfree (hash_d); |
630 | | /* log_printmpi ("ecgen a", a); */ |
631 | | |
632 | | /* Compute Q. */ |
633 | 0 | point_init (&Q); |
634 | 0 | _gcry_mpi_ec_mul_point (&Q, a, ec->G, ec); |
635 | 0 | if (DBG_CIPHER) |
636 | 0 | log_printpnt ("ecgen pk", &Q, ec); |
637 | |
|
638 | 0 | ec->Q = mpi_point_snatch_set (NULL, Q.x, Q.y, Q.z); |
639 | 0 | Q.x = NULL; |
640 | 0 | Q.y = NULL; |
641 | 0 | Q.x = NULL; |
642 | |
|
643 | 0 | leave: |
644 | 0 | _gcry_mpi_release (a); |
645 | 0 | _gcry_mpi_release (x); |
646 | 0 | _gcry_mpi_release (y); |
647 | 0 | return rc; |
648 | 0 | } |
649 | | |
650 | | |
651 | | /* Compute an EdDSA signature. See: |
652 | | * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja |
653 | | * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security |
654 | | * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89. |
655 | | * Document ID: a1a62a2f76d23f65d622484ddd09caf8. |
656 | | * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. |
657 | | * |
658 | | * Despite that this function requires the specification of a hash |
659 | | * algorithm, we only support what has been specified by the paper. |
660 | | * This may change in the future. |
661 | | * |
662 | | * Return the signature struct (r,s) from the message hash. The caller |
663 | | * must have allocated R_R and S. |
664 | | */ |
665 | | |
666 | | /* String to be used with Ed448 */ |
667 | 0 | #define DOM25519 "SigEd25519 no Ed25519 collisions" |
668 | 0 | #define DOM25519_LEN 32 |
669 | 0 | #define DOM448 "SigEd448" |
670 | 0 | #define DOM448_LEN 8 |
671 | | |
672 | | gpg_err_code_t |
673 | | _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, |
674 | | gcry_mpi_t r_r, gcry_mpi_t s, |
675 | | struct pk_encoding_ctx *ctx) |
676 | 0 | { |
677 | 0 | int rc; |
678 | 0 | unsigned int tmp; |
679 | 0 | unsigned char *digest = NULL; |
680 | 0 | const void *mbuf; |
681 | 0 | size_t mlen; |
682 | 0 | unsigned char *rawmpi = NULL; |
683 | 0 | unsigned int rawmpilen = 0; |
684 | 0 | unsigned char *encpk = NULL; /* Encoded public key. */ |
685 | 0 | unsigned int encpklen = 0; |
686 | 0 | mpi_point_struct I; /* Intermediate value. */ |
687 | 0 | gcry_mpi_t a, x, y, r; |
688 | 0 | const char *dom; |
689 | 0 | int domlen, digestlen; |
690 | 0 | int b, i; |
691 | 0 | unsigned char x_olen[2]; |
692 | 0 | unsigned char prehashed_msg[64]; |
693 | 0 | gcry_buffer_t hvec[6]; |
694 | 0 | gcry_buffer_t hvec2[1]; |
695 | |
|
696 | 0 | b = (ec->nbits+7)/8; |
697 | |
|
698 | 0 | if (ec->nbits == 255) |
699 | 0 | { |
700 | 0 | dom = DOM25519; |
701 | 0 | domlen = DOM25519_LEN; |
702 | 0 | digestlen = 64; |
703 | 0 | } |
704 | 0 | else if (ec->nbits == 448) |
705 | 0 | { |
706 | 0 | b++; |
707 | 0 | dom = DOM448; |
708 | 0 | domlen = DOM448_LEN; |
709 | 0 | digestlen = 2 * b; |
710 | 0 | } |
711 | 0 | else |
712 | 0 | return GPG_ERR_NOT_IMPLEMENTED; |
713 | | |
714 | 0 | if (!mpi_is_opaque (input)) |
715 | 0 | return GPG_ERR_INV_DATA; |
716 | | |
717 | | /* Initialize some helpers. */ |
718 | 0 | point_init (&I); |
719 | 0 | a = mpi_snew (0); |
720 | 0 | x = mpi_new (0); |
721 | 0 | y = mpi_new (0); |
722 | 0 | r = mpi_snew (0); |
723 | |
|
724 | 0 | rc = _gcry_ecc_eddsa_compute_h_d (&digest, ec); |
725 | 0 | if (rc) |
726 | 0 | goto leave; |
727 | 0 | _gcry_mpi_set_buffer (a, digest, b, 0); |
728 | | |
729 | | /* Compute the public key if it's not available (only secret part). */ |
730 | 0 | if (ec->Q == NULL) |
731 | 0 | { |
732 | 0 | mpi_point_struct Q; |
733 | |
|
734 | 0 | point_init (&Q); |
735 | 0 | _gcry_mpi_ec_mul_point (&Q, a, ec->G, ec); |
736 | 0 | ec->Q = mpi_point_snatch_set (NULL, Q.x, Q.y, Q.z); |
737 | 0 | } |
738 | 0 | rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, x, y, 0, &encpk, &encpklen); |
739 | 0 | if (rc) |
740 | 0 | goto leave; |
741 | 0 | if (DBG_CIPHER) |
742 | 0 | log_printhex (" e_pk", encpk, encpklen); |
743 | | |
744 | | /* Compute R. */ |
745 | 0 | mbuf = mpi_get_opaque (input, &tmp); |
746 | 0 | mlen = (tmp +7)/8; |
747 | 0 | if (DBG_CIPHER) |
748 | 0 | log_printhex (" m", mbuf, mlen); |
749 | |
|
750 | 0 | memset (hvec, 0, sizeof hvec); |
751 | 0 | i = 0; |
752 | |
|
753 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) |
754 | 0 | { |
755 | 0 | hvec[i].data = (void *)dom; |
756 | 0 | hvec[i].len = domlen; |
757 | 0 | i++; |
758 | 0 | x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); |
759 | 0 | x_olen[1] = ctx->labellen; |
760 | 0 | hvec[i].data = x_olen; |
761 | 0 | hvec[i].len = 2; |
762 | 0 | i++; |
763 | 0 | if (ctx->labellen) |
764 | 0 | { |
765 | 0 | hvec[i].data = ctx->label; |
766 | 0 | hvec[i].len = ctx->labellen; |
767 | 0 | i++; |
768 | 0 | } |
769 | 0 | } |
770 | |
|
771 | 0 | hvec[i].data = digest; |
772 | 0 | hvec[i].off = b; |
773 | 0 | hvec[i].len = b; |
774 | 0 | i++; |
775 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH)) |
776 | 0 | { |
777 | 0 | memset (hvec2, 0, sizeof hvec2); |
778 | |
|
779 | 0 | hvec2[0].data = (char*)mbuf; |
780 | 0 | hvec2[0].len = mlen; |
781 | |
|
782 | 0 | _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64, |
783 | 0 | hvec2, 1); |
784 | 0 | hvec[i].data = (char*)prehashed_msg; |
785 | 0 | hvec[i].len = 64; |
786 | 0 | } |
787 | 0 | else |
788 | 0 | { |
789 | 0 | hvec[i].data = (char*)mbuf; |
790 | 0 | hvec[i].len = mlen; |
791 | 0 | } |
792 | 0 | i++; |
793 | |
|
794 | 0 | rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, |
795 | 0 | hvec, i); |
796 | 0 | if (rc) |
797 | 0 | goto leave; |
798 | 0 | reverse_buffer (digest, digestlen); |
799 | 0 | if (DBG_CIPHER) |
800 | 0 | log_printhex (" r", digest, digestlen); |
801 | 0 | _gcry_mpi_set_buffer (r, digest, digestlen, 0); |
802 | 0 | mpi_mod (r, r, ec->n); |
803 | 0 | _gcry_mpi_ec_mul_point (&I, r, ec->G, ec); |
804 | 0 | if (DBG_CIPHER) |
805 | 0 | log_printpnt (" r", &I, ec); |
806 | | |
807 | | /* Convert R into affine coordinates and apply encoding. */ |
808 | 0 | rc = _gcry_ecc_eddsa_encodepoint (&I, ec, x, y, 0, &rawmpi, &rawmpilen); |
809 | 0 | if (rc) |
810 | 0 | goto leave; |
811 | 0 | if (DBG_CIPHER) |
812 | 0 | log_printhex (" e_r", rawmpi, rawmpilen); |
813 | |
|
814 | 0 | memset (hvec, 0, sizeof hvec); |
815 | 0 | i = 0; |
816 | |
|
817 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) |
818 | 0 | { |
819 | 0 | hvec[i].data = (void *)dom; |
820 | 0 | hvec[i].len = domlen; |
821 | 0 | i++; |
822 | 0 | x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); |
823 | 0 | x_olen[1] = ctx->labellen; |
824 | 0 | hvec[i].data = x_olen; |
825 | 0 | hvec[i].len = 2; |
826 | 0 | i++; |
827 | 0 | if (ctx->labellen) |
828 | 0 | { |
829 | 0 | hvec[i].data = ctx->label; |
830 | 0 | hvec[i].len = ctx->labellen; |
831 | 0 | i++; |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | | /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */ |
836 | 0 | hvec[i].data = rawmpi; /* (this is R) */ |
837 | 0 | hvec[i].len = rawmpilen; |
838 | 0 | i++; |
839 | 0 | hvec[i].data = encpk; |
840 | 0 | hvec[i].len = encpklen; |
841 | 0 | i++; |
842 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH)) |
843 | 0 | { |
844 | 0 | hvec[i].data = (char*)prehashed_msg; |
845 | 0 | hvec[i].len = 64; |
846 | 0 | } |
847 | 0 | else |
848 | 0 | { |
849 | 0 | hvec[i].data = (char*)mbuf; |
850 | 0 | hvec[i].len = mlen; |
851 | 0 | } |
852 | 0 | i++; |
853 | |
|
854 | 0 | rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, |
855 | 0 | hvec, i); |
856 | 0 | if (rc) |
857 | 0 | goto leave; |
858 | | |
859 | | /* No more need for RAWMPI thus we now transfer it to R_R. */ |
860 | 0 | mpi_set_opaque (r_r, rawmpi, rawmpilen*8); |
861 | 0 | rawmpi = NULL; |
862 | |
|
863 | 0 | reverse_buffer (digest, digestlen); |
864 | 0 | if (DBG_CIPHER) |
865 | 0 | log_printhex (" H(R+)", digest, digestlen); |
866 | 0 | _gcry_mpi_set_buffer (s, digest, digestlen, 0); |
867 | 0 | mpi_mulm (s, s, a, ec->n); |
868 | 0 | mpi_addm (s, s, r, ec->n); |
869 | 0 | rc = eddsa_encodempi (s, ec->nbits, &rawmpi, &rawmpilen); |
870 | 0 | if (rc) |
871 | 0 | goto leave; |
872 | 0 | if (DBG_CIPHER) |
873 | 0 | log_printhex (" e_s", rawmpi, rawmpilen); |
874 | 0 | mpi_set_opaque (s, rawmpi, rawmpilen*8); |
875 | 0 | rawmpi = NULL; |
876 | |
|
877 | 0 | rc = 0; |
878 | |
|
879 | 0 | leave: |
880 | 0 | _gcry_mpi_release (a); |
881 | 0 | _gcry_mpi_release (x); |
882 | 0 | _gcry_mpi_release (y); |
883 | 0 | _gcry_mpi_release (r); |
884 | 0 | xfree (digest); |
885 | 0 | point_free (&I); |
886 | 0 | xfree (encpk); |
887 | 0 | xfree (rawmpi); |
888 | 0 | return rc; |
889 | 0 | } |
890 | | |
891 | | |
892 | | /* Verify an EdDSA signature. See sign_eddsa for the reference. |
893 | | * Check if R_IN and S_IN verifies INPUT. |
894 | | */ |
895 | | gpg_err_code_t |
896 | | _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec, |
897 | | gcry_mpi_t r_in, gcry_mpi_t s_in, |
898 | | struct pk_encoding_ctx *ctx) |
899 | 0 | { |
900 | 0 | int rc; |
901 | 0 | int b; |
902 | 0 | unsigned int tmp; |
903 | 0 | unsigned char *encpk = NULL; /* Encoded public key. */ |
904 | 0 | unsigned int encpklen = 0; |
905 | 0 | const void *mbuf, *rbuf; |
906 | 0 | unsigned char *tbuf = NULL; |
907 | 0 | size_t mlen, rlen; |
908 | 0 | unsigned int tlen; |
909 | 0 | unsigned char digest[114]; |
910 | 0 | gcry_mpi_t h, s; |
911 | 0 | mpi_point_struct Ia, Ib; |
912 | 0 | const char *dom; |
913 | 0 | int domlen, digestlen; |
914 | 0 | int i; |
915 | 0 | unsigned char x_olen[2]; |
916 | 0 | unsigned char prehashed_msg[64]; |
917 | 0 | gcry_buffer_t hvec[6]; |
918 | 0 | gcry_buffer_t hvec2[1]; |
919 | |
|
920 | 0 | if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) |
921 | 0 | return GPG_ERR_INV_DATA; |
922 | | |
923 | 0 | b = (ec->nbits+7)/8; |
924 | |
|
925 | 0 | if (ec->nbits == 255) |
926 | 0 | { |
927 | 0 | dom = DOM25519; |
928 | 0 | domlen = DOM25519_LEN; |
929 | 0 | digestlen = 64; |
930 | 0 | } |
931 | 0 | else if (ec->nbits == 448) |
932 | 0 | { |
933 | 0 | b++; |
934 | 0 | dom = DOM448; |
935 | 0 | domlen = DOM448_LEN; |
936 | 0 | digestlen = 2 * b; |
937 | 0 | } |
938 | 0 | else |
939 | 0 | return GPG_ERR_NOT_IMPLEMENTED; |
940 | | |
941 | 0 | point_init (&Ia); |
942 | 0 | point_init (&Ib); |
943 | 0 | h = mpi_new (0); |
944 | 0 | s = mpi_new (0); |
945 | | |
946 | | /* Encode and check the public key. */ |
947 | 0 | rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, |
948 | 0 | &encpk, &encpklen); |
949 | 0 | if (rc) |
950 | 0 | goto leave; |
951 | 0 | if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) |
952 | 0 | { |
953 | 0 | rc = GPG_ERR_BROKEN_PUBKEY; |
954 | 0 | goto leave; |
955 | 0 | } |
956 | 0 | if (DBG_CIPHER) |
957 | 0 | log_printhex (" e_pk", encpk, encpklen); |
958 | 0 | if (encpklen != b) |
959 | 0 | { |
960 | 0 | rc = GPG_ERR_INV_LENGTH; |
961 | 0 | goto leave; |
962 | 0 | } |
963 | | |
964 | | /* Convert the other input parameters. */ |
965 | 0 | mbuf = mpi_get_opaque (input, &tmp); |
966 | 0 | mlen = (tmp +7)/8; |
967 | 0 | if (DBG_CIPHER) |
968 | 0 | log_printhex (" m", mbuf, mlen); |
969 | 0 | rbuf = mpi_get_opaque (r_in, &tmp); |
970 | 0 | rlen = (tmp +7)/8; |
971 | 0 | if (DBG_CIPHER) |
972 | 0 | log_printhex (" r", rbuf, rlen); |
973 | 0 | if (rlen != b) |
974 | 0 | { |
975 | 0 | rc = GPG_ERR_INV_LENGTH; |
976 | 0 | goto leave; |
977 | 0 | } |
978 | | |
979 | 0 | memset (hvec, 0, sizeof hvec); |
980 | 0 | i = 0; |
981 | | |
982 | | /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */ |
983 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) |
984 | 0 | { |
985 | 0 | hvec[i].data = (void *)dom; |
986 | 0 | hvec[i].len = domlen; |
987 | 0 | i++; |
988 | 0 | x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); |
989 | 0 | x_olen[1] = ctx->labellen; |
990 | 0 | hvec[i].data = x_olen; |
991 | 0 | hvec[i].len = 2; |
992 | 0 | i++; |
993 | 0 | if (ctx->labellen) |
994 | 0 | { |
995 | 0 | hvec[i].data = ctx->label; |
996 | 0 | hvec[i].len = ctx->labellen; |
997 | 0 | i++; |
998 | 0 | } |
999 | 0 | } |
1000 | |
|
1001 | 0 | hvec[i].data = (char*)rbuf; |
1002 | 0 | hvec[i].len = rlen; |
1003 | 0 | i++; |
1004 | 0 | hvec[i].data = encpk; |
1005 | 0 | hvec[i].len = encpklen; |
1006 | 0 | i++; |
1007 | 0 | if ((ctx->flags & PUBKEY_FLAG_PREHASH)) |
1008 | 0 | { |
1009 | 0 | memset (hvec2, 0, sizeof hvec2); |
1010 | |
|
1011 | 0 | hvec2[0].data = (char*)mbuf; |
1012 | 0 | hvec2[0].len = mlen; |
1013 | |
|
1014 | 0 | _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64, |
1015 | 0 | hvec2, 1); |
1016 | 0 | hvec[i].data = (char*)prehashed_msg; |
1017 | 0 | hvec[i].len = 64; |
1018 | 0 | } |
1019 | 0 | else |
1020 | 0 | { |
1021 | 0 | hvec[i].data = (char*)mbuf; |
1022 | 0 | hvec[i].len = mlen; |
1023 | 0 | } |
1024 | 0 | i++; |
1025 | |
|
1026 | 0 | rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, |
1027 | 0 | hvec, i); |
1028 | 0 | if (rc) |
1029 | 0 | goto leave; |
1030 | 0 | reverse_buffer (digest, digestlen); |
1031 | 0 | if (DBG_CIPHER) |
1032 | 0 | log_printhex (" H(R+)", digest, digestlen); |
1033 | 0 | _gcry_mpi_set_buffer (h, digest, digestlen, 0); |
1034 | | |
1035 | | /* According to the paper the best way for verification is: |
1036 | | encodepoint(sG - h·Q) = encodepoint(r) |
1037 | | because we don't need to decode R. */ |
1038 | 0 | { |
1039 | 0 | void *sbuf; |
1040 | 0 | unsigned int slen; |
1041 | |
|
1042 | 0 | sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp); |
1043 | 0 | slen = (tmp +7)/8; |
1044 | 0 | reverse_buffer (sbuf, slen); |
1045 | 0 | if (DBG_CIPHER) |
1046 | 0 | log_printhex (" s", sbuf, slen); |
1047 | 0 | _gcry_mpi_set_buffer (s, sbuf, slen, 0); |
1048 | 0 | xfree (sbuf); |
1049 | 0 | if (slen != b) |
1050 | 0 | { |
1051 | 0 | rc = GPG_ERR_INV_LENGTH; |
1052 | 0 | goto leave; |
1053 | 0 | } |
1054 | 0 | } |
1055 | | |
1056 | 0 | _gcry_mpi_ec_mul_point (&Ia, s, ec->G, ec); |
1057 | 0 | _gcry_mpi_ec_mul_point (&Ib, h, ec->Q, ec); |
1058 | 0 | _gcry_mpi_sub (Ib.x, ec->p, Ib.x); |
1059 | 0 | _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ec); |
1060 | 0 | rc = _gcry_ecc_eddsa_encodepoint (&Ia, ec, s, h, 0, &tbuf, &tlen); |
1061 | 0 | if (rc) |
1062 | 0 | goto leave; |
1063 | 0 | if (tlen != rlen || memcmp (tbuf, rbuf, tlen)) |
1064 | 0 | { |
1065 | 0 | rc = GPG_ERR_BAD_SIGNATURE; |
1066 | 0 | goto leave; |
1067 | 0 | } |
1068 | | |
1069 | 0 | rc = 0; |
1070 | |
|
1071 | 0 | leave: |
1072 | 0 | xfree (encpk); |
1073 | 0 | xfree (tbuf); |
1074 | 0 | _gcry_mpi_release (s); |
1075 | 0 | _gcry_mpi_release (h); |
1076 | 0 | point_free (&Ia); |
1077 | 0 | point_free (&Ib); |
1078 | 0 | return rc; |
1079 | 0 | } |