Revise the deterministic for_test variant of HPKE's SetupBaseS.
Although we only support X25519 right now, we may need to support other
KEMs in the future. In the general case, a public/private keypair is
less meaningful. (If something like NTRU-HRSS even goes here, I guess
it'd be the entropy passed to HRSS_encap.)
Instead of taking an entire keypair, just take the private key. Perhaps
we call it the "seed"?
Bug: 410
Change-Id: Ifd6b6ea8ea36e6eca60d303706d6d2620f8c42d4
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47326
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c
index f6aca0f..cc0def5 100644
--- a/crypto/hpke/hpke.c
+++ b/crypto/hpke/hpke.c
@@ -22,6 +22,7 @@
#include <openssl/err.h>
#include <openssl/evp_errors.h>
#include <openssl/hkdf.h>
+#include <openssl/rand.h>
#include <openssl/sha.h>
#include "../internal.h"
@@ -304,34 +305,27 @@
const uint8_t *peer_public_value,
size_t peer_public_value_len,
const uint8_t *info, size_t info_len) {
+ uint8_t seed[X25519_PRIVATE_KEY_LEN];
+ RAND_bytes(seed, sizeof(seed));
+ return EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+ hpke, out_enc, out_enc_len, kdf_id, aead_id, peer_public_value,
+ peer_public_value_len, info, info_len, seed, sizeof(seed));
+}
+
+int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+ EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id, const uint8_t *peer_public_value,
+ size_t peer_public_value_len, const uint8_t *info, size_t info_len,
+ const uint8_t *seed, size_t seed_len) {
if (out_enc_len != X25519_PUBLIC_VALUE_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
-
- // The GenerateKeyPair() step technically belongs in the KEM's Encap()
- // function, but we've moved it up a layer to make it easier for tests to
- // inject an ephemeral keypair.
- uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
- X25519_keypair(out_enc, ephemeral_private);
- return EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- hpke, kdf_id, aead_id, peer_public_value, peer_public_value_len, info,
- info_len, ephemeral_private, sizeof(ephemeral_private), out_enc,
- out_enc_len);
-}
-
-int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t *peer_public_value, size_t peer_public_value_len,
- const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
- size_t ephemeral_private_len, const uint8_t *ephemeral_public,
- size_t ephemeral_public_len) {
if (peer_public_value_len != X25519_PUBLIC_VALUE_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
return 0;
}
- if (ephemeral_private_len != X25519_PRIVATE_KEY_LEN ||
- ephemeral_public_len != X25519_PUBLIC_VALUE_LEN) {
+ if (seed_len != X25519_PRIVATE_KEY_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
@@ -343,9 +337,9 @@
if (hpke->hkdf_md == NULL) {
return 0;
}
+ X25519_public_from_private(out_enc, seed);
uint8_t shared_secret[SHA256_DIGEST_LENGTH];
- if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
- ephemeral_public) ||
+ if (!hpke_encap(hpke, shared_secret, peer_public_value, seed, out_enc) ||
!hpke_key_schedule(hpke, shared_secret, sizeof(shared_secret), info,
info_len)) {
return 0;
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index 5b063a3..e4aa932 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -51,17 +51,18 @@
ASSERT_GT(secret_key_e_.size(), 0u);
// Set up the sender.
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
- public_key_r_.size(), info_.data(), info_.size(), secret_key_e_.data(),
- secret_key_e_.size(), public_key_e_.data(), public_key_e_.size()));
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN];
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+ sender_ctx.get(), enc, sizeof(enc), kdf_id_, aead_id_,
+ public_key_r_.data(), public_key_r_.size(), info_.data(), info_.size(),
+ secret_key_e_.data(), secret_key_e_.size()));
+ EXPECT_EQ(Bytes(enc), Bytes(public_key_e_));
// Set up the receiver.
ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
- public_key_e_.size(), public_key_r_.data(), public_key_r_.size(),
- secret_key_r_.data(), secret_key_r_.size(), info_.data(),
- info_.size()));
+ receiver_ctx.get(), kdf_id_, aead_id_, enc, sizeof(enc),
+ public_key_r_.data(), public_key_r_.size(), secret_key_r_.data(),
+ secret_key_r_.size(), info_.data(), info_.size()));
VerifyEncryptions(sender_ctx.get(), receiver_ctx.get());
VerifyExports(sender_ctx.get());
diff --git a/crypto/hpke/internal.h b/crypto/hpke/internal.h
index cda9b7a..54382c8 100644
--- a/crypto/hpke/internal.h
+++ b/crypto/hpke/internal.h
@@ -94,16 +94,14 @@
uint16_t aead_id, const uint8_t *peer_public_value,
size_t peer_public_value_len, const uint8_t *info, size_t info_len);
-// EVP_HPKE_CTX_setup_base_s_x25519_for_test behaves like
-// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a pre-generated ephemeral
-// sender key. The caller ensures that |ephemeral_public| and
-// |ephemeral_private| are a valid keypair.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t *peer_public_value, size_t peer_public_value_len,
- const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
- size_t ephemeral_private_len, const uint8_t *ephemeral_public,
- size_t ephemeral_public_len);
+// EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing behaves like
+// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a seed value to behave
+// deterministically. This seed is the sender's ephemeral X25519 key.
+OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+ EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+ uint16_t aead_id, const uint8_t *peer_public_value,
+ size_t peer_public_value_len, const uint8_t *info, size_t info_len,
+ const uint8_t *seed, size_t seed_len);
// EVP_HPKE_CTX_setup_base_r_x25519 sets up |hpke| as a recipient context that
// can decrypt messages. It returns one on success, and zero otherwise.