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 | } |
