Coverage Report

Created: 2022-12-08 06:09

/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
}