Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/cipher/ecc-ecdh.c
Line
Count
Source (jump to first uncovered line)
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
21
#include <config.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <errno.h>
26
27
#include "g10lib.h"
28
#include "mpi.h"
29
#include "cipher.h"
30
#include "context.h"
31
#include "ec-context.h"
32
#include "ecc-common.h"
33
34
0
#define ECC_CURVE25519_BYTES 32
35
0
#define ECC_CURVE448_BYTES   56
36
37
static gpg_err_code_t
38
prepare_ec (mpi_ec_t *r_ec, const char *name)
39
0
{
40
0
  int flags = 0;
41
42
0
  if (!strcmp (name, "Curve25519"))
43
0
    flags = PUBKEY_FLAG_DJB_TWEAK;
44
45
0
  return _gcry_mpi_ec_internal_new (r_ec, &flags, "ecc_mul_point", NULL, name);
46
0
}
47
48
unsigned int
49
_gcry_ecc_get_algo_keylen (int curveid)
50
0
{
51
0
  unsigned int len = 0;
52
53
0
  if (curveid == GCRY_ECC_CURVE25519)
54
0
    len = ECC_CURVE25519_BYTES;
55
0
  else if (curveid == GCRY_ECC_CURVE448)
56
0
    len = ECC_CURVE448_BYTES;
57
58
0
  return len;
59
0
}
60
61
/* For Curve25519 and X448, we need to mask the bits and enable the MSB.  */
62
static void
63
ecc_tweak_bits (unsigned char *seckey, size_t seckey_len)
64
0
{
65
0
  if (seckey_len == 32)
66
0
    {
67
0
      seckey[0] &= 0xf8;
68
0
      seckey[31] &= 0x7f;
69
0
      seckey[31] |= 0x40;
70
0
    }
71
0
  else
72
0
    {
73
0
      seckey[0] &= 0xfc;
74
0
      seckey[55] |= 0x80;
75
0
    }
76
0
}
77
78
gpg_err_code_t
79
_gcry_ecc_curve_keypair (const char *curve,
80
                         unsigned char *pubkey, size_t pubkey_len,
81
                         unsigned char *seckey, size_t seckey_len)
82
0
{
83
0
  gpg_err_code_t err;
84
0
  unsigned int nbits;
85
0
  unsigned int nbytes;
86
0
  gcry_mpi_t mpi_k = NULL;
87
0
  mpi_ec_t ec = NULL;
88
0
  mpi_point_struct Q = { NULL, NULL, NULL };
89
0
  gcry_mpi_t x;
90
0
  unsigned int len;
91
0
  unsigned char *buf;
92
93
0
  err = prepare_ec (&ec, curve);
94
0
  if (err)
95
0
    return err;
96
97
0
  nbits = ec->nbits;
98
0
  nbytes = (nbits + 7)/8;
99
100
0
  if (seckey_len != nbytes)
101
0
    return GPG_ERR_INV_ARG;
102
103
0
  if (ec->model == MPI_EC_WEIERSTRASS)
104
0
    {
105
0
      if (pubkey_len != 1 + 2*nbytes)
106
0
        return GPG_ERR_INV_ARG;
107
108
0
      do
109
0
        {
110
0
          mpi_free (mpi_k);
111
0
          mpi_k = mpi_new (nbytes*8);
112
0
          _gcry_randomize (seckey, nbytes, GCRY_STRONG_RANDOM);
113
0
          _gcry_mpi_set_buffer (mpi_k, seckey, nbytes, 0);
114
0
        }
115
0
      while (mpi_cmp (mpi_k, ec->n) >= 0);
116
0
    }
117
0
  else if (ec->model == MPI_EC_MONTGOMERY)
118
0
    {
119
0
      if (pubkey_len != nbytes)
120
0
        return GPG_ERR_INV_ARG;
121
122
0
      _gcry_randomize (seckey, nbytes, GCRY_STRONG_RANDOM);
123
      /* Existing ECC applications with libgcrypt (like gpg-agent in
124
         GnuPG) assumes that scalar is tweaked at key generation time.
125
         For the possible use case where generated key with this routine
126
         may be used with those, we put compatibile behavior here.  */
127
0
      ecc_tweak_bits (seckey, nbytes);
128
0
      mpi_k = _gcry_mpi_set_opaque_copy (NULL, seckey, nbytes*8);
129
0
    }
130
0
  else
131
0
    return GPG_ERR_UNKNOWN_CURVE;
132
133
0
  x = mpi_new (nbits);
134
0
  point_init (&Q);
135
136
0
  _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec);
137
138
0
  if (ec->model == MPI_EC_WEIERSTRASS)
139
0
    {
140
0
      gcry_mpi_t y = mpi_new (nbits);
141
0
      gcry_mpi_t negative = mpi_new (nbits);
142
143
0
      _gcry_mpi_ec_get_affine (x, y, &Q, ec);
144
      /* For the backward compatibility, we check if it's a
145
         "compliant key".  */
146
147
0
      mpi_sub (negative, ec->p, y);
148
0
      if (mpi_cmp (negative, y) < 0)   /* p - y < p */
149
0
        {
150
0
          mpi_free (y);
151
0
          y = negative;
152
0
          mpi_sub (mpi_k, ec->n, mpi_k);
153
0
          buf = _gcry_mpi_get_buffer (mpi_k, 0, &len, NULL);
154
0
          memset (seckey, 0, nbytes - len);
155
0
          memcpy (seckey + nbytes - len, buf, len);
156
0
          xfree (buf);
157
0
        }
158
0
      else /* p - y >= p */
159
0
        mpi_free (negative);
160
161
0
      buf = _gcry_ecc_ec2os_buf (x, y, ec->p, &len);
162
0
      if (!buf)
163
0
        {
164
0
          err = gpg_err_code_from_syserror ();
165
0
          mpi_free (y);
166
0
        }
167
0
      else
168
0
        {
169
0
          if (len != 1 + 2*nbytes)
170
0
            {
171
0
              err = GPG_ERR_INV_ARG;
172
0
            }
173
0
          else
174
0
            {
175
              /* (x,y) in SEC1 point encoding.  */
176
0
              memcpy (pubkey, buf, len);
177
0
            }
178
0
          xfree (buf);
179
0
          mpi_free (y);
180
0
        }
181
0
    }
182
0
  else /* MPI_EC_MONTGOMERY */
183
0
    {
184
0
      _gcry_mpi_ec_get_affine (x, NULL, &Q, ec);
185
186
0
      buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL);
187
0
      if (!buf)
188
0
        err = gpg_err_code_from_syserror ();
189
0
      else
190
0
        {
191
0
          memcpy (pubkey, buf, nbytes);
192
0
          xfree (buf);
193
0
        }
194
0
    }
195
196
0
  mpi_free (x);
197
0
  point_free (&Q);
198
0
  mpi_free (mpi_k);
199
0
  _gcry_mpi_ec_free (ec);
200
0
  return err;
201
0
}
202
203
gpg_err_code_t
204
_gcry_ecc_curve_mul_point (const char *curve,
205
                           unsigned char *result, size_t result_len,
206
                           const unsigned char *scalar, size_t scalar_len,
207
                           const unsigned char *point, size_t point_len)
208
0
{
209
0
  unsigned int nbits;
210
0
  unsigned int nbytes;
211
0
  gpg_err_code_t err;
212
0
  gcry_mpi_t mpi_k = NULL;
213
0
  mpi_ec_t ec = NULL;
214
0
  mpi_point_struct Q = { NULL, NULL, NULL };
215
0
  gcry_mpi_t x = NULL;
216
0
  unsigned int len;
217
0
  unsigned char *buf;
218
219
0
  err = prepare_ec (&ec, curve);
220
0
  if (err)
221
0
    return err;
222
223
0
  nbits = ec->nbits;
224
0
  nbytes = (nbits + 7)/8;
225
226
0
  if (ec->model == MPI_EC_WEIERSTRASS)
227
0
    {
228
0
      if (scalar_len != nbytes
229
0
          || result_len != 1 + 2*nbytes
230
0
          || point_len != 1 + 2*nbytes)
231
0
        {
232
0
          err = GPG_ERR_INV_ARG;
233
0
          goto leave;
234
0
        }
235
236
0
      mpi_k = mpi_new (nbytes*8);
237
0
      _gcry_mpi_set_buffer (mpi_k, scalar, nbytes, 0);
238
0
    }
239
0
  else if (ec->model == MPI_EC_MONTGOMERY)
240
0
    {
241
0
      if (scalar_len != nbytes
242
0
          || result_len != nbytes
243
0
          || point_len != nbytes)
244
0
        {
245
0
          err = GPG_ERR_INV_ARG;
246
0
          goto leave;
247
0
        }
248
249
0
      mpi_k = _gcry_mpi_set_opaque_copy (NULL, scalar, nbytes*8);
250
0
    }
251
0
  else
252
0
    {
253
0
      err = GPG_ERR_UNKNOWN_CURVE;
254
0
      goto leave;
255
0
    }
256
257
0
  point_init (&Q);
258
259
0
  if (point)
260
0
    {
261
0
      gcry_mpi_t mpi_u = _gcry_mpi_set_opaque_copy (NULL, point, point_len*8);
262
0
      mpi_point_struct P;
263
264
0
      point_init (&P);
265
0
      if (ec->model == MPI_EC_WEIERSTRASS)
266
0
        err = _gcry_ecc_sec_decodepoint (mpi_u, ec, &P);
267
0
      else /* MPI_EC_MONTGOMERY */
268
0
        err = _gcry_ecc_mont_decodepoint (mpi_u, ec, &P);
269
0
      mpi_free (mpi_u);
270
0
      if (err)
271
0
        goto leave;
272
0
      _gcry_mpi_ec_mul_point (&Q, mpi_k, &P, ec);
273
0
      point_free (&P);
274
0
    }
275
0
  else
276
0
    _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec);
277
278
0
  x = mpi_new (nbits);
279
0
  if (ec->model == MPI_EC_WEIERSTRASS)
280
0
    {
281
0
      gcry_mpi_t y = mpi_new (nbits);
282
283
0
      _gcry_mpi_ec_get_affine (x, y, &Q, ec);
284
285
0
      buf = _gcry_ecc_ec2os_buf (x, y, ec->p, &len);
286
0
      if (!buf)
287
0
        {
288
0
          err = gpg_err_code_from_syserror ();
289
0
          mpi_free (y);
290
0
        }
291
0
      else
292
0
        {
293
0
          if (len != 1 + 2*nbytes)
294
0
            {
295
0
              err = GPG_ERR_INV_ARG;
296
0
            }
297
0
          else
298
0
            {
299
              /* (x,y) in SEC1 point encoding.  */
300
0
              memcpy (result, buf, len);
301
0
            }
302
0
          xfree (buf);
303
0
          mpi_free (y);
304
0
        }
305
0
    }
306
0
  else                          /* MPI_EC_MONTGOMERY */
307
0
    {
308
0
      _gcry_mpi_ec_get_affine (x, NULL, &Q, ec);
309
0
      buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL);
310
0
      if (!buf)
311
0
        err = gpg_err_code_from_syserror ();
312
0
      else
313
0
        {
314
0
          if (len != nbytes)
315
0
            err = GPG_ERR_INV_ARG;
316
0
          else
317
0
            {
318
              /* x in little endian.  */
319
0
              memcpy (result, buf, nbytes);
320
0
            }
321
0
          xfree (buf);
322
0
        }
323
0
    }
324
0
  mpi_free (x);
325
326
0
 leave:
327
0
  point_free (&Q);
328
0
  mpi_free (mpi_k);
329
0
  _gcry_mpi_ec_free (ec);
330
0
  return err;
331
0
}
332
333
gpg_err_code_t
334
_gcry_ecc_mul_point (int curveid, unsigned char *result,
335
                     const unsigned char *scalar, const unsigned char *point)
336
0
{
337
0
  const char *curve;
338
0
  size_t pubkey_len, seckey_len;
339
340
0
  if (curveid == GCRY_ECC_CURVE25519)
341
0
    {
342
0
      curve = "Curve25519";
343
0
      pubkey_len = seckey_len = 32;
344
0
    }
345
0
  else if (curveid == GCRY_ECC_CURVE448)
346
0
    {
347
0
      curve = "X448";
348
0
      pubkey_len = seckey_len = 56;
349
0
    }
350
0
  else
351
0
    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
352
353
0
  return _gcry_ecc_curve_mul_point (curve, result, pubkey_len,
354
0
                                    scalar, seckey_len,
355
0
                                    point, pubkey_len);
356
0
}