diff options
Diffstat (limited to '')
| -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 |
8 files changed, 1385 insertions, 302 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); | ||
