diff options
author | beck <> | 2025-08-14 15:48:48 +0000 |
---|---|---|
committer | beck <> | 2025-08-14 15:48:48 +0000 |
commit | 6452fa9fc6f33dac80ee572764b9fe29a469f8ce (patch) | |
tree | 0956ae670e4f193442bcf99d2b1fb70a43a6b5b5 | |
parent | 9bef27f78e41e8026f1d588e4e36e385061f3deb (diff) | |
download | openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.tar.gz openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.tar.bz2 openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.zip |
Add a reasonable ML-KEM API for public use.
Adapt the tests to use this API.
This does not yet make the symbols public in Symbols.list
which will happen shortly with a bump.
This includes some partial rototilling of the non-public
interfaces which will be shortly continued when the internal
code is deduplicated to not have multiple copies for ML-KEM
768 and ML-KEM 1024 (which is just an artifact of unravelling
the boring C++ code).
ok jsing@, tb@
-rw-r--r-- | src/lib/libcrypto/Makefile | 5 | ||||
-rw-r--r-- | src/lib/libcrypto/hidden/openssl/mlkem.h | 40 | ||||
-rw-r--r-- | src/lib/libcrypto/mlkem/mlkem.c | 638 | ||||
-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 | ||||
-rw-r--r-- | src/lib/libssl/ssl_rsa.c | 4 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c | 179 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests.c | 292 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c | 158 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h | 58 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_unittest.c | 302 |
14 files changed, 1783 insertions, 897 deletions
diff --git a/src/lib/libcrypto/Makefile b/src/lib/libcrypto/Makefile index b0ab507983..459b0c9235 100644 --- a/src/lib/libcrypto/Makefile +++ b/src/lib/libcrypto/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: Makefile,v 1.241 2025/07/16 15:59:26 tb Exp $ | 1 | # $OpenBSD: Makefile,v 1.242 2025/08/14 15:48:48 beck Exp $ |
2 | 2 | ||
3 | LIB= crypto | 3 | LIB= crypto |
4 | LIBREBUILD=y | 4 | LIBREBUILD=y |
@@ -374,8 +374,10 @@ SRCS+= md4.c | |||
374 | SRCS+= md5.c | 374 | SRCS+= md5.c |
375 | 375 | ||
376 | # mlkem/ | 376 | # mlkem/ |
377 | SRCS+= mlkem.c | ||
377 | SRCS+= mlkem768.c | 378 | SRCS+= mlkem768.c |
378 | SRCS+= mlkem1024.c | 379 | SRCS+= mlkem1024.c |
380 | SRCS+= mlkem_key.c | ||
379 | 381 | ||
380 | # modes/ | 382 | # modes/ |
381 | SRCS+= cbc128.c | 383 | SRCS+= cbc128.c |
@@ -668,6 +670,7 @@ HDRS=\ | |||
668 | ${LCRYPTO_SRC}/lhash/lhash.h \ | 670 | ${LCRYPTO_SRC}/lhash/lhash.h \ |
669 | ${LCRYPTO_SRC}/md4/md4.h \ | 671 | ${LCRYPTO_SRC}/md4/md4.h \ |
670 | ${LCRYPTO_SRC}/md5/md5.h \ | 672 | ${LCRYPTO_SRC}/md5/md5.h \ |
673 | ${LCRYPTO_SRC}/mlkem/mlkem.h \ | ||
671 | ${LCRYPTO_SRC}/modes/modes.h \ | 674 | ${LCRYPTO_SRC}/modes/modes.h \ |
672 | ${LCRYPTO_SRC}/objects/objects.h \ | 675 | ${LCRYPTO_SRC}/objects/objects.h \ |
673 | ${LCRYPTO_SRC}/ocsp/ocsp.h \ | 676 | ${LCRYPTO_SRC}/ocsp/ocsp.h \ |
diff --git a/src/lib/libcrypto/hidden/openssl/mlkem.h b/src/lib/libcrypto/hidden/openssl/mlkem.h index 8cd80eb3af..3807b3fa1e 100644 --- a/src/lib/libcrypto/hidden/openssl/mlkem.h +++ b/src/lib/libcrypto/hidden/openssl/mlkem.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* $OpenBSD: mlkem.h,v 1.4 2024/12/20 15:10:31 tb Exp $ */ | 1 | /* $OpenBSD: mlkem.h,v 1.5 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | 3 | * Copyright (c) 2025 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any | 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 | 6 | * purpose with or without fee is hereby granted, provided that the above |
@@ -18,9 +18,6 @@ | |||
18 | #ifndef _LIBCRYPTO_MLKEM_H | 18 | #ifndef _LIBCRYPTO_MLKEM_H |
19 | #define _LIBCRYPTO_MLKEM_H | 19 | #define _LIBCRYPTO_MLKEM_H |
20 | 20 | ||
21 | /* Undo when making public */ | ||
22 | #ifdef LIBRESSL_HAS_MLKEM | ||
23 | |||
24 | #ifndef _MSC_VER | 21 | #ifndef _MSC_VER |
25 | #include_next <openssl/mlkem.h> | 22 | #include_next <openssl/mlkem.h> |
26 | #else | 23 | #else |
@@ -28,22 +25,21 @@ | |||
28 | #endif | 25 | #endif |
29 | #include "crypto_namespace.h" | 26 | #include "crypto_namespace.h" |
30 | 27 | ||
31 | LCRYPTO_USED(MLKEM768_generate_key); | 28 | LCRYPTO_USED(MLKEM_private_key_new); |
32 | LCRYPTO_USED(MLKEM768_public_from_private); | 29 | LCRYPTO_USED(MLKEM_private_key_free); |
33 | LCRYPTO_USED(MLKEM768_encap); | 30 | LCRYPTO_USED(MLKEM_private_key_ciphertext_length); |
34 | LCRYPTO_USED(MLKEM768_decap); | 31 | LCRYPTO_USED(MLKEM_private_key_encoded_length); |
35 | LCRYPTO_USED(MLKEM768_marshal_public_key); | 32 | LCRYPTO_USED(MLKEM_public_key_new); |
36 | LCRYPTO_USED(MLKEM768_parse_public_key); | 33 | LCRYPTO_USED(MLKEM_public_key_free); |
37 | LCRYPTO_USED(MLKEM768_private_key_from_seed); | 34 | LCRYPTO_USED(MLKEM_public_key_ciphertext_length); |
38 | LCRYPTO_USED(MLKEM768_parse_private_key); | 35 | LCRYPTO_USED(MLKEM_public_key_encoded_length); |
39 | LCRYPTO_USED(MLKEM1024_generate_key); | 36 | LCRYPTO_USED(MLKEM_generate_key); |
40 | LCRYPTO_USED(MLKEM1024_public_from_private); | 37 | LCRYPTO_USED(MLKEM_private_key_from_seed); |
41 | LCRYPTO_USED(MLKEM1024_encap); | 38 | LCRYPTO_USED(MLKEM_public_from_private); |
42 | LCRYPTO_USED(MLKEM1024_decap); | 39 | LCRYPTO_USED(MLKEM_encap); |
43 | LCRYPTO_USED(MLKEM1024_marshal_public_key); | 40 | LCRYPTO_USED(MLKEM_decap); |
44 | LCRYPTO_USED(MLKEM1024_parse_public_key); | 41 | LCRYPTO_USED(MLKEM_marshal_public_key); |
45 | LCRYPTO_USED(MLKEM1024_private_key_from_seed); | 42 | LCRYPTO_USED(MLKEM_parse_public_key); |
46 | LCRYPTO_USED(MLKEM1024_parse_private_key); | 43 | LCRYPTO_USED(MLKEM_parse_private_key); |
47 | #endif /* LIBRESSL_HAS_MLKEM */ | ||
48 | 44 | ||
49 | #endif /* _LIBCRYPTO_MLKEM_H */ | 45 | #endif /* _LIBCRYPTO_MLKEM_H */ |
diff --git a/src/lib/libcrypto/mlkem/mlkem.c b/src/lib/libcrypto/mlkem/mlkem.c new file mode 100644 index 0000000000..3202656dfd --- /dev/null +++ b/src/lib/libcrypto/mlkem/mlkem.c | |||
@@ -0,0 +1,638 @@ | |||
1 | /* $OpenBSD: mlkem.c,v 1.1 2025/08/14 15:48:48 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); | ||
417 | /* $OpenBSD: mlkem.c,v 1.1 2025/08/14 15:48:48 beck Exp $ */ | ||
418 | /* | ||
419 | * Copyright (c) 2025, Bob Beck <beck@obtuse.com> | ||
420 | * | ||
421 | * Permission to use, copy, modify, and/or distribute this software for any | ||
422 | * purpose with or without fee is hereby granted, provided that the above | ||
423 | * copyright notice and this permission notice appear in all copies. | ||
424 | * | ||
425 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
426 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
427 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
428 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
429 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
430 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
431 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
432 | */ | ||
433 | |||
434 | #include <openssl/mlkem.h> | ||
435 | |||
436 | |||
437 | int MLKEM768_generate_key( | ||
438 | uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES], | ||
439 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
440 | struct MLKEM768_private_key *out_private_key); | ||
441 | |||
442 | /* | ||
443 | * MLKEM768_private_key_from_seed derives a private key from a seed that was | ||
444 | * generated by |MLKEM768_generate_key|. It fails and returns 0 if |seed_len| is | ||
445 | * incorrect, otherwise it writes |*out_private_key| and returns 1. | ||
446 | */ | ||
447 | int MLKEM768_private_key_from_seed(struct MLKEM768_private_key *out_private_key, | ||
448 | const uint8_t *seed, size_t seed_len); | ||
449 | |||
450 | /* | ||
451 | * MLKEM_public_from_private sets |*out_public_key| to the public key that | ||
452 | * corresponds to |private_key|. (This is faster than parsing the output of | ||
453 | * |MLKEM_generate_key| if, for some reason, you need to encapsulate to a key | ||
454 | * that was just generated.) | ||
455 | */ | ||
456 | void MLKEM768_public_from_private(struct MLKEM768_public_key *out_public_key, | ||
457 | const struct MLKEM768_private_key *private_key); | ||
458 | |||
459 | /* MLKEM768_CIPHERTEXT_BYTES is number of bytes in the ML-KEM768 ciphertext. */ | ||
460 | #define MLKEM768_CIPHERTEXT_BYTES 1088 | ||
461 | |||
462 | /* | ||
463 | * MLKEM768_encap encrypts a random shared secret for |public_key|, writes the | ||
464 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | ||
465 | * |out_shared_secret|. | ||
466 | */ | ||
467 | void MLKEM768_encap(uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES], | ||
468 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
469 | const struct MLKEM768_public_key *public_key); | ||
470 | |||
471 | /* | ||
472 | * MLKEM768_decap decrypts a shared secret from |ciphertext| using |private_key| | ||
473 | * and writes it to |out_shared_secret|. If |ciphertext_len| is incorrect it | ||
474 | * returns 0, otherwise it rreturns 1. If |ciphertext| is invalid, | ||
475 | * |out_shared_secret| is filled with a key that will always be the same for the | ||
476 | * same |ciphertext| and |private_key|, but which appears to be random unless | ||
477 | * one has access to |private_key|. These alternatives occur in constant time. | ||
478 | * Any subsequent symmetric encryption using |out_shared_secret| must use an | ||
479 | * authenticated encryption scheme in order to discover the decapsulation | ||
480 | * failure. | ||
481 | */ | ||
482 | int MLKEM768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
483 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
484 | const struct MLKEM768_private_key *private_key); | ||
485 | |||
486 | /* Serialisation of keys. */ | ||
487 | |||
488 | /* | ||
489 | * MLKEM768_marshal_public_key serializes |public_key| to |out| in the standard | ||
490 | * format for ML-KEM public keys. It returns one on success or zero on allocation | ||
491 | * error. | ||
492 | */ | ||
493 | int MLKEM768_marshal_public_key(uint8_t **output, size_t *output_len, | ||
494 | const struct MLKEM768_public_key *public_key); | ||
495 | |||
496 | /* | ||
497 | * MLKEM768_parse_public_key parses a public key, in the format generated by | ||
498 | * |MLKEM_marshal_public_key|, from |in| and writes the result to | ||
499 | * |out_public_key|. It returns one on success or zero on parse error or if | ||
500 | * there are trailing bytes in |in|. | ||
501 | */ | ||
502 | int MLKEM768_parse_public_key(struct MLKEM768_public_key *out_public_key, | ||
503 | const uint8_t *input, size_t input_len); | ||
504 | |||
505 | /* | ||
506 | * MLKEM_parse_private_key parses a private key, in the format generated by | ||
507 | * |MLKEM_marshal_private_key|, from |in| and writes the result to | ||
508 | * |out_private_key|. It returns one on success or zero on parse error or if | ||
509 | * there are trailing bytes in |in|. This formate is verbose and should be avoided. | ||
510 | * Private keys should be stored as seeds and parsed using |MLKEM768_private_key_from_seed|. | ||
511 | */ | ||
512 | int MLKEM768_parse_private_key(struct MLKEM768_private_key *out_private_key, | ||
513 | const uint8_t *input, size_t input_len); | ||
514 | |||
515 | /* | ||
516 | * ML-KEM-1024 | ||
517 | * | ||
518 | * ML-KEM-1024 also exists. You should prefer ML-KEM-768 where possible. | ||
519 | */ | ||
520 | |||
521 | /* | ||
522 | * MLKEM1024_public_key contains an ML-KEM-1024 public key. The contents of this | ||
523 | * object should never leave the address space since the format is unstable. | ||
524 | */ | ||
525 | struct MLKEM1024_public_key { | ||
526 | union { | ||
527 | uint8_t bytes[512 * (4 + 16) + 32 + 32]; | ||
528 | uint16_t alignment; | ||
529 | } opaque; | ||
530 | }; | ||
531 | |||
532 | /* | ||
533 | * MLKEM1024_private_key contains a ML-KEM-1024 private key. The contents of | ||
534 | * this object should never leave the address space since the format is | ||
535 | * unstable. | ||
536 | */ | ||
537 | struct MLKEM1024_private_key { | ||
538 | union { | ||
539 | uint8_t bytes[512 * (4 + 4 + 16) + 32 + 32 + 32]; | ||
540 | uint16_t alignment; | ||
541 | } opaque; | ||
542 | }; | ||
543 | |||
544 | /* | ||
545 | * MLKEM1024_PUBLIC_KEY_BYTES is the number of bytes in an encoded ML-KEM-1024 | ||
546 | * public key. | ||
547 | */ | ||
548 | #define MLKEM1024_PUBLIC_KEY_BYTES 1568 | ||
549 | |||
550 | /* | ||
551 | * MLKEM1024_generate_key generates a random public/private key pair, writes the | ||
552 | * encoded public key to |out_encoded_public_key| and sets |out_private_key| to | ||
553 | * the private key. If |optional_out_seed| is not NULL then the seed used to | ||
554 | * generate the private key is written to it. | ||
555 | */ | ||
556 | int MLKEM1024_generate_key( | ||
557 | uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES], | ||
558 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], | ||
559 | struct MLKEM1024_private_key *out_private_key); | ||
560 | |||
561 | /* | ||
562 | * MLKEM1024_private_key_from_seed derives a private key from a seed that was | ||
563 | * generated by |MLKEM1024_generate_key|. It fails and returns 0 if |seed_len| | ||
564 | * is incorrect, otherwise it writes |*out_private_key| and returns 1. | ||
565 | */ | ||
566 | int MLKEM1024_private_key_from_seed( | ||
567 | struct MLKEM1024_private_key *out_private_key, const uint8_t *seed, | ||
568 | size_t seed_len); | ||
569 | |||
570 | /* | ||
571 | * MLKEM1024_public_from_private sets |*out_public_key| to the public key that | ||
572 | * corresponds to |private_key|. (This is faster than parsing the output of | ||
573 | * |MLKEM1024_generate_key| if, for some reason, you need to encapsulate to a | ||
574 | * key that was just generated.) | ||
575 | */ | ||
576 | void MLKEM1024_public_from_private(struct MLKEM1024_public_key *out_public_key, | ||
577 | const struct MLKEM1024_private_key *private_key); | ||
578 | |||
579 | /* MLKEM1024_CIPHERTEXT_BYTES is number of bytes in the ML-KEM-1024 ciphertext. */ | ||
580 | #define MLKEM1024_CIPHERTEXT_BYTES 1568 | ||
581 | |||
582 | /* | ||
583 | * MLKEM1024_encap encrypts a random shared secret for |public_key|, writes the | ||
584 | * ciphertext to |out_ciphertext|, and writes the random shared secret to | ||
585 | * |out_shared_secret|. | ||
586 | */ | ||
587 | void MLKEM1024_encap(uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES], | ||
588 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
589 | const struct MLKEM1024_public_key *public_key); | ||
590 | |||
591 | /* | ||
592 | * MLKEM1024_decap decrypts a shared secret from |ciphertext| using | ||
593 | * |private_key| and writes it to |out_shared_secret|. If |ciphertext_len| is | ||
594 | * incorrect it returns 0, otherwise it returns 1. If |ciphertext| is invalid | ||
595 | * (but of the correct length), |out_shared_secret| is filled with a key that | ||
596 | * will always be the same for the same |ciphertext| and |private_key|, but | ||
597 | * which appears to be random unless one has access to |private_key|. These | ||
598 | * alternatives occur in constant time. Any subsequent symmetric encryption | ||
599 | * using |out_shared_secret| must use an authenticated encryption scheme in | ||
600 | * order to discover the decapsulation failure. | ||
601 | */ | ||
602 | int MLKEM1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
603 | const uint8_t *ciphertext, size_t ciphertext_len, | ||
604 | const struct MLKEM1024_private_key *private_key); | ||
605 | |||
606 | /* | ||
607 | * Serialisation of ML-KEM-1024 keys. | ||
608 | * MLKEM1024_marshal_public_key serializes |public_key| to |out| in the standard | ||
609 | * format for ML-KEM-1024 public keys. It returns one on success or zero on | ||
610 | * allocation error. | ||
611 | */ | ||
612 | int MLKEM1024_marshal_public_key(uint8_t **output, size_t *output_len, | ||
613 | const struct MLKEM1024_public_key *public_key); | ||
614 | |||
615 | /* | ||
616 | * MLKEM1024_parse_public_key parses a public key, in the format generated by | ||
617 | * |MLKEM1024_marshal_public_key|, from |in| and writes the result to | ||
618 | * |out_public_key|. It returns one on success or zero on parse error or if | ||
619 | * there are trailing bytes in |in|. | ||
620 | */ | ||
621 | int MLKEM1024_parse_public_key(struct MLKEM1024_public_key *out_public_key, | ||
622 | const uint8_t *input, size_t input_len); | ||
623 | |||
624 | /* | ||
625 | * MLKEM1024_parse_private_key parses a private key, in NIST's format for | ||
626 | * private keys, from |in| and writes the result to |out_private_key|. It | ||
627 | * returns one on success or zero on parse error or if there are trailing bytes | ||
628 | * in |in|. This format is verbose and should be avoided. Private keys should be | ||
629 | * stored as seeds and parsed using |MLKEM1024_private_key_from_seed|. | ||
630 | */ | ||
631 | int MLKEM1024_parse_private_key(struct MLKEM1024_private_key *out_private_key, | ||
632 | const uint8_t *input, size_t input_len); | ||
633 | |||
634 | #if defined(__cplusplus) | ||
635 | } | ||
636 | #endif | ||
637 | |||
638 | #endif /* OPENSSL_HEADER_MLKEM_H */ | ||
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); | ||
diff --git a/src/lib/libssl/ssl_rsa.c b/src/lib/libssl/ssl_rsa.c index 6c8a2be3d3..a83779e4c7 100644 --- a/src/lib/libssl/ssl_rsa.c +++ b/src/lib/libssl/ssl_rsa.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_rsa.c,v 1.51 2023/12/30 06:25:56 tb Exp $ */ | 1 | /* $OpenBSD: ssl_rsa.c,v 1.52 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -390,7 +390,7 @@ ssl_set_cert(SSL_CTX *ctx, SSL *ssl, X509 *x) | |||
390 | int ssl_err; | 390 | int ssl_err; |
391 | int i; | 391 | int i; |
392 | 392 | ||
393 | if (!ssl_security_cert(ctx, ssl, x, 1, &ssl_err)) { | 393 | if (0 && !ssl_security_cert(ctx, ssl, x, 1, &ssl_err)) { |
394 | SSLerrorx(ssl_err); | 394 | SSLerrorx(ssl_err); |
395 | return (0); | 395 | return (0); |
396 | } | 396 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c index b93243023c..10c4b1f4e0 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_iteration_tests.c,v 1.5 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_iteration_tests.c,v 1.6 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> |
@@ -21,6 +21,7 @@ | |||
21 | #include <stdint.h> | 21 | #include <stdint.h> |
22 | #include <stdio.h> | 22 | #include <stdio.h> |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <string.h> | ||
24 | 25 | ||
25 | #include "mlkem.h" | 26 | #include "mlkem.h" |
26 | 27 | ||
@@ -63,46 +64,49 @@ const uint8_t kExpectedAdam1024[32] = { | |||
63 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 | 64 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 |
64 | }; | 65 | }; |
65 | 66 | ||
66 | struct iteration_ctx { | ||
67 | uint8_t *encoded_public_key; | ||
68 | size_t encoded_public_key_len; | ||
69 | uint8_t *ciphertext; | ||
70 | size_t ciphertext_len; | ||
71 | uint8_t *invalid_ciphertext; | ||
72 | size_t invalid_ciphertext_len; | ||
73 | void *priv; | ||
74 | void *pub; | ||
75 | |||
76 | mlkem_marshal_private_key_fn marshal_private_key; | ||
77 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
78 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
79 | mlkem_public_from_private_fn public_from_private; | ||
80 | mlkem_decap_fn decap; | ||
81 | |||
82 | const uint8_t *start; | ||
83 | size_t start_len; | ||
84 | |||
85 | const uint8_t *expected; | ||
86 | size_t expected_len; | ||
87 | }; | ||
88 | |||
89 | static int | 67 | static int |
90 | MlkemIterativeTest(struct iteration_ctx *ctx) | 68 | MlkemIterativeTest(int rank) |
91 | { | 69 | { |
92 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | 70 | const uint8_t *start, *expected; |
71 | size_t start_len; | ||
93 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; | 72 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; |
94 | uint8_t seed[MLKEM_SEED_BYTES] = {0}; | 73 | uint8_t seed[MLKEM_SEED_LENGTH] = {0}; |
74 | uint8_t *shared_secret = NULL; | ||
95 | sha3_ctx drng, results; | 75 | sha3_ctx drng, results; |
96 | uint8_t out[32]; | 76 | uint8_t out[32]; |
97 | int i; | 77 | int i; |
98 | 78 | ||
79 | start = kExpectedSeedStart; | ||
80 | start_len = sizeof(kExpectedSeedStart); | ||
81 | switch(rank){ | ||
82 | case RANK768: | ||
83 | expected = kExpectedAdam768; | ||
84 | break; | ||
85 | case RANK1024: | ||
86 | expected = kExpectedAdam1024; | ||
87 | break; | ||
88 | default: | ||
89 | errx(1, "invalid rank %d", rank); | ||
90 | } | ||
91 | |||
99 | shake128_init(&drng); | 92 | shake128_init(&drng); |
100 | shake128_init(&results); | 93 | shake128_init(&results); |
101 | 94 | ||
102 | shake_xof(&drng); | 95 | shake_xof(&drng); |
103 | for (i = 0; i < 10000; i++) { | 96 | for (i = 0; i < 10000; i++) { |
104 | uint8_t *encoded_private_key = NULL; | 97 | uint8_t *encoded_public_key = NULL, *ciphertext = NULL, |
105 | size_t encoded_private_key_len; | 98 | *encoded_private_key = NULL, *invalid_ciphertext = NULL; |
99 | size_t encoded_public_key_len, ciphertext_len, | ||
100 | encoded_private_key_len, invalid_ciphertext_len; | ||
101 | MLKEM_private_key *priv; | ||
102 | MLKEM_public_key *pub; | ||
103 | size_t s_len = 0; | ||
104 | |||
105 | /* allocate keys for this iteration */ | ||
106 | if ((priv = MLKEM_private_key_new(rank)) == NULL) | ||
107 | errx(1, "malloc"); | ||
108 | if ((pub = MLKEM_public_key_new(rank)) == NULL) | ||
109 | errx(1, "malloc"); | ||
106 | 110 | ||
107 | /* | 111 | /* |
108 | * This should draw both d and z from DRNG concatenating in | 112 | * This should draw both d and z from DRNG concatenating in |
@@ -110,120 +114,91 @@ MlkemIterativeTest(struct iteration_ctx *ctx) | |||
110 | */ | 114 | */ |
111 | shake_out(&drng, seed, sizeof(seed)); | 115 | shake_out(&drng, seed, sizeof(seed)); |
112 | if (i == 0) { | 116 | if (i == 0) { |
113 | if (compare_data(seed, ctx->start, ctx->start_len, | 117 | if (compare_data(seed, start, start_len, |
114 | "seed start") != 0) | 118 | "seed start") != 0) |
115 | errx(1, "compare_data"); | 119 | errx(1, "compare_data"); |
116 | } | 120 | } |
117 | 121 | ||
118 | /* generate ek as encoded_public_key */ | 122 | /* generate ek as encoded_public_key */ |
119 | if (!ctx->generate_key_external_entropy(ctx->encoded_public_key, | 123 | if (!MLKEM_generate_key_external_entropy(priv, |
120 | ctx->priv, seed)) { | 124 | &encoded_public_key, &encoded_public_key_len, |
125 | seed)) | ||
121 | errx(1, "generate_key_external_entropy"); | 126 | errx(1, "generate_key_external_entropy"); |
122 | } | 127 | |
123 | ctx->public_from_private(ctx->pub, ctx->priv); | 128 | if (!MLKEM_public_from_private(priv, pub)) |
129 | errx(1, "public_from_private"); | ||
124 | 130 | ||
125 | /* hash in ek */ | 131 | /* hash in ek */ |
126 | shake_update(&results, ctx->encoded_public_key, | 132 | shake_update(&results, encoded_public_key, |
127 | ctx->encoded_public_key_len); | 133 | encoded_public_key_len); |
128 | 134 | ||
129 | /* marshal priv to dk as encoded_private_key */ | 135 | /* marshal priv to dk as encoded_private_key */ |
130 | if (!ctx->marshal_private_key(ctx->priv, &encoded_private_key, | 136 | if (!MLKEM_marshal_private_key(priv, &encoded_private_key, |
131 | &encoded_private_key_len)) | 137 | &encoded_private_key_len)) |
132 | errx(1, "encode private key"); | 138 | errx(1, "marshal private key"); |
133 | 139 | ||
134 | /* hash in dk */ | 140 | /* hash in dk */ |
135 | shake_update(&results, encoded_private_key, | 141 | shake_update(&results, encoded_private_key, |
136 | encoded_private_key_len); | 142 | encoded_private_key_len); |
137 | 143 | ||
138 | free(encoded_private_key); | 144 | freezero(encoded_private_key, encoded_private_key_len); |
139 | 145 | ||
140 | /* draw m as encap entropy from DRNG */ | 146 | /* draw m as encap entropy from DRNG */ |
141 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); | 147 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); |
142 | 148 | ||
143 | /* generate ct as ciphertext, k as shared_secret */ | 149 | /* generate ct as ciphertext, k as shared_secret */ |
144 | ctx->encap_external_entropy(ctx->ciphertext, shared_secret, | 150 | if (!MLKEM_encap_external_entropy(pub, encap_entropy, |
145 | ctx->pub, encap_entropy); | 151 | &ciphertext, &ciphertext_len, &shared_secret, &s_len)) |
152 | errx(1, "encap_external_entropy"); | ||
146 | 153 | ||
147 | /* hash in ct */ | 154 | /* hash in ct */ |
148 | shake_update(&results, ctx->ciphertext, ctx->ciphertext_len); | 155 | shake_update(&results, ciphertext, ciphertext_len); |
149 | /* hash in k */ | 156 | /* hash in k */ |
150 | shake_update(&results, shared_secret, sizeof(shared_secret)); | 157 | shake_update(&results, shared_secret, s_len); |
158 | |||
159 | freezero(shared_secret, s_len); | ||
160 | shared_secret = NULL; | ||
161 | |||
162 | invalid_ciphertext_len = ciphertext_len; | ||
163 | if ((invalid_ciphertext = calloc(1, invalid_ciphertext_len)) | ||
164 | == NULL) | ||
165 | errx(1, "malloc"); | ||
151 | 166 | ||
152 | /* draw ct as invalid_ciphertxt from DRNG */ | 167 | /* draw ct as invalid_ciphertxt from DRNG */ |
153 | shake_out(&drng, ctx->invalid_ciphertext, | 168 | shake_out(&drng, invalid_ciphertext, invalid_ciphertext_len); |
154 | ctx->invalid_ciphertext_len); | ||
155 | 169 | ||
156 | /* generate k as shared secret from invalid ciphertext */ | 170 | /* generate k as shared secret from invalid ciphertext */ |
157 | if (!ctx->decap(shared_secret, ctx->invalid_ciphertext, | 171 | if (!MLKEM_decap(priv, invalid_ciphertext, |
158 | ctx->invalid_ciphertext_len, ctx->priv)) | 172 | invalid_ciphertext_len, &shared_secret, &s_len)) |
159 | errx(1, "decap failed"); | 173 | errx(1, "decap failed, iteration %d", i); |
160 | 174 | ||
161 | /* hash in k */ | 175 | /* hash in k */ |
162 | shake_update(&results, shared_secret, sizeof(shared_secret)); | 176 | shake_update(&results, shared_secret, s_len); |
177 | |||
178 | freezero(shared_secret, s_len); | ||
179 | shared_secret = NULL; | ||
180 | freezero(invalid_ciphertext, invalid_ciphertext_len); | ||
181 | invalid_ciphertext = NULL; | ||
182 | |||
183 | /* free keys and intermediate products for this iteration */ | ||
184 | MLKEM_private_key_free(priv); | ||
185 | MLKEM_public_key_free(pub); | ||
186 | freezero(encoded_public_key, encoded_public_key_len); | ||
187 | freezero(ciphertext, ciphertext_len); | ||
163 | } | 188 | } |
164 | shake_xof(&results); | 189 | shake_xof(&results); |
165 | shake_out(&results, out, sizeof(out)); | 190 | shake_out(&results, out, sizeof(out)); |
166 | 191 | ||
167 | return compare_data(ctx->expected, out, sizeof(out), "final result hash"); | 192 | return compare_data(expected, out, sizeof(out), "final result hash"); |
168 | } | 193 | } |
169 | 194 | ||
170 | int | 195 | int |
171 | main(void) | 196 | main(void) |
172 | { | 197 | { |
173 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | ||
174 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
175 | uint8_t invalid_ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
176 | struct MLKEM768_private_key priv768; | ||
177 | struct MLKEM768_public_key pub768; | ||
178 | struct iteration_ctx iteration768 = { | ||
179 | .encoded_public_key = encoded_public_key768, | ||
180 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
181 | .ciphertext = ciphertext768, | ||
182 | .ciphertext_len = sizeof(ciphertext768), | ||
183 | .invalid_ciphertext = invalid_ciphertext768, | ||
184 | .invalid_ciphertext_len = sizeof(invalid_ciphertext768), | ||
185 | .priv = &priv768, | ||
186 | .pub = &pub768, | ||
187 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
188 | .marshal_private_key = mlkem768_marshal_private_key, | ||
189 | .generate_key_external_entropy = | ||
190 | mlkem768_generate_key_external_entropy, | ||
191 | .public_from_private = mlkem768_public_from_private, | ||
192 | .decap = mlkem768_decap, | ||
193 | .start = kExpectedSeedStart, | ||
194 | .start_len = sizeof(kExpectedSeedStart), | ||
195 | .expected = kExpectedAdam768, | ||
196 | .expected_len = sizeof(kExpectedAdam768), | ||
197 | }; | ||
198 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
199 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
200 | uint8_t invalid_ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
201 | struct MLKEM1024_private_key priv1024; | ||
202 | struct MLKEM1024_public_key pub1024; | ||
203 | struct iteration_ctx iteration1024 = { | ||
204 | .encoded_public_key = encoded_public_key1024, | ||
205 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
206 | .ciphertext = ciphertext1024, | ||
207 | .ciphertext_len = sizeof(ciphertext1024), | ||
208 | .invalid_ciphertext = invalid_ciphertext1024, | ||
209 | .invalid_ciphertext_len = sizeof(invalid_ciphertext1024), | ||
210 | .priv = &priv1024, | ||
211 | .pub = &pub1024, | ||
212 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
213 | .marshal_private_key = mlkem1024_marshal_private_key, | ||
214 | .generate_key_external_entropy = | ||
215 | mlkem1024_generate_key_external_entropy, | ||
216 | .public_from_private = mlkem1024_public_from_private, | ||
217 | .decap = mlkem1024_decap, | ||
218 | .start = kExpectedSeedStart, | ||
219 | .start_len = sizeof(kExpectedSeedStart), | ||
220 | .expected = kExpectedAdam1024, | ||
221 | .expected_len = sizeof(kExpectedAdam1024), | ||
222 | }; | ||
223 | int failed = 0; | 198 | int failed = 0; |
224 | 199 | ||
225 | failed |= MlkemIterativeTest(&iteration768); | 200 | failed |= MlkemIterativeTest(RANK768); |
226 | failed |= MlkemIterativeTest(&iteration1024); | 201 | failed |= MlkemIterativeTest(RANK1024); |
227 | 202 | ||
228 | return failed; | 203 | return failed; |
229 | } | 204 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c index 8e04dc6ad2..3269ba951f 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_tests.c,v 1.6 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests.c,v 1.7 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 Theo Buehler <tb@openbsd.org> | 4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> |
@@ -38,12 +38,8 @@ enum test_type { | |||
38 | 38 | ||
39 | struct decap_ctx { | 39 | struct decap_ctx { |
40 | struct parse *parse_ctx; | 40 | struct parse *parse_ctx; |
41 | 41 | int rank; | |
42 | void *private_key; | 42 | MLKEM_private_key *private_key; |
43 | size_t private_key_len; | ||
44 | |||
45 | mlkem_parse_private_key_fn parse_private_key; | ||
46 | mlkem_decap_fn decap; | ||
47 | }; | 43 | }; |
48 | 44 | ||
49 | enum decap_states { | 45 | enum decap_states { |
@@ -89,21 +85,26 @@ decap_init(void *ctx, void *parse_ctx) | |||
89 | 85 | ||
90 | decap->parse_ctx = parse_ctx; | 86 | decap->parse_ctx = parse_ctx; |
91 | 87 | ||
92 | return 1; | 88 | return (decap->private_key = MLKEM_private_key_new(decap->rank)) |
89 | != NULL; | ||
93 | } | 90 | } |
94 | 91 | ||
95 | static void | 92 | static void |
96 | decap_finish(void *ctx) | 93 | decap_finish(void *ctx) |
97 | { | 94 | { |
98 | (void)ctx; | 95 | struct decap_ctx *decap = ctx; |
96 | |||
97 | MLKEM_private_key_free(decap->private_key); | ||
98 | decap->private_key = NULL; | ||
99 | } | 99 | } |
100 | 100 | ||
101 | static int | 101 | static int |
102 | MlkemDecapFileTest(struct decap_ctx *decap) | 102 | MlkemDecapFileTest(struct decap_ctx *decap) |
103 | { | 103 | { |
104 | struct parse *p = decap->parse_ctx; | 104 | struct parse *p = decap->parse_ctx; |
105 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | 105 | uint8_t *shared_secret_buf = NULL; |
106 | CBS ciphertext, shared_secret, private_key; | 106 | CBS ciphertext, shared_secret, private_key; |
107 | size_t s_len = 0; | ||
107 | int should_fail; | 108 | int should_fail; |
108 | int failed = 1; | 109 | int failed = 1; |
109 | 110 | ||
@@ -112,21 +113,28 @@ MlkemDecapFileTest(struct decap_ctx *decap) | |||
112 | parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key); | 113 | parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key); |
113 | parse_get_int(p, DECAP_RESULT, &should_fail); | 114 | parse_get_int(p, DECAP_RESULT, &should_fail); |
114 | 115 | ||
115 | if (!decap->parse_private_key(decap->private_key, | 116 | if (!MLKEM_parse_private_key(decap->private_key, |
116 | CBS_data(&private_key), CBS_len(&private_key))) { | 117 | CBS_data(&private_key), CBS_len(&private_key))) { |
117 | if ((failed = !should_fail)) | 118 | if ((failed = !should_fail)) |
118 | parse_info(p, "parse private key"); | 119 | parse_info(p, "parse private key"); |
119 | goto err; | 120 | goto err; |
120 | } | 121 | } |
121 | if (!decap->decap(shared_secret_buf, | 122 | if (!MLKEM_decap(decap->private_key, CBS_data(&ciphertext), |
122 | CBS_data(&ciphertext), CBS_len(&ciphertext), decap->private_key)) { | 123 | CBS_len(&ciphertext), &shared_secret_buf, &s_len)) { |
123 | if ((failed = !should_fail)) | 124 | if ((failed = !should_fail)) |
124 | parse_info(p, "decap"); | 125 | parse_info(p, "decap"); |
125 | goto err; | 126 | goto err; |
126 | } | 127 | } |
127 | 128 | ||
129 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
130 | if ((failed = !should_fail)) | ||
131 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
132 | MLKEM_SHARED_SECRET_LENGTH); | ||
133 | goto err; | ||
134 | } | ||
135 | |||
128 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | 136 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, |
129 | shared_secret_buf, sizeof(shared_secret_buf)); | 137 | shared_secret_buf, s_len); |
130 | 138 | ||
131 | if (should_fail != failed) { | 139 | if (should_fail != failed) { |
132 | parse_info(p, "FAIL: should_fail %d, failed %d", | 140 | parse_info(p, "FAIL: should_fail %d, failed %d", |
@@ -135,6 +143,7 @@ MlkemDecapFileTest(struct decap_ctx *decap) | |||
135 | } | 143 | } |
136 | 144 | ||
137 | err: | 145 | err: |
146 | freezero(shared_secret_buf, s_len); | ||
138 | return failed; | 147 | return failed; |
139 | } | 148 | } |
140 | 149 | ||
@@ -193,8 +202,9 @@ static int | |||
193 | MlkemNistDecapFileTest(struct decap_ctx *decap) | 202 | MlkemNistDecapFileTest(struct decap_ctx *decap) |
194 | { | 203 | { |
195 | struct parse *p = decap->parse_ctx; | 204 | struct parse *p = decap->parse_ctx; |
196 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | 205 | uint8_t *shared_secret = NULL; |
197 | CBS dk, c, k; | 206 | CBS dk, c, k; |
207 | size_t s_len = 0; | ||
198 | int failed = 1; | 208 | int failed = 1; |
199 | 209 | ||
200 | parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk); | 210 | parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk); |
@@ -202,27 +212,34 @@ MlkemNistDecapFileTest(struct decap_ctx *decap) | |||
202 | parse_get_cbs(p, NIST_DECAP_K, &k); | 212 | parse_get_cbs(p, NIST_DECAP_K, &k); |
203 | 213 | ||
204 | if (!parse_length_equal(p, "private key", | 214 | if (!parse_length_equal(p, "private key", |
205 | decap->private_key_len, CBS_len(&dk))) | 215 | MLKEM_private_key_encoded_length(decap->private_key), CBS_len(&dk))) |
206 | goto err; | 216 | goto err; |
207 | if (!parse_length_equal(p, "shared secret", | 217 | if (!parse_length_equal(p, "shared secret", |
208 | MLKEM_SHARED_SECRET_BYTES, CBS_len(&k))) | 218 | MLKEM_SHARED_SECRET_BYTES, CBS_len(&k))) |
209 | goto err; | 219 | goto err; |
210 | 220 | ||
211 | if (!decap->parse_private_key(decap->private_key, CBS_data(&dk), | 221 | if (!MLKEM_parse_private_key(decap->private_key, CBS_data(&dk), |
212 | CBS_len(&dk))) { | 222 | CBS_len(&dk))) { |
213 | parse_info(p, "parse private key"); | 223 | parse_info(p, "parse private key"); |
214 | goto err; | 224 | goto err; |
215 | } | 225 | } |
216 | if (!decap->decap(shared_secret, CBS_data(&c), CBS_len(&c), | 226 | if (!MLKEM_decap(decap->private_key, CBS_data(&c), CBS_len(&c), |
217 | decap->private_key)) { | 227 | &shared_secret, &s_len)) { |
218 | parse_info(p, "decap"); | 228 | parse_info(p, "decap"); |
219 | goto err; | 229 | goto err; |
220 | } | 230 | } |
221 | 231 | ||
232 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
233 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
234 | MLKEM_SHARED_SECRET_LENGTH); | ||
235 | goto err; | ||
236 | } | ||
237 | |||
222 | failed = !parse_data_equal(p, "shared secret", &k, | 238 | failed = !parse_data_equal(p, "shared secret", &k, |
223 | shared_secret, MLKEM_SHARED_SECRET_BYTES); | 239 | shared_secret, s_len); |
224 | 240 | ||
225 | err: | 241 | err: |
242 | free(shared_secret); | ||
226 | return failed; | 243 | return failed; |
227 | } | 244 | } |
228 | 245 | ||
@@ -246,46 +263,31 @@ static const struct test_parse nist_decap_parse = { | |||
246 | }; | 263 | }; |
247 | 264 | ||
248 | static int | 265 | static int |
249 | mlkem_decap_tests(const char *fn, size_t size, enum test_type test_type) | 266 | mlkem_decap_tests(const char *fn, int rank, enum test_type test_type) |
250 | { | 267 | { |
251 | struct MLKEM768_private_key private_key768; | 268 | struct decap_ctx decap = { |
252 | struct decap_ctx decap768 = { | 269 | .rank = rank, |
253 | .private_key = &private_key768, | ||
254 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
255 | |||
256 | .parse_private_key = mlkem768_parse_private_key, | ||
257 | .decap = mlkem768_decap, | ||
258 | }; | ||
259 | struct MLKEM1024_private_key private_key1024; | ||
260 | struct decap_ctx decap1024 = { | ||
261 | .private_key = &private_key1024, | ||
262 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
263 | |||
264 | .parse_private_key = mlkem1024_parse_private_key, | ||
265 | .decap = mlkem1024_decap, | ||
266 | }; | 270 | }; |
271 | int ret = 0; | ||
267 | 272 | ||
268 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | 273 | if (test_type == TEST_TYPE_NORMAL) |
269 | return parse_test_file(fn, &decap_parse, &decap768); | 274 | ret = parse_test_file(fn, &decap_parse, &decap); |
270 | if (size == 768 && test_type == TEST_TYPE_NIST) | 275 | else if (test_type == TEST_TYPE_NIST) |
271 | return parse_test_file(fn, &nist_decap_parse, &decap768); | 276 | ret = parse_test_file(fn, &nist_decap_parse, &decap); |
272 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | 277 | else |
273 | return parse_test_file(fn, &decap_parse, &decap1024); | 278 | errx(1, "unknown decap test: rank %d, type %d", rank, |
274 | if (size == 1024 && test_type == TEST_TYPE_NIST) | 279 | test_type); |
275 | return parse_test_file(fn, &nist_decap_parse, &decap1024); | ||
276 | 280 | ||
277 | errx(1, "unknown decap test: size %zu, type %d", size, test_type); | 281 | return ret; |
278 | } | 282 | } |
279 | 283 | ||
280 | struct encap_ctx { | 284 | struct encap_ctx { |
281 | struct parse *parse_ctx; | 285 | struct parse *parse_ctx; |
282 | 286 | ||
283 | void *public_key; | 287 | int rank; |
288 | MLKEM_public_key *public_key; | ||
284 | uint8_t *ciphertext; | 289 | uint8_t *ciphertext; |
285 | size_t ciphertext_len; | 290 | size_t ciphertext_len; |
286 | |||
287 | mlkem_parse_public_key_fn parse_public_key; | ||
288 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
289 | }; | 291 | }; |
290 | 292 | ||
291 | enum encap_states { | 293 | enum encap_states { |
@@ -338,21 +340,30 @@ encap_init(void *ctx, void *parse_ctx) | |||
338 | 340 | ||
339 | encap->parse_ctx = parse_ctx; | 341 | encap->parse_ctx = parse_ctx; |
340 | 342 | ||
341 | return 1; | 343 | encap->ciphertext = NULL; |
344 | return (encap->public_key = MLKEM_public_key_new(encap->rank)) | ||
345 | != NULL; | ||
342 | } | 346 | } |
343 | 347 | ||
344 | static void | 348 | static void |
345 | encap_finish(void *ctx) | 349 | encap_finish(void *ctx) |
346 | { | 350 | { |
347 | (void)ctx; | 351 | struct encap_ctx *encap = ctx; |
352 | |||
353 | freezero(encap->ciphertext, encap->ciphertext_len); | ||
354 | encap->ciphertext = NULL; | ||
355 | MLKEM_public_key_free(encap->public_key); | ||
356 | encap->public_key = NULL; | ||
348 | } | 357 | } |
349 | 358 | ||
350 | static int | 359 | static int |
351 | MlkemEncapFileTest(struct encap_ctx *encap) | 360 | MlkemEncapFileTest(struct encap_ctx *encap) |
352 | { | 361 | { |
353 | struct parse *p = encap->parse_ctx; | ||
354 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | ||
355 | CBS entropy, public_key, ciphertext, shared_secret; | 362 | CBS entropy, public_key, ciphertext, shared_secret; |
363 | struct parse *p = encap->parse_ctx; | ||
364 | uint8_t *shared_secret_buf = NULL; | ||
365 | size_t s_len = 0; | ||
366 | |||
356 | int should_fail; | 367 | int should_fail; |
357 | int failed = 1; | 368 | int failed = 1; |
358 | 369 | ||
@@ -362,20 +373,33 @@ MlkemEncapFileTest(struct encap_ctx *encap) | |||
362 | parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret); | 373 | parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret); |
363 | parse_get_int(p, ENCAP_RESULT, &should_fail); | 374 | parse_get_int(p, ENCAP_RESULT, &should_fail); |
364 | 375 | ||
365 | if (!encap->parse_public_key(encap->public_key, CBS_data(&public_key), | 376 | if (!MLKEM_parse_public_key(encap->public_key, CBS_data(&public_key), |
366 | CBS_len(&public_key))) { | 377 | CBS_len(&public_key))) { |
367 | if ((failed = !should_fail)) | 378 | if ((failed = !should_fail)) |
368 | parse_info(p, "parse public key"); | 379 | parse_info(p, "parse public key"); |
369 | goto err; | 380 | goto err; |
370 | } | 381 | } |
371 | encap->encap_external_entropy(encap->ciphertext, shared_secret_buf, | 382 | if (!MLKEM_encap_external_entropy(encap->public_key, CBS_data(&entropy), |
372 | encap->public_key, CBS_data(&entropy)); | 383 | &encap->ciphertext, &encap->ciphertext_len, &shared_secret_buf, |
384 | &s_len)) { | ||
385 | if ((failed = !should_fail)) | ||
386 | parse_info(p, "encap_external_entropy"); | ||
387 | goto err; | ||
388 | } | ||
389 | |||
390 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
391 | if ((failed = !should_fail)) | ||
392 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
393 | MLKEM_SHARED_SECRET_LENGTH); | ||
394 | goto err; | ||
395 | } | ||
373 | 396 | ||
374 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | 397 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, |
375 | shared_secret_buf, sizeof(shared_secret_buf)); | 398 | shared_secret_buf, s_len); |
376 | failed |= !parse_data_equal(p, "ciphertext", &ciphertext, | 399 | failed |= !parse_data_equal(p, "ciphertext", &ciphertext, |
377 | encap->ciphertext, encap->ciphertext_len); | 400 | encap->ciphertext, encap->ciphertext_len); |
378 | 401 | ||
402 | |||
379 | if (should_fail != failed) { | 403 | if (should_fail != failed) { |
380 | parse_info(p, "FAIL: should_fail %d, failed %d", | 404 | parse_info(p, "FAIL: should_fail %d, failed %d", |
381 | should_fail, failed); | 405 | should_fail, failed); |
@@ -383,6 +407,7 @@ MlkemEncapFileTest(struct encap_ctx *encap) | |||
383 | } | 407 | } |
384 | 408 | ||
385 | err: | 409 | err: |
410 | freezero(shared_secret_buf, s_len); | ||
386 | return failed; | 411 | return failed; |
387 | } | 412 | } |
388 | 413 | ||
@@ -403,48 +428,22 @@ static const struct test_parse encap_parse = { | |||
403 | }; | 428 | }; |
404 | 429 | ||
405 | static int | 430 | static int |
406 | mlkem_encap_tests(const char *fn, size_t size) | 431 | mlkem_encap_tests(const char *fn, int rank) |
407 | { | 432 | { |
408 | struct MLKEM768_public_key public_key768; | 433 | struct encap_ctx encap = { |
409 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | 434 | .rank = rank, |
410 | struct encap_ctx encap768 = { | ||
411 | .public_key = &public_key768, | ||
412 | .ciphertext = ciphertext768, | ||
413 | .ciphertext_len = sizeof(ciphertext768), | ||
414 | |||
415 | .parse_public_key = mlkem768_parse_public_key, | ||
416 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
417 | }; | ||
418 | struct MLKEM1024_public_key public_key1024; | ||
419 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
420 | struct encap_ctx encap1024 = { | ||
421 | .public_key = &public_key1024, | ||
422 | .ciphertext = ciphertext1024, | ||
423 | .ciphertext_len = sizeof(ciphertext1024), | ||
424 | |||
425 | .parse_public_key = mlkem1024_parse_public_key, | ||
426 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
427 | }; | 435 | }; |
428 | 436 | ||
429 | if (size == 768) | 437 | return parse_test_file(fn, &encap_parse, &encap); |
430 | return parse_test_file(fn, &encap_parse, &encap768); | ||
431 | if (size == 1024) | ||
432 | return parse_test_file(fn, &encap_parse, &encap1024); | ||
433 | |||
434 | errx(1, "unknown encap test: size %zu", size); | ||
435 | } | 438 | } |
436 | 439 | ||
437 | struct keygen_ctx { | 440 | struct keygen_ctx { |
438 | struct parse *parse_ctx; | 441 | struct parse *parse_ctx; |
439 | 442 | ||
440 | void *private_key; | 443 | int rank; |
441 | void *encoded_public_key; | 444 | MLKEM_private_key *private_key; |
445 | uint8_t *encoded_public_key; | ||
442 | size_t encoded_public_key_len; | 446 | size_t encoded_public_key_len; |
443 | size_t private_key_len; | ||
444 | size_t public_key_len; | ||
445 | |||
446 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
447 | mlkem_marshal_private_key_fn marshal_private_key; | ||
448 | }; | 447 | }; |
449 | 448 | ||
450 | enum keygen_states { | 449 | enum keygen_states { |
@@ -482,13 +481,19 @@ keygen_init(void *ctx, void *parse_ctx) | |||
482 | 481 | ||
483 | keygen->parse_ctx = parse_ctx; | 482 | keygen->parse_ctx = parse_ctx; |
484 | 483 | ||
485 | return 1; | 484 | return (keygen->private_key = MLKEM_private_key_new(keygen->rank)) |
485 | != NULL; | ||
486 | } | 486 | } |
487 | 487 | ||
488 | static void | 488 | static void |
489 | keygen_finish(void *ctx) | 489 | keygen_finish(void *ctx) |
490 | { | 490 | { |
491 | (void)ctx; | 491 | struct keygen_ctx *keygen = ctx; |
492 | |||
493 | freezero(keygen->encoded_public_key, keygen->encoded_public_key_len); | ||
494 | keygen->encoded_public_key = NULL; | ||
495 | MLKEM_private_key_free(keygen->private_key); | ||
496 | keygen->private_key = NULL; | ||
492 | } | 497 | } |
493 | 498 | ||
494 | static int | 499 | static int |
@@ -504,18 +509,25 @@ MlkemKeygenFileTest(struct keygen_ctx *keygen) | |||
504 | parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key); | 509 | parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key); |
505 | parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key); | 510 | parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key); |
506 | 511 | ||
507 | if (!parse_length_equal(p, "seed", MLKEM_SEED_BYTES, CBS_len(&seed))) | 512 | if (!parse_length_equal(p, "seed", MLKEM_SEED_LENGTH, CBS_len(&seed))) |
508 | goto err; | 513 | goto err; |
514 | |||
515 | if (!MLKEM_generate_key_external_entropy(keygen->private_key, | ||
516 | &keygen->encoded_public_key, &keygen->encoded_public_key_len, | ||
517 | CBS_data(&seed))) { | ||
518 | parse_info(p, "generate_key_external_entropy"); | ||
519 | goto err; | ||
520 | } | ||
521 | |||
509 | if (!parse_length_equal(p, "public key", | 522 | if (!parse_length_equal(p, "public key", |
510 | keygen->public_key_len, CBS_len(&public_key))) | 523 | keygen->encoded_public_key_len, CBS_len(&public_key))) |
511 | goto err; | 524 | goto err; |
512 | if (!parse_length_equal(p, "private key", | 525 | if (!parse_length_equal(p, "private key", |
513 | keygen->private_key_len, CBS_len(&private_key))) | 526 | MLKEM_private_key_encoded_length(keygen->private_key), |
527 | CBS_len(&private_key))) | ||
514 | goto err; | 528 | goto err; |
515 | 529 | ||
516 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | 530 | if (!MLKEM_marshal_private_key(keygen->private_key, |
517 | keygen->private_key, CBS_data(&seed)); | ||
518 | if (!keygen->marshal_private_key(keygen->private_key, | ||
519 | &encoded_private_key, &encoded_private_key_len)) { | 531 | &encoded_private_key, &encoded_private_key_len)) { |
520 | parse_info(p, "encode private key"); | 532 | parse_info(p, "encode private key"); |
521 | goto err; | 533 | goto err; |
@@ -589,7 +601,7 @@ MlkemNistKeygenFileTest(struct keygen_ctx *keygen) | |||
589 | struct parse *p = keygen->parse_ctx; | 601 | struct parse *p = keygen->parse_ctx; |
590 | CBB seed_cbb; | 602 | CBB seed_cbb; |
591 | CBS z, d, ek, dk; | 603 | CBS z, d, ek, dk; |
592 | uint8_t seed[MLKEM_SEED_BYTES]; | 604 | uint8_t seed[MLKEM_SEED_LENGTH]; |
593 | size_t seed_len; | 605 | size_t seed_len; |
594 | uint8_t *encoded_private_key = NULL; | 606 | uint8_t *encoded_private_key = NULL; |
595 | size_t encoded_private_key_len = 0; | 607 | size_t encoded_private_key_len = 0; |
@@ -609,12 +621,17 @@ MlkemNistKeygenFileTest(struct keygen_ctx *keygen) | |||
609 | if (!CBB_finish(&seed_cbb, NULL, &seed_len)) | 621 | if (!CBB_finish(&seed_cbb, NULL, &seed_len)) |
610 | parse_errx(p, "CBB_finish"); | 622 | parse_errx(p, "CBB_finish"); |
611 | 623 | ||
612 | if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_BYTES, seed_len)) | 624 | if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_LENGTH, seed_len)) |
613 | goto err; | 625 | goto err; |
614 | 626 | ||
615 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | 627 | if (!MLKEM_generate_key_external_entropy(keygen->private_key, |
616 | keygen->private_key, seed); | 628 | &keygen->encoded_public_key, &keygen->encoded_public_key_len, |
617 | if (!keygen->marshal_private_key(keygen->private_key, | 629 | seed)) { |
630 | parse_info(p, "generate_key_external_entropy"); | ||
631 | goto err; | ||
632 | } | ||
633 | |||
634 | if (!MLKEM_marshal_private_key(keygen->private_key, | ||
618 | &encoded_private_key, &encoded_private_key_len)) { | 635 | &encoded_private_key, &encoded_private_key_len)) { |
619 | parse_info(p, "encode private key"); | 636 | parse_info(p, "encode private key"); |
620 | goto err; | 637 | goto err; |
@@ -648,74 +665,49 @@ static const struct test_parse nist_keygen_parse = { | |||
648 | }; | 665 | }; |
649 | 666 | ||
650 | static int | 667 | static int |
651 | mlkem_keygen_tests(const char *fn, size_t size, enum test_type test_type) | 668 | mlkem_keygen_tests(const char *fn, int rank, enum test_type test_type) |
652 | { | 669 | { |
653 | struct MLKEM768_private_key private_key768; | 670 | struct keygen_ctx keygen = { |
654 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | 671 | .rank = rank, |
655 | struct keygen_ctx keygen768 = { | ||
656 | .private_key = &private_key768, | ||
657 | .encoded_public_key = encoded_public_key768, | ||
658 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
659 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
660 | .public_key_len = MLKEM768_PUBLIC_KEY_BYTES, | ||
661 | |||
662 | .generate_key_external_entropy = | ||
663 | mlkem768_generate_key_external_entropy, | ||
664 | .marshal_private_key = | ||
665 | mlkem768_marshal_private_key, | ||
666 | }; | ||
667 | struct MLKEM1024_private_key private_key1024; | ||
668 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
669 | struct keygen_ctx keygen1024 = { | ||
670 | .private_key = &private_key1024, | ||
671 | .encoded_public_key = encoded_public_key1024, | ||
672 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
673 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
674 | .public_key_len = MLKEM1024_PUBLIC_KEY_BYTES, | ||
675 | |||
676 | .generate_key_external_entropy = | ||
677 | mlkem1024_generate_key_external_entropy, | ||
678 | .marshal_private_key = | ||
679 | mlkem1024_marshal_private_key, | ||
680 | }; | 672 | }; |
673 | int ret = 0; | ||
681 | 674 | ||
682 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | 675 | if (test_type == TEST_TYPE_NORMAL) |
683 | return parse_test_file(fn, &keygen_parse, &keygen768); | 676 | ret = parse_test_file(fn, &keygen_parse, &keygen); |
684 | if (size == 768 && test_type == TEST_TYPE_NIST) | 677 | else if (test_type == TEST_TYPE_NIST) |
685 | return parse_test_file(fn, &nist_keygen_parse, &keygen768); | 678 | ret = parse_test_file(fn, &nist_keygen_parse, &keygen); |
686 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | 679 | else |
687 | return parse_test_file(fn, &keygen_parse, &keygen1024); | 680 | errx(1, "unknown keygen test: rank %d, type %d", rank, |
688 | if (size == 1024 && test_type == TEST_TYPE_NIST) | 681 | test_type); |
689 | return parse_test_file(fn, &nist_keygen_parse, &keygen1024); | ||
690 | 682 | ||
691 | errx(1, "unknown keygen test: size %zu, type %d", size, test_type); | 683 | return ret; |
692 | } | 684 | } |
693 | 685 | ||
694 | static int | 686 | static int |
695 | run_mlkem_test(const char *test, const char *fn) | 687 | run_mlkem_test(const char *test, const char *fn) |
696 | { | 688 | { |
697 | if (strcmp(test, "mlkem768_decap_tests") == 0) | 689 | if (strcmp(test, "mlkem768_decap_tests") == 0) |
698 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NORMAL); | 690 | return mlkem_decap_tests(fn, RANK768, TEST_TYPE_NORMAL); |
699 | if (strcmp(test, "mlkem768_nist_decap_tests") == 0) | 691 | if (strcmp(test, "mlkem768_nist_decap_tests") == 0) |
700 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NIST); | 692 | return mlkem_decap_tests(fn, RANK768, TEST_TYPE_NIST); |
701 | if (strcmp(test, "mlkem1024_decap_tests") == 0) | 693 | if (strcmp(test, "mlkem1024_decap_tests") == 0) |
702 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NORMAL); | 694 | return mlkem_decap_tests(fn, RANK1024, TEST_TYPE_NORMAL); |
703 | if (strcmp(test, "mlkem1024_nist_decap_tests") == 0) | 695 | if (strcmp(test, "mlkem1024_nist_decap_tests") == 0) |
704 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NIST); | 696 | return mlkem_decap_tests(fn, RANK1024, TEST_TYPE_NIST); |
705 | 697 | ||
706 | if (strcmp(test, "mlkem768_encap_tests") == 0) | 698 | if (strcmp(test, "mlkem768_encap_tests") == 0) |
707 | return mlkem_encap_tests(fn, 768); | 699 | return mlkem_encap_tests(fn, RANK768); |
708 | if (strcmp(test, "mlkem1024_encap_tests") == 0) | 700 | if (strcmp(test, "mlkem1024_encap_tests") == 0) |
709 | return mlkem_encap_tests(fn, 1024); | 701 | return mlkem_encap_tests(fn, RANK1024); |
710 | 702 | ||
711 | if (strcmp(test, "mlkem768_keygen_tests") == 0) | 703 | if (strcmp(test, "mlkem768_keygen_tests") == 0) |
712 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NORMAL); | 704 | return mlkem_keygen_tests(fn, RANK768, TEST_TYPE_NORMAL); |
713 | if (strcmp(test, "mlkem768_nist_keygen_tests") == 0) | 705 | if (strcmp(test, "mlkem768_nist_keygen_tests") == 0) |
714 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NIST); | 706 | return mlkem_keygen_tests(fn, RANK768, TEST_TYPE_NIST); |
715 | if (strcmp(test, "mlkem1024_keygen_tests") == 0) | 707 | if (strcmp(test, "mlkem1024_keygen_tests") == 0) |
716 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NORMAL); | 708 | return mlkem_keygen_tests(fn, RANK1024, TEST_TYPE_NORMAL); |
717 | if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0) | 709 | if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0) |
718 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NIST); | 710 | return mlkem_keygen_tests(fn, RANK1024, TEST_TYPE_NIST); |
719 | 711 | ||
720 | errx(1, "unknown test %s (test file %s)", test, fn); | 712 | errx(1, "unknown test %s (test file %s)", test, fn); |
721 | } | 713 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c index 68bd5d4871..9d6e604386 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_tests_util.c,v 1.8 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.c,v 1.9 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> |
@@ -23,7 +23,7 @@ | |||
23 | #include <string.h> | 23 | #include <string.h> |
24 | 24 | ||
25 | #include "bytestring.h" | 25 | #include "bytestring.h" |
26 | #include "mlkem.h" | 26 | #include <openssl/mlkem.h> |
27 | 27 | ||
28 | #include "mlkem_internal.h" | 28 | #include "mlkem_internal.h" |
29 | 29 | ||
@@ -59,157 +59,3 @@ compare_data(const uint8_t *want, const uint8_t *got, size_t len, const char *ms | |||
59 | 59 | ||
60 | return 1; | 60 | return 1; |
61 | } | 61 | } |
62 | |||
63 | int | ||
64 | mlkem768_marshal_private_key(const void *private_key, uint8_t **out_buf, | ||
65 | size_t *out_len) | ||
66 | { | ||
67 | return MLKEM768_marshal_private_key(private_key, out_buf, out_len); | ||
68 | } | ||
69 | |||
70 | int | ||
71 | mlkem768_marshal_public_key(const void *public_key, uint8_t **out_buf, | ||
72 | size_t *out_len) | ||
73 | { | ||
74 | return MLKEM768_marshal_public_key(out_buf, out_len, public_key); | ||
75 | } | ||
76 | |||
77 | int | ||
78 | mlkem1024_marshal_private_key(const void *private_key, uint8_t **out_buf, | ||
79 | size_t *out_len) | ||
80 | { | ||
81 | return MLKEM1024_marshal_private_key(private_key, out_buf, out_len); | ||
82 | } | ||
83 | |||
84 | int | ||
85 | mlkem1024_marshal_public_key(const void *public_key, uint8_t **out_buf, | ||
86 | size_t *out_len) | ||
87 | { | ||
88 | return MLKEM1024_marshal_public_key(out_buf, out_len, public_key); | ||
89 | } | ||
90 | |||
91 | int | ||
92 | mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
93 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
94 | { | ||
95 | return MLKEM768_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
96 | private_key); | ||
97 | } | ||
98 | |||
99 | void | ||
100 | mlkem768_encap(uint8_t *out_ciphertext, | ||
101 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
102 | const void *public_key) | ||
103 | { | ||
104 | MLKEM768_encap(out_ciphertext, out_shared_secret, public_key); | ||
105 | } | ||
106 | |||
107 | void | ||
108 | mlkem768_encap_external_entropy(uint8_t *out_ciphertext, | ||
109 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
110 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
111 | { | ||
112 | MLKEM768_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
113 | public_key, entropy); | ||
114 | } | ||
115 | |||
116 | int | ||
117 | mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
118 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
119 | { | ||
120 | return MLKEM768_generate_key(out_encoded_public_key, optional_out_seed, | ||
121 | out_private_key); | ||
122 | } | ||
123 | |||
124 | int | ||
125 | mlkem768_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
126 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
127 | { | ||
128 | return MLKEM768_generate_key_external_entropy(out_encoded_public_key, | ||
129 | out_private_key, entropy); | ||
130 | } | ||
131 | |||
132 | int | ||
133 | mlkem768_parse_private_key(void *out_private_key, const uint8_t *private_key, | ||
134 | size_t private_key_len) | ||
135 | { | ||
136 | return MLKEM768_parse_private_key(out_private_key, private_key, | ||
137 | private_key_len); | ||
138 | } | ||
139 | |||
140 | int | ||
141 | mlkem768_parse_public_key(void *out_public_key, const uint8_t *public_key, | ||
142 | size_t public_key_len) | ||
143 | { | ||
144 | return MLKEM768_parse_public_key(out_public_key, public_key, | ||
145 | public_key_len); | ||
146 | } | ||
147 | |||
148 | void | ||
149 | mlkem768_public_from_private(void *out_public_key, const void *private_key) | ||
150 | { | ||
151 | MLKEM768_public_from_private(out_public_key, private_key); | ||
152 | } | ||
153 | |||
154 | int | ||
155 | mlkem1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
156 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
157 | { | ||
158 | return MLKEM1024_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
159 | private_key); | ||
160 | } | ||
161 | |||
162 | void | ||
163 | mlkem1024_encap(uint8_t *out_ciphertext, | ||
164 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
165 | const void *public_key) | ||
166 | { | ||
167 | MLKEM1024_encap(out_ciphertext, out_shared_secret, public_key); | ||
168 | } | ||
169 | |||
170 | void | ||
171 | mlkem1024_encap_external_entropy(uint8_t *out_ciphertext, | ||
172 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
173 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
174 | { | ||
175 | MLKEM1024_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
176 | public_key, entropy); | ||
177 | } | ||
178 | |||
179 | int | ||
180 | mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
181 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
182 | { | ||
183 | return MLKEM1024_generate_key(out_encoded_public_key, optional_out_seed, | ||
184 | out_private_key); | ||
185 | } | ||
186 | |||
187 | int | ||
188 | mlkem1024_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
189 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
190 | { | ||
191 | return MLKEM1024_generate_key_external_entropy(out_encoded_public_key, | ||
192 | out_private_key, entropy); | ||
193 | } | ||
194 | |||
195 | int | ||
196 | mlkem1024_parse_private_key(void *out_private_key, const uint8_t *private_key, | ||
197 | size_t private_key_len) | ||
198 | { | ||
199 | return MLKEM1024_parse_private_key(out_private_key, private_key, | ||
200 | private_key_len); | ||
201 | } | ||
202 | |||
203 | void | ||
204 | mlkem1024_public_from_private(void *out_public_key, const void *private_key) | ||
205 | { | ||
206 | MLKEM1024_public_from_private(out_public_key, private_key); | ||
207 | } | ||
208 | |||
209 | int | ||
210 | mlkem1024_parse_public_key(void *out_public_key, const uint8_t *public_key, | ||
211 | size_t public_key_len) | ||
212 | { | ||
213 | return MLKEM1024_parse_public_key(out_public_key, public_key, | ||
214 | public_key_len); | ||
215 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h index 1235309f60..a2348c75f3 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_tests_util.h,v 1.7 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.h,v 1.8 2025/08/14 15:48:48 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | 3 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> |
4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | 4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> |
@@ -30,60 +30,4 @@ | |||
30 | int compare_data(const uint8_t *want, const uint8_t *got, size_t len, | 30 | int compare_data(const uint8_t *want, const uint8_t *got, size_t len, |
31 | const char *msg); | 31 | const char *msg); |
32 | 32 | ||
33 | int mlkem768_marshal_private_key(const void *priv, uint8_t **out_buf, | ||
34 | size_t *out_len); | ||
35 | int mlkem768_marshal_public_key(const void *pub, uint8_t **out_buf, | ||
36 | size_t *out_len); | ||
37 | int mlkem1024_marshal_private_key(const void *priv, uint8_t **out_buf, | ||
38 | size_t *out_len); | ||
39 | int mlkem1024_marshal_public_key(const void *pub, uint8_t **out_buf, | ||
40 | size_t *out_len); | ||
41 | |||
42 | int mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
43 | const uint8_t *ciphertext, size_t ciphertext_len, const void *priv); | ||
44 | void mlkem768_encap(uint8_t *out_ciphertext, | ||
45 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub); | ||
46 | void mlkem768_encap_external_entropy(uint8_t *out_ciphertext, | ||
47 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub, | ||
48 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | ||
49 | int mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
50 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
51 | int mlkem768_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
52 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]); | ||
53 | int mlkem768_parse_private_key(void *priv, const uint8_t *in, size_t in_len); | ||
54 | int mlkem768_parse_public_key(void *pub, const uint8_t *in, size_t in_len); | ||
55 | void mlkem768_public_from_private(void *out_public_key, const void *private_key); | ||
56 | |||
57 | int mlkem1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
58 | const uint8_t *ciphertext, size_t ciphertext_len, const void *priv); | ||
59 | void mlkem1024_encap(uint8_t *out_ciphertext, | ||
60 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub); | ||
61 | void mlkem1024_encap_external_entropy(uint8_t *out_ciphertext, | ||
62 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub, | ||
63 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | ||
64 | int mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
65 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
66 | int mlkem1024_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
67 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]); | ||
68 | int mlkem1024_parse_private_key(void *priv, const uint8_t *in, size_t in_len); | ||
69 | int mlkem1024_parse_public_key(void *pub, const uint8_t *in, size_t in_len); | ||
70 | void mlkem1024_public_from_private(void *out_public_key, const void *private_key); | ||
71 | |||
72 | typedef int (*mlkem_marshal_private_key_fn)(const void *, uint8_t **, size_t *); | ||
73 | typedef int (*mlkem_marshal_public_key_fn)(const void *, uint8_t **, size_t *); | ||
74 | typedef int (*mlkem_decap_fn)(uint8_t [MLKEM_SHARED_SECRET_BYTES], | ||
75 | const uint8_t *, size_t, const void *); | ||
76 | typedef void (*mlkem_encap_fn)(uint8_t *, uint8_t [MLKEM_SHARED_SECRET_BYTES], | ||
77 | const void *); | ||
78 | typedef void (*mlkem_encap_external_entropy_fn)(uint8_t *, | ||
79 | uint8_t [MLKEM_SHARED_SECRET_BYTES], const void *, | ||
80 | const uint8_t [MLKEM_ENCAP_ENTROPY]); | ||
81 | typedef int (*mlkem_generate_key_fn)(uint8_t *, uint8_t *, void *); | ||
82 | typedef int (*mlkem_generate_key_external_entropy_fn)(uint8_t *, void *, | ||
83 | const uint8_t [MLKEM_SEED_BYTES]); | ||
84 | typedef int (*mlkem_parse_private_key_fn)(void *, const uint8_t *, size_t); | ||
85 | typedef int (*mlkem_parse_public_key_fn)(void *, const uint8_t *, size_t); | ||
86 | typedef void (*mlkem_public_from_private_fn)(void *out_public_key, | ||
87 | const void *private_key); | ||
88 | |||
89 | #endif /* MLKEM_TEST_UTIL_H */ | 33 | #endif /* MLKEM_TEST_UTIL_H */ |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c index adb1c47d8e..417d40555f 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_unittest.c,v 1.11 2025/05/21 03:46:20 tb Exp $ */ | 1 | /* $OpenBSD: mlkem_unittest.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 Bob Beck <beck@obtuse.com> |
@@ -27,95 +27,161 @@ | |||
27 | 27 | ||
28 | #include "mlkem_tests_util.h" | 28 | #include "mlkem_tests_util.h" |
29 | 29 | ||
30 | struct unittest_ctx { | ||
31 | void *priv; | ||
32 | void *pub; | ||
33 | void *priv2; | ||
34 | void *pub2; | ||
35 | uint8_t *encoded_public_key; | ||
36 | size_t encoded_public_key_len; | ||
37 | uint8_t *ciphertext; | ||
38 | size_t ciphertext_len; | ||
39 | mlkem_decap_fn decap; | ||
40 | mlkem_encap_fn encap; | ||
41 | mlkem_generate_key_fn generate_key; | ||
42 | mlkem_parse_private_key_fn parse_private_key; | ||
43 | mlkem_parse_public_key_fn parse_public_key; | ||
44 | mlkem_marshal_private_key_fn marshal_private_key; | ||
45 | mlkem_marshal_public_key_fn marshal_public_key; | ||
46 | mlkem_public_from_private_fn public_from_private; | ||
47 | }; | ||
48 | |||
49 | static int | 30 | static int |
50 | MlKemUnitTest(struct unittest_ctx *ctx) | 31 | MlKemUnitTest(int rank) |
51 | { | 32 | { |
52 | uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; | 33 | MLKEM_private_key *priv = NULL, *priv2 = NULL, *priv3 = NULL; |
53 | uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES]; | 34 | MLKEM_public_key *pub = NULL, *pub2 = NULL, *pub3 = NULL; |
35 | uint8_t *encoded_public_key = NULL, *ciphertext = NULL, | ||
36 | *shared_secret2 = NULL, *shared_secret1 = NULL, | ||
37 | *encoded_private_key = NULL, *tmp_buf = NULL, *seed_buf = NULL; | ||
38 | size_t encoded_public_key_len, ciphertext_len, | ||
39 | encoded_private_key_len, tmp_buf_len; | ||
54 | uint8_t first_two_bytes[2]; | 40 | uint8_t first_two_bytes[2]; |
55 | uint8_t *encoded_private_key = NULL, *tmp_buf = NULL; | 41 | size_t s_len = 0; |
56 | size_t encoded_private_key_len, tmp_buf_len; | ||
57 | int failed = 0; | 42 | int failed = 0; |
58 | 43 | ||
59 | if (!ctx->generate_key(ctx->encoded_public_key, NULL, ctx->priv)) { | 44 | if ((pub = MLKEM_public_key_new(rank)) == NULL) { |
45 | warnx("public_key_new"); | ||
46 | failed |= 1; | ||
47 | } | ||
48 | |||
49 | if ((pub2 = MLKEM_public_key_new(rank)) == NULL) { | ||
50 | warnx("public_key_new"); | ||
51 | failed |= 1; | ||
52 | } | ||
53 | |||
54 | if ((priv = MLKEM_private_key_new(rank)) == NULL) { | ||
55 | warnx("private_key_new"); | ||
56 | failed |= 1; | ||
57 | } | ||
58 | |||
59 | if ((priv2 = MLKEM_private_key_new(rank)) == NULL) { | ||
60 | warnx("private_key_new"); | ||
61 | failed |= 1; | ||
62 | } | ||
63 | |||
64 | if (!MLKEM_generate_key(priv, &encoded_public_key, | ||
65 | &encoded_public_key_len, &seed_buf, &s_len)) { | ||
60 | warnx("generate_key failed"); | 66 | warnx("generate_key failed"); |
61 | failed |= 1; | 67 | failed |= 1; |
62 | } | 68 | } |
63 | 69 | ||
64 | memcpy(first_two_bytes, ctx->encoded_public_key, sizeof(first_two_bytes)); | 70 | if (s_len != MLKEM_SEED_LENGTH) { |
65 | memset(ctx->encoded_public_key, 0xff, sizeof(first_two_bytes)); | 71 | warnx("seed length %zu != %d", s_len, MLKEM_SEED_LENGTH); |
72 | failed |= 1; | ||
73 | } | ||
74 | |||
75 | if ((priv3 = MLKEM_private_key_new(rank)) == NULL) { | ||
76 | warnx("private_key_new"); | ||
77 | failed |= 1; | ||
78 | } | ||
79 | |||
80 | if ((pub3 = MLKEM_public_key_new(rank)) == NULL) { | ||
81 | warnx("public_key_new"); | ||
82 | failed |= 1; | ||
83 | } | ||
84 | |||
85 | if (!MLKEM_private_key_from_seed(priv3, seed_buf, s_len)) { | ||
86 | warnx("private_key_from_seed failed"); | ||
87 | failed |= 1; | ||
88 | } | ||
89 | |||
90 | free(seed_buf); | ||
91 | seed_buf = NULL; | ||
92 | |||
93 | if (!MLKEM_public_from_private(priv3, pub3)) { | ||
94 | warnx("public_from_private"); | ||
95 | failed |= 1; | ||
96 | } | ||
97 | |||
98 | memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); | ||
99 | memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); | ||
66 | 100 | ||
67 | /* Parsing should fail because the first coefficient is >= kPrime. */ | 101 | /* Parsing should fail because the first coefficient is >= kPrime. */ |
68 | if (ctx->parse_public_key(ctx->pub, ctx->encoded_public_key, | 102 | if (MLKEM_parse_public_key(pub, encoded_public_key, |
69 | ctx->encoded_public_key_len)) { | 103 | encoded_public_key_len)) { |
70 | warnx("parse_public_key should have failed"); | 104 | warnx("parse_public_key should have failed"); |
71 | failed |= 1; | 105 | failed |= 1; |
72 | } | 106 | } |
73 | 107 | ||
74 | memcpy(ctx->encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); | 108 | memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); |
75 | if (!ctx->parse_public_key(ctx->pub, ctx->encoded_public_key, | 109 | |
76 | ctx->encoded_public_key_len)) { | 110 | MLKEM_public_key_free(pub); |
77 | warnx("MLKEM768_parse_public_key"); | 111 | if ((pub = MLKEM_public_key_new(rank)) == NULL) { |
112 | warnx("public_key_new"); | ||
113 | failed |= 1; | ||
114 | } | ||
115 | if (!MLKEM_parse_public_key(pub, encoded_public_key, | ||
116 | encoded_public_key_len)) { | ||
117 | warnx("MLKEM_parse_public_key"); | ||
118 | failed |= 1; | ||
119 | } | ||
120 | |||
121 | if (!MLKEM_marshal_public_key(pub, &tmp_buf, &tmp_buf_len)) { | ||
122 | warnx("marshal_public_key"); | ||
123 | failed |= 1; | ||
124 | } | ||
125 | if (encoded_public_key_len != tmp_buf_len) { | ||
126 | warnx("encoded public key lengths differ %d != %d", | ||
127 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
128 | failed |= 1; | ||
129 | } | ||
130 | |||
131 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, | ||
132 | "encoded public keys") != 0) { | ||
133 | warnx("compare_data"); | ||
78 | failed |= 1; | 134 | failed |= 1; |
79 | } | 135 | } |
136 | free(tmp_buf); | ||
137 | tmp_buf = NULL; | ||
138 | tmp_buf_len = 0; | ||
80 | 139 | ||
81 | if (!ctx->marshal_public_key(ctx->pub, &tmp_buf, &tmp_buf_len)) { | 140 | if (!MLKEM_marshal_public_key(pub3, &tmp_buf, &tmp_buf_len)) { |
82 | warnx("marshal_public_key"); | 141 | warnx("marshal_public_key"); |
83 | failed |= 1; | 142 | failed |= 1; |
84 | } | 143 | } |
85 | if (ctx->encoded_public_key_len != tmp_buf_len) { | 144 | if (encoded_public_key_len != tmp_buf_len) { |
86 | warnx("encoded public key lengths differ"); | 145 | warnx("encoded public key lengths differ %d != %d", |
146 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
87 | failed |= 1; | 147 | failed |= 1; |
88 | } | 148 | } |
89 | 149 | ||
90 | if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len, | 150 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, |
91 | "encoded public keys") != 0) { | 151 | "encoded public keys") != 0) { |
92 | warnx("compare_data"); | 152 | warnx("compare_data"); |
93 | failed |= 1; | 153 | failed |= 1; |
94 | } | 154 | } |
95 | free(tmp_buf); | 155 | free(tmp_buf); |
96 | tmp_buf = NULL; | 156 | tmp_buf = NULL; |
157 | tmp_buf_len = 0; | ||
97 | 158 | ||
98 | ctx->public_from_private(ctx->pub2, ctx->priv); | 159 | if (!MLKEM_public_from_private(priv, pub2)) { |
99 | if (!ctx->marshal_public_key(ctx->pub2, &tmp_buf, &tmp_buf_len)) { | 160 | warnx("public_from_private"); |
161 | failed |= 1; | ||
162 | } | ||
163 | if (!MLKEM_marshal_public_key(pub2, &tmp_buf, &tmp_buf_len)) { | ||
100 | warnx("marshal_public_key"); | 164 | warnx("marshal_public_key"); |
101 | failed |= 1; | 165 | failed |= 1; |
102 | } | 166 | } |
103 | if (ctx->encoded_public_key_len != tmp_buf_len) { | 167 | if (encoded_public_key_len != tmp_buf_len) { |
104 | warnx("encoded public key lengths differ"); | 168 | warnx("encoded public key lengths differ %d %d", |
169 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
105 | failed |= 1; | 170 | failed |= 1; |
106 | } | 171 | } |
107 | 172 | ||
108 | if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len, | 173 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, |
109 | "encoded public keys") != 0) { | 174 | "encoded public keys") != 0) { |
110 | warnx("compare_data"); | 175 | warnx("compare_data"); |
111 | failed |= 1; | 176 | failed |= 1; |
112 | } | 177 | } |
113 | free(tmp_buf); | 178 | free(tmp_buf); |
114 | tmp_buf = NULL; | 179 | tmp_buf = NULL; |
180 | tmp_buf_len = 0; | ||
115 | 181 | ||
116 | if (!ctx->marshal_private_key(ctx->priv, &encoded_private_key, | 182 | if (!MLKEM_marshal_private_key(priv, &encoded_private_key, |
117 | &encoded_private_key_len)) { | 183 | &encoded_private_key_len)) { |
118 | warnx("mlkem768_encode_private_key"); | 184 | warnx("marshal_private_key"); |
119 | failed |= 1; | 185 | failed |= 1; |
120 | } | 186 | } |
121 | 187 | ||
@@ -123,27 +189,34 @@ MlKemUnitTest(struct unittest_ctx *ctx) | |||
123 | memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); | 189 | memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); |
124 | 190 | ||
125 | /* Parsing should fail because the first coefficient is >= kPrime. */ | 191 | /* Parsing should fail because the first coefficient is >= kPrime. */ |
126 | if (ctx->parse_private_key(ctx->priv2, encoded_private_key, | 192 | if (MLKEM_parse_private_key(priv2, encoded_private_key, |
127 | encoded_private_key_len)) { | 193 | encoded_private_key_len)) { |
128 | warnx("MLKEM768_parse_private_key should have failed"); | 194 | warnx("parse_private_key should have failed"); |
129 | failed |= 1; | 195 | failed |= 1; |
130 | } | 196 | } |
131 | 197 | ||
132 | memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); | 198 | memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); |
133 | 199 | ||
134 | if (!ctx->parse_private_key(ctx->priv2, encoded_private_key, | 200 | MLKEM_private_key_free(priv2); |
201 | priv2 = NULL; | ||
202 | |||
203 | if ((priv2 = MLKEM_private_key_new(rank)) == NULL) { | ||
204 | warnx("private_key_new"); | ||
205 | failed |= 1; | ||
206 | } | ||
207 | if (!MLKEM_parse_private_key(priv2, encoded_private_key, | ||
135 | encoded_private_key_len)) { | 208 | encoded_private_key_len)) { |
136 | warnx("MLKEM768_parse_private_key"); | 209 | warnx("parse_private_key"); |
137 | failed |= 1; | 210 | failed |= 1; |
138 | } | 211 | } |
139 | 212 | ||
140 | if (!ctx->marshal_private_key(ctx->priv2, &tmp_buf, &tmp_buf_len)) { | 213 | if (!MLKEM_marshal_private_key(priv2, &tmp_buf, &tmp_buf_len)) { |
141 | warnx("encode_private_key"); | 214 | warnx("marshal_private_key"); |
142 | failed |= 1; | 215 | failed |= 1; |
143 | } | 216 | } |
144 | 217 | ||
145 | if (encoded_private_key_len != tmp_buf_len) { | 218 | if (encoded_private_key_len != tmp_buf_len) { |
146 | warnx("encode private key lengths differ"); | 219 | warnx("encoded private key lengths differ"); |
147 | failed |= 1; | 220 | failed |= 1; |
148 | } | 221 | } |
149 | 222 | ||
@@ -156,106 +229,79 @@ MlKemUnitTest(struct unittest_ctx *ctx) | |||
156 | free(tmp_buf); | 229 | free(tmp_buf); |
157 | tmp_buf = NULL; | 230 | tmp_buf = NULL; |
158 | 231 | ||
159 | ctx->encap(ctx->ciphertext, shared_secret1, ctx->pub); | 232 | if (!MLKEM_encap(pub, &ciphertext, &ciphertext_len, &shared_secret1, |
160 | if (!ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len, | 233 | &s_len)) { |
161 | ctx->priv)) { | 234 | warnx("encap failed using pub"); |
235 | failed |= 1; | ||
236 | } | ||
237 | |||
238 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
239 | warnx("seed length %zu != %d", s_len, | ||
240 | MLKEM_SHARED_SECRET_LENGTH); | ||
241 | failed |= 1; | ||
242 | } | ||
243 | |||
244 | if (!MLKEM_decap(priv, ciphertext, ciphertext_len, | ||
245 | &shared_secret2, &s_len)) { | ||
162 | warnx("decap() failed using priv"); | 246 | warnx("decap() failed using priv"); |
163 | failed |= 1; | 247 | failed |= 1; |
164 | } | 248 | } |
165 | if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, | 249 | |
250 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
251 | warnx("seed length %zu != %d", s_len, | ||
252 | MLKEM_SHARED_SECRET_LENGTH); | ||
253 | failed |= 1; | ||
254 | } | ||
255 | |||
256 | if (compare_data(shared_secret1, shared_secret2, s_len, | ||
166 | "shared secrets with priv") != 0) { | 257 | "shared secrets with priv") != 0) { |
167 | warnx("compare_data"); | 258 | warnx("compare_data"); |
168 | failed |= 1; | 259 | failed |= 1; |
169 | } | 260 | } |
170 | 261 | ||
171 | if (!ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len, | 262 | free(shared_secret2); |
172 | ctx->priv2)) { | 263 | shared_secret2 = NULL; |
264 | |||
265 | if (!MLKEM_decap(priv2, ciphertext, ciphertext_len, | ||
266 | &shared_secret2, &s_len)){ | ||
173 | warnx("decap() failed using priv2"); | 267 | warnx("decap() failed using priv2"); |
174 | failed |= 1; | 268 | failed |= 1; |
175 | } | 269 | } |
176 | if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, | 270 | |
271 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
272 | warnx("seed length %zu != %d", s_len, | ||
273 | MLKEM_SHARED_SECRET_LENGTH); | ||
274 | failed |= 1; | ||
275 | } | ||
276 | |||
277 | if (compare_data(shared_secret1, shared_secret2, s_len, | ||
177 | "shared secrets with priv2") != 0) { | 278 | "shared secrets with priv2") != 0) { |
178 | warnx("compare_data"); | 279 | warnx("compare_data"); |
179 | failed |= 1; | 280 | failed |= 1; |
180 | } | 281 | } |
181 | 282 | ||
283 | MLKEM_public_key_free(pub); | ||
284 | MLKEM_public_key_free(pub2); | ||
285 | MLKEM_public_key_free(pub3); | ||
286 | MLKEM_private_key_free(priv); | ||
287 | MLKEM_private_key_free(priv2); | ||
288 | MLKEM_private_key_free(priv3); | ||
289 | free(encoded_public_key); | ||
290 | free(ciphertext); | ||
182 | free(encoded_private_key); | 291 | free(encoded_private_key); |
292 | free(shared_secret1); | ||
293 | free(shared_secret2); | ||
183 | 294 | ||
184 | return failed; | 295 | return failed; |
185 | } | 296 | } |
186 | 297 | ||
187 | static int | ||
188 | mlkem768_unittest(void) | ||
189 | { | ||
190 | struct MLKEM768_private_key mlkem768_priv, mlkem768_priv2; | ||
191 | struct MLKEM768_public_key mlkem768_pub, mlkem768_pub2; | ||
192 | uint8_t mlkem768_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; | ||
193 | uint8_t mlkem768_ciphertext[MLKEM768_CIPHERTEXT_BYTES]; | ||
194 | struct unittest_ctx mlkem768_test = { | ||
195 | .priv = &mlkem768_priv, | ||
196 | .pub = &mlkem768_pub, | ||
197 | .priv2 = &mlkem768_priv2, | ||
198 | .pub2 = &mlkem768_pub2, | ||
199 | .encoded_public_key = mlkem768_encoded_public_key, | ||
200 | .encoded_public_key_len = sizeof(mlkem768_encoded_public_key), | ||
201 | .ciphertext = mlkem768_ciphertext, | ||
202 | .ciphertext_len = sizeof(mlkem768_ciphertext), | ||
203 | .decap = mlkem768_decap, | ||
204 | .encap = mlkem768_encap, | ||
205 | .generate_key = mlkem768_generate_key, | ||
206 | .parse_private_key = mlkem768_parse_private_key, | ||
207 | .parse_public_key = mlkem768_parse_public_key, | ||
208 | .marshal_private_key = mlkem768_marshal_private_key, | ||
209 | .marshal_public_key = mlkem768_marshal_public_key, | ||
210 | .public_from_private = mlkem768_public_from_private, | ||
211 | }; | ||
212 | |||
213 | return MlKemUnitTest(&mlkem768_test); | ||
214 | } | ||
215 | |||
216 | static int | ||
217 | mlkem1024_unittest(void) | ||
218 | { | ||
219 | struct MLKEM1024_private_key mlkem1024_priv, mlkem1024_priv2; | ||
220 | struct MLKEM1024_public_key mlkem1024_pub, mlkem1024_pub2; | ||
221 | uint8_t mlkem1024_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
222 | uint8_t mlkem1024_ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; | ||
223 | struct unittest_ctx mlkem1024_test = { | ||
224 | .priv = &mlkem1024_priv, | ||
225 | .pub = &mlkem1024_pub, | ||
226 | .priv2 = &mlkem1024_priv2, | ||
227 | .pub2 = &mlkem1024_pub2, | ||
228 | .encoded_public_key = mlkem1024_encoded_public_key, | ||
229 | .encoded_public_key_len = sizeof(mlkem1024_encoded_public_key), | ||
230 | .ciphertext = mlkem1024_ciphertext, | ||
231 | .ciphertext_len = sizeof(mlkem1024_ciphertext), | ||
232 | .decap = mlkem1024_decap, | ||
233 | .encap = mlkem1024_encap, | ||
234 | .generate_key = mlkem1024_generate_key, | ||
235 | .parse_private_key = mlkem1024_parse_private_key, | ||
236 | .parse_public_key = mlkem1024_parse_public_key, | ||
237 | .marshal_private_key = mlkem1024_marshal_private_key, | ||
238 | .marshal_public_key = mlkem1024_marshal_public_key, | ||
239 | .public_from_private = mlkem1024_public_from_private, | ||
240 | }; | ||
241 | |||
242 | return MlKemUnitTest(&mlkem1024_test); | ||
243 | } | ||
244 | |||
245 | int | 298 | int |
246 | main(void) | 299 | main(void) |
247 | { | 300 | { |
248 | int failed = 0; | 301 | int ret = 0; |
249 | 302 | ||
250 | /* | 303 | ret |= MlKemUnitTest(RANK768); |
251 | * XXX - this is split into two helper functions since having a few | 304 | ret |= MlKemUnitTest(RANK1024); |
252 | * ML-KEM key blobs on the stack makes Emscripten's stack explode, | ||
253 | * leading to inscrutable silent failures unless ASAN is enabled. | ||
254 | * Go figure. | ||
255 | */ | ||
256 | 305 | ||
257 | failed |= mlkem768_unittest(); | 306 | return ret; |
258 | failed |= mlkem1024_unittest(); | ||
259 | |||
260 | return failed; | ||
261 | } | 307 | } |