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>
grpc-202302
David Benjamin 4 years ago committed by CQ bot account: commit-bot@chromium.org
parent 198c5f56f6
commit da4390f4ef
  1. 38
      crypto/hpke/hpke.c
  2. 17
      crypto/hpke/hpke_test.cc
  3. 18
      crypto/hpke/internal.h

@ -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 @@ int EVP_HPKE_CTX_setup_base_s_x25519(EVP_HPKE_CTX *hpke, uint8_t *out_enc,
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 @@ int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
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;

@ -51,17 +51,18 @@ class HPKETestVector {
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());

@ -94,16 +94,14 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519(
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.

Loading…
Cancel
Save