Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/cipher/kem.c
Line
Count
Source (jump to first uncovered line)
1
/* kem.c  - Key Encapsulation Mechanisms
2
 * Copyright (C) 2023 Simon Josefsson <simon@josefsson.org>
3
 * Copyright (C) 2023 g10 Code GmbH
4
 *
5
 * This file is part of Libgcrypt.
6
 *
7
 * Libgcrypt is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation; either version 2.1 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * Libgcrypt is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
19
 * SPDX-License-Identifier: LGPL-2.1-or-later
20
 */
21
22
#include <config.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <errno.h>
27
28
#include "g10lib.h"
29
#include "cipher.h"
30
#include "sntrup761.h"
31
#include "mceliece6688128f.h"
32
#include "kyber.h"
33
#include "kem-ecc.h"
34
35
36
/* Information about the the KEM algoithms for use by the s-expression
37
 * interface.  */
38
static const struct
39
{
40
  const char *name;           /* Name of the algo.  */
41
  unsigned int namelen;       /* Only here to avoid strlen calls.  */
42
  int algo;                   /* KEM algo number.   */
43
  unsigned int nbits;         /* Number of bits.    */
44
  unsigned int fips:1;        /* True if this is a FIPS140-3 approved KEM. */
45
  int pubkey_len;             /* Length of the public key.  */
46
  int seckey_len;             /* Length of the secret key.  */
47
} kem_infos[] =
48
  {
49
    { "sntrup761", 9, GCRY_KEM_SNTRUP761,  761, 0,
50
      GCRY_KEM_SNTRUP761_PUBKEY_LEN, GCRY_KEM_SNTRUP761_SECKEY_LEN },
51
    { "kyber512",  8, GCRY_KEM_MLKEM512,   512, 0,
52
      GCRY_KEM_MLKEM512_PUBKEY_LEN,  GCRY_KEM_MLKEM512_SECKEY_LEN },
53
    { "kyber768",  8, GCRY_KEM_MLKEM768,   768, 1,
54
      GCRY_KEM_MLKEM768_PUBKEY_LEN,  GCRY_KEM_MLKEM768_SECKEY_LEN },
55
    { "kyber1024", 9, GCRY_KEM_MLKEM1024, 1024, 1,
56
      GCRY_KEM_MLKEM1024_PUBKEY_LEN, GCRY_KEM_MLKEM1024_SECKEY_LEN },
57
    { NULL }
58
  };
59
60
/* This is a short version of kem_infos from above.  It is required
61
 * for the algoithm module interface.  Keep in sync.  */
62
static const char *kem_names[] =
63
  {
64
    "sntrup761",
65
    "kyber512",
66
    "kyber768",
67
    "kyber1024",
68
    NULL
69
  };
70
71
72
73

74
/* Helper for sntrup761.  */
75
static void
76
sntrup761_random (void *ctx, size_t length, uint8_t *dst)
77
0
{
78
0
  (void)ctx;
79
80
0
  _gcry_randomize (dst, length, GCRY_STRONG_RANDOM);
81
0
}
82
83
84
gcry_err_code_t
85
_gcry_kem_genkey (int algo,
86
                   void *pubkey, size_t pubkey_len,
87
                   void *seckey, size_t seckey_len,
88
                   const void *optional, size_t optional_len)
89
0
{
90
0
  switch (algo)
91
0
    {
92
0
    case GCRY_KEM_SNTRUP761:
93
0
      if (seckey_len != GCRY_KEM_SNTRUP761_SECKEY_LEN
94
0
          || pubkey_len != GCRY_KEM_SNTRUP761_PUBKEY_LEN)
95
0
        return GPG_ERR_INV_ARG;
96
0
      sntrup761_keypair (pubkey, seckey, NULL, sntrup761_random);
97
0
      return 0;
98
99
0
    case GCRY_KEM_CM6688128F:
100
0
      mceliece6688128f_keypair (pubkey, seckey);
101
0
      return 0;
102
103
0
    case GCRY_KEM_MLKEM512:
104
0
      if (seckey_len != GCRY_KEM_MLKEM512_SECKEY_LEN
105
0
          || pubkey_len != GCRY_KEM_MLKEM512_PUBKEY_LEN
106
0
          || (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
107
0
        return GPG_ERR_INV_ARG;
108
0
      kyber_keypair (algo, pubkey, seckey, optional);
109
0
      return 0;
110
111
0
    case GCRY_KEM_MLKEM768:
112
0
      if (seckey_len != GCRY_KEM_MLKEM768_SECKEY_LEN
113
0
          || pubkey_len != GCRY_KEM_MLKEM768_PUBKEY_LEN
114
0
          || (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
115
0
        return GPG_ERR_INV_ARG;
116
0
      kyber_keypair (algo, pubkey, seckey, optional);
117
0
      return 0;
118
119
0
    case GCRY_KEM_MLKEM1024:
120
0
      if (seckey_len != GCRY_KEM_MLKEM1024_SECKEY_LEN
121
0
          || pubkey_len != GCRY_KEM_MLKEM1024_PUBKEY_LEN
122
0
          || (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
123
0
        return GPG_ERR_INV_ARG;
124
0
      kyber_keypair (algo, pubkey, seckey, optional);
125
0
      return 0;
126
127
0
    case GCRY_KEM_RAW_X25519:
128
0
    case GCRY_KEM_RAW_X448:
129
0
    case GCRY_KEM_RAW_BP256:
130
0
    case GCRY_KEM_RAW_BP384:
131
0
    case GCRY_KEM_RAW_BP512:
132
0
    case GCRY_KEM_RAW_P256R1:
133
0
    case GCRY_KEM_RAW_P384R1:
134
0
    case GCRY_KEM_RAW_P521R1:
135
0
    case GCRY_KEM_DHKEM25519:
136
0
    case GCRY_KEM_DHKEM448:
137
0
      return _gcry_ecc_raw_keypair (algo, pubkey, pubkey_len,
138
0
                                    seckey, seckey_len);
139
140
0
    default:
141
0
      return GPG_ERR_UNKNOWN_ALGORITHM;
142
0
    }
143
144
0
  return GPG_ERR_UNKNOWN_ALGORITHM;
145
0
}
146
147
148
gcry_err_code_t
149
_gcry_kem_encap (int algo,
150
                 const void *pubkey, size_t pubkey_len,
151
                 void *ciphertext, size_t ciphertext_len,
152
                 void *shared, size_t shared_len,
153
                 const void *optional, size_t optional_len)
154
0
{
155
0
  switch (algo)
156
0
    {
157
0
    case GCRY_KEM_SNTRUP761:
158
0
      if (optional != NULL || optional_len != 0)
159
0
        return GPG_ERR_INV_VALUE;
160
0
      if (pubkey_len != GCRY_KEM_SNTRUP761_PUBKEY_LEN
161
0
          || ciphertext_len != GCRY_KEM_SNTRUP761_ENCAPS_LEN
162
0
          || shared_len != GCRY_KEM_SNTRUP761_SHARED_LEN)
163
0
        return GPG_ERR_INV_VALUE;
164
0
      sntrup761_enc (ciphertext, shared, pubkey, NULL, sntrup761_random);
165
0
      return 0;
166
167
0
    case GCRY_KEM_CM6688128F:
168
0
      if (optional != NULL)
169
0
  return GPG_ERR_INV_VALUE;
170
0
      mceliece6688128f_enc (ciphertext, shared, pubkey);
171
0
      return 0;
172
173
0
    case GCRY_KEM_MLKEM512:
174
0
    case GCRY_KEM_MLKEM768:
175
0
    case GCRY_KEM_MLKEM1024:
176
0
      if (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN)
177
0
  return GPG_ERR_INV_VALUE;
178
0
      kyber_encap (algo, ciphertext, shared, pubkey, optional);
179
0
      return 0;
180
181
0
    case GCRY_KEM_RAW_X25519:
182
0
    case GCRY_KEM_RAW_X448:
183
0
    case GCRY_KEM_RAW_BP256:
184
0
    case GCRY_KEM_RAW_BP384:
185
0
    case GCRY_KEM_RAW_BP512:
186
0
    case GCRY_KEM_RAW_P256R1:
187
0
    case GCRY_KEM_RAW_P384R1:
188
0
    case GCRY_KEM_RAW_P521R1:
189
0
      if (optional != NULL)
190
0
        return GPG_ERR_INV_VALUE;
191
0
      return _gcry_ecc_raw_encap (algo, pubkey, pubkey_len,
192
0
                                  ciphertext, ciphertext_len,
193
0
                                  shared, shared_len);
194
195
0
    case GCRY_KEM_DHKEM25519:
196
0
    case GCRY_KEM_DHKEM448:
197
0
      if (optional != NULL)
198
0
        return GPG_ERR_INV_VALUE;
199
0
      return _gcry_ecc_dhkem_encap (algo, pubkey, ciphertext, shared);
200
201
0
    default:
202
0
      return GPG_ERR_UNKNOWN_ALGORITHM;
203
0
    }
204
0
  return GPG_ERR_UNKNOWN_ALGORITHM;
205
0
}
206
207
208
gcry_err_code_t
209
_gcry_kem_decap (int algo,
210
                 const void *seckey, size_t seckey_len,
211
                 const void *ciphertext, size_t ciphertext_len,
212
                 void *shared, size_t shared_len,
213
                 const void *optional, size_t optional_len)
214
0
{
215
0
  switch (algo)
216
0
    {
217
0
    case GCRY_KEM_SNTRUP761:
218
0
      if (optional != NULL || optional_len != 0)
219
0
        return GPG_ERR_INV_VALUE;
220
0
      if (seckey_len != GCRY_KEM_SNTRUP761_SECKEY_LEN
221
0
          || ciphertext_len != GCRY_KEM_SNTRUP761_ENCAPS_LEN
222
0
          || shared_len != GCRY_KEM_SNTRUP761_SHARED_LEN)
223
0
        return GPG_ERR_INV_VALUE;
224
0
      sntrup761_dec (shared, ciphertext, seckey);
225
0
      return 0;
226
227
0
    case GCRY_KEM_CM6688128F:
228
0
      if (optional != NULL)
229
0
  return GPG_ERR_INV_VALUE;
230
0
      mceliece6688128f_dec (shared, ciphertext, seckey);
231
0
      return 0;
232
233
0
    case GCRY_KEM_MLKEM512:
234
0
    case GCRY_KEM_MLKEM768:
235
0
    case GCRY_KEM_MLKEM1024:
236
0
      if (optional != NULL)
237
0
        return GPG_ERR_INV_VALUE;
238
0
      kyber_decap (algo, shared, ciphertext, seckey);
239
0
      return 0;
240
241
0
    case GCRY_KEM_RAW_X25519:
242
0
    case GCRY_KEM_RAW_X448:
243
0
    case GCRY_KEM_RAW_BP256:
244
0
    case GCRY_KEM_RAW_BP384:
245
0
    case GCRY_KEM_RAW_BP512:
246
0
    case GCRY_KEM_RAW_P256R1:
247
0
    case GCRY_KEM_RAW_P384R1:
248
0
    case GCRY_KEM_RAW_P521R1:
249
0
      if (optional != NULL)
250
0
        return GPG_ERR_INV_VALUE;
251
0
      return _gcry_ecc_raw_decap (algo, seckey, seckey_len,
252
0
                                  ciphertext, ciphertext_len,
253
0
                                  shared, shared_len);
254
255
0
    case GCRY_KEM_DHKEM25519:
256
0
    case GCRY_KEM_DHKEM448:
257
0
      return _gcry_ecc_dhkem_decap (algo, seckey, ciphertext, shared,
258
0
                                    optional);
259
260
0
    default:
261
0
      return GPG_ERR_UNKNOWN_ALGORITHM;
262
0
    }
263
0
  return GPG_ERR_UNKNOWN_ALGORITHM;
264
0
}
265
266
267
268
/* Generate a KEM keypair using the s-expression interface.  The
269
 * GENPARAMS is prety simple in this case because it has only the
270
 * algorithm name.  For example:
271
 *   (kyber768)
272
 */
273
static gcry_err_code_t
274
kem_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
275
0
{
276
0
  gpg_err_code_t ec;
277
0
  const char *algo;
278
0
  size_t algolen;
279
0
  const char *name;
280
0
  int i;
281
0
  int algoid;
282
0
  void *pubkey = NULL;
283
0
  void *seckey = NULL;
284
0
  size_t pubkey_len, seckey_len;
285
286
0
  algo = sexp_nth_data (genparms, 0, &algolen);
287
0
  if (!algo || !algolen)
288
0
    return GPG_ERR_PUBKEY_ALGO;
289
0
  for (i=0; (name=kem_infos[i].name); i++)
290
0
    if (kem_infos[i].namelen == algolen && !memcmp (name, algo, algolen))
291
0
      break;
292
0
  if (!name)
293
0
    return GPG_ERR_WRONG_PUBKEY_ALGO;
294
0
  algoid = kem_infos[i].algo;
295
0
  pubkey_len = kem_infos[i].pubkey_len;
296
0
  seckey_len = kem_infos[i].seckey_len;
297
  /* (from here on we can jump to leave for cleanup)  */
298
299
  /* Allocate buffers for the created key.  */
300
0
  seckey = xtrycalloc_secure (1, seckey_len);
301
0
  if (!seckey)
302
0
    {
303
0
      ec = gpg_err_code_from_syserror ();
304
0
      goto leave;
305
0
    }
306
0
  pubkey = xtrycalloc (1, pubkey_len);
307
0
  if (!pubkey)
308
0
    {
309
0
      ec = gpg_err_code_from_syserror ();
310
0
      goto leave;
311
0
    }
312
313
  /* Generate key.  */
314
0
  ec = _gcry_kem_genkey (algoid, pubkey, pubkey_len, seckey, seckey_len,
315
0
                         NULL, 0);
316
0
  if (ec)
317
0
    goto leave;
318
319
  /* Put the key into an s-expression.  */
320
0
  ec = sexp_build (r_skey, NULL,
321
0
                   "(key-data"
322
0
                   " (public-key"
323
0
                   "  (%s(p%b)))"
324
0
                   " (private-key"
325
0
                   "  (%s(p%b)(s%b))))",
326
0
                   name,
327
0
                   (int)pubkey_len, pubkey,
328
0
                   name,
329
0
                   (int)pubkey_len, pubkey,
330
0
                   (int)seckey_len, seckey);
331
332
333
  /* FIXME: Add FIPS selftest.  */
334
335
0
 leave:
336
0
  if (seckey)
337
0
    {
338
0
      wipememory (seckey, seckey_len);
339
0
      xfree (seckey);
340
0
    }
341
0
  xfree (pubkey);
342
0
  return ec;
343
0
}
344
345
346
/* Compute a keygrip.  MD is the hash context which we are going to
347
 * update.  KEYPARAM is an S-expression with the key parameters, this
348
 * is usually a public key but may also be a secret key.  An example
349
 * of such an S-expression is:
350
 *
351
 *     (kyber768
352
 *       (p #4243...#)
353
 *       (s #1718...#))
354
 *
355
 * What we hash is the algorithm name, \x00 and the value of p.
356
 * Including the algorithm name allows us to see a different key
357
 * despite that it uses the same parameters.  Whether this is a good
358
 * decision is not clear - but it should not harm.
359
 */
360
static gpg_err_code_t
361
kem_compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
362
0
{
363
0
  gcry_sexp_t l1;
364
0
  const char *algo, *data;
365
0
  size_t algolen, datalen;
366
0
  const char *name;
367
0
  int i;
368
369
0
  algo = sexp_nth_data (keyparam, 0, &algolen);
370
0
  if (!algo || !algolen)
371
0
    return GPG_ERR_PUBKEY_ALGO;
372
0
  for (i=0; (name=kem_infos[i].name); i++)
373
0
    if (kem_infos[i].namelen == algolen && !memcmp (name, algo, algolen))
374
0
      break;
375
0
  if (!name)
376
0
    return GPG_ERR_WRONG_PUBKEY_ALGO;
377
378
0
  _gcry_md_write (md, name, algolen+1); /* (also hash the nul) */
379
380
0
  l1 = sexp_find_token (keyparam, "p", 1);
381
0
  if (!l1)
382
0
    return GPG_ERR_NO_OBJ;
383
384
0
  data = sexp_nth_data (l1, 1, &datalen);
385
0
  if (!data)
386
0
    {
387
0
      sexp_release (l1);
388
0
      return GPG_ERR_NO_OBJ;
389
0
    }
390
391
0
  _gcry_md_write (md, data, datalen);
392
0
  sexp_release (l1);
393
394
0
  return 0;
395
0
}
396
397
398
/* Return the number of bits for the key described by PARMS.  On error
399
 * 0 is returned. */
400
static unsigned int
401
kem_get_nbits (gcry_sexp_t keyparam)
402
0
{
403
0
  const char *algo;
404
0
  size_t algolen;
405
0
  const char *name;
406
0
  int i;
407
408
0
  algo = sexp_nth_data (keyparam, 0, &algolen);
409
0
  if (!algo || !algolen)
410
0
    return 0;  /* GPG_ERR_PUBKEY_ALGO */
411
0
  for (i=0; (name=kem_infos[i].name); i++)
412
0
    if (kem_infos[i].namelen == algolen && !memcmp (name, algo, algolen))
413
0
      break;
414
0
  if (!name)
415
0
    return 0;  /* GPG_ERR_WRONG_PUBKEY_ALGO */
416
417
0
  return kem_infos[i].nbits;
418
0
}
419
420
421
/* Generic structure to represent some KEM algorithms in our public
422
 * key system.  */
423
gcry_pk_spec_t _gcry_pubkey_spec_kem =
424
  {
425
    GCRY_PK_KEM, { 0, 0 },
426
    GCRY_PK_USAGE_ENCR,
427
    "KEM", kem_names,
428
    "p", "s", "k", "", "p",
429
    kem_generate,
430
    NULL,  /* kem_check_secret_key */
431
    NULL,  /* encrypt_raw - Use gcry_kem_encap instead.  */
432
    NULL,  /* decrypt_raw - Use gcry_kem_decap unstead.  */
433
    NULL,  /* sign */
434
    NULL,  /* verify */
435
    kem_get_nbits,
436
    NULL,  /* selftests */
437
    kem_compute_keygrip,
438
    NULL,  /* get_curve */
439
    NULL   /* get_curve_param */
440
  };