diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c index 09677588e18..784cfbb0a49 100644 --- a/crypto/hpke/hpke.c +++ b/crypto/hpke/hpke.c @@ -18,11 +18,12 @@ #include #include "../internal.h" +#include "../fipsmodule/ml_kem/ml_kem.h" -// This file implements RFC 9180. +// This file implements RFC 9180 and draft-ietf-hpke-pq-04. -#define MAX_SEED_LEN X25519_PRIVATE_KEY_LEN +#define MAX_SEED_LEN 64 #define MAX_SHARED_SECRET_LEN SHA256_DIGEST_LENGTH struct evp_hpke_kem_st { @@ -143,12 +144,30 @@ static int x25519_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key, return 0; } - OPENSSL_memcpy(key->private_key, priv_key, priv_key_len); + key->private_key = OPENSSL_memdup(priv_key, X25519_PRIVATE_KEY_LEN); + if (key->private_key == NULL) { + return 0; + } + key->public_key = OPENSSL_malloc(X25519_PUBLIC_VALUE_LEN); + if (key->public_key == NULL) { + OPENSSL_free(key->private_key); + key->private_key = NULL; + return 0; + } X25519_public_from_private(key->public_key, priv_key); return 1; } static int x25519_generate_key(EVP_HPKE_KEY *key) { + key->private_key = OPENSSL_malloc(X25519_PRIVATE_KEY_LEN); + key->public_key = OPENSSL_malloc(X25519_PUBLIC_VALUE_LEN); + if (key->private_key == NULL || key->public_key == NULL) { + OPENSSL_free(key->private_key); + OPENSSL_free(key->public_key); + key->private_key = NULL; + key->public_key = NULL; + return 0; + } X25519_keypair(key->public_key, key->private_key); return 1; } @@ -301,6 +320,355 @@ const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256(void) { return &kKEM; } + +// ML-KEM KEM implementations (draft-ietf-hpke-pq-04). + +static int mlkem512_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key, + size_t priv_key_len) { + if (priv_key_len != MLKEM512_SECRET_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + if (ml_kem_512_check_sk(priv_key, priv_key_len) != 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + key->private_key = OPENSSL_memdup(priv_key, MLKEM512_SECRET_KEY_BYTES); + if (key->private_key == NULL) { + return 0; + } + size_t pk_offset = MLKEM512_SECRET_KEY_BYTES - MLKEM512_PUBLIC_KEY_BYTES - 64; + key->public_key = OPENSSL_memdup(priv_key + pk_offset, + MLKEM512_PUBLIC_KEY_BYTES); + if (key->public_key == NULL) { + OPENSSL_free(key->private_key); + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem512_generate_key(EVP_HPKE_KEY *key) { + key->public_key = OPENSSL_malloc(MLKEM512_PUBLIC_KEY_BYTES); + key->private_key = OPENSSL_malloc(MLKEM512_SECRET_KEY_BYTES); + if (key->public_key == NULL || key->private_key == NULL) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + size_t pk_len = MLKEM512_PUBLIC_KEY_BYTES; + size_t sk_len = MLKEM512_SECRET_KEY_BYTES; + if (ml_kem_512_keypair(key->public_key, &pk_len, + key->private_key, &sk_len) != 0) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem512_encap_with_seed( + const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, uint8_t *out_enc, size_t *out_enc_len, + size_t max_enc, const uint8_t *peer_public_key, size_t peer_public_key_len, + const uint8_t *seed, size_t seed_len) { + if (max_enc < MLKEM512_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + return 0; + } + if (peer_public_key_len != MLKEM512_PUBLIC_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + if (seed_len != MLKEM512_ENCAPS_SEED_LEN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + size_t ct_len = MLKEM512_CIPHERTEXT_BYTES; + size_t ss_len = MLKEM512_SHARED_SECRET_LEN; + if (ml_kem_512_encapsulate_deterministic(out_enc, &ct_len, + out_shared_secret, &ss_len, + peer_public_key, seed) != 0) { + return 0; + } + + *out_enc_len = ct_len; + *out_shared_secret_len = ss_len; + return 1; +} + +static int mlkem512_decap(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, const uint8_t *enc, + size_t enc_len) { + if (enc_len != MLKEM512_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + + size_t ss_len = MLKEM512_SHARED_SECRET_LEN; + if (ml_kem_512_decapsulate(out_shared_secret, &ss_len, + enc, key->private_key) != 0) { + return 0; + } + + *out_shared_secret_len = ss_len; + return 1; +} + +const EVP_HPKE_KEM *EVP_hpke_mlkem512(void) { + static const EVP_HPKE_KEM kKEM = { + /*id=*/EVP_HPKE_KEM_MLKEM512, + /*public_key_len=*/MLKEM512_PUBLIC_KEY_BYTES, + /*private_key_len=*/MLKEM512_SECRET_KEY_BYTES, + /*seed_len=*/MLKEM512_ENCAPS_SEED_LEN, + /*enc_len=*/MLKEM512_CIPHERTEXT_BYTES, + mlkem512_init_key, + mlkem512_generate_key, + mlkem512_encap_with_seed, + mlkem512_decap, + NULL, + NULL, + }; + return &kKEM; +} + + +static int mlkem768_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key, + size_t priv_key_len) { + if (priv_key_len != MLKEM768_SECRET_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + if (ml_kem_768_check_sk(priv_key, priv_key_len) != 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + key->private_key = OPENSSL_memdup(priv_key, MLKEM768_SECRET_KEY_BYTES); + if (key->private_key == NULL) { + return 0; + } + size_t pk_offset = MLKEM768_SECRET_KEY_BYTES - MLKEM768_PUBLIC_KEY_BYTES - 64; + key->public_key = OPENSSL_memdup(priv_key + pk_offset, + MLKEM768_PUBLIC_KEY_BYTES); + if (key->public_key == NULL) { + OPENSSL_free(key->private_key); + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem768_generate_key(EVP_HPKE_KEY *key) { + key->public_key = OPENSSL_malloc(MLKEM768_PUBLIC_KEY_BYTES); + key->private_key = OPENSSL_malloc(MLKEM768_SECRET_KEY_BYTES); + if (key->public_key == NULL || key->private_key == NULL) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + size_t pk_len = MLKEM768_PUBLIC_KEY_BYTES; + size_t sk_len = MLKEM768_SECRET_KEY_BYTES; + if (ml_kem_768_keypair(key->public_key, &pk_len, + key->private_key, &sk_len) != 0) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem768_encap_with_seed( + const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, uint8_t *out_enc, size_t *out_enc_len, + size_t max_enc, const uint8_t *peer_public_key, size_t peer_public_key_len, + const uint8_t *seed, size_t seed_len) { + if (max_enc < MLKEM768_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + return 0; + } + if (peer_public_key_len != MLKEM768_PUBLIC_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + if (seed_len != MLKEM768_ENCAPS_SEED_LEN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + size_t ct_len = MLKEM768_CIPHERTEXT_BYTES; + size_t ss_len = MLKEM768_SHARED_SECRET_LEN; + if (ml_kem_768_encapsulate_deterministic(out_enc, &ct_len, + out_shared_secret, &ss_len, + peer_public_key, seed) != 0) { + return 0; + } + + *out_enc_len = ct_len; + *out_shared_secret_len = ss_len; + return 1; +} + +static int mlkem768_decap(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, const uint8_t *enc, + size_t enc_len) { + if (enc_len != MLKEM768_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + + size_t ss_len = MLKEM768_SHARED_SECRET_LEN; + if (ml_kem_768_decapsulate(out_shared_secret, &ss_len, + enc, key->private_key) != 0) { + return 0; + } + + *out_shared_secret_len = ss_len; + return 1; +} + +const EVP_HPKE_KEM *EVP_hpke_mlkem768(void) { + static const EVP_HPKE_KEM kKEM = { + /*id=*/EVP_HPKE_KEM_MLKEM768, + /*public_key_len=*/MLKEM768_PUBLIC_KEY_BYTES, + /*private_key_len=*/MLKEM768_SECRET_KEY_BYTES, + /*seed_len=*/MLKEM768_ENCAPS_SEED_LEN, + /*enc_len=*/MLKEM768_CIPHERTEXT_BYTES, + mlkem768_init_key, + mlkem768_generate_key, + mlkem768_encap_with_seed, + mlkem768_decap, + NULL, + NULL, + }; + return &kKEM; +} + + +static int mlkem1024_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key, + size_t priv_key_len) { + if (priv_key_len != MLKEM1024_SECRET_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + if (ml_kem_1024_check_sk(priv_key, priv_key_len) != 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + key->private_key = OPENSSL_memdup(priv_key, MLKEM1024_SECRET_KEY_BYTES); + if (key->private_key == NULL) { + return 0; + } + size_t pk_offset = + MLKEM1024_SECRET_KEY_BYTES - MLKEM1024_PUBLIC_KEY_BYTES - 64; + key->public_key = OPENSSL_memdup(priv_key + pk_offset, + MLKEM1024_PUBLIC_KEY_BYTES); + if (key->public_key == NULL) { + OPENSSL_free(key->private_key); + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem1024_generate_key(EVP_HPKE_KEY *key) { + key->public_key = OPENSSL_malloc(MLKEM1024_PUBLIC_KEY_BYTES); + key->private_key = OPENSSL_malloc(MLKEM1024_SECRET_KEY_BYTES); + if (key->public_key == NULL || key->private_key == NULL) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + size_t pk_len = MLKEM1024_PUBLIC_KEY_BYTES; + size_t sk_len = MLKEM1024_SECRET_KEY_BYTES; + if (ml_kem_1024_keypair(key->public_key, &pk_len, + key->private_key, &sk_len) != 0) { + OPENSSL_free(key->public_key); + OPENSSL_free(key->private_key); + key->public_key = NULL; + key->private_key = NULL; + return 0; + } + return 1; +} + +static int mlkem1024_encap_with_seed( + const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, uint8_t *out_enc, size_t *out_enc_len, + size_t max_enc, const uint8_t *peer_public_key, size_t peer_public_key_len, + const uint8_t *seed, size_t seed_len) { + if (max_enc < MLKEM1024_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE); + return 0; + } + if (peer_public_key_len != MLKEM1024_PUBLIC_KEY_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + if (seed_len != MLKEM1024_ENCAPS_SEED_LEN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + size_t ct_len = MLKEM1024_CIPHERTEXT_BYTES; + size_t ss_len = MLKEM1024_SHARED_SECRET_LEN; + if (ml_kem_1024_encapsulate_deterministic(out_enc, &ct_len, + out_shared_secret, &ss_len, + peer_public_key, seed) != 0) { + return 0; + } + + *out_enc_len = ct_len; + *out_shared_secret_len = ss_len; + return 1; +} + +static int mlkem1024_decap(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret, + size_t *out_shared_secret_len, const uint8_t *enc, + size_t enc_len) { + if (enc_len != MLKEM1024_CIPHERTEXT_BYTES) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY); + return 0; + } + + size_t ss_len = MLKEM1024_SHARED_SECRET_LEN; + if (ml_kem_1024_decapsulate(out_shared_secret, &ss_len, + enc, key->private_key) != 0) { + return 0; + } + + *out_shared_secret_len = ss_len; + return 1; +} + +const EVP_HPKE_KEM *EVP_hpke_mlkem1024(void) { + static const EVP_HPKE_KEM kKEM = { + /*id=*/EVP_HPKE_KEM_MLKEM1024, + /*public_key_len=*/MLKEM1024_PUBLIC_KEY_BYTES, + /*private_key_len=*/MLKEM1024_SECRET_KEY_BYTES, + /*seed_len=*/MLKEM1024_ENCAPS_SEED_LEN, + /*enc_len=*/MLKEM1024_CIPHERTEXT_BYTES, + mlkem1024_init_key, + mlkem1024_generate_key, + mlkem1024_encap_with_seed, + mlkem1024_decap, + NULL, + NULL, + }; + return &kKEM; +} + + uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem) { return kem->id; } size_t EVP_HPKE_KEM_public_key_len(const EVP_HPKE_KEM *kem) { @@ -318,8 +686,17 @@ void EVP_HPKE_KEY_zero(EVP_HPKE_KEY *key) { } void EVP_HPKE_KEY_cleanup(EVP_HPKE_KEY *key) { - // Nothing to clean up for now, but we may introduce a cleanup process in the - // future. + if (key->private_key != NULL) { + if (key->kem != NULL) { + OPENSSL_cleanse(key->private_key, key->kem->private_key_len); + } + OPENSSL_free(key->private_key); + key->private_key = NULL; + } + if (key->public_key != NULL) { + OPENSSL_free(key->public_key); + key->public_key = NULL; + } } EVP_HPKE_KEY *EVP_HPKE_KEY_new(void) { @@ -339,15 +716,33 @@ void EVP_HPKE_KEY_free(EVP_HPKE_KEY *key) { } int EVP_HPKE_KEY_copy(EVP_HPKE_KEY *dst, const EVP_HPKE_KEY *src) { - // For now, |EVP_HPKE_KEY| is trivially copyable. - OPENSSL_memcpy(dst, src, sizeof(EVP_HPKE_KEY)); + EVP_HPKE_KEY_cleanup(dst); + dst->kem = src->kem; + dst->private_key = NULL; + dst->public_key = NULL; + if (src->kem == NULL) { + return 1; + } + dst->private_key = OPENSSL_memdup(src->private_key, src->kem->private_key_len); + if (dst->private_key == NULL) { + dst->kem = NULL; + return 0; + } + dst->public_key = OPENSSL_memdup(src->public_key, src->kem->public_key_len); + if (dst->public_key == NULL) { + OPENSSL_free(dst->private_key); + dst->private_key = NULL; + dst->kem = NULL; + return 0; + } return 1; } void EVP_HPKE_KEY_move(EVP_HPKE_KEY *out, EVP_HPKE_KEY *in) { EVP_HPKE_KEY_cleanup(out); - // For now, |EVP_HPKE_KEY| is trivially movable. - OPENSSL_memcpy(out, in, sizeof(EVP_HPKE_KEY)); + out->kem = in->kem; + out->private_key = in->private_key; + out->public_key = in->public_key; EVP_HPKE_KEY_zero(in); } @@ -406,6 +801,11 @@ const EVP_HPKE_KDF *EVP_hpke_hkdf_sha256(void) { return &kKDF; } +const EVP_HPKE_KDF *EVP_hpke_hkdf_sha384(void) { + static const EVP_HPKE_KDF kKDF = {EVP_HPKE_HKDF_SHA384, &EVP_sha384}; + return &kKDF; +} + uint16_t EVP_HPKE_KDF_id(const EVP_HPKE_KDF *kdf) { return kdf->id; } const EVP_MD *EVP_HPKE_KDF_hkdf_md(const EVP_HPKE_KDF *kdf) { @@ -550,8 +950,6 @@ EVP_HPKE_CTX *EVP_HPKE_CTX_new(void) { if (ctx == NULL) { return NULL; } - // NO-OP: struct already zeroed - //EVP_HPKE_CTX_zero(ctx); return ctx; } @@ -641,7 +1039,6 @@ int EVP_HPKE_CTX_setup_auth_sender_with_seed_for_testing( const uint8_t *info, size_t info_len, const uint8_t *seed, size_t seed_len) { if (key->kem->auth_encap_with_seed == NULL) { - // Not all HPKE KEMs support AuthEncap. OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } @@ -670,7 +1067,6 @@ int EVP_HPKE_CTX_setup_auth_recipient( const uint8_t *info, size_t info_len, const uint8_t *peer_public_key, size_t peer_public_key_len) { if (key->kem->auth_decap == NULL) { - // Not all HPKE KEMs support AuthDecap. OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc index 6501c08b5f6..3d0d30c710d 100644 --- a/crypto/hpke/hpke_test.cc +++ b/crypto/hpke/hpke_test.cc @@ -34,6 +34,7 @@ const decltype(&EVP_hpke_aes_128_gcm) kAllAEADs[] = { const decltype(&EVP_hpke_hkdf_sha256) kAllKDFs[] = { &EVP_hpke_hkdf_sha256, + &EVP_hpke_hkdf_sha384, }; // HPKETestVector corresponds to one array member in the published @@ -333,7 +334,7 @@ TEST(HPKETest, RoundTrip) { // Generate the recipient's keypair. ScopedEVP_HPKE_KEY key; ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); - uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN]; + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; size_t public_key_r_len; ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, &public_key_r_len, sizeof(public_key_r))); @@ -342,10 +343,10 @@ TEST(HPKETest, RoundTrip) { ScopedEVP_HPKE_KEY sender_key; ASSERT_TRUE( EVP_HPKE_KEY_generate(sender_key.get(), kem)); - uint8_t public_key_s[X25519_PUBLIC_VALUE_LEN]; + uint8_t public_key_s[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; size_t public_key_s_len; ASSERT_TRUE(EVP_HPKE_KEY_public_key(sender_key.get(), public_key_s, - &public_key_s_len, sizeof(public_key_r))); + &public_key_s_len, sizeof(public_key_s))); for (const auto kdf : kAllKDFs) { SCOPED_TRACE(EVP_HPKE_KDF_id(kdf())); @@ -387,7 +388,7 @@ TEST(HPKETest, RoundTrip) { // Test the base mode. { ScopedEVP_HPKE_CTX sender_ctx; - uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_sender( sender_ctx.get(), enc, &enc_len, sizeof(enc), kem, kdf(), @@ -405,7 +406,7 @@ TEST(HPKETest, RoundTrip) { // Test the auth mode. { ScopedEVP_HPKE_CTX sender_ctx; - uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_auth_sender( sender_ctx.get(), enc, &enc_len, sizeof(enc), sender_key.get(), @@ -449,7 +450,7 @@ TEST(HPKETest, X25519EncapSmallOrderPoint) { SCOPED_TRACE(EVP_HPKE_AEAD_id(aead())); // Set up the sender, passing in kSmallOrderPoint as |peer_public_key|. ScopedEVP_HPKE_CTX sender_ctx; - uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; size_t enc_len; EXPECT_FALSE(EVP_HPKE_CTX_setup_sender( sender_ctx.get(), enc, &enc_len, sizeof(enc), @@ -516,7 +517,7 @@ TEST(HPKETest, SenderInvalidOpen) { // Set up the sender. ScopedEVP_HPKE_CTX sender_ctx; - uint8_t enc[X25519_PUBLIC_VALUE_LEN]; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; size_t enc_len; ASSERT_TRUE(EVP_HPKE_CTX_setup_sender( sender_ctx.get(), enc, &enc_len, sizeof(enc), @@ -624,5 +625,449 @@ TEST(HPKETest, InternalParseIntSafe) { ASSERT_FALSE(ParseIntSafe(&u16, "65536")); } +// ML-KEM HPKE tests. + +struct MLKEMTestParam { + const char *name; + const EVP_HPKE_KEM *(*kem_func)(void); + const EVP_HPKE_KDF *(*kdf_func)(void); + const EVP_HPKE_AEAD *(*aead_func)(void); +}; + +class HPKEMLKEMTest : public testing::TestWithParam {}; + +TEST_P(HPKEMLKEMTest, RoundTrip) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + // Generate the recipient's keypair. + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + EXPECT_EQ(public_key_r_len, EVP_HPKE_KEM_public_key_len(kem)); + + // Sender setup. + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); + EXPECT_EQ(enc_len, EVP_HPKE_KEM_enc_len(kem)); + + // Seal a message. + const char kPlaintext[] = "Hello, post-quantum world!"; + const uint8_t kAad[] = {0xde, 0xad, 0xbe, 0xef}; + std::vector ciphertext(sizeof(kPlaintext) + + EVP_HPKE_CTX_max_overhead(sender_ctx.get())); + size_t ciphertext_len; + ASSERT_TRUE(EVP_HPKE_CTX_seal( + sender_ctx.get(), ciphertext.data(), &ciphertext_len, ciphertext.size(), + reinterpret_cast(kPlaintext), sizeof(kPlaintext), kAad, + sizeof(kAad))); + + // Recipient setup. + ScopedEVP_HPKE_CTX recipient_ctx; + ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), key.get(), kdf, + aead, enc, enc_len, nullptr, 0)); + + // Open the message. + std::vector plaintext(ciphertext_len); + size_t plaintext_len; + ASSERT_TRUE(EVP_HPKE_CTX_open(recipient_ctx.get(), plaintext.data(), + &plaintext_len, plaintext.size(), + ciphertext.data(), ciphertext_len, kAad, + sizeof(kAad))); + EXPECT_EQ(Bytes(plaintext.data(), plaintext_len), + Bytes(kPlaintext, sizeof(kPlaintext))); +} + +TEST_P(HPKEMLKEMTest, MultiMessage) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); + + ScopedEVP_HPKE_CTX recipient_ctx; + ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), key.get(), kdf, + aead, enc, enc_len, nullptr, 0)); + + for (int i = 0; i < 10; i++) { + std::string msg = "message " + std::to_string(i); + std::vector ct(msg.size() + EVP_HPKE_CTX_max_overhead(sender_ctx.get())); + size_t ct_len; + ASSERT_TRUE(EVP_HPKE_CTX_seal( + sender_ctx.get(), ct.data(), &ct_len, ct.size(), + reinterpret_cast(msg.data()), msg.size(), nullptr, 0)); + + std::vector pt(ct_len); + size_t pt_len; + ASSERT_TRUE(EVP_HPKE_CTX_open(recipient_ctx.get(), pt.data(), &pt_len, + pt.size(), ct.data(), ct_len, nullptr, 0)); + EXPECT_EQ(Bytes(pt.data(), pt_len), + Bytes(reinterpret_cast(msg.data()), msg.size())); + } +} + +TEST_P(HPKEMLKEMTest, KeySerializationRoundTrip) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + // Export the private key. + std::vector priv_key(EVP_HPKE_KEM_private_key_len(kem)); + size_t priv_key_len; + ASSERT_TRUE(EVP_HPKE_KEY_private_key(key.get(), priv_key.data(), + &priv_key_len, priv_key.size())); + EXPECT_EQ(priv_key_len, EVP_HPKE_KEM_private_key_len(kem)); + + // Export the public key. + std::vector pub_key(EVP_HPKE_KEM_public_key_len(kem)); + size_t pub_key_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), pub_key.data(), &pub_key_len, + pub_key.size())); + EXPECT_EQ(pub_key_len, EVP_HPKE_KEM_public_key_len(kem)); + + // Re-import the private key and verify the public key matches. + ScopedEVP_HPKE_KEY key2; + ASSERT_TRUE( + EVP_HPKE_KEY_init(key2.get(), kem, priv_key.data(), priv_key_len)); + + std::vector pub_key2(EVP_HPKE_KEM_public_key_len(kem)); + size_t pub_key2_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key2.get(), pub_key2.data(), + &pub_key2_len, pub_key2.size())); + EXPECT_EQ(Bytes(pub_key.data(), pub_key_len), + Bytes(pub_key2.data(), pub_key2_len)); +} + +TEST_P(HPKEMLKEMTest, KeyCopyAndMove) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + // Test copy. + { + ScopedEVP_HPKE_KEY key_copy; + ASSERT_TRUE(EVP_HPKE_KEY_copy(key_copy.get(), key.get())); + + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); + + const char kPlaintext[] = "copy test"; + std::vector ct(sizeof(kPlaintext) + + EVP_HPKE_CTX_max_overhead(sender_ctx.get())); + size_t ct_len; + ASSERT_TRUE(EVP_HPKE_CTX_seal( + sender_ctx.get(), ct.data(), &ct_len, ct.size(), + reinterpret_cast(kPlaintext), sizeof(kPlaintext), + nullptr, 0)); + + ScopedEVP_HPKE_CTX recipient_ctx; + ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), + key_copy.get(), kdf, aead, enc, + enc_len, nullptr, 0)); + + std::vector pt(ct_len); + size_t pt_len; + ASSERT_TRUE(EVP_HPKE_CTX_open(recipient_ctx.get(), pt.data(), &pt_len, + pt.size(), ct.data(), ct_len, nullptr, 0)); + EXPECT_EQ(Bytes(pt.data(), pt_len), Bytes(kPlaintext, sizeof(kPlaintext))); + } + + // Test move. + { + ScopedEVP_HPKE_KEY key_moved; + ScopedEVP_HPKE_KEY key_temp; + ASSERT_TRUE(EVP_HPKE_KEY_copy(key_temp.get(), key.get())); + EVP_HPKE_KEY_move(key_moved.get(), key_temp.get()); + + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); + + const char kPlaintext[] = "move test"; + std::vector ct(sizeof(kPlaintext) + + EVP_HPKE_CTX_max_overhead(sender_ctx.get())); + size_t ct_len; + ASSERT_TRUE(EVP_HPKE_CTX_seal( + sender_ctx.get(), ct.data(), &ct_len, ct.size(), + reinterpret_cast(kPlaintext), sizeof(kPlaintext), + nullptr, 0)); + + ScopedEVP_HPKE_CTX recipient_ctx; + ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), + key_moved.get(), kdf, aead, enc, + enc_len, nullptr, 0)); + + std::vector pt(ct_len); + size_t pt_len; + ASSERT_TRUE(EVP_HPKE_CTX_open(recipient_ctx.get(), pt.data(), &pt_len, + pt.size(), ct.data(), ct_len, nullptr, 0)); + EXPECT_EQ(Bytes(pt.data(), pt_len), Bytes(kPlaintext, sizeof(kPlaintext))); + } +} + +TEST_P(HPKEMLKEMTest, AuthModeNotSupported) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + // Auth sender should fail. + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + EXPECT_FALSE(EVP_HPKE_CTX_setup_auth_sender( + sender_ctx.get(), enc, &enc_len, sizeof(enc), key.get(), kdf, aead, + public_key_r, public_key_r_len, nullptr, 0)); + + // Auth recipient should fail. + uint8_t fake_enc[EVP_HPKE_MAX_ENC_LENGTH] = {0}; + ScopedEVP_HPKE_CTX recipient_ctx; + EXPECT_FALSE(EVP_HPKE_CTX_setup_auth_recipient( + recipient_ctx.get(), key.get(), kdf, aead, fake_enc, + EVP_HPKE_KEM_enc_len(kem), nullptr, 0, public_key_r, public_key_r_len)); +} + +TEST_P(HPKEMLKEMTest, WrongCiphertextSize) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + // Attempt to set up recipient with wrong-sized enc. + uint8_t bogus_enc[100] = {0xff}; + ScopedEVP_HPKE_CTX recipient_ctx; + EXPECT_FALSE(EVP_HPKE_CTX_setup_recipient( + recipient_ctx.get(), key.get(), kdf, aead, bogus_enc, sizeof(bogus_enc), + nullptr, 0)); +} + +TEST_P(HPKEMLKEMTest, ExportSecret) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); + + ScopedEVP_HPKE_CTX recipient_ctx; + ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), key.get(), kdf, + aead, enc, enc_len, nullptr, 0)); + + const uint8_t kContext[] = {0x01, 0x02, 0x03}; + uint8_t sender_export[32]; + uint8_t recipient_export[32]; + ASSERT_TRUE(EVP_HPKE_CTX_export(sender_ctx.get(), sender_export, + sizeof(sender_export), kContext, + sizeof(kContext))); + ASSERT_TRUE(EVP_HPKE_CTX_export(recipient_ctx.get(), recipient_export, + sizeof(recipient_export), kContext, + sizeof(kContext))); + EXPECT_EQ(Bytes(sender_export), Bytes(recipient_export)); +} + +TEST_P(HPKEMLKEMTest, InvalidPrivateKeyLength) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + + const uint8_t bogus_key[100] = {0xff}; + ScopedEVP_HPKE_KEY key; + EXPECT_FALSE(EVP_HPKE_KEY_init(key.get(), kem, bogus_key, sizeof(bogus_key))); +} + +TEST_P(HPKEMLKEMTest, CorruptedPrivateKey) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + + // A buffer of the right length but garbage content should fail check_sk. + std::vector garbage(EVP_HPKE_KEM_private_key_len(kem), 0xAB); + ScopedEVP_HPKE_KEY key; + EXPECT_FALSE( + EVP_HPKE_KEY_init(key.get(), kem, garbage.data(), garbage.size())); +} + +TEST_P(HPKEMLKEMTest, WrongSeedLength) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len = 0; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + // Use setup_sender_with_seed_for_testing with wrong seed length. + const uint8_t bad_seed[5] = {1, 2, 3, 4, 5}; + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + EXPECT_FALSE(EVP_HPKE_CTX_setup_sender_with_seed_for_testing( + sender_ctx.get(), enc, &enc_len, sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, nullptr, 0, bad_seed, sizeof(bad_seed))); +} + +TEST_P(HPKEMLKEMTest, InvalidPublicKeyLength) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + const uint8_t bogus_pk[100] = {0xff}; + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH]; + size_t enc_len; + EXPECT_FALSE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, bogus_pk, + sizeof(bogus_pk), nullptr, 0)); +} + +TEST_P(HPKEMLKEMTest, EncBufferTooSmall) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + const EVP_HPKE_KDF *kdf = param.kdf_func(); + const EVP_HPKE_AEAD *aead = param.aead_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t public_key_r[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; + size_t public_key_r_len = 0; + ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r, + &public_key_r_len, sizeof(public_key_r))); + + ScopedEVP_HPKE_CTX sender_ctx; + uint8_t enc[10]; + size_t enc_len; + EXPECT_FALSE(EVP_HPKE_CTX_setup_sender(sender_ctx.get(), enc, &enc_len, + sizeof(enc), kem, kdf, aead, + public_key_r, public_key_r_len, + nullptr, 0)); +} + +TEST_P(HPKEMLKEMTest, PublicKeyBufferTooSmall) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t small_buf[10]; + size_t out_len; + EXPECT_FALSE( + EVP_HPKE_KEY_public_key(key.get(), small_buf, &out_len, sizeof(small_buf))); +} + +TEST(HPKETest, CopyZeroedKey) { + ScopedEVP_HPKE_KEY src; + ScopedEVP_HPKE_KEY dst; + EXPECT_TRUE(EVP_HPKE_KEY_copy(dst.get(), src.get())); +} + +TEST_P(HPKEMLKEMTest, PrivateKeyBufferTooSmall) { + const MLKEMTestParam ¶m = GetParam(); + const EVP_HPKE_KEM *kem = param.kem_func(); + + ScopedEVP_HPKE_KEY key; + ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), kem)); + + uint8_t small_buf[10]; + size_t out_len; + EXPECT_FALSE( + EVP_HPKE_KEY_private_key(key.get(), small_buf, &out_len, sizeof(small_buf))); +} + +static const MLKEMTestParam kMLKEMTestParams[] = { + {"MLKEM512_SHA256_AES128GCM", &EVP_hpke_mlkem512, &EVP_hpke_hkdf_sha256, + &EVP_hpke_aes_128_gcm}, + {"MLKEM768_SHA256_AES256GCM", &EVP_hpke_mlkem768, &EVP_hpke_hkdf_sha256, + &EVP_hpke_aes_256_gcm}, + {"MLKEM1024_SHA384_AES256GCM", &EVP_hpke_mlkem1024, &EVP_hpke_hkdf_sha384, + &EVP_hpke_aes_256_gcm}, + {"MLKEM1024_SHA256_AES256GCM", &EVP_hpke_mlkem1024, &EVP_hpke_hkdf_sha256, + &EVP_hpke_aes_256_gcm}, + {"MLKEM1024_SHA384_ChaCha20Poly1305", &EVP_hpke_mlkem1024, + &EVP_hpke_hkdf_sha384, &EVP_hpke_chacha20_poly1305}, +}; + +INSTANTIATE_TEST_SUITE_P(HPKEMLKEM, HPKEMLKEMTest, + testing::ValuesIn(kMLKEMTestParams), + [](const testing::TestParamInfo &info) { + return info.param.name; + }); + } // namespace bssl diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h index a40577a2f5b..16635cf72c6 100644 --- a/include/openssl/hpke.h +++ b/include/openssl/hpke.h @@ -30,11 +30,17 @@ extern "C" { // The following constants are KEM identifiers. #define EVP_HPKE_DHKEM_X25519_HKDF_SHA256 0x0020 +#define EVP_HPKE_KEM_MLKEM512 0x0040 +#define EVP_HPKE_KEM_MLKEM768 0x0041 +#define EVP_HPKE_KEM_MLKEM1024 0x0042 // The following functions are KEM algorithms which may be used with HPKE. Note // that, while some HPKE KEMs use KDFs internally, this is separate from the // |EVP_HPKE_KDF| selection. OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256(void); +OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_mlkem512(void); +OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_mlkem768(void); +OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_mlkem1024(void); // EVP_HPKE_KEM_id returns the HPKE KEM identifier for |kem|, which // will be one of the |EVP_HPKE_KEM_*| constants. @@ -42,7 +48,7 @@ OPENSSL_EXPORT uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem); // EVP_HPKE_MAX_PUBLIC_KEY_LENGTH is the maximum length of an encoded public key // for all KEMs currently supported by this library. -#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 32 +#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 1568 // EVP_HPKE_KEM_public_key_len returns the length of a public key for |kem|. // This value will be at most |EVP_HPKE_MAX_PUBLIC_KEY_LENGTH|. @@ -50,7 +56,7 @@ OPENSSL_EXPORT size_t EVP_HPKE_KEM_public_key_len(const EVP_HPKE_KEM *kem); // EVP_HPKE_MAX_PRIVATE_KEY_LENGTH is the maximum length of an encoded private // key for all KEMs currently supported by this library. -#define EVP_HPKE_MAX_PRIVATE_KEY_LENGTH 32 +#define EVP_HPKE_MAX_PRIVATE_KEY_LENGTH 3168 // EVP_HPKE_KEM_private_key_len returns the length of a private key for |kem|. // This value will be at most |EVP_HPKE_MAX_PRIVATE_KEY_LENGTH|. @@ -58,7 +64,7 @@ OPENSSL_EXPORT size_t EVP_HPKE_KEM_private_key_len(const EVP_HPKE_KEM *kem); // EVP_HPKE_MAX_ENC_LENGTH is the maximum length of "enc", the encapsulated // shared secret, for all KEMs currently supported by this library. -#define EVP_HPKE_MAX_ENC_LENGTH 32 +#define EVP_HPKE_MAX_ENC_LENGTH 1568 // EVP_HPKE_KEM_enc_len returns the length of the "enc", the encapsulated shared // secret, for |kem|. This value will be at most |EVP_HPKE_MAX_ENC_LENGTH|. @@ -66,9 +72,11 @@ OPENSSL_EXPORT size_t EVP_HPKE_KEM_enc_len(const EVP_HPKE_KEM *kem); // The following constants are KDF identifiers. #define EVP_HPKE_HKDF_SHA256 0x0001 +#define EVP_HPKE_HKDF_SHA384 0x0002 // The following functions are KDF algorithms which may be used with HPKE. OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_hpke_hkdf_sha256(void); +OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_hpke_hkdf_sha384(void); // EVP_HPKE_KDF_id returns the HPKE KDF identifier for |kdf|. OPENSSL_EXPORT uint16_t EVP_HPKE_KDF_id(const EVP_HPKE_KDF *kdf); @@ -364,8 +372,8 @@ struct evp_hpke_ctx_st { struct evp_hpke_key_st { const EVP_HPKE_KEM *kem; - uint8_t private_key[X25519_PRIVATE_KEY_LEN]; - uint8_t public_key[X25519_PUBLIC_VALUE_LEN]; + uint8_t *private_key; + uint8_t *public_key; };