Refer to EVP_HPKE_CTX by a consistent name.

It's sometimes hpke and sometimes ctx. Our other EVP_FOO_CTX types are
usually called ctx, so use ctx.

Bug: 410
Change-Id: Ib1c6d8018ffd8fd180b89f5be58283f3f098e44b
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47404
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
grpc-202302
David Benjamin 4 years ago
parent 1d58cd1fd3
commit 1eb7769e11
  1. 112
      crypto/hpke/hpke.c
  2. 44
      crypto/hpke/internal.h

@ -285,31 +285,31 @@ uint16_t EVP_HPKE_AEAD_id(const EVP_HPKE_AEAD *aead) { return aead->id; }
// The suite_id for non-KEM pieces of HPKE is defined as concat("HPKE",
// I2OSP(kem_id, 2), I2OSP(kdf_id, 2), I2OSP(aead_id, 2)).
static int hpke_build_suite_id(const EVP_HPKE_CTX *hpke,
static int hpke_build_suite_id(const EVP_HPKE_CTX *ctx,
uint8_t out[HPKE_SUITE_ID_LEN]) {
CBB cbb;
int ret = CBB_init_fixed(&cbb, out, HPKE_SUITE_ID_LEN) &&
add_label_string(&cbb, "HPKE") &&
CBB_add_u16(&cbb, EVP_HPKE_DHKEM_X25519_HKDF_SHA256) &&
CBB_add_u16(&cbb, hpke->kdf->id) &&
CBB_add_u16(&cbb, hpke->aead->id);
CBB_add_u16(&cbb, ctx->kdf->id) &&
CBB_add_u16(&cbb, ctx->aead->id);
CBB_cleanup(&cbb);
return ret;
}
#define HPKE_MODE_BASE 0
static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
static int hpke_key_schedule(EVP_HPKE_CTX *ctx, const uint8_t *shared_secret,
size_t shared_secret_len, const uint8_t *info,
size_t info_len) {
uint8_t suite_id[HPKE_SUITE_ID_LEN];
if (!hpke_build_suite_id(hpke, suite_id)) {
if (!hpke_build_suite_id(ctx, suite_id)) {
return 0;
}
// psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id)
// TODO(davidben): Precompute this value and store it with the EVP_HPKE_KDF.
const EVP_MD *hkdf_md = hpke->kdf->hkdf_md_func();
const EVP_MD *hkdf_md = ctx->kdf->hkdf_md_func();
uint8_t psk_id_hash[EVP_MAX_MD_SIZE];
size_t psk_id_hash_len;
if (!hpke_labeled_extract(hkdf_md, psk_id_hash, &psk_id_hash_len, NULL, 0,
@ -349,18 +349,18 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
}
// key = LabeledExpand(secret, "key", key_schedule_context, Nk)
const EVP_AEAD *aead = hpke->aead->aead_func();
const EVP_AEAD *aead = ctx->aead->aead_func();
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
const size_t kKeyLen = EVP_AEAD_key_length(aead);
if (!hpke_labeled_expand(hkdf_md, key, kKeyLen, secret, secret_len, suite_id,
sizeof(suite_id), "key", context, context_len) ||
!EVP_AEAD_CTX_init(&hpke->aead_ctx, aead, key, kKeyLen,
!EVP_AEAD_CTX_init(&ctx->aead_ctx, aead, key, kKeyLen,
EVP_AEAD_DEFAULT_TAG_LENGTH, NULL)) {
return 0;
}
// base_nonce = LabeledExpand(secret, "base_nonce", key_schedule_context, Nn)
if (!hpke_labeled_expand(hkdf_md, hpke->base_nonce,
if (!hpke_labeled_expand(hkdf_md, ctx->base_nonce,
EVP_AEAD_nonce_length(aead), secret, secret_len,
suite_id, sizeof(suite_id), "base_nonce", context,
context_len)) {
@ -368,7 +368,7 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
}
// exporter_secret = LabeledExpand(secret, "exp", key_schedule_context, Nh)
if (!hpke_labeled_expand(hkdf_md, hpke->exporter_secret, EVP_MD_size(hkdf_md),
if (!hpke_labeled_expand(hkdf_md, ctx->exporter_secret, EVP_MD_size(hkdf_md),
secret, secret_len, suite_id, sizeof(suite_id),
"exp", context, context_len)) {
return 0;
@ -386,7 +386,7 @@ void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx) {
EVP_AEAD_CTX_cleanup(&ctx->aead_ctx);
}
int EVP_HPKE_CTX_setup_sender(EVP_HPKE_CTX *hpke, uint8_t *out_enc,
int EVP_HPKE_CTX_setup_sender(EVP_HPKE_CTX *ctx, uint8_t *out_enc,
size_t *out_enc_len, size_t max_enc,
const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf,
const EVP_HPKE_AEAD *aead,
@ -396,128 +396,128 @@ int EVP_HPKE_CTX_setup_sender(EVP_HPKE_CTX *hpke, uint8_t *out_enc,
uint8_t seed[MAX_SEED_LEN];
RAND_bytes(seed, kem->seed_len);
return EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
hpke, out_enc, out_enc_len, max_enc, kem, kdf, aead, peer_public_key,
ctx, out_enc, out_enc_len, max_enc, kem, kdf, aead, peer_public_key,
peer_public_key_len, info, info_len, seed, kem->seed_len);
}
int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
const uint8_t *peer_public_key, size_t peer_public_key_len,
const uint8_t *info, size_t info_len, const uint8_t *seed,
size_t seed_len) {
EVP_HPKE_CTX_zero(hpke);
hpke->is_sender = 1;
hpke->kdf = kdf;
hpke->aead = aead;
EVP_HPKE_CTX_zero(ctx);
ctx->is_sender = 1;
ctx->kdf = kdf;
ctx->aead = aead;
uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
size_t shared_secret_len;
if (!kem->encap_with_seed(kem, shared_secret, &shared_secret_len, out_enc,
out_enc_len, max_enc, peer_public_key,
peer_public_key_len, seed, seed_len) ||
!hpke_key_schedule(hpke, shared_secret, shared_secret_len, info,
!hpke_key_schedule(ctx, shared_secret, shared_secret_len, info,
info_len)) {
EVP_HPKE_CTX_cleanup(hpke);
EVP_HPKE_CTX_cleanup(ctx);
return 0;
}
return 1;
}
int EVP_HPKE_CTX_setup_recipient(EVP_HPKE_CTX *hpke, const EVP_HPKE_KEY *key,
int EVP_HPKE_CTX_setup_recipient(EVP_HPKE_CTX *ctx, const EVP_HPKE_KEY *key,
const EVP_HPKE_KDF *kdf,
const EVP_HPKE_AEAD *aead, const uint8_t *enc,
size_t enc_len, const uint8_t *info,
size_t info_len) {
EVP_HPKE_CTX_zero(hpke);
hpke->is_sender = 0;
hpke->kdf = kdf;
hpke->aead = aead;
EVP_HPKE_CTX_zero(ctx);
ctx->is_sender = 0;
ctx->kdf = kdf;
ctx->aead = aead;
uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
size_t shared_secret_len;
if (!key->kem->decap(key, shared_secret, &shared_secret_len, enc, enc_len) ||
!hpke_key_schedule(hpke, shared_secret, sizeof(shared_secret), info,
!hpke_key_schedule(ctx, shared_secret, sizeof(shared_secret), info,
info_len)) {
EVP_HPKE_CTX_cleanup(hpke);
EVP_HPKE_CTX_cleanup(ctx);
return 0;
}
return 1;
}
static void hpke_nonce(const EVP_HPKE_CTX *hpke, uint8_t *out_nonce,
static void hpke_nonce(const EVP_HPKE_CTX *ctx, uint8_t *out_nonce,
size_t nonce_len) {
assert(nonce_len >= 8);
// Write padded big-endian bytes of |hpke->seq| to |out_nonce|.
// Write padded big-endian bytes of |ctx->seq| to |out_nonce|.
OPENSSL_memset(out_nonce, 0, nonce_len);
uint64_t seq_copy = hpke->seq;
uint64_t seq_copy = ctx->seq;
for (size_t i = 0; i < 8; i++) {
out_nonce[nonce_len - i - 1] = seq_copy & 0xff;
seq_copy >>= 8;
}
// XOR the encoded sequence with the |hpke->base_nonce|.
// XOR the encoded sequence with the |ctx->base_nonce|.
for (size_t i = 0; i < nonce_len; i++) {
out_nonce[i] ^= hpke->base_nonce[i];
out_nonce[i] ^= ctx->base_nonce[i];
}
}
int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
int EVP_HPKE_CTX_open(EVP_HPKE_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
if (hpke->is_sender) {
if (ctx->is_sender) {
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (hpke->seq == UINT64_MAX) {
if (ctx->seq == UINT64_MAX) {
OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
return 0;
}
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
hpke_nonce(hpke, nonce, nonce_len);
const size_t nonce_len = EVP_AEAD_nonce_length(ctx->aead_ctx.aead);
hpke_nonce(ctx, nonce, nonce_len);
if (!EVP_AEAD_CTX_open(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
if (!EVP_AEAD_CTX_open(&ctx->aead_ctx, out, out_len, max_out_len, nonce,
nonce_len, in, in_len, ad, ad_len)) {
return 0;
}
hpke->seq++;
ctx->seq++;
return 1;
}
int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
if (!hpke->is_sender) {
if (!ctx->is_sender) {
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (hpke->seq == UINT64_MAX) {
if (ctx->seq == UINT64_MAX) {
OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
return 0;
}
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
hpke_nonce(hpke, nonce, nonce_len);
const size_t nonce_len = EVP_AEAD_nonce_length(ctx->aead_ctx.aead);
hpke_nonce(ctx, nonce, nonce_len);
if (!EVP_AEAD_CTX_seal(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
if (!EVP_AEAD_CTX_seal(&ctx->aead_ctx, out, out_len, max_out_len, nonce,
nonce_len, in, in_len, ad, ad_len)) {
return 0;
}
hpke->seq++;
ctx->seq++;
return 1;
}
int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *ctx, uint8_t *out,
size_t secret_len, const uint8_t *context,
size_t context_len) {
uint8_t suite_id[HPKE_SUITE_ID_LEN];
if (!hpke_build_suite_id(hpke, suite_id)) {
if (!hpke_build_suite_id(ctx, suite_id)) {
return 0;
}
const EVP_MD *hkdf_md = hpke->kdf->hkdf_md_func();
if (!hpke_labeled_expand(hkdf_md, out, secret_len, hpke->exporter_secret,
const EVP_MD *hkdf_md = ctx->kdf->hkdf_md_func();
if (!hpke_labeled_expand(hkdf_md, out, secret_len, ctx->exporter_secret,
EVP_MD_size(hkdf_md), suite_id, sizeof(suite_id),
"sec", context, context_len)) {
return 0;
@ -525,15 +525,15 @@ int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
return 1;
}
size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *hpke) {
assert(hpke->is_sender);
return EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&hpke->aead_ctx));
size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *ctx) {
assert(ctx->is_sender);
return EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&ctx->aead_ctx));
}
const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *hpke) {
return hpke->aead;
const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx) {
return ctx->aead;
}
const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *hpke) {
return hpke->kdf;
const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *ctx) {
return ctx->kdf;
}

@ -139,7 +139,7 @@ OPENSSL_EXPORT void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx);
#define EVP_HPKE_MAX_ENC_LENGTH 32
// EVP_HPKE_CTX_setup_sender implements the SetupBaseS HPKE operation. It
// encapsulates a shared secret for |peer_public_key| and sets up |hpke| as a
// encapsulates a shared secret for |peer_public_key| and sets up |ctx| as a
// sender context. It writes the encapsulated shared secret to |out_enc| and
// sets |*out_enc_len| to the number of bytes written. It writes at most
// |max_enc| bytes and fails if the buffer is too small. Setting |max_enc| to at
@ -153,7 +153,7 @@ OPENSSL_EXPORT void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx);
// recipient. Callers must then call |EVP_HPKE_CTX_cleanup| when done. On
// failure, calling |EVP_HPKE_CTX_cleanup| is safe, but not required.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender(
EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
const uint8_t *peer_public_key, size_t peer_public_key_len,
const uint8_t *info, size_t info_len);
@ -163,13 +163,13 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender(
// The seed's format depends on |kem|. For X25519, it is the sender's
// ephemeral private key.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
const uint8_t *peer_public_key, size_t peer_public_key_len,
const uint8_t *info, size_t info_len, const uint8_t *seed, size_t seed_len);
// EVP_HPKE_CTX_setup_recipient implements the SetupBaseR HPKE operation. It
// decapsulates the shared secret in |enc| with |key| and sets up |hpke| as a
// decapsulates the shared secret in |enc| with |key| and sets up |ctx| as a
// recipient context. It returns one on success and zero on failure. Note that
// |enc| may be invalid, in which case this function will return an error.
//
@ -177,7 +177,7 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
// sender. Callers must then call |EVP_HPKE_CTX_cleanup| when done. On failure,
// calling |EVP_HPKE_CTX_cleanup| is safe, but not required.
OPENSSL_EXPORT int EVP_HPKE_CTX_setup_recipient(
EVP_HPKE_CTX *hpke, const EVP_HPKE_KEY *key, const EVP_HPKE_KDF *kdf,
EVP_HPKE_CTX *ctx, const EVP_HPKE_KEY *key, const EVP_HPKE_KDF *kdf,
const EVP_HPKE_AEAD *aead, const uint8_t *enc, size_t enc_len,
const uint8_t *info, size_t info_len);
@ -187,11 +187,11 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_recipient(
// Once set up, callers may encrypt or decrypt with an |EVP_HPKE_CTX| using the
// following functions.
// EVP_HPKE_CTX_open uses the HPKE context |hpke| to authenticate |in_len| bytes
// EVP_HPKE_CTX_open uses the HPKE context |ctx| to authenticate |in_len| bytes
// from |in| and |ad_len| bytes from |ad| and to decrypt at most |in_len| bytes
// into |out|. It returns one on success, and zero otherwise.
//
// This operation will fail if the |hpke| context is not set up as a receiver.
// This operation will fail if the |ctx| context is not set up as a receiver.
//
// Note that HPKE encryption is stateful and ordered. The sender's first call to
// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
@ -200,16 +200,16 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_setup_recipient(
// At most |in_len| bytes are written to |out|. In order to ensure success,
// |max_out_len| should be at least |in_len|. On successful return, |*out_len|
// is set to the actual number of bytes written.
OPENSSL_EXPORT int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out,
OPENSSL_EXPORT int EVP_HPKE_CTX_open(EVP_HPKE_CTX *ctx, uint8_t *out,
size_t *out_len, size_t max_out_len,
const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len);
// EVP_HPKE_CTX_seal uses the HPKE context |hpke| to encrypt and authenticate
// EVP_HPKE_CTX_seal uses the HPKE context |ctx| to encrypt and authenticate
// |in_len| bytes of ciphertext |in| and authenticate |ad_len| bytes from |ad|,
// writing the result to |out|. It returns one on success and zero otherwise.
//
// This operation will fail if the |hpke| context is not set up as a sender.
// This operation will fail if the |ctx| context is not set up as a sender.
//
// Note that HPKE encryption is stateful and ordered. The sender's first call to
// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
@ -220,17 +220,17 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out,
//
// To ensure success, |max_out_len| should be |in_len| plus the result of
// |EVP_HPKE_CTX_max_overhead| or |EVP_HPKE_MAX_OVERHEAD|.
OPENSSL_EXPORT int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *hpke, uint8_t *out,
OPENSSL_EXPORT int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *ctx, uint8_t *out,
size_t *out_len, size_t max_out_len,
const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len);
// EVP_HPKE_CTX_export uses the HPKE context |hpke| to export a secret of
// EVP_HPKE_CTX_export uses the HPKE context |ctx| to export a secret of
// |secret_len| bytes into |out|. This function uses |context_len| bytes from
// |context| as a context string for the secret. This is necessary to separate
// different uses of exported secrets and bind relevant caller-specific context
// into the output. It returns one on success and zero otherwise.
OPENSSL_EXPORT int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
OPENSSL_EXPORT int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *ctx, uint8_t *out,
size_t secret_len,
const uint8_t *context,
size_t context_len);
@ -240,17 +240,17 @@ OPENSSL_EXPORT int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
#define EVP_HPKE_MAX_OVERHEAD EVP_AEAD_MAX_OVERHEAD
// EVP_HPKE_CTX_max_overhead returns the maximum number of additional bytes
// added by sealing data with |EVP_HPKE_CTX_seal|. The |hpke| context must be
// set up as a sender.
OPENSSL_EXPORT size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *hpke);
// added by sealing data with |EVP_HPKE_CTX_seal|. The |ctx| context must be set
// up as a sender.
OPENSSL_EXPORT size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *ctx);
// EVP_HPKE_CTX_aead returns |hpke|'s configured AEAD, or NULL if the context
// has not been set up.
OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *hpke);
// EVP_HPKE_CTX_aead returns |ctx|'s configured AEAD, or NULL if the context has
// not been set up.
OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx);
// EVP_HPKE_CTX_kdf returns |hpke|'s configured KDF, or NULL if the context
// has not been set up.
OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *hpke);
// EVP_HPKE_CTX_kdf returns |ctx|'s configured KDF, or NULL if the context has
// not been set up.
OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *ctx);
// Private structures.

Loading…
Cancel
Save