Coverage Report

Created: 2026-10-28 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/kem.c
Line
Count
Source
1
/* kem.c -  KEM helper functions
2
 * Copyright (C) 2024  g10 Code GmbH.
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * GnuPG is free software; you can redistribute and/or modify this
7
 * part of GnuPG under the terms of either
8
 *
9
 *   - the GNU Lesser General Public License as published by the Free
10
 *     Software Foundation; either version 3 of the License, or (at
11
 *     your option) any later version.
12
 *
13
 * or
14
 *
15
 *   - the GNU General Public License as published by the Free
16
 *     Software Foundation; either version 2 of the License, or (at
17
 *     your option) any later version.
18
 *
19
 * or both in parallel, as here.
20
 *
21
 * GnuPG is distributed in the hope that it will be useful, but
22
 * WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
 * General Public License for more details.
25
 *
26
 * You should have received copies of the GNU General Public License
27
 * and the GNU Lesser General Public License along with this program;
28
 * if not, see <https://www.gnu.org/licenses/>.
29
 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
30
 */
31
32
#include <config.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <gpg-error.h>
36
#include <gcrypt.h>
37
#include "mischelp.h"
38
#include "util.h"
39
40
/* domSeperation as per *PGP specs. */
41
0
#define KMAC_KEY "OpenPGPCompositeKeyDerivationFunction"
42
43
/* customizationString as per *PGP specs. */
44
0
#define KMAC_CUSTOM "KDF"
45
46
/* The blocksize used for Keccak by compute_kmac256.  */
47
0
#define KECCAK512_BLOCKSIZE 136
48
49
50
51
static gpg_error_t
52
compute_kmac256 (void *digest, size_t digestlen,
53
                 const void *key, size_t keylen,
54
                 const void *custom, size_t customlen,
55
                 gcry_buffer_t *data_iov, int data_iovlen)
56
0
{
57
0
  gpg_error_t err;
58
0
  gcry_buffer_t iov[20];
59
0
  const unsigned char headPAD[2] = { 1, KECCAK512_BLOCKSIZE };
60
0
  unsigned char headK[3];
61
0
  const unsigned char pad[KECCAK512_BLOCKSIZE] = { 0 };
62
0
  unsigned char right_encode_L[3];
63
0
  unsigned int len;
64
0
  int iovcnt;
65
66
0
  if (data_iovlen >= DIM(iov) - 6)
67
0
    return gpg_error (GPG_ERR_TOO_LARGE);
68
69
  /* Check the validity conditions of NIST SP 800-185 */
70
0
  if (keylen >= 255 || customlen >= 255 || digestlen >= 255)
71
0
    return gpg_error (GPG_ERR_TOO_LARGE);
72
73
0
  iovcnt = 0;
74
0
  iov[iovcnt].data = "KMAC";
75
0
  iov[iovcnt].off = 0;
76
0
  iov[iovcnt].len = 4;
77
0
  iovcnt++;
78
79
0
  iov[iovcnt].data = (void *)custom;
80
0
  iov[iovcnt].off = 0;
81
0
  iov[iovcnt].len = customlen;
82
0
  iovcnt++;
83
84
0
  iov[iovcnt].data = (void *)headPAD;
85
0
  iov[iovcnt].off = 0;
86
0
  iov[iovcnt].len = sizeof (headPAD);
87
0
  iovcnt++;
88
89
0
  if (keylen < 32)
90
0
    {
91
0
      headK[0] = 1;
92
0
      headK[1] = (keylen*8)&0xff;
93
0
      iov[iovcnt].data = headK;
94
0
      iov[iovcnt].off = 0;
95
0
      iov[iovcnt].len = 2;
96
0
    }
97
0
  else
98
0
    {
99
0
      headK[0] = 2;
100
0
      headK[1] = (keylen*8)>>8;
101
0
      headK[2] = (keylen*8)&0xff;
102
0
      iov[iovcnt].data = headK;
103
0
      iov[iovcnt].off = 0;
104
0
      iov[iovcnt].len = 3;
105
0
    }
106
0
  iovcnt++;
107
108
0
  iov[iovcnt].data = (void *)key;
109
0
  iov[iovcnt].off = 0;
110
0
  iov[iovcnt].len = keylen;
111
0
  iovcnt++;
112
113
0
  len = iov[2].len + iov[3].len + iov[4].len;
114
0
  len %= KECCAK512_BLOCKSIZE;
115
116
0
  iov[iovcnt].data = (unsigned char *)pad;
117
0
  iov[iovcnt].off = 0;
118
0
  iov[iovcnt].len = sizeof (pad) - len;
119
0
  iovcnt++;
120
121
0
  memcpy (&iov[iovcnt], data_iov, data_iovlen * sizeof (gcry_buffer_t));
122
0
  iovcnt += data_iovlen;
123
124
0
  if (digestlen < 32)
125
0
    {
126
0
      right_encode_L[0] = (digestlen * 8) & 0xff;
127
0
      right_encode_L[1] = 1;
128
0
    }
129
0
  else
130
0
    {
131
0
      right_encode_L[0] = (digestlen * 8) >> 8;
132
0
      right_encode_L[1] = (digestlen * 8) & 0xff;
133
0
      right_encode_L[2] = 2;
134
0
    }
135
136
0
  iov[iovcnt].data = right_encode_L;
137
0
  iov[iovcnt].off = 0;
138
0
  iov[iovcnt].len = 3;
139
0
  iovcnt++;
140
141
0
  err = gcry_md_hash_buffers_ext (GCRY_MD_CSHAKE256, 0,
142
0
                                  digest, digestlen, iov, iovcnt);
143
0
  return err;
144
0
}
145
146
147
/* Compute KEK for ECC with KDF_ALGO, HASHALGO, ECDH result, and
148
 * KDF_PARAMS.
149
 *
150
 * KDF_PARAMS is specified by upper layer.
151
 */
152
gpg_error_t
153
gnupg_ecc_kem_kdf (void *kek, size_t kek_len, int kdf_algo,
154
                   int hashalgo, const void *ecdh, size_t ecdh_len,
155
                   const unsigned char *kdf_params, size_t kdf_params_len)
156
0
{
157
  /* Traditional ECC */
158
0
  gpg_error_t err;
159
0
  gcry_kdf_hd_t hd;
160
0
  unsigned long param[1];
161
162
0
  param[0] = kek_len;
163
0
  err = gcry_kdf_open (&hd, kdf_algo, hashalgo, param, 1,
164
0
                       ecdh, ecdh_len, NULL, 0, NULL, 0,
165
0
                       kdf_params, kdf_params_len);
166
0
  if (!err)
167
0
    {
168
0
      gcry_kdf_compute (hd, NULL);
169
0
      gcry_kdf_final (hd, kek_len, kek);
170
0
      gcry_kdf_close (hd);
171
0
    }
172
173
0
  return err;
174
0
}
175
176
177
/* Compute KEK for ECC with HASHALGO, ECDH result, ciphertext in
178
 * ECC_CT (which is an ephemeral key), and public key in ECC_PK.
179
 */
180
gpg_error_t
181
gnupg_ecc_kem_simple_kdf (void *kek, size_t kek_len,
182
                          int hashalgo, const void *ecdh, size_t ecdh_len,
183
                          const void *ecc_ct, size_t ecc_ct_len,
184
                          const void *ecc_pk, size_t ecc_pk_len)
185
0
{
186
  /* ECC part in composite KEM */
187
0
  gcry_buffer_t iov[3];
188
0
  unsigned int dlen;
189
190
0
  dlen = gcry_md_get_algo_dlen (hashalgo);
191
0
  if (kek_len != dlen)
192
0
    return gpg_error (GPG_ERR_INV_LENGTH);
193
194
0
  memset (iov, 0, sizeof (iov));
195
196
0
  iov[0].data = (unsigned char *)ecdh;
197
0
  iov[0].len = ecdh_len;
198
0
  iov[1].data = (unsigned char *)ecc_ct;
199
0
  iov[1].len = ecc_ct_len;
200
0
  iov[2].data = (unsigned char *)ecc_pk;
201
0
  iov[2].len = ecc_pk_len;
202
0
  gcry_md_hash_buffers (hashalgo, 0, kek, iov, 3);
203
204
0
  return 0;
205
0
}
206
207
208
/* Compute KEK by combining two KEMs.  The caller provides a buffer
209
 * KEK allocated with size KEK_LEN which will receive the computed
210
 * KEK. (ECC_SS, ECC_SS_LEN) is the shared secret of the first key.
211
 * (ECC_CT, ECC_CT_LEN) is the ciphertext of the first key.
212
 * (MLKEM_SS, ECC_SS_LEN) is the shared secret of the second key.
213
 * (MLKEM_CT, MLKEM_CT_LEN) is the ciphertext of the second key.
214
 * (FIXEDINFO, FIXEDINFO_LEN) is an octet string used to bind the KEK
215
 * to a the key; for PGP we use the concatenation of the session key's
216
 * algorithm id and the v5 fingerprint of the key.  */
217
gpg_error_t
218
gnupg_kem_combiner (void *kek, size_t kek_len,
219
                    const void *ecc_ss, size_t ecc_ss_len,
220
                    const void *ecc_ct, size_t ecc_ct_len,
221
                    const void *mlkem_ss, size_t mlkem_ss_len,
222
                    const void *mlkem_ct, size_t mlkem_ct_len,
223
                    const void *fixedinfo, size_t fixedinfo_len)
224
0
{
225
0
  gpg_error_t err;
226
0
  gcry_buffer_t iov[6];
227
228
0
  memset (iov, 0, sizeof (iov));
229
230
0
  iov[0].data = "\x00\x00\x00\x01"; /* Counter */
231
0
  iov[0].len = 4;
232
233
0
  iov[1].data = (unsigned char *)ecc_ss;
234
0
  iov[1].len = ecc_ss_len;
235
236
0
  iov[2].data = (unsigned char *)ecc_ct;
237
0
  iov[2].len = ecc_ct_len;
238
239
0
  iov[3].data = (unsigned char *)mlkem_ss;
240
0
  iov[3].len = mlkem_ss_len;
241
242
0
  iov[4].data = (unsigned char *)mlkem_ct;
243
0
  iov[4].len = mlkem_ct_len;
244
245
0
  iov[5].data = (unsigned char *)fixedinfo;
246
0
  iov[5].len = fixedinfo_len;
247
248
0
  err = compute_kmac256 (kek, kek_len,
249
0
                         KMAC_KEY, strlen (KMAC_KEY),
250
0
                         KMAC_CUSTOM, strlen (KMAC_CUSTOM), iov, 6);
251
0
  return err;
252
0
}
253
254
255
/* Compute KEK by combining two KEMs; this ise the RFC9980 version
256
 * using SHA3-256.  The caller provides a buffer KEK allocated with
257
 * size KEK_LEN which will receive the computed
258
 * KEK. (ECC_SS,ECC_SS_LEN) is the shared secret of the first key.
259
 * (ECC_CT,ECC_CT_LEN) is the ciphertext of the first key.
260
 * (ECC_PK,ECC_PK_LEN) is the public key of the first key.
261
 * (MLKEM_SS,ECC_SS_LEN) is the shared secret of the second key.
262
 * (FIXEDINFO, FIXEDINFO_LEN) is an octet string used to bind the KEK
263
 * to a the key.  */
264
gpg_error_t
265
gnupg_kem_combiner_sha3_256 (void *kek, size_t kek_len,
266
                             const void *ecc_ss, size_t ecc_ss_len,
267
                             const void *ecc_ct, size_t ecc_ct_len,
268
                             const void *ecc_pk, size_t ecc_pk_len,
269
                             const void *mlkem_ss, size_t mlkem_ss_len,
270
                             const void *fixedinfo, size_t fixedinfo_len)
271
0
{
272
0
  gpg_error_t err;
273
0
  gcry_buffer_t iov[5];
274
275
0
  memset (iov, 0, sizeof (iov));
276
277
0
  iov[0].data = (unsigned char *)mlkem_ss;
278
0
  iov[0].len = mlkem_ss_len;
279
280
0
  iov[1].data = (unsigned char *)ecc_ss;
281
0
  iov[1].len = ecc_ss_len;
282
283
0
  iov[2].data = (unsigned char *)ecc_ct;
284
0
  iov[2].len = ecc_ct_len;
285
286
0
  iov[3].data = (unsigned char *)ecc_pk;
287
0
  iov[3].len = ecc_pk_len;
288
289
0
  iov[4].data = (unsigned char *)fixedinfo;
290
0
  iov[4].len = fixedinfo_len;
291
292
0
  err = gcry_md_hash_buffers_ext (GCRY_MD_SHA3_256, 0,
293
0
                                  kek, kek_len, iov, 5);
294
0
  return err;
295
0
}
296
297
298

299
300
#define ECC_CURVE25519_INDEX 0
301
static const struct gnupg_ecc_params ecc_table[] =
302
  {
303
    {
304
      "Curve25519",
305
      33, 32, 32,
306
      GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519,
307
      1, 1, 0
308
    },
309
    {
310
      "ietf25",
311
      32, 32, 32,
312
      GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519,
313
      0, 0, 0
314
    },
315
    {
316
      "X448",
317
      56, 56, 56,
318
      GCRY_MD_SHA3_512, GCRY_KEM_RAW_X448,
319
      0, 0, 0
320
    },
321
    {
322
      "NIST P-256",
323
      65, 32, 65,
324
      GCRY_MD_SHA3_256, GCRY_KEM_RAW_P256R1,
325
      0, 0, 1
326
    },
327
    {
328
      "NIST P-384",
329
      97, 48, 97,
330
      GCRY_MD_SHA3_512, GCRY_KEM_RAW_P384R1,
331
      0, 0, 1
332
    },
333
    {
334
      "NIST P-521",
335
      133, 66, 133,
336
      GCRY_MD_SHA3_512, GCRY_KEM_RAW_P521R1,
337
      0, 0, 1
338
    },
339
    {
340
      "brainpoolP256r1",
341
      65, 32, 65,
342
      GCRY_MD_SHA3_256, GCRY_KEM_RAW_BP256,
343
      0, 0, 1
344
    },
345
    {
346
      "brainpoolP384r1",
347
      97, 48, 97,
348
      GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP384,
349
      0, 0, 1
350
    },
351
    {
352
      "brainpoolP512r1",
353
      129, 64, 129,
354
      GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP512,
355
      0, 0, 1
356
    },
357
#ifdef GCRY_KEM_RAW_P256K1
358
    {
359
      "secp256k1",
360
      65, 32, 65,
361
      GCRY_MD_SHA3_256, GCRY_KEM_RAW_P256K1,
362
      0, 0, 1
363
    },
364
#endif
365
    { NULL, 0, 0, 0, 0, 0, 0, 0, 0 }
366
};
367
368
369
/* Return the ECC parameters for CURVE.  CURVE is expected to be the
370
 * canonical name.  */
371
const struct gnupg_ecc_params *
372
gnupg_get_ecc_params (const char *curve)
373
0
{
374
0
  int i;
375
376
0
  for (i = 0; ecc_table[i].curve; i++)
377
0
    if (!strcmp (ecc_table[i].curve, curve))
378
0
      return &ecc_table[i];
379
380
0
  return NULL;
381
0
}