EVP_HPKE_KEM: Clean up legacy KEM implementation hooks

Now that every HPKE KEM is implemented by an EVP_KEM, remove the legacy
function pointers and lengths from EVP_HPKE_KEM, the
private_key/public_key buffers from EVP_HPKE_KEY, and the code paths
that used them.

Bug: 535883377
Change-Id: I9aef06318f9eb941b1cd15c3b8559c106a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/103807
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Lily Chen <chlily@google.com>
diff --git a/crypto/hpke/hpke.cc b/crypto/hpke/hpke.cc
index 8e92882..9316327 100644
--- a/crypto/hpke/hpke.cc
+++ b/crypto/hpke/hpke.cc
@@ -33,7 +33,6 @@
 #include <openssl/hkdf.h>
 #include <openssl/mem.h>
 #include <openssl/mlkem.h>
-#include <openssl/rand.h>
 #include <openssl/sha2.h>
 #include <openssl/span.h>
 #include <openssl/xwing.h>
@@ -49,7 +48,6 @@
 
 // This file implements RFC 9180.
 
-#define MAX_SEED_LEN XWING_SEED_LEN
 #define MAX_SHARED_SECRET_LEN SHA256_DIGEST_LENGTH
 #define MAX_DHKEM_DH_SHARED_KEY_LEN X25519_SHARED_KEY_LEN
 #define MAX_DHKEM_PUBLIC_KEY_LEN 65  // kP256PublicValueLen
@@ -115,66 +113,21 @@
 struct evp_hpke_kem_st {
   uint16_t id;
 
-  // evp_kem_func and key_method, if non-null, provide the EVP_PKEY_CTX and
-  // EVP_KEM functionality backing this EVP_HPKE_KEM. If these are non-null,
-  // then (until fully migrated):
-  //  * `init_key`, `generate_key`, and `derive_key` are null (these operations
-  //    are supplied by `key_method`),
-  //  * `encap_with_seed`, and `decap` are null (these operations are supplied
-  //    by the `EVP_KEM`),
-  //  * `public_key_len` and `private_key_len` are zero (they are supplied by
-  //    `key_method`), and
-  //  * `seed_len` and `enc_len` are zero (they are supplied by the `EVP_KEM`).
-  //  * `auth_encap_with_seed` and `auth_decap` are null (`evp_auth_encap`,
-  //    `evp_auth_encap_external_entropy`, and `evp_auth_decap` may be populated
-  //    instead).
-  // TODO(crbug.com/535883377): Unify EVP_HPKE_KEM and EVP_KEM for all supported
-  // HPKE KEMs.
   const EVP_KEM *(*evp_kem_func)();
   const HpkeKeyMethod *key_method;
 
-  size_t public_key_len;
-  size_t private_key_len;
-  size_t seed_len;
-  size_t enc_len;
-  int (*init_key)(EVP_HPKE_KEY *key, const uint8_t *priv_key,
-                  size_t priv_key_len);
-  int (*generate_key)(EVP_HPKE_KEY *key);
-  int (*derive_key)(EVP_HPKE_KEY *key, Span<const uint8_t> ikm);
-  int (*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);
-  int (*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);
-  int (*auth_encap_with_seed)(const EVP_HPKE_KEY *key,
-                              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);
-  int (*auth_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, const uint8_t *peer_public_key,
-                    size_t peer_public_key_len);
-  // TODO(crbug.com/535883377): Migrate to these function signatures and remove
-  // `evp_` prefix.
-  int (*evp_auth_encap)(const EVP_KEM *kem, Span<uint8_t> out_ciphertext,
-                        Span<uint8_t> out_secret, const EVP_PKEY *peer_key,
-                        const EVP_PKEY *auth_key);
-  int (*evp_auth_encap_external_entropy)(const EVP_KEM *kem,
-                                         Span<uint8_t> out_ciphertext,
-                                         Span<uint8_t> out_secret,
-                                         const EVP_PKEY *peer_key,
-                                         const EVP_PKEY *auth_key,
-                                         Span<const uint8_t> entropy);
-  int (*evp_auth_decap)(const EVP_KEM *kem, Span<uint8_t> out_secret,
-                        Span<const uint8_t> ciphertext, const EVP_PKEY *key,
-                        const EVP_PKEY *auth_key);
+  int (*auth_encap)(const EVP_KEM *kem, Span<uint8_t> out_ciphertext,
+                    Span<uint8_t> out_secret, const EVP_PKEY *peer_key,
+                    const EVP_PKEY *auth_key);
+  int (*auth_encap_external_entropy)(const EVP_KEM *kem,
+                                     Span<uint8_t> out_ciphertext,
+                                     Span<uint8_t> out_secret,
+                                     const EVP_PKEY *peer_key,
+                                     const EVP_PKEY *auth_key,
+                                     Span<const uint8_t> entropy);
+  int (*auth_decap)(const EVP_KEM *kem, Span<uint8_t> out_secret,
+                    Span<const uint8_t> ciphertext, const EVP_PKEY *key,
+                    const EVP_PKEY *auth_key);
 };
 
 struct evp_hpke_kdf_st {
@@ -620,24 +573,13 @@
 }
 
 const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256() {
-  static const EVP_HPKE_KEM kKEM = {
+  static constexpr EVP_HPKE_KEM kKEM = {
       /*id=*/EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
       /*evp_kem_func=*/&EVP_kem_dhkem_x25519_hkdf_sha256,
       /*key_method=*/&kX25519KeyMethod,
-      /*public_key_len=*/0,
-      /*private_key_len=*/0,
-      /*seed_len=*/0,
-      /*enc_len=*/0,
-      /*init_key=*/nullptr,
-      /*generate_key=*/nullptr,
-      /*derive_key=*/nullptr,
-      /*encap_with_seed=*/nullptr,
-      /*decap=*/nullptr,
-      /*auth_encap_with_seed=*/nullptr,
-      /*auth_decap=*/nullptr,
-      /*evp_auth_encap=*/&dhkem_auth_encap,
-      /*evp_auth_encap_external_entropy=*/&dhkem_auth_encap_external_entropy,
-      /*evp_auth_decap=*/&dhkem_auth_decap,
+      /*auth_encap=*/&dhkem_auth_encap,
+      /*auth_encap_external_entropy=*/&dhkem_auth_encap_external_entropy,
+      /*auth_decap=*/&dhkem_auth_decap,
   };
   return &kKEM;
 }
@@ -769,34 +711,17 @@
 }
 
 const EVP_HPKE_KEM *EVP_hpke_p256_hkdf_sha256() {
-  static const EVP_HPKE_KEM kKEM = {
+  static constexpr EVP_HPKE_KEM kKEM = {
       /*id=*/EVP_HPKE_DHKEM_P256_HKDF_SHA256,
       /*evp_kem_func=*/&EVP_kem_dhkem_p256_hkdf_sha256,
       /*key_method=*/&kP256KeyMethod,
-      /*public_key_len=*/0,
-      /*private_key_len=*/0,
-      /*seed_len=*/0,
-      /*enc_len=*/0,
-      /*init_key=*/nullptr,
-      /*generate_key=*/nullptr,
-      /*derive_key=*/nullptr,
-      /*encap_with_seed=*/nullptr,
-      /*decap=*/nullptr,
-      /*auth_encap_with_seed=*/nullptr,
-      /*auth_decap=*/nullptr,
-      /*evp_auth_encap=*/&dhkem_auth_encap,
-      /*evp_auth_encap_external_entropy=*/&dhkem_auth_encap_external_entropy,
-      /*evp_auth_decap=*/&dhkem_auth_decap,
+      /*auth_encap=*/&dhkem_auth_encap,
+      /*auth_encap_external_entropy=*/&dhkem_auth_encap_external_entropy,
+      /*auth_decap=*/&dhkem_auth_decap,
   };
   return &kKEM;
 }
 
-#define XWING_PRIVATE_KEY_LEN XWING_PRIVATE_KEY_BYTES
-#define XWING_PUBLIC_KEY_LEN XWING_PUBLIC_KEY_BYTES
-#define XWING_PUBLIC_VALUE_LEN XWING_CIPHERTEXT_BYTES
-#define XWING_SEED_LEN 64
-#define XWING_SHARED_KEY_LEN XWING_SHARED_SECRET_BYTES
-
 template <size_t SEED_BYTES>
 static EVP_PKEY *shake256_derive_key_pair_from_private_seed(
     const EVP_PKEY_ALG *alg, uint16_t kem_suite_id, Span<const uint8_t> ikm) {
@@ -808,38 +733,27 @@
 
 static constexpr HpkeKeyMethod kXwingKeyMethod = {
     /*hpke_kem_id=*/EVP_HPKE_XWING,
-    /*public_key_len=*/XWING_PUBLIC_KEY_LEN,
-    /*private_key_len=*/XWING_PRIVATE_KEY_LEN,
+    /*public_key_len=*/XWING_PUBLIC_KEY_BYTES,
+    /*private_key_len=*/XWING_PRIVATE_KEY_BYTES,
     /*alg_func=*/&EVP_pkey_xwing,
     /*deserialize_private_key=*/&EVP_PKEY_from_private_seed,
     /*serialize_private_key=*/&EVP_PKEY_get_private_seed,
     /*deserialize_public_key=*/&EVP_PKEY_from_raw_public_key,
     /*serialize_public_key=*/&EVP_PKEY_get_raw_public_key,
     /*derive_key_pair=*/
-    shake256_derive_key_pair_from_private_seed<XWING_PRIVATE_KEY_LEN>,
+    shake256_derive_key_pair_from_private_seed<XWING_PRIVATE_KEY_BYTES>,
 };
 
 const EVP_HPKE_KEM *EVP_hpke_xwing() {
-  static const EVP_HPKE_KEM kKEM = {
+  static constexpr EVP_HPKE_KEM kKEM = {
       /*id=*/EVP_HPKE_XWING,
       /*evp_kem_func=*/&EVP_kem_xwing,
       /*key_method=*/&kXwingKeyMethod,
-      /*public_key_len=*/0,
-      /*private_key_len=*/0,
-      /*seed_len=*/0,
-      /*enc_len=*/0,
-      /*init_key=*/nullptr,
-      /*generate_key=*/nullptr,
-      /*derive_key=*/nullptr,
-      /*encap_with_seed=*/nullptr,
-      /*decap=*/nullptr,
       // X-Wing doesn't support authenticated encapsulation/decapsulation:
       // https://datatracker.ietf.org/doc/html/draft-connolly-cfrg-xwing-kem-08#name-use-in-hpke
-      /*auth_encap_with_seed=*/nullptr,
+      /*auth_encap=*/nullptr,
+      /*auth_encap_external_entropy=*/nullptr,
       /*auth_decap=*/nullptr,
-      /*evp_auth_encap=*/nullptr,
-      /*evp_auth_encap_external_entropy=*/nullptr,
-      /*evp_auth_decap=*/nullptr,
   };
   return &kKEM;
 }
@@ -858,26 +772,15 @@
 };
 
 const EVP_HPKE_KEM *EVP_hpke_mlkem768() {
-  static const EVP_HPKE_KEM kKEM = {
+  static constexpr EVP_HPKE_KEM kKEM = {
       /*id=*/EVP_HPKE_MLKEM768,
       /*evp_kem_func=*/&EVP_kem_ml_kem_768,
       /*key_method=*/&kMlkem768KeyMethod,
-      /*public_key_len=*/0,
-      /*private_key_len=*/0,
-      /*seed_len=*/0,
-      /*enc_len=*/0,
-      /*init_key=*/nullptr,
-      /*generate_key=*/nullptr,
-      /*derive_key=*/nullptr,
-      /*encap_with_seed=*/nullptr,
-      /*decap=*/nullptr,
       // ML-KEM doesn't support authenticated encapsulation/decapsulation:
       // https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/01/
-      /*auth_encap_with_seed=*/nullptr,
+      /*auth_encap=*/nullptr,
+      /*auth_encap_external_entropy=*/nullptr,
       /*auth_decap=*/nullptr,
-      /*evp_auth_encap=*/nullptr,
-      /*evp_auth_encap_external_entropy=*/nullptr,
-      /*evp_auth_decap=*/nullptr,
   };
   return &kKEM;
 }
@@ -896,88 +799,41 @@
 };
 
 const EVP_HPKE_KEM *EVP_hpke_mlkem1024() {
-  static const EVP_HPKE_KEM kKEM = {
+  static constexpr EVP_HPKE_KEM kKEM = {
       /*id=*/EVP_HPKE_MLKEM1024,
       /*evp_kem_func=*/&EVP_kem_ml_kem_1024,
       /*key_method=*/&kMlkem1024KeyMethod,
-      /*public_key_len=*/0,
-      /*private_key_len=*/0,
-      /*seed_len=*/0,
-      /*enc_len=*/0,
-      /*init_key=*/nullptr,
-      /*generate_key=*/nullptr,
-      /*derive_key=*/nullptr,
-      /*encap_with_seed=*/nullptr,
-      /*decap=*/nullptr,
       // ML-KEM doesn't support authenticated encapsulation/decapsulation:
       // https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/01/
-      /*auth_encap_with_seed=*/nullptr,
+      /*auth_encap=*/nullptr,
+      /*auth_encap_external_entropy=*/nullptr,
       /*auth_decap=*/nullptr,
-      /*evp_auth_encap=*/nullptr,
-      /*evp_auth_encap_external_entropy=*/nullptr,
-      /*evp_auth_decap=*/nullptr,
   };
   return &kKEM;
 }
 
-namespace {
-
-// Temporary helper to switch between EVP_KEM-based implementation and legacy
-// EVP_HPKE_KEM implementation.
-// TODO(crbug.com/535883377): Unify EVP_HPKE_KEM and EVP_KEM for all supported
-// HPKE KEMs.
-
-bool uses_evp(const EVP_HPKE_KEM *kem) {
-  return kem->evp_kem_func != nullptr && kem->key_method != nullptr;
-}
-
-}  // namespace
-
 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) {
-  if (uses_evp(kem)) {
-    return kem->key_method->public_key_len;
-  }
-  return kem->public_key_len;
+  return kem->key_method->public_key_len;
 }
 
 size_t EVP_HPKE_KEM_private_key_len(const EVP_HPKE_KEM *kem) {
-  if (uses_evp(kem)) {
-    return kem->key_method->private_key_len;
-  }
-  return kem->private_key_len;
+  return kem->key_method->private_key_len;
 }
 
-// TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-// HPKE KEMs.
 size_t EVP_HPKE_KEM_enc_len(const EVP_HPKE_KEM *kem) {
-  if (uses_evp(kem)) {
-    return EVP_KEM_ciphertext_len(kem->evp_kem_func());
-  }
-  return kem->enc_len;
+  return EVP_KEM_ciphertext_len(kem->evp_kem_func());
 }
 
-// TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-// HPKE KEMs.
 size_t EVP_HPKE_KEM_shared_secret_len(const EVP_HPKE_KEM *kem) {
-  if (uses_evp(kem)) {
-    return EVP_KEM_secret_len(kem->evp_kem_func());
-  }
-  // All other KEMs have the same shared secret length. We assume we'll finish
-  // https://crbug.com/503758094 and move all KEMs to EVP before adding one that
-  // breaks this.
-  return SHA256_DIGEST_LENGTH;
+  return EVP_KEM_secret_len(kem->evp_kem_func());
 }
 
-// TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-// HPKE KEMs.
 void EVP_HPKE_KEY_zero(EVP_HPKE_KEY *key) {
   OPENSSL_memset(key, 0, sizeof(EVP_HPKE_KEY));
 }
 
-// TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-// HPKE KEMs.
 void EVP_HPKE_KEY_cleanup(EVP_HPKE_KEY *key) {
   EVP_PKEY_free(key->pkey);
   key->pkey = nullptr;
@@ -999,8 +855,6 @@
   }
 }
 
-// TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-// HPKE KEMs.
 int EVP_HPKE_KEY_copy(EVP_HPKE_KEY *dst, const EVP_HPKE_KEY *src) {
   dst->kem = src->kem;
   OPENSSL_memcpy(dst->private_key, src->private_key, sizeof(src->private_key));
@@ -1022,44 +876,26 @@
                       const uint8_t *priv_key, size_t priv_key_len) {
   EVP_HPKE_KEY_zero(key);
   key->kem = kem;
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(kem)) {
-    UniquePtr<EVP_PKEY> pkey(kem->key_method->deserialize_private_key(
-        kem->key_method->alg_func(), priv_key, priv_key_len));
-    if (pkey == nullptr) {
-      key->kem = nullptr;
-      return 0;
-    }
-    key->pkey = pkey.release();
-    return 1;
-  }
-  if (!kem->init_key(key, priv_key, priv_key_len)) {
+  UniquePtr<EVP_PKEY> pkey(kem->key_method->deserialize_private_key(
+      kem->key_method->alg_func(), priv_key, priv_key_len));
+  if (pkey == nullptr) {
     key->kem = nullptr;
     return 0;
   }
+  key->pkey = pkey.release();
   return 1;
 }
 
 int EVP_HPKE_KEY_generate(EVP_HPKE_KEY *key, const EVP_HPKE_KEM *kem) {
   EVP_HPKE_KEY_zero(key);
   key->kem = kem;
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(kem)) {
-    UniquePtr<EVP_PKEY> pkey(
-        EVP_PKEY_generate_from_alg(kem->key_method->alg_func()));
-    if (pkey == nullptr) {
-      key->kem = nullptr;
-      return 0;
-    }
-    key->pkey = pkey.release();
-    return 1;
-  }
-  if (!kem->generate_key(key)) {
+  UniquePtr<EVP_PKEY> pkey(
+      EVP_PKEY_generate_from_alg(kem->key_method->alg_func()));
+  if (pkey == nullptr) {
     key->kem = nullptr;
     return 0;
   }
+  key->pkey = pkey.release();
   return 1;
 }
 
@@ -1067,22 +903,13 @@
                         const uint8_t *ikm, size_t ikm_len) {
   EVP_HPKE_KEY_zero(key);
   key->kem = kem;
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(kem)) {
-    UniquePtr<EVP_PKEY> pkey(kem->key_method->derive_key_pair(
-        kem->key_method->alg_func(), kem->id, Span(ikm, ikm_len)));
-    if (pkey == nullptr) {
-      key->kem = nullptr;
-      return 0;
-    }
-    key->pkey = pkey.release();
-    return 1;
-  }
-  if (!kem->derive_key(key, Span(ikm, ikm_len))) {
+  UniquePtr<EVP_PKEY> pkey(kem->key_method->derive_key_pair(
+      kem->key_method->alg_func(), kem->id, Span(ikm, ikm_len)));
+  if (pkey == nullptr) {
     key->kem = nullptr;
     return 0;
   }
+  key->pkey = pkey.release();
   return 1;
 }
 
@@ -1096,15 +923,8 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
     return 0;
   }
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(key->kem)) {
-    *out_len = max_out;
-    return key->kem->key_method->serialize_public_key(key->pkey, out, out_len);
-  }
-  OPENSSL_memcpy(out, key->public_key, key->kem->public_key_len);
-  *out_len = key->kem->public_key_len;
-  return 1;
+  *out_len = max_out;
+  return key->kem->key_method->serialize_public_key(key->pkey, out, out_len);
 }
 
 int EVP_HPKE_KEY_private_key(const EVP_HPKE_KEY *key, uint8_t *out,
@@ -1113,15 +933,8 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
     return 0;
   }
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(key->kem)) {
-    *out_len = max_out;
-    return key->kem->key_method->serialize_private_key(key->pkey, out, out_len);
-  }
-  OPENSSL_memcpy(out, key->private_key, key->kem->private_key_len);
-  *out_len = key->kem->private_key_len;
-  return 1;
+  *out_len = max_out;
+  return key->kem->key_method->serialize_private_key(key->pkey, out, out_len);
 }
 
 
@@ -1290,6 +1103,60 @@
   }
 }
 
+static int hpke_setup_sender_impl(
+    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,
+    Span<const uint8_t> peer_public_key, Span<const uint8_t> info,
+    std::optional<Span<const uint8_t>> entropy) {
+  EVP_HPKE_CTX_zero(ctx);
+  ctx->is_sender = 1;
+  ctx->kem = kem;
+  ctx->kdf = kdf;
+  ctx->aead = aead;
+
+  const EVP_KEM *evp_kem = kem->evp_kem_func();
+  if (max_enc < EVP_KEM_ciphertext_len(evp_kem)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+    return 0;
+  }
+  *out_enc_len = EVP_KEM_ciphertext_len(evp_kem);
+
+  // Check the length here rather than in `EVP_PKEY`, so that the
+  // expected error is emitted.
+  // TODO(crbug.com/535883377): Clean up error codes.
+  if (peer_public_key.size() != kem->key_method->public_key_len) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+    return 0;
+  }
+  UniquePtr<EVP_PKEY> peer_pubkey(kem->key_method->deserialize_public_key(
+      kem->key_method->alg_func(), peer_public_key.data(),
+      peer_public_key.size()));
+  if (peer_pubkey == nullptr) {
+    return 0;
+  }
+  InplaceVector<uint8_t, MAX_SHARED_SECRET_LEN> shared_secret;
+  if (!shared_secret.TryResizeForOverwrite(evp_kem->secret_len)) {
+    OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+  int encap_ok =
+      entropy.has_value()
+          ? EVP_KEM_encap_external_entropy_for_testing(
+                evp_kem, out_enc, *out_enc_len, shared_secret.data(),
+                shared_secret.size(), peer_pubkey.get(), entropy->data(),
+                entropy->size())
+          : EVP_KEM_encap(evp_kem, out_enc, *out_enc_len, shared_secret.data(),
+                          shared_secret.size(), peer_pubkey.get());
+  if (!encap_ok ||
+      !hpke_key_schedule(ctx, HPKE_MODE_BASE, shared_secret.data(),
+                         shared_secret.size(), info.data(), info.size())) {
+    EVP_HPKE_CTX_cleanup(ctx);
+    return 0;
+  }
+  return 1;
+}
+
+
 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,
@@ -1297,51 +1164,10 @@
                               const uint8_t *peer_public_key,
                               size_t peer_public_key_len, const uint8_t *info,
                               size_t info_len) {
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(kem)) {
-    EVP_HPKE_CTX_zero(ctx);
-    ctx->is_sender = 1;
-    ctx->kem = kem;
-    ctx->kdf = kdf;
-    ctx->aead = aead;
-    uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-    size_t shared_secret_len;
-
-    const EVP_KEM *evp_kem = kem->evp_kem_func();
-    if (max_enc < EVP_KEM_ciphertext_len(evp_kem)) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
-      return 0;
-    }
-    *out_enc_len = EVP_KEM_ciphertext_len(evp_kem);
-    shared_secret_len = EVP_KEM_secret_len(evp_kem);
-    assert(size_t{MAX_SHARED_SECRET_LEN} >= shared_secret_len);
-
-    // Check the length here rather than in `EVP_PKEY`, so that the
-    // expected error is emitted.
-    // TODO(crbug.com/535883377): Clean up error codes.
-    if (peer_public_key_len != kem->key_method->public_key_len) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
-      return 0;
-    }
-    UniquePtr<EVP_PKEY> peer_pubkey(kem->key_method->deserialize_public_key(
-        kem->key_method->alg_func(), peer_public_key, peer_public_key_len));
-    if (peer_pubkey == nullptr ||
-        !EVP_KEM_encap(evp_kem, out_enc, *out_enc_len, shared_secret,
-                       shared_secret_len, peer_pubkey.get()) ||
-        !hpke_key_schedule(ctx, HPKE_MODE_BASE, shared_secret,
-                           shared_secret_len, info, info_len)) {
-      EVP_HPKE_CTX_cleanup(ctx);
-      return 0;
-    }
-    return 1;
-  }
-
-  uint8_t seed[MAX_SEED_LEN];
-  RAND_bytes(seed, kem->seed_len);
-  return EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
-      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);
+  return hpke_setup_sender_impl(ctx, out_enc, out_enc_len, max_enc, kem, kdf,
+                                aead,
+                                Span(peer_public_key, peer_public_key_len),
+                                Span(info, info_len), /*entropy=*/std::nullopt);
 }
 
 int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
@@ -1350,56 +1176,10 @@
     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(ctx);
-  ctx->is_sender = 1;
-  ctx->kem = kem;
-  ctx->kdf = kdf;
-  ctx->aead = aead;
-  uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-  size_t shared_secret_len;
-
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(kem)) {
-    const EVP_KEM *evp_kem = kem->evp_kem_func();
-    if (max_enc < EVP_KEM_ciphertext_len(evp_kem)) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
-      return 0;
-    }
-    *out_enc_len = EVP_KEM_ciphertext_len(evp_kem);
-    shared_secret_len = EVP_KEM_secret_len(evp_kem);
-    assert(size_t{MAX_SHARED_SECRET_LEN} >= shared_secret_len);
-
-    // Check the length here rather than in `EVP_PKEY`, so that the
-    // expected error is emitted.
-    // TODO(crbug.com/535883377): Clean up error codes.
-    if (peer_public_key_len != kem->key_method->public_key_len) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
-      return 0;
-    }
-    UniquePtr<EVP_PKEY> peer_pubkey(kem->key_method->deserialize_public_key(
-        kem->key_method->alg_func(), peer_public_key, peer_public_key_len));
-    if (peer_pubkey == nullptr ||
-        !EVP_KEM_encap_external_entropy_for_testing(
-            evp_kem, out_enc, *out_enc_len, shared_secret, shared_secret_len,
-            peer_pubkey.get(), seed, seed_len) ||
-        !hpke_key_schedule(ctx, HPKE_MODE_BASE, shared_secret,
-                           shared_secret_len, info, info_len)) {
-      EVP_HPKE_CTX_cleanup(ctx);
-      return 0;
-    }
-    return 1;
-  }
-
-  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(ctx, HPKE_MODE_BASE, shared_secret, shared_secret_len,
-                         info, info_len)) {
-    EVP_HPKE_CTX_cleanup(ctx);
-    return 0;
-  }
-  return 1;
+  return hpke_setup_sender_impl(ctx, out_enc, out_enc_len, max_enc, kem, kdf,
+                                aead,
+                                Span(peer_public_key, peer_public_key_len),
+                                Span(info, info_len), Span(seed, seed_len));
 }
 
 int EVP_HPKE_CTX_setup_recipient_with_shared_secret(
@@ -1432,35 +1212,27 @@
                                  size_t info_len) {
   EVP_HPKE_CTX_zero(ctx);
 
-  uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-  size_t shared_secret_len = 0;
+  const EVP_KEM *evp_kem = key->kem->evp_kem_func();
+  const EVP_PKEY *decap_key = key->pkey;
 
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  int decap_ok;
-  if (uses_evp(key->kem)) {
-    const EVP_KEM *evp_kem = key->kem->evp_kem_func();
-    const EVP_PKEY *decap_key = key->pkey;
-    shared_secret_len = EVP_KEM_secret_len(evp_kem);
-    assert(size_t{MAX_SHARED_SECRET_LEN} >= shared_secret_len);
-
-    // Check the length here rather than in `EVP_KEM_decap`, so that the
-    // expected error is emitted.
-    // TODO(crbug.com/535883377): Clean up error codes.
-    if (enc_len != EVP_KEM_ciphertext_len(evp_kem)) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
-      return 0;
-    }
-    decap_ok = EVP_KEM_decap(evp_kem, shared_secret, shared_secret_len, enc,
-                             enc_len, decap_key);
-  } else {
-    decap_ok =
-        key->kem->decap(key, shared_secret, &shared_secret_len, enc, enc_len);
+  // Check the length here rather than in `EVP_KEM_decap`, so that the
+  // expected error is emitted.
+  // TODO(crbug.com/535883377): Clean up error codes.
+  if (enc_len != EVP_KEM_ciphertext_len(evp_kem)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+    return 0;
   }
 
-  return decap_ok && EVP_HPKE_CTX_setup_recipient_with_shared_secret(
-                         ctx, key->kem, kdf, aead, shared_secret,
-                         shared_secret_len, info, info_len);
+  InplaceVector<uint8_t, MAX_SHARED_SECRET_LEN> shared_secret;
+  if (!shared_secret.TryResizeForOverwrite(evp_kem->secret_len)) {
+    OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+  return EVP_KEM_decap(evp_kem, shared_secret.data(), shared_secret.size(), enc,
+                       enc_len, decap_key) &&
+         EVP_HPKE_CTX_setup_recipient_with_shared_secret(
+             ctx, key->kem, kdf, aead, shared_secret.data(),
+             shared_secret.size(), info, info_len);
 }
 
 static int hpke_setup_auth_sender_impl(
@@ -1468,10 +1240,8 @@
     const EVP_HPKE_KEY *key, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
     Span<const uint8_t> peer_public_key, Span<const uint8_t> info,
     std::optional<Span<const uint8_t>> entropy) {
-  assert(uses_evp(key->kem));
-
-  if (entropy.has_value() ? key->kem->evp_auth_encap_external_entropy == nullptr
-                          : key->kem->evp_auth_encap == nullptr) {
+  if (entropy.has_value() ? key->kem->auth_encap_external_entropy == nullptr
+                          : key->kem->auth_encap == nullptr) {
     // Not all HPKE KEMs support AuthEncap.
     OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
@@ -1502,16 +1272,19 @@
     return 0;
   }
 
-  uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-  assert(sizeof(shared_secret) >= kem->secret_len);
+  InplaceVector<uint8_t, MAX_SHARED_SECRET_LEN> shared_secret;
+  if (!shared_secret.TryResizeForOverwrite(kem->secret_len)) {
+    OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
   Span<uint8_t> enc_span(out_enc, kem->ciphertext_len);
-  Span<uint8_t> secret_span(shared_secret, kem->secret_len);
+  Span<uint8_t> secret_span(shared_secret);
   int auth_encap_ok =
       entropy.has_value()
-          ? key->kem->evp_auth_encap_external_entropy(
+          ? key->kem->auth_encap_external_entropy(
                 kem, enc_span, secret_span, peer_key.get(), key->pkey, *entropy)
-          : key->kem->evp_auth_encap(kem, enc_span, secret_span, peer_key.get(),
-                                     key->pkey);
+          : key->kem->auth_encap(kem, enc_span, secret_span, peer_key.get(),
+                                 key->pkey);
   if (!auth_encap_ok ||
       !hpke_key_schedule(ctx, HPKE_MODE_AUTH, secret_span.data(),
                          secret_span.size(), info.data(), info.size())) {
@@ -1527,25 +1300,10 @@
     const EVP_HPKE_KEY *key, 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) {
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(key->kem)) {
-    return hpke_setup_auth_sender_impl(
-        ctx, out_enc, out_enc_len, max_enc, key, kdf, aead,
-        Span(peer_public_key, peer_public_key_len), Span(info, info_len),
-        /*entropy=*/std::nullopt);
-  }
-
-  if (key->kem->auth_encap_with_seed == nullptr) {
-    // Not all HPKE KEMs support AuthEncap.
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-    return 0;
-  }
-  uint8_t seed[MAX_SEED_LEN];
-  RAND_bytes(seed, key->kem->seed_len);
-  return EVP_HPKE_CTX_setup_auth_sender_with_seed_for_testing(
-      ctx, out_enc, out_enc_len, max_enc, key, kdf, aead, peer_public_key,
-      peer_public_key_len, info, info_len, seed, key->kem->seed_len);
+  return hpke_setup_auth_sender_impl(
+      ctx, out_enc, out_enc_len, max_enc, key, kdf, aead,
+      Span(peer_public_key, peer_public_key_len), Span(info, info_len),
+      /*entropy=*/std::nullopt);
 }
 
 int EVP_HPKE_CTX_setup_auth_sender_with_seed_for_testing(
@@ -1554,37 +1312,10 @@
     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) {
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  if (uses_evp(key->kem)) {
-    return hpke_setup_auth_sender_impl(
-        ctx, out_enc, out_enc_len, max_enc, key, kdf, aead,
-        Span(peer_public_key, peer_public_key_len), Span(info, info_len),
-        Span(seed, seed_len));
-  }
-
-  if (key->kem->auth_encap_with_seed == nullptr) {
-    // Not all HPKE KEMs support AuthEncap.
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-    return 0;
-  }
-
-  EVP_HPKE_CTX_zero(ctx);
-  ctx->is_sender = 1;
-  ctx->kem = key->kem;
-  ctx->kdf = kdf;
-  ctx->aead = aead;
-  uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-  size_t shared_secret_len;
-  if (!key->kem->auth_encap_with_seed(
-          key, 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(ctx, HPKE_MODE_AUTH, shared_secret, shared_secret_len,
-                         info, info_len)) {
-    EVP_HPKE_CTX_cleanup(ctx);
-    return 0;
-  }
-  return 1;
+  return hpke_setup_auth_sender_impl(
+      ctx, out_enc, out_enc_len, max_enc, key, kdf, aead,
+      Span(peer_public_key, peer_public_key_len), Span(info, info_len),
+      Span(seed, seed_len));
 }
 
 int EVP_HPKE_CTX_setup_auth_recipient(
@@ -1592,8 +1323,7 @@
     const EVP_HPKE_AEAD *aead, const uint8_t *enc, size_t enc_len,
     const uint8_t *info, size_t info_len, const uint8_t *peer_public_key,
     size_t peer_public_key_len) {
-  if ((uses_evp(key->kem) && key->kem->evp_auth_decap == nullptr) ||
-      (!uses_evp(key->kem) && key->kem->auth_decap == nullptr)) {
+  if (key->kem->auth_decap == nullptr) {
     // Not all HPKE KEMs support AuthDecap.
     OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
@@ -1604,35 +1334,26 @@
   ctx->kem = key->kem;
   ctx->kdf = kdf;
   ctx->aead = aead;
-  uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
-  size_t shared_secret_len = 0;
-  // TODO(crbug.com/535883377): Implement in terms of EVP_KEM for all supported
-  // HPKE KEMs.
-  int auth_decap_ok;
-  if (uses_evp(key->kem)) {
-    const EVP_KEM *kem = key->kem->evp_kem_func();
-    if (enc_len != kem->ciphertext_len ||
-        peer_public_key_len != key->kem->key_method->public_key_len) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
-      return 0;
-    }
-    UniquePtr<EVP_PKEY> peer_key(key->kem->key_method->deserialize_public_key(
-        key->kem->key_method->alg_func(), peer_public_key,
-        peer_public_key_len));
-    if (peer_key == nullptr) {
-      return 0;
-    }
-    auth_decap_ok =
-        key->kem->evp_auth_decap(kem, Span(shared_secret, kem->secret_len),
-                                 Span(enc, enc_len), key->pkey, peer_key.get());
-    shared_secret_len = kem->secret_len;
-  } else {
-    auth_decap_ok =
-        key->kem->auth_decap(key, shared_secret, &shared_secret_len, enc,
-                             enc_len, peer_public_key, peer_public_key_len);
+  const EVP_KEM *kem = key->kem->evp_kem_func();
+  InplaceVector<uint8_t, MAX_SHARED_SECRET_LEN> shared_secret;
+  if (!shared_secret.TryResizeForOverwrite(kem->secret_len)) {
+    OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+    return 0;
   }
-  if (!auth_decap_ok || !hpke_key_schedule(ctx, HPKE_MODE_AUTH, shared_secret,
-                                           shared_secret_len, info, info_len)) {
+  if (enc_len != kem->ciphertext_len ||
+      peer_public_key_len != key->kem->key_method->public_key_len) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+    return 0;
+  }
+  UniquePtr<EVP_PKEY> peer_key(key->kem->key_method->deserialize_public_key(
+      key->kem->key_method->alg_func(), peer_public_key, peer_public_key_len));
+  if (peer_key == nullptr) {
+    return 0;
+  }
+  if (!key->kem->auth_decap(kem, Span(shared_secret), Span(enc, enc_len),
+                            key->pkey, peer_key.get()) ||
+      !hpke_key_schedule(ctx, HPKE_MODE_AUTH, shared_secret.data(),
+                         shared_secret.size(), info, info_len)) {
     EVP_HPKE_CTX_cleanup(ctx);
     return 0;
   }