diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem.c | 416 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem.h | 329 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem1024.c | 71 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem768.c | 73 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem_internal.h | 331 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem_key.c | 200 |
6 files changed, 1141 insertions, 279 deletions
diff --git a/src/lib/libcrypto/mlkem/mlkem.c b/src/lib/libcrypto/mlkem/mlkem.c new file mode 100644 index 0000000000..bf53e5d77a --- /dev/null +++ b/src/lib/libcrypto/mlkem/mlkem.c | |||
@@ -0,0 +1,416 @@ | |||
1 | /* $OpenBSD: mlkem.c,v 1.2 2025/08/14 16:04:01 beck Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2025, Bob Beck <beck@obtuse.com> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
12 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
14 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | #include <stdlib.h> | ||
18 | |||
19 | #include <openssl/mlkem.h> | ||
20 | #include "mlkem_internal.h" | ||
21 | |||
22 | static inline int | ||
23 | private_key_is_new(const MLKEM_private_key *key) | ||
24 | { | ||
25 | return (key != NULL && | ||
26 | key->state == MLKEM_PRIVATE_KEY_UNINITIALIZED && | ||
27 | (key->rank == RANK768 || key->rank == RANK1024)); | ||
28 | } | ||
29 | |||
30 | static inline int | ||
31 | private_key_is_valid(const MLKEM_private_key *key) | ||
32 | { | ||
33 | return (key != NULL && | ||
34 | key->state == MLKEM_PRIVATE_KEY_INITIALIZED && | ||
35 | (key->rank == RANK768 || key->rank == RANK1024)); | ||
36 | } | ||
37 | |||
38 | static inline int | ||
39 | public_key_is_new(const MLKEM_public_key *key) | ||
40 | { | ||
41 | return (key != NULL && | ||
42 | key->state == MLKEM_PUBLIC_KEY_UNINITIALIZED && | ||
43 | (key->rank == RANK768 || key->rank == RANK1024)); | ||
44 | } | ||
45 | |||
46 | static inline int | ||
47 | public_key_is_valid(const MLKEM_public_key *key) | ||
48 | { | ||
49 | return (key != NULL && | ||
50 | key->state == MLKEM_PUBLIC_KEY_INITIALIZED && | ||
51 | (key->rank == RANK768 || key->rank == RANK1024)); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * ML-KEM operations | ||
56 | */ | ||
57 | |||
58 | int | ||
59 | MLKEM_generate_key_external_entropy(MLKEM_private_key *private_key, | ||
60 | uint8_t **out_encoded_public_key, size_t *out_encoded_public_key_len, | ||
61 | const uint8_t *entropy) | ||
62 | { | ||
63 | uint8_t *k = NULL; | ||
64 | size_t k_len = 0; | ||
65 | int ret = 0; | ||
66 | |||
67 | if (*out_encoded_public_key != NULL) | ||
68 | goto err; | ||
69 | |||
70 | if (!private_key_is_new(private_key)) | ||
71 | goto err; | ||
72 | |||
73 | k_len = MLKEM768_PUBLIC_KEY_BYTES; | ||
74 | if (private_key->rank == RANK1024) | ||
75 | k_len = MLKEM1024_PUBLIC_KEY_BYTES; | ||
76 | |||
77 | if ((k = calloc(1, k_len)) == NULL) | ||
78 | goto err; | ||
79 | |||
80 | switch (private_key->rank) { | ||
81 | case RANK768: | ||
82 | if (!MLKEM768_generate_key_external_entropy(k, private_key, | ||
83 | entropy)) | ||
84 | goto err; | ||
85 | break; | ||
86 | case RANK1024: | ||
87 | if (!MLKEM1024_generate_key_external_entropy(k, private_key, | ||
88 | entropy)) | ||
89 | goto err; | ||
90 | break; | ||
91 | } | ||
92 | |||
93 | private_key->state = MLKEM_PRIVATE_KEY_INITIALIZED; | ||
94 | |||
95 | *out_encoded_public_key = k; | ||
96 | *out_encoded_public_key_len = k_len; | ||
97 | k = NULL; | ||
98 | |||
99 | ret = 1; | ||
100 | |||
101 | err: | ||
102 | freezero(k, k_len); | ||
103 | |||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | int | ||
108 | MLKEM_generate_key(MLKEM_private_key *private_key, | ||
109 | uint8_t **out_encoded_public_key, size_t *out_encoded_public_key_len, | ||
110 | uint8_t **out_optional_seed, size_t *out_optional_seed_len) | ||
111 | { | ||
112 | uint8_t *entropy_buf = NULL; | ||
113 | int ret = 0; | ||
114 | |||
115 | if (*out_encoded_public_key != NULL) | ||
116 | goto err; | ||
117 | |||
118 | if (out_optional_seed != NULL && *out_optional_seed != NULL) | ||
119 | goto err; | ||
120 | |||
121 | if ((entropy_buf = calloc(1, MLKEM_SEED_LENGTH)) == NULL) | ||
122 | goto err; | ||
123 | |||
124 | arc4random_buf(entropy_buf, MLKEM_SEED_LENGTH); | ||
125 | if (!MLKEM_generate_key_external_entropy(private_key, | ||
126 | out_encoded_public_key, out_encoded_public_key_len, | ||
127 | entropy_buf)) | ||
128 | goto err; | ||
129 | |||
130 | if (out_optional_seed != NULL) { | ||
131 | *out_optional_seed = entropy_buf; | ||
132 | *out_optional_seed_len = MLKEM_SEED_LENGTH; | ||
133 | entropy_buf = NULL; | ||
134 | } | ||
135 | |||
136 | ret = 1; | ||
137 | |||
138 | err: | ||
139 | freezero(entropy_buf, MLKEM_SEED_LENGTH); | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | LCRYPTO_ALIAS(MLKEM_generate_key); | ||
144 | |||
145 | int | ||
146 | MLKEM_private_key_from_seed(MLKEM_private_key *private_key, | ||
147 | const uint8_t *seed, size_t seed_len) | ||
148 | { | ||
149 | int ret = 0; | ||
150 | |||
151 | if (!private_key_is_new(private_key)) | ||
152 | goto err; | ||
153 | |||
154 | if (seed_len != MLKEM_SEED_LENGTH) | ||
155 | goto err; | ||
156 | |||
157 | switch (private_key->rank) { | ||
158 | case RANK768: | ||
159 | if (!MLKEM768_private_key_from_seed(seed, | ||
160 | seed_len, private_key)) | ||
161 | goto err; | ||
162 | break; | ||
163 | case RANK1024: | ||
164 | if (!MLKEM1024_private_key_from_seed(private_key, | ||
165 | seed, seed_len)) | ||
166 | goto err; | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | private_key->state = MLKEM_PRIVATE_KEY_INITIALIZED; | ||
171 | |||
172 | ret = 1; | ||
173 | |||
174 | err: | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | LCRYPTO_ALIAS(MLKEM_private_key_from_seed); | ||
179 | |||
180 | int | ||
181 | MLKEM_public_from_private(const MLKEM_private_key *private_key, | ||
182 | MLKEM_public_key *public_key) | ||
183 | { | ||
184 | if (!private_key_is_valid(private_key)) | ||
185 | return 0; | ||
186 | if (!public_key_is_new(public_key)) | ||
187 | return 0; | ||
188 | if (public_key->rank != private_key->rank) | ||
189 | return 0; | ||
190 | switch (private_key->rank) { | ||
191 | case RANK768: | ||
192 | MLKEM768_public_from_private(private_key, public_key); | ||
193 | break; | ||
194 | case RANK1024: | ||
195 | MLKEM1024_public_from_private(private_key, public_key); | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | public_key->state = MLKEM_PUBLIC_KEY_INITIALIZED; | ||
200 | |||
201 | return 1; | ||
202 | } | ||
203 | LCRYPTO_ALIAS(MLKEM_public_from_private); | ||
204 | |||
205 | int | ||
206 | MLKEM_encap_external_entropy(const MLKEM_public_key *public_key, | ||
207 | const uint8_t *entropy, uint8_t **out_ciphertext, | ||
208 | size_t *out_ciphertext_len, uint8_t **out_shared_secret, | ||
209 | size_t *out_shared_secret_len) | ||
210 | { | ||
211 | uint8_t *secret = NULL; | ||
212 | uint8_t *ciphertext = NULL; | ||
213 | size_t ciphertext_len = 0; | ||
214 | int ret = 0; | ||
215 | |||
216 | if (*out_ciphertext != NULL) | ||
217 | goto err; | ||
218 | |||
219 | if (*out_shared_secret != NULL) | ||
220 | goto err; | ||
221 | |||
222 | if (!public_key_is_valid(public_key)) | ||
223 | goto err; | ||
224 | |||
225 | if ((secret = calloc(1, MLKEM_SHARED_SECRET_LENGTH)) == NULL) | ||
226 | goto err; | ||
227 | |||
228 | ciphertext_len = MLKEM_public_key_ciphertext_length(public_key); | ||
229 | |||
230 | if ((ciphertext = calloc(1, ciphertext_len)) == NULL) | ||
231 | goto err; | ||
232 | |||
233 | switch (public_key->rank) { | ||
234 | case RANK768: | ||
235 | MLKEM768_encap_external_entropy(ciphertext, secret, public_key, | ||
236 | entropy); | ||
237 | break; | ||
238 | |||
239 | case RANK1024: | ||
240 | MLKEM1024_encap_external_entropy(ciphertext, secret, public_key, | ||
241 | entropy); | ||
242 | break; | ||
243 | } | ||
244 | *out_ciphertext = ciphertext; | ||
245 | *out_ciphertext_len = ciphertext_len; | ||
246 | ciphertext = NULL; | ||
247 | *out_shared_secret = secret; | ||
248 | *out_shared_secret_len = MLKEM_SHARED_SECRET_LENGTH; | ||
249 | secret = NULL; | ||
250 | |||
251 | ret = 1; | ||
252 | |||
253 | err: | ||
254 | freezero(secret, MLKEM_SHARED_SECRET_LENGTH); | ||
255 | freezero(ciphertext, ciphertext_len); | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | int | ||
261 | MLKEM_encap(const MLKEM_public_key *public_key, | ||
262 | uint8_t **out_ciphertext, size_t *out_ciphertext_len, | ||
263 | uint8_t **out_shared_secret, size_t *out_shared_secret_len) | ||
264 | { | ||
265 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; | ||
266 | |||
267 | arc4random_buf(entropy, MLKEM_ENCAP_ENTROPY); | ||
268 | |||
269 | return MLKEM_encap_external_entropy(public_key, entropy, out_ciphertext, | ||
270 | out_ciphertext_len, out_shared_secret, out_shared_secret_len); | ||
271 | } | ||
272 | LCRYPTO_ALIAS(MLKEM_encap); | ||
273 | |||
274 | int | ||
275 | MLKEM_decap(const MLKEM_private_key *private_key, | ||
276 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
277 | uint8_t **out_shared_secret, size_t *out_shared_secret_len) | ||
278 | { | ||
279 | uint8_t *s = NULL; | ||
280 | int ret = 0; | ||
281 | |||
282 | if (*out_shared_secret != NULL) | ||
283 | goto err; | ||
284 | |||
285 | if (!private_key_is_valid(private_key)) | ||
286 | goto err; | ||
287 | |||
288 | if (ciphertext_len != MLKEM_private_key_ciphertext_length(private_key)) | ||
289 | goto err; | ||
290 | |||
291 | if ((s = calloc(1, MLKEM_SHARED_SECRET_LENGTH)) == NULL) | ||
292 | goto err; | ||
293 | |||
294 | switch (private_key->rank) { | ||
295 | case RANK768: | ||
296 | MLKEM768_decap(private_key, ciphertext, ciphertext_len, s); | ||
297 | break; | ||
298 | |||
299 | case RANK1024: | ||
300 | MLKEM1024_decap(private_key, ciphertext, ciphertext_len, s); | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | *out_shared_secret = s; | ||
305 | *out_shared_secret_len = MLKEM_SHARED_SECRET_LENGTH; | ||
306 | s = NULL; | ||
307 | |||
308 | ret = 1; | ||
309 | |||
310 | err: | ||
311 | freezero(s, MLKEM_SHARED_SECRET_LENGTH); | ||
312 | |||
313 | return ret; | ||
314 | } | ||
315 | LCRYPTO_ALIAS(MLKEM_decap); | ||
316 | |||
317 | int | ||
318 | MLKEM_marshal_public_key(const MLKEM_public_key *public_key, uint8_t **out, | ||
319 | size_t *out_len) | ||
320 | { | ||
321 | if (*out != NULL) | ||
322 | return 0; | ||
323 | |||
324 | if (!public_key_is_valid(public_key)) | ||
325 | return 0; | ||
326 | |||
327 | switch (public_key->rank) { | ||
328 | case RANK768: | ||
329 | return MLKEM768_marshal_public_key(public_key, out, out_len); | ||
330 | case RANK1024: | ||
331 | return MLKEM1024_marshal_public_key(public_key, out, out_len); | ||
332 | default: | ||
333 | return 0; | ||
334 | } | ||
335 | } | ||
336 | LCRYPTO_ALIAS(MLKEM_marshal_public_key); | ||
337 | |||
338 | /* | ||
339 | * Not exposed publicly, becuase the NIST private key format is gigantisch, and | ||
340 | * seeds should be used instead. Used for the NIST tests. | ||
341 | */ | ||
342 | int | ||
343 | MLKEM_marshal_private_key(const MLKEM_private_key *private_key, uint8_t **out, | ||
344 | size_t *out_len) | ||
345 | { | ||
346 | if (*out != NULL) | ||
347 | return 0; | ||
348 | |||
349 | if (!private_key_is_valid(private_key)) | ||
350 | return 0; | ||
351 | |||
352 | switch (private_key->rank) { | ||
353 | case RANK768: | ||
354 | return MLKEM768_marshal_private_key(private_key, out, out_len); | ||
355 | case RANK1024: | ||
356 | return MLKEM1024_marshal_private_key(private_key, out, out_len); | ||
357 | default: | ||
358 | return 0; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | int | ||
363 | MLKEM_parse_public_key(MLKEM_public_key *public_key, const uint8_t *in, | ||
364 | size_t in_len) | ||
365 | { | ||
366 | if (!public_key_is_new(public_key)) | ||
367 | return 0; | ||
368 | |||
369 | if (in_len != MLKEM_public_key_encoded_length(public_key)) | ||
370 | return 0; | ||
371 | |||
372 | switch (public_key->rank) { | ||
373 | case RANK768: | ||
374 | if (!MLKEM768_parse_public_key(in, in_len, | ||
375 | public_key)) | ||
376 | return 0; | ||
377 | break; | ||
378 | case RANK1024: | ||
379 | if (!MLKEM1024_parse_public_key(in, in_len, | ||
380 | public_key)) | ||
381 | return 0; | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | public_key->state = MLKEM_PUBLIC_KEY_INITIALIZED; | ||
386 | |||
387 | return 1; | ||
388 | } | ||
389 | LCRYPTO_ALIAS(MLKEM_parse_public_key); | ||
390 | |||
391 | int | ||
392 | MLKEM_parse_private_key(MLKEM_private_key *private_key, const uint8_t *in, | ||
393 | size_t in_len) | ||
394 | { | ||
395 | if (!private_key_is_new(private_key)) | ||
396 | return 0; | ||
397 | |||
398 | if (in_len != MLKEM_private_key_encoded_length(private_key)) | ||
399 | return 0; | ||
400 | |||
401 | switch (private_key->rank) { | ||
402 | case RANK768: | ||
403 | if (!MLKEM768_parse_private_key(in, in_len, private_key)) | ||
404 | return 0; | ||
405 | break; | ||
406 | case RANK1024: | ||
407 | if (!MLKEM1024_parse_private_key(in, in_len, private_key)) | ||
408 | return 0; | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | private_key->state = MLKEM_PRIVATE_KEY_INITIALIZED; | ||
413 | |||
414 | return 1; | ||
415 | } | ||
416 | LCRYPTO_ALIAS(MLKEM_parse_private_key); | ||
diff --git a/src/lib/libcrypto/mlkem/mlkem.h b/src/lib/libcrypto/mlkem/mlkem.h index a2c5d7fed0..31d4858195 100644 --- a/src/lib/libcrypto/mlkem/mlkem.h +++ b/src/lib/libcrypto/mlkem/mlkem.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* $OpenBSD: mlkem.h,v 1.6 2025/05/19 06:47:40 beck Exp $ */ | 1 | /* $OpenBSD: mlkem.h,v 1.7 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2025 Bob Beck <beck@obtuse.com> |
4 | * | 4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above |
@@ -26,253 +26,202 @@ extern "C" { | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * ML-KEM-768 | 29 | * ML-KEM constants |
30 | * | ||
31 | * This implements the Module-Lattice-Based Key-Encapsulation Mechanism from | ||
32 | * https://csrc.nist.gov/pubs/fips/204/final | ||
33 | */ | 30 | */ |
34 | 31 | ||
35 | /* | 32 | #define RANK768 3 |
36 | * MLKEM768_public_key contains a ML-KEM-768 public key. The contents of this | 33 | #define RANK1024 4 |
37 | * object should never leave the address space since the format is unstable. | ||
38 | */ | ||
39 | struct MLKEM768_public_key { | ||
40 | union { | ||
41 | uint8_t bytes[512 * (3 + 9) + 32 + 32]; | ||
42 | uint16_t alignment; | ||
43 | } opaque; | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * MLKEM768_private_key contains a ML-KEM-768 private key. The contents of this | ||
48 | * object should never leave the address space since the format is unstable. | ||
49 | */ | ||
50 | struct MLKEM768_private_key { | ||
51 | union { | ||
52 | uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; | ||
53 | uint16_t alignment; | ||
54 | } opaque; | ||
55 | }; | ||
56 | 34 | ||
57 | /* | 35 | /* |
58 | * MLKEM768_PUBLIC_KEY_BYTES is the number of bytes in an encoded ML-KEM768 public | 36 | * ML-KEM keys |
59 | * key. | ||
60 | */ | 37 | */ |
61 | #define MLKEM768_PUBLIC_KEY_BYTES 1184 | ||
62 | 38 | ||
63 | /* MLKEM_SEED_BYTES is the number of bytes in an ML-KEM seed. */ | 39 | typedef struct MLKEM_private_key_st MLKEM_private_key; |
64 | #define MLKEM_SEED_BYTES 64 | 40 | typedef struct MLKEM_public_key_st MLKEM_public_key; |
65 | 41 | ||
66 | /* | 42 | /* |
67 | * MLKEM_SHARED_SECRET_BYTES is the number of bytes in the ML-KEM768 shared | 43 | * MLKEM_private_key_new allocates a new uninitialized ML-KEM private key for |
68 | * secret. Although the round-3 specification has a variable-length output, the | 44 | * |rank|, which must be RANK768 or RANK1024. It returns a pointer to an |
69 | * final ML-KEM construction is expected to use a fixed 32-byte output. To | 45 | * allocated structure suitable for holding a generated private key of the |
70 | * simplify the future transition, we apply the same restriction. | 46 | * corresponding rank on success, NULL is returned on failure. The caller is |
47 | * responsible for deallocating the resulting key with |MLKEM_private_key_free|. | ||
71 | */ | 48 | */ |
72 | #define MLKEM_SHARED_SECRET_BYTES 32 | 49 | MLKEM_private_key *MLKEM_private_key_new(int rank); |
73 | 50 | ||
74 | /* | 51 | /* |
75 | * MLKEM_generate_key generates a random public/private key pair, writes the | 52 | * MLKEM_private_key_free zeroes and frees all memory for |key| if |key| is |
76 | * encoded public key to |out_encoded_public_key| and sets |out_private_key| to | 53 | * non NULL. If |key| is NULL it does nothing and returns. |
77 | * the private key. If |optional_out_seed| is not NULL then the seed used to | ||
78 | * generate the private key is written to it. | ||
79 | */ | 54 | */ |
80 | int MLKEM768_generate_key( | 55 | void MLKEM_private_key_free(MLKEM_private_key *key); |
81 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | ||
82 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
83 | struct MLKEM768_private_key *out_private_key); | ||
84 | 56 | ||
85 | /* | 57 | /* |
86 | * MLKEM768_private_key_from_seed derives a private key from a seed that was | 58 | * MLKEM_private_key_encoded_length the number of bytes used by the encoded form |
87 | * generated by |MLKEM768_generate_key|. It fails and returns 0 if |seed_len| is | 59 | * of |key|. Thie corresponds to the length of the buffer allocated for the |
88 | * incorrect, otherwise it writes |*out_private_key| and returns 1. | 60 | * encoded_public_key from |MLKEM_marshal_private_key|. Zero is returned if |
61 | * |key| is NULL or has an invalid rank. | ||
89 | */ | 62 | */ |
90 | int MLKEM768_private_key_from_seed(struct MLKEM768_private_key *out_private_key, | 63 | size_t MLKEM_private_key_encoded_length(const MLKEM_private_key *key); |
91 | const uint8_t *seed, size_t seed_len); | ||
92 | 64 | ||
93 | /* | 65 | /* |
94 | * MLKEM_public_from_private sets |*out_public_key| to the public key that | 66 | * MLKEM_private_key_ciphertext_length returns the number of bytes of ciphertext |
95 | * corresponds to |private_key|. (This is faster than parsing the output of | 67 | * required to decrypt a shared secret with |key| using |MLKEM_decap|. Zero is |
96 | * |MLKEM_generate_key| if, for some reason, you need to encapsulate to a key | 68 | * returned if |key| is NULL or has an invalid rank. |
97 | * that was just generated.) | ||
98 | */ | 69 | */ |
99 | void MLKEM768_public_from_private(struct MLKEM768_public_key *out_public_key, | 70 | size_t MLKEM_private_key_ciphertext_length(const MLKEM_private_key *key); |
100 | const struct MLKEM768_private_key *private_key); | ||
101 | |||
102 | /* MLKEM768_CIPHERTEXT_BYTES is number of bytes in the ML-KEM768 ciphertext. */ | ||
103 | #define MLKEM768_CIPHERTEXT_BYTES 1088 | ||
104 | 71 | ||
105 | /* | 72 | /* |
106 | * MLKEM768_encap encrypts a random shared secret for |public_key|, writes the | 73 | * MLKEM_public_key_new allocates a new uninitialized ML-KEM public key for |
107 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | 74 | * |rank|, which must be RANK768 or RANK1024. It returns a pointer to an |
108 | * |out_shared_secret|. | 75 | * allocated structure suitable for holding a generated public key of the |
76 | * corresponding rank on success, NULL is returned on failure. The caller is | ||
77 | * responsible for deallocating the resulting key with |MLKEM_public_key_free|. | ||
109 | */ | 78 | */ |
110 | void MLKEM768_encap(uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | 79 | MLKEM_public_key *MLKEM_public_key_new(int rank); |
111 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
112 | const struct MLKEM768_public_key *public_key); | ||
113 | 80 | ||
114 | /* | 81 | /* |
115 | * MLKEM768_decap decrypts a shared secret from |ciphertext| using |private_key| | 82 | * MLKEM_public_key_free zeros and deallocates all memory for |key| if |key| is |
116 | * and writes it to |out_shared_secret|. If |ciphertext_len| is incorrect it | 83 | * non NULL. If |key| is NULL it does nothing and returns. |
117 | * returns 0, otherwise it rreturns 1. If |ciphertext| is invalid, | ||
118 | * |out_shared_secret| is filled with a key that will always be the same for the | ||
119 | * same |ciphertext| and |private_key|, but which appears to be random unless | ||
120 | * one has access to |private_key|. These alternatives occur in constant time. | ||
121 | * Any subsequent symmetric encryption using |out_shared_secret| must use an | ||
122 | * authenticated encryption scheme in order to discover the decapsulation | ||
123 | * failure. | ||
124 | */ | 84 | */ |
125 | int MLKEM768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 85 | void MLKEM_public_key_free(MLKEM_public_key *key); |
126 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
127 | const struct MLKEM768_private_key *private_key); | ||
128 | |||
129 | /* Serialisation of keys. */ | ||
130 | 86 | ||
131 | /* | 87 | /* |
132 | * MLKEM768_marshal_public_key serializes |public_key| to |out| in the standard | 88 | * MLKEM_public_key_encoded_length the number of bytes used by the encoded form |
133 | * format for ML-KEM public keys. It returns one on success or zero on allocation | 89 | * of |key|. Thie corresponds to the length of the buffer allocated for the |
134 | * error. | 90 | * encoded_public_key from |MLKEM_generate_key| or |MLKEM_marshal_public_key|. |
91 | * Zero is returned if |key| is NULL or has an invalid rank. | ||
135 | */ | 92 | */ |
136 | int MLKEM768_marshal_public_key(uint8_t **output, size_t *output_len, | 93 | size_t MLKEM_public_key_encoded_length(const MLKEM_public_key *key); |
137 | const struct MLKEM768_public_key *public_key); | ||
138 | 94 | ||
139 | /* | 95 | /* |
140 | * MLKEM768_parse_public_key parses a public key, in the format generated by | 96 | * MLKEM_public_key_cipertext_length returns the number of bytes produced as the |
141 | * |MLKEM_marshal_public_key|, from |in| and writes the result to | 97 | * ciphertext when encrypting a shared secret with |key| using |MLKEM_encap|. Zero |
142 | * |out_public_key|. It returns one on success or zero on parse error or if | 98 | * is returned if |key| is NULL or has an invalid rank. |
143 | * there are trailing bytes in |in|. | ||
144 | */ | 99 | */ |
145 | int MLKEM768_parse_public_key(struct MLKEM768_public_key *out_public_key, | 100 | size_t MLKEM_public_key_ciphertext_length(const MLKEM_public_key *key); |
146 | const uint8_t *input, size_t input_len); | ||
147 | 101 | ||
148 | /* | 102 | /* |
149 | * MLKEM_parse_private_key parses a private key, in the format generated by | 103 | * ML-KEM operations |
150 | * |MLKEM_marshal_private_key|, from |in| and writes the result to | ||
151 | * |out_private_key|. It returns one on success or zero on parse error or if | ||
152 | * there are trailing bytes in |in|. This formate is verbose and should be avoided. | ||
153 | * Private keys should be stored as seeds and parsed using |MLKEM768_private_key_from_seed|. | ||
154 | */ | 104 | */ |
155 | int MLKEM768_parse_private_key(struct MLKEM768_private_key *out_private_key, | ||
156 | const uint8_t *input, size_t input_len); | ||
157 | 105 | ||
158 | /* | 106 | /* |
159 | * ML-KEM-1024 | 107 | * MLKEM_generate_key generates a random private/public key pair, initializing |
108 | * |private_key|. It returns one on success, and zero on failure or error. | ||
109 | * |private_key| must be a new uninitialized key. |*out_encoded_public_key| and | ||
110 | * |*out_optional_seed|, if provided, must have the value of NULL. On success, a | ||
111 | * pointer to the encoded public key of the correct size for |key| is returned | ||
112 | * in |out_encoded_public_key|, and the length in bytes of | ||
113 | * |*out_encoded_public_key| is returned in |out_encoded_public_key_len|. If | ||
114 | * |out_optional_seed| is not NULL, a pointer to the seed used to generate the | ||
115 | * private key is returned in |*out_optional_seed| and the length in bytes of | ||
116 | * the seed is returned in |*out_optional_seed_len|. The caller is responsible | ||
117 | * for freeing the values returned in |out_encoded_public_key|, and | ||
118 | * |out_optional_seed|. | ||
160 | * | 119 | * |
161 | * ML-KEM-1024 also exists. You should prefer ML-KEM-768 where possible. | 120 | * In the event a private key needs to be saved, The normal best practice is to |
162 | */ | 121 | * save |out_optional_seed| as the private key, along with the ML-KEM rank value. |
163 | 122 | * An MLKEM_private_key of the correct rank can then be constructed using | |
164 | /* | 123 | * |MLKEM_private_key_from_seed|. |
165 | * MLKEM1024_public_key contains an ML-KEM-1024 public key. The contents of this | ||
166 | * object should never leave the address space since the format is unstable. | ||
167 | */ | ||
168 | struct MLKEM1024_public_key { | ||
169 | union { | ||
170 | uint8_t bytes[512 * (4 + 16) + 32 + 32]; | ||
171 | uint16_t alignment; | ||
172 | } opaque; | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * MLKEM1024_private_key contains a ML-KEM-1024 private key. The contents of | ||
177 | * this object should never leave the address space since the format is | ||
178 | * unstable. | ||
179 | */ | ||
180 | struct MLKEM1024_private_key { | ||
181 | union { | ||
182 | uint8_t bytes[512 * (4 + 4 + 16) + 32 + 32 + 32]; | ||
183 | uint16_t alignment; | ||
184 | } opaque; | ||
185 | }; | ||
186 | |||
187 | /* | ||
188 | * MLKEM1024_PUBLIC_KEY_BYTES is the number of bytes in an encoded ML-KEM-1024 | ||
189 | * public key. | ||
190 | */ | 124 | */ |
191 | #define MLKEM1024_PUBLIC_KEY_BYTES 1568 | 125 | int MLKEM_generate_key(MLKEM_private_key *private_key, |
126 | uint8_t **out_encoded_public_key, size_t *out_encoded_public_key_len, | ||
127 | uint8_t **out_optional_seed, size_t *out_optional_seed_len); | ||
192 | 128 | ||
193 | /* | 129 | /* |
194 | * MLKEM1024_generate_key generates a random public/private key pair, writes the | 130 | * MLKEM_private_key_from_seed derives a private key from a seed that was |
195 | * encoded public key to |out_encoded_public_key| and sets |out_private_key| to | 131 | * generated by |MLKEM_generate_key| initializing |private_key|. It returns one |
196 | * the private key. If |optional_out_seed| is not NULL then the seed used to | 132 | * on success, and zero on failure or error. |private_key| must be a new |
197 | * generate the private key is written to it. | 133 | * uninitialized key. |seed_len| must be MLKEM_SEED_LENGTH. |
134 | * | ||
135 | * For |private_key| to match the key generated by |MLKEM_generate_key|, | ||
136 | * |private_key| must have been created with the same rank as used when generating | ||
137 | * the key. | ||
198 | */ | 138 | */ |
199 | int MLKEM1024_generate_key( | 139 | int MLKEM_private_key_from_seed(MLKEM_private_key *private_key, |
200 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | 140 | const uint8_t *seed, size_t seed_len); |
201 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
202 | struct MLKEM1024_private_key *out_private_key); | ||
203 | 141 | ||
204 | /* | 142 | /* |
205 | * MLKEM1024_private_key_from_seed derives a private key from a seed that was | 143 | * MLKEM_public_from_private initializes |public_key| with the public key that |
206 | * generated by |MLKEM1024_generate_key|. It fails and returns 0 if |seed_len| | 144 | * corresponds to |private_key|. It returns one on success and zero on |
207 | * is incorrect, otherwise it writes |*out_private_key| and returns 1. | 145 | * error. This is faster than parsing the output of |MLKEM_generate_key| if, for |
146 | * some reason, you need to encapsulate to a key that was just | ||
147 | * generated. |private key| must be a new uninitialized key, of the same rank as | ||
148 | * |public_key|. | ||
208 | */ | 149 | */ |
209 | int MLKEM1024_private_key_from_seed( | 150 | int MLKEM_public_from_private(const MLKEM_private_key *private_key, |
210 | struct MLKEM1024_private_key *out_private_key, const uint8_t *seed, | 151 | MLKEM_public_key *public_key); |
211 | size_t seed_len); | ||
212 | 152 | ||
213 | /* | 153 | /* |
214 | * MLKEM1024_public_from_private sets |*out_public_key| to the public key that | 154 | * MLKEM_encap encrypts a random shared secret for an initialized |
215 | * corresponds to |private_key|. (This is faster than parsing the output of | 155 | * |public_key|. It returns one on success, and zero on failure or error. |*out |
216 | * |MLKEM1024_generate_key| if, for some reason, you need to encapsulate to a | 156 | * ciphertext| and |*out_shared_secret| must have the value NULL. On success, a |
217 | * key that was just generated.) | 157 | * pointer to the ciphertext of the correct size for |key| is returned in |
158 | * |out_ciphertext|, the length in bytes of |*out_ciphertext| is returned in | ||
159 | * |*out_ciphertext_len|, a pointer to the random shared secret is returned in | ||
160 | * |out_shared_secret|, and the length in bytes of |*out_shared_secret| is | ||
161 | * returned in |*out_ciphtertext_len|. The caller is responsible for zeroing and | ||
162 | * freeing the values returned in |out_ciphertext| and |out_shared_secret| | ||
218 | */ | 163 | */ |
219 | void MLKEM1024_public_from_private(struct MLKEM1024_public_key *out_public_key, | 164 | int MLKEM_encap(const MLKEM_public_key *public_key, |
220 | const struct MLKEM1024_private_key *private_key); | 165 | uint8_t **out_ciphertext, size_t *out_ciphertext_len, |
221 | 166 | uint8_t **out_shared_secret, size_t *out_shared_secret_len); | |
222 | /* MLKEM1024_CIPHERTEXT_BYTES is number of bytes in the ML-KEM-1024 ciphertext. */ | ||
223 | #define MLKEM1024_CIPHERTEXT_BYTES 1568 | ||
224 | 167 | ||
225 | /* | 168 | /* |
226 | * MLKEM1024_encap encrypts a random shared secret for |public_key|, writes the | 169 | * MLKEM_decap decrypts a shared secret from |ciphertext| using an initialized |
227 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | 170 | * |private_key|. It returns a pointer to the shared secret|out_shared_secret| |
228 | * |out_shared_secret|. | 171 | * and the length in bytes of |*out_shared_secret| in |*out_shared_secret_len|. |
229 | */ | 172 | * |
230 | void MLKEM1024_encap(uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | 173 | * If |ciphertext_len| is incorrect for |private_key|, |*out_shared_secret| is |
231 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 174 | * not NULL, or memory can not be allocated, it returns zero, otherwise it |
232 | const struct MLKEM1024_public_key *public_key); | 175 | * returns one. If |ciphertext| is invalid, a pointer is returned in |
233 | 176 | * |out_shared_secret| pointing to a key that will always be the same for the | |
234 | /* | 177 | * same |ciphertext| and |private_key|, but which appears to be random unless |
235 | * MLKEM1024_decap decrypts a shared secret from |ciphertext| using | 178 | * one has access to |private_key|. These alternatives occur in constant time. |
236 | * |private_key| and writes it to |out_shared_secret|. If |ciphertext_len| is | 179 | * Any subsequent symmetric encryption using |out_shared_secret| must use an |
237 | * incorrect it returns 0, otherwise it returns 1. If |ciphertext| is invalid | 180 | * authenticated encryption scheme in order to discover the decapsulation |
238 | * (but of the correct length), |out_shared_secret| is filled with a key that | 181 | * failure. The caller is responsible for zeroing and freeing the value returned |
239 | * will always be the same for the same |ciphertext| and |private_key|, but | 182 | * in |out_shared_secret|. |
240 | * which appears to be random unless one has access to |private_key|. These | ||
241 | * alternatives occur in constant time. Any subsequent symmetric encryption | ||
242 | * using |out_shared_secret| must use an authenticated encryption scheme in | ||
243 | * order to discover the decapsulation failure. | ||
244 | */ | 183 | */ |
245 | int MLKEM1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 184 | int MLKEM_decap(const MLKEM_private_key *private_key, |
246 | const uint8_t *ciphertext, size_t ciphertext_len, | 185 | const uint8_t *ciphertext, size_t ciphertext_len, |
247 | const struct MLKEM1024_private_key *private_key); | 186 | uint8_t **out_shared_secret, size_t *out_shared_secret_len); |
187 | |||
188 | /* Serialization of ML-KEM keys. */ | ||
248 | 189 | ||
249 | /* | 190 | /* |
250 | * Serialisation of ML-KEM-1024 keys. | 191 | * MLKEM_marshal_public_key serializes an initialized |public_key| in the |
251 | * MLKEM1024_marshal_public_key serializes |public_key| to |out| in the standard | 192 | * standard format for ML-KEM public keys. It returns one on success or zero on |
252 | * format for ML-KEM-1024 public keys. It returns one on success or zero on | 193 | * allocation error or failure. |*out| must have the value NULL. On success a |
253 | * allocation error. | 194 | * pointer is returned in |out| to the encoded public key matching |public_key|, |
195 | * and a pointer to the length in bytes of the encoded public key is stored in | ||
196 | * |out_len|. The caller is responsible for freeing the values returned in | ||
197 | * |out|. | ||
254 | */ | 198 | */ |
255 | int MLKEM1024_marshal_public_key(uint8_t **output, size_t *output_len, | 199 | int MLKEM_marshal_public_key(const MLKEM_public_key *public_key, uint8_t **out, |
256 | const struct MLKEM1024_public_key *public_key); | 200 | size_t *out_len); |
257 | 201 | ||
258 | /* | 202 | /* |
259 | * MLKEM1024_parse_public_key parses a public key, in the format generated by | 203 | * MLKEM_parse_public_key parses a public key, in the format generated by |
260 | * |MLKEM1024_marshal_public_key|, from |in| and writes the result to | 204 | * |MLKEM_marshal_public_key|, from |in|. It returns one on success or zero on |
261 | * |out_public_key|. It returns one on success or zero on parse error or if | 205 | * error or failure. |public_key| must be a new uninitialized key. |in_len| must |
262 | * there are trailing bytes in |in|. | 206 | * be the correct length for the encoded format of |public_key. On success |
207 | * |public_key| is initialized to the value parsed from |in|. | ||
263 | */ | 208 | */ |
264 | int MLKEM1024_parse_public_key(struct MLKEM1024_public_key *out_public_key, | 209 | int MLKEM_parse_public_key(MLKEM_public_key *public_key, const uint8_t *in, |
265 | const uint8_t *input, size_t input_len); | 210 | size_t in_len); |
266 | 211 | ||
267 | /* | 212 | /* |
268 | * MLKEM1024_parse_private_key parses a private key, in NIST's format for | 213 | * MLKEM_parse_private_key parses a private key, in the format generated by |
269 | * private keys, from |in| and writes the result to |out_private_key|. It | 214 | * |MLKEM_marshal_private_key|, from |in|. It returns one on success or zero on |
270 | * returns one on success or zero on parse error or if there are trailing bytes | 215 | * error or failure. |private_key| must be a new uninitialized key. |in_len| |
271 | * in |in|. This format is verbose and should be avoided. Private keys should be | 216 | * must be the correct length for the encoded format of |private_key. On success |
272 | * stored as seeds and parsed using |MLKEM1024_private_key_from_seed|. | 217 | * |private_key| is initialized to the value parsed from |in|. |
218 | * | ||
219 | * This format is wastefully verbose and should be avoided. Private keys should | ||
220 | * be stored as seeds from |MLKEM_generate_key|, and then parsed using | ||
221 | * |MLKEM_private_key_from_seed|. | ||
273 | */ | 222 | */ |
274 | int MLKEM1024_parse_private_key(struct MLKEM1024_private_key *out_private_key, | 223 | int MLKEM_parse_private_key(MLKEM_private_key *private_key, const uint8_t *in, |
275 | const uint8_t *input, size_t input_len); | 224 | size_t in_len); |
276 | 225 | ||
277 | #if defined(__cplusplus) | 226 | #if defined(__cplusplus) |
278 | } | 227 | } |
diff --git a/src/lib/libcrypto/mlkem/mlkem1024.c b/src/lib/libcrypto/mlkem/mlkem1024.c index 26c4716539..8f4f41f8ff 100644 --- a/src/lib/libcrypto/mlkem/mlkem1024.c +++ b/src/lib/libcrypto/mlkem/mlkem1024.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: mlkem1024.c,v 1.11 2025/05/21 02:18:11 kenjiro Exp $ */ | 1 | /* $OpenBSD: mlkem1024.c,v 1.12 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024, Google Inc. |
4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024, 2025 Bob Beck <beck@obtuse.com> |
5 | * | 5 | * |
6 | * Permission to use, copy, modify, and/or distribute this software for any | 6 | * Permission to use, copy, modify, and/or distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -20,18 +20,14 @@ | |||
20 | #include <stdlib.h> | 20 | #include <stdlib.h> |
21 | #include <string.h> | 21 | #include <string.h> |
22 | 22 | ||
23 | #include "bytestring.h" | 23 | #include <openssl/mlkem.h> |
24 | #include "mlkem.h" | ||
25 | 24 | ||
25 | #include "bytestring.h" | ||
26 | #include "sha3_internal.h" | 26 | #include "sha3_internal.h" |
27 | #include "mlkem_internal.h" | 27 | #include "mlkem_internal.h" |
28 | #include "constant_time.h" | 28 | #include "constant_time.h" |
29 | #include "crypto_internal.h" | 29 | #include "crypto_internal.h" |
30 | 30 | ||
31 | /* Remove later */ | ||
32 | #undef LCRYPTO_ALIAS | ||
33 | #define LCRYPTO_ALIAS(A) | ||
34 | |||
35 | /* | 31 | /* |
36 | * See | 32 | * See |
37 | * https://csrc.nist.gov/pubs/fips/203/final | 33 | * https://csrc.nist.gov/pubs/fips/203/final |
@@ -80,7 +76,6 @@ kdf(uint8_t out[MLKEM_SHARED_SECRET_BYTES], const uint8_t failure_secret[32], | |||
80 | } | 76 | } |
81 | 77 | ||
82 | #define DEGREE 256 | 78 | #define DEGREE 256 |
83 | #define RANK1024 4 | ||
84 | 79 | ||
85 | static const size_t kBarrettMultiplier = 5039; | 80 | static const size_t kBarrettMultiplier = 5039; |
86 | static const unsigned kBarrettShift = 24; | 81 | static const unsigned kBarrettShift = 24; |
@@ -809,9 +804,11 @@ struct public_key { | |||
809 | CTASSERT(sizeof(struct MLKEM1024_public_key) == sizeof(struct public_key)); | 804 | CTASSERT(sizeof(struct MLKEM1024_public_key) == sizeof(struct public_key)); |
810 | 805 | ||
811 | static struct public_key * | 806 | static struct public_key * |
812 | public_key_1024_from_external(const struct MLKEM1024_public_key *external) | 807 | public_key_1024_from_external(const MLKEM_public_key *external) |
813 | { | 808 | { |
814 | return (struct public_key *)external; | 809 | if (external->rank != RANK1024) |
810 | return NULL; | ||
811 | return (struct public_key *)external->key_1024; | ||
815 | } | 812 | } |
816 | 813 | ||
817 | struct private_key { | 814 | struct private_key { |
@@ -823,9 +820,11 @@ struct private_key { | |||
823 | CTASSERT(sizeof(struct MLKEM1024_private_key) == sizeof(struct private_key)); | 820 | CTASSERT(sizeof(struct MLKEM1024_private_key) == sizeof(struct private_key)); |
824 | 821 | ||
825 | static struct private_key * | 822 | static struct private_key * |
826 | private_key_1024_from_external(const struct MLKEM1024_private_key *external) | 823 | private_key_1024_from_external(const MLKEM_private_key *external) |
827 | { | 824 | { |
828 | return (struct private_key *)external; | 825 | if (external->rank != RANK1024) |
826 | return NULL; | ||
827 | return (struct private_key *)external->key_1024; | ||
829 | } | 828 | } |
830 | 829 | ||
831 | /* | 830 | /* |
@@ -835,7 +834,7 @@ private_key_1024_from_external(const struct MLKEM1024_private_key *external) | |||
835 | int | 834 | int |
836 | MLKEM1024_generate_key(uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | 835 | MLKEM1024_generate_key(uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], |
837 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | 836 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], |
838 | struct MLKEM1024_private_key *out_private_key) | 837 | MLKEM_private_key *out_private_key) |
839 | { | 838 | { |
840 | uint8_t entropy_buf[MLKEM_SEED_BYTES]; | 839 | uint8_t entropy_buf[MLKEM_SEED_BYTES]; |
841 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : | 840 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : |
@@ -845,10 +844,9 @@ MLKEM1024_generate_key(uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES | |||
845 | return MLKEM1024_generate_key_external_entropy(out_encoded_public_key, | 844 | return MLKEM1024_generate_key_external_entropy(out_encoded_public_key, |
846 | out_private_key, entropy); | 845 | out_private_key, entropy); |
847 | } | 846 | } |
848 | LCRYPTO_ALIAS(MLKEM1024_generate_key); | ||
849 | 847 | ||
850 | int | 848 | int |
851 | MLKEM1024_private_key_from_seed(struct MLKEM1024_private_key *out_private_key, | 849 | MLKEM1024_private_key_from_seed(MLKEM_private_key *out_private_key, |
852 | const uint8_t *seed, size_t seed_len) | 850 | const uint8_t *seed, size_t seed_len) |
853 | { | 851 | { |
854 | uint8_t public_key_bytes[MLKEM1024_PUBLIC_KEY_BYTES]; | 852 | uint8_t public_key_bytes[MLKEM1024_PUBLIC_KEY_BYTES]; |
@@ -859,7 +857,6 @@ MLKEM1024_private_key_from_seed(struct MLKEM1024_private_key *out_private_key, | |||
859 | return MLKEM1024_generate_key_external_entropy(public_key_bytes, | 857 | return MLKEM1024_generate_key_external_entropy(public_key_bytes, |
860 | out_private_key, seed); | 858 | out_private_key, seed); |
861 | } | 859 | } |
862 | LCRYPTO_ALIAS(MLKEM1024_private_key_from_seed); | ||
863 | 860 | ||
864 | static int | 861 | static int |
865 | mlkem_marshal_public_key(CBB *out, const struct public_key *pub) | 862 | mlkem_marshal_public_key(CBB *out, const struct public_key *pub) |
@@ -872,7 +869,7 @@ mlkem_marshal_public_key(CBB *out, const struct public_key *pub) | |||
872 | int | 869 | int |
873 | MLKEM1024_generate_key_external_entropy( | 870 | MLKEM1024_generate_key_external_entropy( |
874 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | 871 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], |
875 | struct MLKEM1024_private_key *out_private_key, | 872 | MLKEM_private_key *out_private_key, |
876 | const uint8_t entropy[MLKEM_SEED_BYTES]) | 873 | const uint8_t entropy[MLKEM_SEED_BYTES]) |
877 | { | 874 | { |
878 | struct private_key *priv = private_key_1024_from_external( | 875 | struct private_key *priv = private_key_1024_from_external( |
@@ -920,8 +917,8 @@ MLKEM1024_generate_key_external_entropy( | |||
920 | } | 917 | } |
921 | 918 | ||
922 | void | 919 | void |
923 | MLKEM1024_public_from_private(struct MLKEM1024_public_key *out_public_key, | 920 | MLKEM1024_public_from_private(const MLKEM_private_key *private_key, |
924 | const struct MLKEM1024_private_key *private_key) | 921 | MLKEM_public_key *out_public_key) |
925 | { | 922 | { |
926 | struct public_key *const pub = public_key_1024_from_external( | 923 | struct public_key *const pub = public_key_1024_from_external( |
927 | out_public_key); | 924 | out_public_key); |
@@ -930,7 +927,6 @@ MLKEM1024_public_from_private(struct MLKEM1024_public_key *out_public_key, | |||
930 | 927 | ||
931 | *pub = priv->pub; | 928 | *pub = priv->pub; |
932 | } | 929 | } |
933 | LCRYPTO_ALIAS(MLKEM1024_public_from_private); | ||
934 | 930 | ||
935 | /* | 931 | /* |
936 | * Encrypts a message with given randomness to the ciphertext in |out|. Without | 932 | * Encrypts a message with given randomness to the ciphertext in |out|. Without |
@@ -972,9 +968,9 @@ encrypt_cpa(uint8_t out[MLKEM1024_CIPHERTEXT_BYTES], | |||
972 | 968 | ||
973 | /* Calls MLKEM1024_encap_external_entropy| with random bytes */ | 969 | /* Calls MLKEM1024_encap_external_entropy| with random bytes */ |
974 | void | 970 | void |
975 | MLKEM1024_encap(uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | 971 | MLKEM1024_encap(const MLKEM_public_key *public_key, |
976 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 972 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], |
977 | const struct MLKEM1024_public_key *public_key) | 973 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]) |
978 | { | 974 | { |
979 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; | 975 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; |
980 | 976 | ||
@@ -982,14 +978,13 @@ MLKEM1024_encap(uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | |||
982 | MLKEM1024_encap_external_entropy(out_ciphertext, out_shared_secret, | 978 | MLKEM1024_encap_external_entropy(out_ciphertext, out_shared_secret, |
983 | public_key, entropy); | 979 | public_key, entropy); |
984 | } | 980 | } |
985 | LCRYPTO_ALIAS(MLKEM1024_encap); | ||
986 | 981 | ||
987 | /* See section 6.2 of the spec. */ | 982 | /* See section 6.2 of the spec. */ |
988 | void | 983 | void |
989 | MLKEM1024_encap_external_entropy( | 984 | MLKEM1024_encap_external_entropy( |
990 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | 985 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], |
991 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 986 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], |
992 | const struct MLKEM1024_public_key *public_key, | 987 | const MLKEM_public_key *public_key, |
993 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | 988 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) |
994 | { | 989 | { |
995 | const struct public_key *pub = public_key_1024_from_external(public_key); | 990 | const struct public_key *pub = public_key_1024_from_external(public_key); |
@@ -1025,10 +1020,10 @@ decrypt_cpa(uint8_t out[32], const struct private_key *priv, | |||
1025 | 1020 | ||
1026 | /* See section 6.3 */ | 1021 | /* See section 6.3 */ |
1027 | int | 1022 | int |
1028 | MLKEM1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 1023 | MLKEM1024_decap(const MLKEM_private_key *private_key, |
1029 | const uint8_t *ciphertext, size_t ciphertext_len, | 1024 | const uint8_t *ciphertext, size_t ciphertext_len, |
1030 | const struct MLKEM1024_private_key *private_key) | 1025 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]) |
1031 | { | 1026 | { |
1032 | const struct private_key *priv = private_key_1024_from_external( | 1027 | const struct private_key *priv = private_key_1024_from_external( |
1033 | private_key); | 1028 | private_key); |
1034 | uint8_t expected_ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; | 1029 | uint8_t expected_ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; |
@@ -1059,11 +1054,10 @@ MLKEM1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | |||
1059 | 1054 | ||
1060 | return 1; | 1055 | return 1; |
1061 | } | 1056 | } |
1062 | LCRYPTO_ALIAS(MLKEM1024_decap); | ||
1063 | 1057 | ||
1064 | int | 1058 | int |
1065 | MLKEM1024_marshal_public_key(uint8_t **output, size_t *output_len, | 1059 | MLKEM1024_marshal_public_key(const MLKEM_public_key *public_key, |
1066 | const struct MLKEM1024_public_key *public_key) | 1060 | uint8_t **output, size_t *output_len) |
1067 | { | 1061 | { |
1068 | int ret = 0; | 1062 | int ret = 0; |
1069 | CBB cbb; | 1063 | CBB cbb; |
@@ -1083,7 +1077,6 @@ MLKEM1024_marshal_public_key(uint8_t **output, size_t *output_len, | |||
1083 | 1077 | ||
1084 | return ret; | 1078 | return ret; |
1085 | } | 1079 | } |
1086 | LCRYPTO_ALIAS(MLKEM1024_marshal_public_key); | ||
1087 | 1080 | ||
1088 | /* | 1081 | /* |
1089 | * mlkem_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate | 1082 | * mlkem_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate |
@@ -1107,8 +1100,8 @@ mlkem_parse_public_key_no_hash(struct public_key *pub, CBS *in) | |||
1107 | } | 1100 | } |
1108 | 1101 | ||
1109 | int | 1102 | int |
1110 | MLKEM1024_parse_public_key(struct MLKEM1024_public_key *public_key, | 1103 | MLKEM1024_parse_public_key(const uint8_t *input, size_t input_len, |
1111 | const uint8_t *input, size_t input_len) | 1104 | MLKEM_public_key *public_key) |
1112 | { | 1105 | { |
1113 | struct public_key *pub = public_key_1024_from_external(public_key); | 1106 | struct public_key *pub = public_key_1024_from_external(public_key); |
1114 | CBS cbs; | 1107 | CBS cbs; |
@@ -1123,10 +1116,9 @@ MLKEM1024_parse_public_key(struct MLKEM1024_public_key *public_key, | |||
1123 | 1116 | ||
1124 | return 1; | 1117 | return 1; |
1125 | } | 1118 | } |
1126 | LCRYPTO_ALIAS(MLKEM1024_parse_public_key); | ||
1127 | 1119 | ||
1128 | int | 1120 | int |
1129 | MLKEM1024_marshal_private_key(const struct MLKEM1024_private_key *private_key, | 1121 | MLKEM1024_marshal_private_key(const MLKEM_private_key *private_key, |
1130 | uint8_t **out_private_key, size_t *out_private_key_len) | 1122 | uint8_t **out_private_key, size_t *out_private_key_len) |
1131 | { | 1123 | { |
1132 | const struct private_key *const priv = private_key_1024_from_external( | 1124 | const struct private_key *const priv = private_key_1024_from_external( |
@@ -1160,8 +1152,8 @@ MLKEM1024_marshal_private_key(const struct MLKEM1024_private_key *private_key, | |||
1160 | } | 1152 | } |
1161 | 1153 | ||
1162 | int | 1154 | int |
1163 | MLKEM1024_parse_private_key(struct MLKEM1024_private_key *out_private_key, | 1155 | MLKEM1024_parse_private_key(const uint8_t *input, size_t input_len, |
1164 | const uint8_t *input, size_t input_len) | 1156 | MLKEM_private_key *out_private_key) |
1165 | { | 1157 | { |
1166 | struct private_key *const priv = private_key_1024_from_external( | 1158 | struct private_key *const priv = private_key_1024_from_external( |
1167 | out_private_key); | 1159 | out_private_key); |
@@ -1189,4 +1181,3 @@ MLKEM1024_parse_private_key(struct MLKEM1024_private_key *out_private_key, | |||
1189 | 1181 | ||
1190 | return 1; | 1182 | return 1; |
1191 | } | 1183 | } |
1192 | LCRYPTO_ALIAS(MLKEM1024_parse_private_key); | ||
diff --git a/src/lib/libcrypto/mlkem/mlkem768.c b/src/lib/libcrypto/mlkem/mlkem768.c index 653b92d8d8..1a44b9413f 100644 --- a/src/lib/libcrypto/mlkem/mlkem768.c +++ b/src/lib/libcrypto/mlkem/mlkem768.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem768.c,v 1.12 2025/05/20 00:30:38 beck Exp $ */ | 1 | /* $OpenBSD: mlkem768.c,v 1.13 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024, Google Inc. |
4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> |
@@ -19,19 +19,16 @@ | |||
19 | #include <assert.h> | 19 | #include <assert.h> |
20 | #include <stdlib.h> | 20 | #include <stdlib.h> |
21 | #include <string.h> | 21 | #include <string.h> |
22 | #include <stdio.h> | ||
22 | 23 | ||
23 | #include "bytestring.h" | 24 | #include <openssl/mlkem.h> |
24 | #include "mlkem.h" | ||
25 | 25 | ||
26 | #include "bytestring.h" | ||
26 | #include "sha3_internal.h" | 27 | #include "sha3_internal.h" |
27 | #include "mlkem_internal.h" | 28 | #include "mlkem_internal.h" |
28 | #include "constant_time.h" | 29 | #include "constant_time.h" |
29 | #include "crypto_internal.h" | 30 | #include "crypto_internal.h" |
30 | 31 | ||
31 | /* Remove later */ | ||
32 | #undef LCRYPTO_ALIAS | ||
33 | #define LCRYPTO_ALIAS(A) | ||
34 | |||
35 | /* | 32 | /* |
36 | * See | 33 | * See |
37 | * https://csrc.nist.gov/pubs/fips/203/final | 34 | * https://csrc.nist.gov/pubs/fips/203/final |
@@ -80,7 +77,6 @@ kdf(uint8_t out[MLKEM_SHARED_SECRET_BYTES], const uint8_t failure_secret[32], | |||
80 | } | 77 | } |
81 | 78 | ||
82 | #define DEGREE 256 | 79 | #define DEGREE 256 |
83 | #define RANK768 3 | ||
84 | 80 | ||
85 | static const size_t kBarrettMultiplier = 5039; | 81 | static const size_t kBarrettMultiplier = 5039; |
86 | static const unsigned kBarrettShift = 24; | 82 | static const unsigned kBarrettShift = 24; |
@@ -809,9 +805,11 @@ struct public_key { | |||
809 | CTASSERT(sizeof(struct MLKEM768_public_key) == sizeof(struct public_key)); | 805 | CTASSERT(sizeof(struct MLKEM768_public_key) == sizeof(struct public_key)); |
810 | 806 | ||
811 | static struct public_key * | 807 | static struct public_key * |
812 | public_key_768_from_external(const struct MLKEM768_public_key *external) | 808 | public_key_768_from_external(const MLKEM_public_key *external) |
813 | { | 809 | { |
814 | return (struct public_key *)external; | 810 | if (external->rank != RANK768) |
811 | return NULL; | ||
812 | return (struct public_key *)external->key_768; | ||
815 | } | 813 | } |
816 | 814 | ||
817 | struct private_key { | 815 | struct private_key { |
@@ -823,9 +821,11 @@ struct private_key { | |||
823 | CTASSERT(sizeof(struct MLKEM768_private_key) == sizeof(struct private_key)); | 821 | CTASSERT(sizeof(struct MLKEM768_private_key) == sizeof(struct private_key)); |
824 | 822 | ||
825 | static struct private_key * | 823 | static struct private_key * |
826 | private_key_768_from_external(const struct MLKEM768_private_key *external) | 824 | private_key_768_from_external(const MLKEM_private_key *external) |
827 | { | 825 | { |
828 | return (struct private_key *)external; | 826 | if (external->rank != RANK768) |
827 | return NULL; | ||
828 | return (struct private_key *)external->key_768; | ||
829 | } | 829 | } |
830 | 830 | ||
831 | /* | 831 | /* |
@@ -835,7 +835,7 @@ private_key_768_from_external(const struct MLKEM768_private_key *external) | |||
835 | int | 835 | int |
836 | MLKEM768_generate_key(uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | 836 | MLKEM768_generate_key(uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], |
837 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | 837 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], |
838 | struct MLKEM768_private_key *out_private_key) | 838 | MLKEM_private_key *out_private_key) |
839 | { | 839 | { |
840 | uint8_t entropy_buf[MLKEM_SEED_BYTES]; | 840 | uint8_t entropy_buf[MLKEM_SEED_BYTES]; |
841 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : | 841 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : |
@@ -845,12 +845,12 @@ MLKEM768_generate_key(uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | |||
845 | return MLKEM768_generate_key_external_entropy(out_encoded_public_key, | 845 | return MLKEM768_generate_key_external_entropy(out_encoded_public_key, |
846 | out_private_key, entropy); | 846 | out_private_key, entropy); |
847 | } | 847 | } |
848 | LCRYPTO_ALIAS(MLKEM768_generate_key); | ||
849 | 848 | ||
850 | int | 849 | int |
851 | MLKEM768_private_key_from_seed(struct MLKEM768_private_key *out_private_key, | 850 | MLKEM768_private_key_from_seed(const uint8_t *seed, size_t seed_len, |
852 | const uint8_t *seed, size_t seed_len) | 851 | MLKEM_private_key *out_private_key) |
853 | { | 852 | { |
853 | /* XXX stack */ | ||
854 | uint8_t public_key_bytes[MLKEM768_PUBLIC_KEY_BYTES]; | 854 | uint8_t public_key_bytes[MLKEM768_PUBLIC_KEY_BYTES]; |
855 | 855 | ||
856 | if (seed_len != MLKEM_SEED_BYTES) { | 856 | if (seed_len != MLKEM_SEED_BYTES) { |
@@ -859,7 +859,6 @@ MLKEM768_private_key_from_seed(struct MLKEM768_private_key *out_private_key, | |||
859 | return MLKEM768_generate_key_external_entropy(public_key_bytes, | 859 | return MLKEM768_generate_key_external_entropy(public_key_bytes, |
860 | out_private_key, seed); | 860 | out_private_key, seed); |
861 | } | 861 | } |
862 | LCRYPTO_ALIAS(MLKEM768_private_key_from_seed); | ||
863 | 862 | ||
864 | static int | 863 | static int |
865 | mlkem_marshal_public_key(CBB *out, const struct public_key *pub) | 864 | mlkem_marshal_public_key(CBB *out, const struct public_key *pub) |
@@ -872,7 +871,7 @@ mlkem_marshal_public_key(CBB *out, const struct public_key *pub) | |||
872 | int | 871 | int |
873 | MLKEM768_generate_key_external_entropy( | 872 | MLKEM768_generate_key_external_entropy( |
874 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | 873 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], |
875 | struct MLKEM768_private_key *out_private_key, | 874 | MLKEM_private_key *out_private_key, |
876 | const uint8_t entropy[MLKEM_SEED_BYTES]) | 875 | const uint8_t entropy[MLKEM_SEED_BYTES]) |
877 | { | 876 | { |
878 | struct private_key *priv = private_key_768_from_external( | 877 | struct private_key *priv = private_key_768_from_external( |
@@ -920,9 +919,8 @@ MLKEM768_generate_key_external_entropy( | |||
920 | } | 919 | } |
921 | 920 | ||
922 | void | 921 | void |
923 | MLKEM768_public_from_private(struct MLKEM768_public_key *out_public_key, | 922 | MLKEM768_public_from_private(const MLKEM_private_key *private_key, |
924 | const struct MLKEM768_private_key *private_key) | 923 | MLKEM_public_key *out_public_key) { |
925 | { | ||
926 | struct public_key *const pub = public_key_768_from_external( | 924 | struct public_key *const pub = public_key_768_from_external( |
927 | out_public_key); | 925 | out_public_key); |
928 | const struct private_key *const priv = private_key_768_from_external( | 926 | const struct private_key *const priv = private_key_768_from_external( |
@@ -930,7 +928,6 @@ MLKEM768_public_from_private(struct MLKEM768_public_key *out_public_key, | |||
930 | 928 | ||
931 | *pub = priv->pub; | 929 | *pub = priv->pub; |
932 | } | 930 | } |
933 | LCRYPTO_ALIAS(MLKEM768_public_from_private); | ||
934 | 931 | ||
935 | /* | 932 | /* |
936 | * Encrypts a message with given randomness to the ciphertext in |out|. Without | 933 | * Encrypts a message with given randomness to the ciphertext in |out|. Without |
@@ -972,9 +969,9 @@ encrypt_cpa(uint8_t out[MLKEM768_CIPHERTEXT_BYTES], | |||
972 | 969 | ||
973 | /* Calls MLKEM768_encap_external_entropy| with random bytes */ | 970 | /* Calls MLKEM768_encap_external_entropy| with random bytes */ |
974 | void | 971 | void |
975 | MLKEM768_encap(uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | 972 | MLKEM768_encap(const MLKEM_public_key *public_key, |
976 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 973 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], |
977 | const struct MLKEM768_public_key *public_key) | 974 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]) |
978 | { | 975 | { |
979 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; | 976 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; |
980 | 977 | ||
@@ -982,14 +979,13 @@ MLKEM768_encap(uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | |||
982 | MLKEM768_encap_external_entropy(out_ciphertext, | 979 | MLKEM768_encap_external_entropy(out_ciphertext, |
983 | out_shared_secret, public_key, entropy); | 980 | out_shared_secret, public_key, entropy); |
984 | } | 981 | } |
985 | LCRYPTO_ALIAS(MLKEM768_encap); | ||
986 | 982 | ||
987 | /* See section 6.2 of the spec. */ | 983 | /* See section 6.2 of the spec. */ |
988 | void | 984 | void |
989 | MLKEM768_encap_external_entropy( | 985 | MLKEM768_encap_external_entropy( |
990 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | 986 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], |
991 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 987 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], |
992 | const struct MLKEM768_public_key *public_key, | 988 | const MLKEM_public_key *public_key, |
993 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | 989 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) |
994 | { | 990 | { |
995 | const struct public_key *pub = public_key_768_from_external(public_key); | 991 | const struct public_key *pub = public_key_768_from_external(public_key); |
@@ -1025,9 +1021,8 @@ decrypt_cpa(uint8_t out[32], const struct private_key *priv, | |||
1025 | 1021 | ||
1026 | /* See section 6.3 */ | 1022 | /* See section 6.3 */ |
1027 | int | 1023 | int |
1028 | MLKEM768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 1024 | MLKEM768_decap(const MLKEM_private_key *private_key, const uint8_t *ciphertext, |
1029 | const uint8_t *ciphertext, size_t ciphertext_len, | 1025 | size_t ciphertext_len, uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]) |
1030 | const struct MLKEM768_private_key *private_key) | ||
1031 | { | 1026 | { |
1032 | const struct private_key *priv = private_key_768_from_external( | 1027 | const struct private_key *priv = private_key_768_from_external( |
1033 | private_key); | 1028 | private_key); |
@@ -1059,11 +1054,10 @@ MLKEM768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | |||
1059 | 1054 | ||
1060 | return 1; | 1055 | return 1; |
1061 | } | 1056 | } |
1062 | LCRYPTO_ALIAS(MLKEM768_decap); | ||
1063 | 1057 | ||
1064 | int | 1058 | int |
1065 | MLKEM768_marshal_public_key(uint8_t **output, size_t *output_len, | 1059 | MLKEM768_marshal_public_key(const MLKEM_public_key *public_key, |
1066 | const struct MLKEM768_public_key *public_key) | 1060 | uint8_t **output, size_t *output_len) |
1067 | { | 1061 | { |
1068 | int ret = 0; | 1062 | int ret = 0; |
1069 | CBB cbb; | 1063 | CBB cbb; |
@@ -1083,7 +1077,6 @@ MLKEM768_marshal_public_key(uint8_t **output, size_t *output_len, | |||
1083 | 1077 | ||
1084 | return ret; | 1078 | return ret; |
1085 | } | 1079 | } |
1086 | LCRYPTO_ALIAS(MLKEM768_marshal_public_key); | ||
1087 | 1080 | ||
1088 | /* | 1081 | /* |
1089 | * mlkem_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate | 1082 | * mlkem_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate |
@@ -1107,8 +1100,8 @@ mlkem_parse_public_key_no_hash(struct public_key *pub, CBS *in) | |||
1107 | } | 1100 | } |
1108 | 1101 | ||
1109 | int | 1102 | int |
1110 | MLKEM768_parse_public_key(struct MLKEM768_public_key *public_key, | 1103 | MLKEM768_parse_public_key(const uint8_t *input, size_t input_len, |
1111 | const uint8_t *input, size_t input_len) | 1104 | MLKEM_public_key *public_key) |
1112 | { | 1105 | { |
1113 | struct public_key *pub = public_key_768_from_external(public_key); | 1106 | struct public_key *pub = public_key_768_from_external(public_key); |
1114 | CBS cbs; | 1107 | CBS cbs; |
@@ -1123,10 +1116,9 @@ MLKEM768_parse_public_key(struct MLKEM768_public_key *public_key, | |||
1123 | 1116 | ||
1124 | return 1; | 1117 | return 1; |
1125 | } | 1118 | } |
1126 | LCRYPTO_ALIAS(MLKEM768_parse_public_key); | ||
1127 | 1119 | ||
1128 | int | 1120 | int |
1129 | MLKEM768_marshal_private_key(const struct MLKEM768_private_key *private_key, | 1121 | MLKEM768_marshal_private_key(const MLKEM_private_key *private_key, |
1130 | uint8_t **out_private_key, size_t *out_private_key_len) | 1122 | uint8_t **out_private_key, size_t *out_private_key_len) |
1131 | { | 1123 | { |
1132 | const struct private_key *const priv = private_key_768_from_external( | 1124 | const struct private_key *const priv = private_key_768_from_external( |
@@ -1160,8 +1152,8 @@ MLKEM768_marshal_private_key(const struct MLKEM768_private_key *private_key, | |||
1160 | } | 1152 | } |
1161 | 1153 | ||
1162 | int | 1154 | int |
1163 | MLKEM768_parse_private_key(struct MLKEM768_private_key *out_private_key, | 1155 | MLKEM768_parse_private_key(const uint8_t *input, size_t input_len, |
1164 | const uint8_t *input, size_t input_len) | 1156 | MLKEM_private_key *out_private_key) |
1165 | { | 1157 | { |
1166 | struct private_key *const priv = private_key_768_from_external( | 1158 | struct private_key *const priv = private_key_768_from_external( |
1167 | out_private_key); | 1159 | out_private_key); |
@@ -1189,4 +1181,3 @@ MLKEM768_parse_private_key(struct MLKEM768_private_key *out_private_key, | |||
1189 | 1181 | ||
1190 | return 1; | 1182 | return 1; |
1191 | } | 1183 | } |
1192 | LCRYPTO_ALIAS(MLKEM768_parse_private_key); | ||
diff --git a/src/lib/libcrypto/mlkem/mlkem_internal.h b/src/lib/libcrypto/mlkem/mlkem_internal.h index 1e051970a8..776f8aac17 100644 --- a/src/lib/libcrypto/mlkem/mlkem_internal.h +++ b/src/lib/libcrypto/mlkem/mlkem_internal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_internal.h,v 1.7 2025/05/20 00:33:40 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_internal.h,v 1.8 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2023, Google Inc. | 3 | * Copyright (c) 2023, Google Inc. |
4 | * | 4 | * |
@@ -26,6 +26,253 @@ extern "C" { | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | __BEGIN_HIDDEN_DECLS | 28 | __BEGIN_HIDDEN_DECLS |
29 | /* | ||
30 | * MLKEM_SEED_LENGTH is the number of bytes in an ML-KEM seed. An ML-KEM | ||
31 | * seed is normally used to represent a private key. | ||
32 | */ | ||
33 | #define MLKEM_SEED_LENGTH 64 | ||
34 | |||
35 | /* | ||
36 | * MLKEM_SHARED_SECRET_LENGTH is the number of bytes in an ML-KEM shared | ||
37 | * secret. | ||
38 | */ | ||
39 | #define MLKEM_SHARED_SECRET_LENGTH 32 | ||
40 | |||
41 | /* | ||
42 | * |MLKEM_encap_external_entropy| behaves exactly like the public |MLKEM_encap| | ||
43 | * with the entropy provided by the caller. It is directly called internally | ||
44 | * and by tests. | ||
45 | */ | ||
46 | int | ||
47 | MLKEM_encap_external_entropy(const MLKEM_public_key *public_key, | ||
48 | const uint8_t *entropy, uint8_t **out_ciphertext, | ||
49 | size_t *out_ciphertext_len, uint8_t **out_shared_secret, | ||
50 | size_t *out_shared_secret_len); | ||
51 | |||
52 | /* | ||
53 | * |MLKEM_generate_key_external_entropy| behaves exactly like the public | ||
54 | * |MLKEM_generate_key| with the entropy provided by the caller. | ||
55 | * It is directly called internally and by tests. | ||
56 | */ | ||
57 | int | ||
58 | MLKEM_generate_key_external_entropy(MLKEM_private_key *private_key, | ||
59 | uint8_t **out_encoded_public_key, size_t *out_encoded_public_key_len, | ||
60 | const uint8_t *entropy); | ||
61 | /* | ||
62 | * Marshals a private key to encoded format, used for NIST tests. | ||
63 | */ | ||
64 | int MLKEM_marshal_private_key(const MLKEM_private_key *private_key, | ||
65 | uint8_t **out, size_t *out_len); | ||
66 | |||
67 | /* | ||
68 | * ML-KEM-768 | ||
69 | * | ||
70 | * This implements the Module-Lattice-Based Key-Encapsulation Mechanism from | ||
71 | * https://csrc.nist.gov/pubs/fips/204/final | ||
72 | */ | ||
73 | |||
74 | /* | ||
75 | * MLKEM768_PUBLIC_KEY_BYTES is the number of bytes in an encoded ML-KEM768 public | ||
76 | * key. | ||
77 | */ | ||
78 | #define MLKEM768_PUBLIC_KEY_BYTES 1184 | ||
79 | |||
80 | /* MLKEM_SEED_BYTES is the number of bytes in an ML-KEM seed. */ | ||
81 | #define MLKEM_SEED_BYTES 64 | ||
82 | |||
83 | /* | ||
84 | * MLKEM_SHARED_SECRET_BYTES is the number of bytes in the ML-KEM768 shared | ||
85 | * secret. Although the round-3 specification has a variable-length output, the | ||
86 | * final ML-KEM construction is expected to use a fixed 32-byte output. To | ||
87 | * simplify the future transition, we apply the same restriction. | ||
88 | */ | ||
89 | #define MLKEM_SHARED_SECRET_BYTES 32 | ||
90 | |||
91 | /* | ||
92 | * MLKEM_generate_key generates a random public/private key pair, writes the | ||
93 | * encoded public key to |out_encoded_public_key| and sets |out_private_key| to | ||
94 | * the private key. If |optional_out_seed| is not NULL then the seed used to | ||
95 | * generate the private key is written to it. | ||
96 | */ | ||
97 | int MLKEM768_generate_key( | ||
98 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | ||
99 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
100 | MLKEM_private_key *out_private_key); | ||
101 | |||
102 | /* | ||
103 | * MLKEM768_private_key_from_seed derives a private key from a seed that was | ||
104 | * generated by |MLKEM768_generate_key|. It fails and returns 0 if |seed_len| is | ||
105 | * incorrect, otherwise it writes |*out_private_key| and returns 1. | ||
106 | */ | ||
107 | int MLKEM768_private_key_from_seed(const uint8_t *seed, size_t seed_len, | ||
108 | MLKEM_private_key *out_private_key); | ||
109 | |||
110 | /* | ||
111 | * MLKEM_public_from_private sets |*out_public_key| to the public key that | ||
112 | * corresponds to |private_key|. (This is faster than parsing the output of | ||
113 | * |MLKEM_generate_key| if, for some reason, you need to encapsulate to a key | ||
114 | * that was just generated.) | ||
115 | */ | ||
116 | void MLKEM768_public_from_private(const MLKEM_private_key *private_key, | ||
117 | MLKEM_public_key *out_public_key); | ||
118 | |||
119 | /* MLKEM768_CIPHERTEXT_BYTES is number of bytes in the ML-KEM768 ciphertext. */ | ||
120 | #define MLKEM768_CIPHERTEXT_BYTES 1088 | ||
121 | |||
122 | /* | ||
123 | * MLKEM768_encap encrypts a random shared secret for |public_key|, writes the | ||
124 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | ||
125 | * |out_shared_secret|. | ||
126 | */ | ||
127 | void MLKEM768_encap(const MLKEM_public_key *public_key, | ||
128 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | ||
129 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]); | ||
130 | |||
131 | /* | ||
132 | * MLKEM768_decap decrypts a shared secret from |ciphertext| using |private_key| | ||
133 | * and writes it to |out_shared_secret|. If |ciphertext_len| is incorrect it | ||
134 | * returns 0, otherwise it rreturns 1. If |ciphertext| is invalid, | ||
135 | * |out_shared_secret| is filled with a key that will always be the same for the | ||
136 | * same |ciphertext| and |private_key|, but which appears to be random unless | ||
137 | * one has access to |private_key|. These alternatives occur in constant time. | ||
138 | * Any subsequent symmetric encryption using |out_shared_secret| must use an | ||
139 | * authenticated encryption scheme in order to discover the decapsulation | ||
140 | * failure. | ||
141 | */ | ||
142 | int MLKEM768_decap(const MLKEM_private_key *private_key, | ||
143 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
144 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]); | ||
145 | |||
146 | /* Serialisation of keys. */ | ||
147 | |||
148 | /* | ||
149 | * MLKEM768_marshal_public_key serializes |public_key| to |out| in the standard | ||
150 | * format for ML-KEM public keys. It returns one on success or zero on allocation | ||
151 | * error. | ||
152 | */ | ||
153 | int MLKEM768_marshal_public_key(const MLKEM_public_key *public_key, | ||
154 | uint8_t **output, size_t *output_len); | ||
155 | |||
156 | /* | ||
157 | * MLKEM768_parse_public_key parses a public key, in the format generated by | ||
158 | * |MLKEM_marshal_public_key|, from |in| and writes the result to | ||
159 | * |out_public_key|. It returns one on success or zero on parse error or if | ||
160 | * there are trailing bytes in |in|. | ||
161 | */ | ||
162 | int MLKEM768_parse_public_key(const uint8_t *input, size_t input_len, | ||
163 | MLKEM_public_key *out_public_key); | ||
164 | |||
165 | /* | ||
166 | * MLKEM_parse_private_key parses a private key, in the format generated by | ||
167 | * |MLKEM_marshal_private_key|, from |in| and writes the result to | ||
168 | * |out_private_key|. It returns one on success or zero on parse error or if | ||
169 | * there are trailing bytes in |in|. This formate is verbose and should be avoided. | ||
170 | * Private keys should be stored as seeds and parsed using |MLKEM768_private_key_from_seed|. | ||
171 | */ | ||
172 | int MLKEM768_parse_private_key(const uint8_t *input, size_t input_len, | ||
173 | MLKEM_private_key *out_private_key); | ||
174 | |||
175 | /* | ||
176 | * ML-KEM-1024 | ||
177 | * | ||
178 | * ML-KEM-1024 also exists. You should prefer ML-KEM-768 where possible. | ||
179 | */ | ||
180 | |||
181 | /* | ||
182 | * MLKEM1024_PUBLIC_KEY_BYTES is the number of bytes in an encoded ML-KEM-1024 | ||
183 | * public key. | ||
184 | */ | ||
185 | #define MLKEM1024_PUBLIC_KEY_BYTES 1568 | ||
186 | |||
187 | /* | ||
188 | * MLKEM1024_generate_key generates a random public/private key pair, writes the | ||
189 | * encoded public key to |out_encoded_public_key| and sets |out_private_key| to | ||
190 | * the private key. If |optional_out_seed| is not NULL then the seed used to | ||
191 | * generate the private key is written to it. | ||
192 | */ | ||
193 | int MLKEM1024_generate_key( | ||
194 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | ||
195 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
196 | MLKEM_private_key *out_private_key); | ||
197 | |||
198 | /* | ||
199 | * MLKEM1024_private_key_from_seed derives a private key from a seed that was | ||
200 | * generated by |MLKEM1024_generate_key|. It fails and returns 0 if |seed_len| | ||
201 | * is incorrect, otherwise it writes |*out_private_key| and returns 1. | ||
202 | */ | ||
203 | int MLKEM1024_private_key_from_seed( | ||
204 | MLKEM_private_key *out_private_key, const uint8_t *seed, | ||
205 | size_t seed_len); | ||
206 | |||
207 | /* | ||
208 | * MLKEM1024_public_from_private sets |*out_public_key| to the public key that | ||
209 | * corresponds to |private_key|. (This is faster than parsing the output of | ||
210 | * |MLKEM1024_generate_key| if, for some reason, you need to encapsulate to a | ||
211 | * key that was just generated.) | ||
212 | */ | ||
213 | void MLKEM1024_public_from_private(const MLKEM_private_key *private_key, | ||
214 | MLKEM_public_key *out_public_key); | ||
215 | |||
216 | /* MLKEM1024_CIPHERTEXT_BYTES is number of bytes in the ML-KEM-1024 ciphertext. */ | ||
217 | #define MLKEM1024_CIPHERTEXT_BYTES 1568 | ||
218 | |||
219 | /* | ||
220 | * MLKEM1024_encap encrypts a random shared secret for |public_key|, writes the | ||
221 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | ||
222 | * |out_shared_secret|. | ||
223 | */ | ||
224 | void MLKEM1024_encap(const MLKEM_public_key *public_key, | ||
225 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | ||
226 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]); | ||
227 | |||
228 | |||
229 | /* | ||
230 | * MLKEM1024_decap decrypts a shared secret from |ciphertext| using | ||
231 | * |private_key| and writes it to |out_shared_secret|. If |ciphertext_len| is | ||
232 | * incorrect it returns 0, otherwise it returns 1. If |ciphertext| is invalid | ||
233 | * (but of the correct length), |out_shared_secret| is filled with a key that | ||
234 | * will always be the same for the same |ciphertext| and |private_key|, but | ||
235 | * which appears to be random unless one has access to |private_key|. These | ||
236 | * alternatives occur in constant time. Any subsequent symmetric encryption | ||
237 | * using |out_shared_secret| must use an authenticated encryption scheme in | ||
238 | * order to discover the decapsulation failure. | ||
239 | */ | ||
240 | int MLKEM1024_decap(const MLKEM_private_key *private_key, | ||
241 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
242 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES]); | ||
243 | |||
244 | /* | ||
245 | * Serialisation of ML-KEM-1024 keys. | ||
246 | * MLKEM1024_marshal_public_key serializes |public_key| to |out| in the standard | ||
247 | * format for ML-KEM-1024 public keys. It returns one on success or zero on | ||
248 | * allocation error. | ||
249 | */ | ||
250 | int MLKEM1024_marshal_public_key(const MLKEM_public_key *public_key, | ||
251 | uint8_t **output, size_t *output_len); | ||
252 | |||
253 | |||
254 | /* | ||
255 | * MLKEM1024_parse_public_key parses a public key, in the format generated by | ||
256 | * |MLKEM1024_marshal_public_key|, from |in| and writes the result to | ||
257 | * |out_public_key|. It returns one on success or zero on parse error or if | ||
258 | * there are trailing bytes in |in|. | ||
259 | */ | ||
260 | int MLKEM1024_parse_public_key(const uint8_t *input, size_t input_len, | ||
261 | MLKEM_public_key *out_public_key); | ||
262 | |||
263 | |||
264 | /* | ||
265 | * MLKEM1024_parse_private_key parses a private key, in NIST's format for | ||
266 | * private keys, from |in| and writes the result to |out_private_key|. It | ||
267 | * returns one on success or zero on parse error or if there are trailing bytes | ||
268 | * in |in|. This format is verbose and should be avoided. Private keys should be | ||
269 | * stored as seeds and parsed using |MLKEM1024_private_key_from_seed|. | ||
270 | */ | ||
271 | int MLKEM1024_parse_private_key(const uint8_t *input, size_t input_len, | ||
272 | MLKEM_private_key *out_private_key); | ||
273 | |||
274 | |||
275 | /* XXXX Truly internal stuff below, also in need of de-duping */ | ||
29 | 276 | ||
30 | /* | 277 | /* |
31 | * MLKEM_ENCAP_ENTROPY is the number of bytes of uniformly random entropy | 278 | * MLKEM_ENCAP_ENTROPY is the number of bytes of uniformly random entropy |
@@ -35,6 +282,49 @@ __BEGIN_HIDDEN_DECLS | |||
35 | #define MLKEM_ENCAP_ENTROPY 32 | 282 | #define MLKEM_ENCAP_ENTROPY 32 |
36 | 283 | ||
37 | /* | 284 | /* |
285 | * MLKEM768_public_key contains a ML-KEM-768 public key. The contents of this | ||
286 | * object should never leave the address space since the format is unstable. | ||
287 | */ | ||
288 | struct MLKEM768_public_key { | ||
289 | union { | ||
290 | uint8_t bytes[512 * (3 + 9) + 32 + 32]; | ||
291 | uint16_t alignment; | ||
292 | } opaque; | ||
293 | }; | ||
294 | |||
295 | /* | ||
296 | * MLKEM768_private_key contains a ML-KEM-768 private key. The contents of this | ||
297 | * object should never leave the address space since the format is unstable. | ||
298 | */ | ||
299 | struct MLKEM768_private_key { | ||
300 | union { | ||
301 | uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; | ||
302 | uint16_t alignment; | ||
303 | } opaque; | ||
304 | }; | ||
305 | |||
306 | /* Public opaque ML-KEM key structures. */ | ||
307 | |||
308 | #define MLKEM_PUBLIC_KEY_UNINITIALIZED 1 | ||
309 | #define MLKEM_PUBLIC_KEY_INITIALIZED 2 | ||
310 | #define MLKEM_PRIVATE_KEY_UNINITIALIZED 3 | ||
311 | #define MLKEM_PRIVATE_KEY_INITIALIZED 4 | ||
312 | |||
313 | struct MLKEM_public_key_st { | ||
314 | uint16_t rank; | ||
315 | int state; | ||
316 | struct MLKEM768_public_key *key_768; | ||
317 | struct MLKEM1024_public_key *key_1024; | ||
318 | }; | ||
319 | |||
320 | struct MLKEM_private_key_st { | ||
321 | uint16_t rank; | ||
322 | int state; | ||
323 | struct MLKEM768_private_key *key_768; | ||
324 | struct MLKEM1024_private_key *key_1024; | ||
325 | }; | ||
326 | |||
327 | /* | ||
38 | * MLKEM768_generate_key_external_entropy is a deterministic function to create a | 328 | * MLKEM768_generate_key_external_entropy is a deterministic function to create a |
39 | * pair of ML-KEM 768 keys, using the supplied entropy. The entropy needs to be | 329 | * pair of ML-KEM 768 keys, using the supplied entropy. The entropy needs to be |
40 | * uniformly random generated. This function is should only be used for tests, | 330 | * uniformly random generated. This function is should only be used for tests, |
@@ -43,7 +333,7 @@ __BEGIN_HIDDEN_DECLS | |||
43 | */ | 333 | */ |
44 | int MLKEM768_generate_key_external_entropy( | 334 | int MLKEM768_generate_key_external_entropy( |
45 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | 335 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], |
46 | struct MLKEM768_private_key *out_private_key, | 336 | MLKEM_private_key *out_private_key, |
47 | const uint8_t entropy[MLKEM_SEED_BYTES]); | 337 | const uint8_t entropy[MLKEM_SEED_BYTES]); |
48 | 338 | ||
49 | /* | 339 | /* |
@@ -57,11 +347,11 @@ int MLKEM768_generate_key_external_entropy( | |||
57 | * format for ML-KEM private keys. It returns one on success or zero on | 347 | * format for ML-KEM private keys. It returns one on success or zero on |
58 | * allocation error. | 348 | * allocation error. |
59 | */ | 349 | */ |
60 | int MLKEM768_marshal_private_key(const struct MLKEM768_private_key *private_key, | 350 | int MLKEM768_marshal_private_key(const MLKEM_private_key *private_key, |
61 | uint8_t **out_private_key, size_t *out_private_key_len); | 351 | uint8_t **out_private_key, size_t *out_private_key_len); |
62 | 352 | ||
63 | /* | 353 | /* |
64 | * MLKEM_encap_external_entropy behaves like |MLKEM_encap|, but uses | 354 | * MLKEM768_encap_external_entropy behaves like |MLKEM768_encap|, but uses |
65 | * |MLKEM_ENCAP_ENTROPY| bytes of |entropy| for randomization. The decapsulating | 355 | * |MLKEM_ENCAP_ENTROPY| bytes of |entropy| for randomization. The decapsulating |
66 | * side will be able to recover |entropy| in full. This function should only be | 356 | * side will be able to recover |entropy| in full. This function should only be |
67 | * used for tests, regular callers should use the non-deterministic | 357 | * used for tests, regular callers should use the non-deterministic |
@@ -70,9 +360,34 @@ int MLKEM768_marshal_private_key(const struct MLKEM768_private_key *private_key, | |||
70 | void MLKEM768_encap_external_entropy( | 360 | void MLKEM768_encap_external_entropy( |
71 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | 361 | uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], |
72 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 362 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], |
73 | const struct MLKEM768_public_key *public_key, | 363 | const MLKEM_public_key *public_key, |
74 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | 364 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); |
75 | 365 | ||
366 | |||
367 | /* | ||
368 | * MLKEM1024_public_key contains an ML-KEM-1024 public key. The contents of this | ||
369 | * object should never leave the address space since the format is unstable. | ||
370 | */ | ||
371 | struct MLKEM1024_public_key { | ||
372 | union { | ||
373 | uint8_t bytes[512 * (4 + 16) + 32 + 32]; | ||
374 | uint16_t alignment; | ||
375 | } opaque; | ||
376 | }; | ||
377 | |||
378 | /* | ||
379 | * MLKEM1024_private_key contains a ML-KEM-1024 private key. The contents of | ||
380 | * this object should never leave the address space since the format is | ||
381 | * unstable. | ||
382 | */ | ||
383 | struct MLKEM1024_private_key { | ||
384 | union { | ||
385 | uint8_t bytes[512 * (4 + 4 + 16) + 32 + 32 + 32]; | ||
386 | uint16_t alignment; | ||
387 | } opaque; | ||
388 | }; | ||
389 | |||
390 | |||
76 | /* | 391 | /* |
77 | * MLKEM1024_generate_key_external_entropy is a deterministic function to create a | 392 | * MLKEM1024_generate_key_external_entropy is a deterministic function to create a |
78 | * pair of ML-KEM 1024 keys, using the supplied entropy. The entropy needs to be | 393 | * pair of ML-KEM 1024 keys, using the supplied entropy. The entropy needs to be |
@@ -82,7 +397,7 @@ void MLKEM768_encap_external_entropy( | |||
82 | */ | 397 | */ |
83 | int MLKEM1024_generate_key_external_entropy( | 398 | int MLKEM1024_generate_key_external_entropy( |
84 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | 399 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], |
85 | struct MLKEM1024_private_key *out_private_key, | 400 | MLKEM_private_key *out_private_key, |
86 | const uint8_t entropy[MLKEM_SEED_BYTES]); | 401 | const uint8_t entropy[MLKEM_SEED_BYTES]); |
87 | 402 | ||
88 | /* | 403 | /* |
@@ -97,7 +412,7 @@ int MLKEM1024_generate_key_external_entropy( | |||
97 | * allocation error. | 412 | * allocation error. |
98 | */ | 413 | */ |
99 | int MLKEM1024_marshal_private_key( | 414 | int MLKEM1024_marshal_private_key( |
100 | const struct MLKEM1024_private_key *private_key, uint8_t **out_private_key, | 415 | const MLKEM_private_key *private_key, uint8_t **out_private_key, |
101 | size_t *out_private_key_len); | 416 | size_t *out_private_key_len); |
102 | 417 | ||
103 | /* | 418 | /* |
@@ -110,7 +425,7 @@ int MLKEM1024_marshal_private_key( | |||
110 | void MLKEM1024_encap_external_entropy( | 425 | void MLKEM1024_encap_external_entropy( |
111 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | 426 | uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], |
112 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | 427 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], |
113 | const struct MLKEM1024_public_key *public_key, | 428 | const MLKEM_public_key *public_key, |
114 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | 429 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); |
115 | 430 | ||
116 | __END_HIDDEN_DECLS | 431 | __END_HIDDEN_DECLS |
diff --git a/src/lib/libcrypto/mlkem/mlkem_key.c b/src/lib/libcrypto/mlkem/mlkem_key.c new file mode 100644 index 0000000000..051d8f2b88 --- /dev/null +++ b/src/lib/libcrypto/mlkem/mlkem_key.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* $OpenBSD: mlkem_key.c,v 1.1 2025/08/14 15:48:48 beck Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2025 Bob Beck <beck@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | |||
21 | #include <openssl/mlkem.h> | ||
22 | |||
23 | #include "mlkem_internal.h" | ||
24 | |||
25 | MLKEM_private_key * | ||
26 | MLKEM_private_key_new(int rank) | ||
27 | { | ||
28 | struct MLKEM1024_private_key *key_1024 = NULL; | ||
29 | struct MLKEM768_private_key *key_768 = NULL; | ||
30 | MLKEM_private_key *key = NULL; | ||
31 | MLKEM_private_key *ret = NULL; | ||
32 | |||
33 | if ((key = calloc(1, sizeof(MLKEM_private_key))) == NULL) | ||
34 | goto err; | ||
35 | |||
36 | switch (rank) { | ||
37 | case RANK768: | ||
38 | if ((key_768 = calloc(1, sizeof(*key_768))) == | ||
39 | NULL) | ||
40 | goto err; | ||
41 | key->key_768 = key_768; | ||
42 | break; | ||
43 | case RANK1024: | ||
44 | if ((key_1024 = calloc(1, sizeof(*key_1024))) == | ||
45 | NULL) | ||
46 | goto err; | ||
47 | key->key_1024 = key_1024; | ||
48 | break; | ||
49 | default: | ||
50 | goto err; | ||
51 | } | ||
52 | key->rank = rank; | ||
53 | key->state = MLKEM_PRIVATE_KEY_UNINITIALIZED; | ||
54 | |||
55 | ret = key; | ||
56 | key= NULL; | ||
57 | |||
58 | err: | ||
59 | MLKEM_private_key_free(key); | ||
60 | |||
61 | return ret; | ||
62 | } | ||
63 | LCRYPTO_ALIAS(MLKEM_private_key_new); | ||
64 | |||
65 | void | ||
66 | MLKEM_private_key_free(MLKEM_private_key *key) | ||
67 | { | ||
68 | if (key == NULL) | ||
69 | return; | ||
70 | |||
71 | freezero(key->key_768, sizeof(*key->key_768)); | ||
72 | freezero(key->key_1024, sizeof(*key->key_1024)); | ||
73 | freezero(key, sizeof(*key)); | ||
74 | } | ||
75 | LCRYPTO_ALIAS(MLKEM_private_key_free); | ||
76 | |||
77 | size_t | ||
78 | MLKEM_private_key_encoded_length(const MLKEM_private_key *key) | ||
79 | { | ||
80 | if (key == NULL) | ||
81 | return 0; | ||
82 | |||
83 | switch (key->rank) { | ||
84 | case RANK768: | ||
85 | return MLKEM768_PRIVATE_KEY_BYTES; | ||
86 | case RANK1024: | ||
87 | return MLKEM1024_PRIVATE_KEY_BYTES; | ||
88 | default: | ||
89 | return 0; | ||
90 | } | ||
91 | return 0; | ||
92 | } | ||
93 | LCRYPTO_ALIAS(MLKEM_private_key_encoded_length); | ||
94 | |||
95 | size_t | ||
96 | MLKEM_private_key_ciphertext_length(const MLKEM_private_key *key) | ||
97 | { | ||
98 | if (key == NULL) | ||
99 | return 0; | ||
100 | |||
101 | switch (key->rank) { | ||
102 | case RANK768: | ||
103 | return MLKEM768_CIPHERTEXT_BYTES; | ||
104 | case RANK1024: | ||
105 | return MLKEM1024_CIPHERTEXT_BYTES; | ||
106 | default: | ||
107 | return 0; | ||
108 | } | ||
109 | return 0; | ||
110 | } | ||
111 | LCRYPTO_ALIAS(MLKEM_private_key_ciphertext_length); | ||
112 | |||
113 | MLKEM_public_key * | ||
114 | MLKEM_public_key_new(int rank) | ||
115 | { | ||
116 | struct MLKEM1024_public_key *key_1024 = NULL; | ||
117 | struct MLKEM768_public_key *key_768 = NULL; | ||
118 | MLKEM_public_key *key = NULL; | ||
119 | MLKEM_public_key *ret = NULL; | ||
120 | |||
121 | if ((key = calloc(1, sizeof(MLKEM_public_key))) == NULL) | ||
122 | goto err; | ||
123 | |||
124 | switch (rank) { | ||
125 | case RANK768: | ||
126 | if ((key_768 = calloc(1, sizeof(*key_768))) == | ||
127 | NULL) | ||
128 | goto err; | ||
129 | key->key_768 = key_768; | ||
130 | break; | ||
131 | case RANK1024: | ||
132 | if ((key_1024 = calloc(1, sizeof(*key_1024))) == | ||
133 | NULL) | ||
134 | goto err; | ||
135 | key->key_1024 = key_1024; | ||
136 | break; | ||
137 | default: | ||
138 | goto err; | ||
139 | } | ||
140 | |||
141 | key->rank = rank; | ||
142 | key->state = MLKEM_PUBLIC_KEY_UNINITIALIZED; | ||
143 | |||
144 | ret = key; | ||
145 | key = NULL; | ||
146 | |||
147 | err: | ||
148 | MLKEM_public_key_free(key); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | LCRYPTO_ALIAS(MLKEM_public_key_new); | ||
153 | |||
154 | void | ||
155 | MLKEM_public_key_free(MLKEM_public_key *key) | ||
156 | { | ||
157 | if (key == NULL) | ||
158 | return; | ||
159 | |||
160 | freezero(key->key_768, sizeof(*key->key_768)); | ||
161 | freezero(key->key_1024, sizeof(*key->key_1024)); | ||
162 | freezero(key, sizeof(*key)); | ||
163 | } | ||
164 | LCRYPTO_ALIAS(MLKEM_public_key_free); | ||
165 | |||
166 | size_t | ||
167 | MLKEM_public_key_encoded_length(const MLKEM_public_key *key) | ||
168 | { | ||
169 | if (key == NULL) | ||
170 | return 0; | ||
171 | |||
172 | switch (key->rank) { | ||
173 | case RANK768: | ||
174 | return MLKEM768_PUBLIC_KEY_BYTES; | ||
175 | case RANK1024: | ||
176 | return MLKEM1024_PUBLIC_KEY_BYTES; | ||
177 | default: | ||
178 | return 0; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | LCRYPTO_ALIAS(MLKEM_public_key_encoded_length); | ||
183 | |||
184 | size_t | ||
185 | MLKEM_public_key_ciphertext_length(const MLKEM_public_key *key) | ||
186 | { | ||
187 | if (key == NULL) | ||
188 | return 0; | ||
189 | |||
190 | switch (key->rank) { | ||
191 | case RANK768: | ||
192 | return MLKEM768_CIPHERTEXT_BYTES; | ||
193 | case RANK1024: | ||
194 | return MLKEM1024_CIPHERTEXT_BYTES; | ||
195 | default: | ||
196 | return 0; | ||
197 | } | ||
198 | return 0; | ||
199 | } | ||
200 | LCRYPTO_ALIAS(MLKEM_public_key_ciphertext_length); | ||