Add X-Wing KEM option for HPKE.
Co-Authored-by: Guillaume Endignoux <guillaumee@google.com>
Change-Id: I5d9d78b61c6b4c1ea1d4f16cc24d9f096fd902cf
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/80247
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.cc b/crypto/hpke/hpke.cc
index 5d8e54c..321f9db 100644
--- a/crypto/hpke/hpke.cc
+++ b/crypto/hpke/hpke.cc
@@ -28,6 +28,7 @@
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha2.h>
+#include <openssl/xwing.h>
#include "../fipsmodule/ec/internal.h"
#include "../internal.h"
@@ -35,7 +36,7 @@
// This file implements RFC 9180.
-#define MAX_SEED_LEN X25519_PRIVATE_KEY_LEN
+#define MAX_SEED_LEN XWING_SEED_LEN
#define MAX_SHARED_SECRET_LEN SHA256_DIGEST_LENGTH
struct evp_hpke_kem_st {
@@ -601,6 +602,122 @@
return &kKEM;
}
+#define XWING_PRIVATE_KEY_LEN 32
+#define XWING_PUBLIC_KEY_LEN 1216
+#define XWING_PUBLIC_VALUE_LEN 1120
+#define XWING_SEED_LEN 64
+#define XWING_SHARED_KEY_LEN 32
+
+static int xwing_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key,
+ size_t priv_key_len) {
+ CBS cbs;
+ CBS_init(&cbs, priv_key, priv_key_len);
+ XWING_private_key private_key;
+ if (!XWING_parse_private_key(&private_key, &cbs) || CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (!XWING_public_from_private(key->public_key, &private_key)) {
+ return 0;
+ }
+
+ if (priv_key_len > sizeof(key->private_key)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+ OPENSSL_memcpy(key->private_key, priv_key, priv_key_len);
+ return 1;
+}
+
+static int xwing_generate_key(EVP_HPKE_KEY *key) {
+ XWING_private_key private_key;
+ if (!XWING_generate_key(key->public_key, &private_key)) {
+ return 0;
+ }
+
+ CBB cbb;
+ CBB_init_fixed(&cbb, key->private_key, XWING_PRIVATE_KEY_LEN);
+ if (!XWING_marshal_private_key(&cbb, &private_key) ||
+ CBB_len(&cbb) != XWING_PRIVATE_KEY_LEN) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int xwing_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 < XWING_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+ if (peer_public_key_len != XWING_PUBLIC_KEY_LEN ||
+ seed_len != XWING_SEED_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (!XWING_encap_external_entropy(out_enc, out_shared_secret, peer_public_key,
+ seed)) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ *out_enc_len = XWING_PUBLIC_VALUE_LEN;
+ *out_shared_secret_len = XWING_SHARED_KEY_LEN;
+ return 1;
+}
+
+static int xwing_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 != XWING_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, key->private_key, XWING_PRIVATE_KEY_LEN);
+ XWING_private_key private_key;
+ if (!XWING_parse_private_key(&private_key, &cbs)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (!XWING_decap(out_shared_secret, enc, &private_key)) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ *out_shared_secret_len = XWING_SHARED_KEY_LEN;
+ return 1;
+}
+
+const EVP_HPKE_KEM *EVP_hpke_xwing(void) {
+ static const EVP_HPKE_KEM kKEM = {
+ /*id=*/EVP_HPKE_XWING,
+ /*public_key_len=*/XWING_PUBLIC_KEY_LEN,
+ /*private_key_len=*/XWING_PRIVATE_KEY_LEN,
+ /*seed_len=*/XWING_SEED_LEN,
+ /*enc_len=*/XWING_PUBLIC_VALUE_LEN,
+ xwing_init_key,
+ xwing_generate_key,
+ xwing_encap_with_seed,
+ xwing_decap,
+ // 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_decap= */ nullptr,
+ };
+ 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) {
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index 4503257..91263d2 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -40,6 +40,7 @@
const decltype(&EVP_hpke_x25519_hkdf_sha256) kAllKEMs[] = {
&EVP_hpke_p256_hkdf_sha256,
&EVP_hpke_x25519_hkdf_sha256,
+ &EVP_hpke_xwing
};
const decltype(&EVP_hpke_aes_128_gcm) kAllAEADs[] = {
@@ -73,7 +74,8 @@
uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH];
size_t enc_len = 0;
- // X25519 uses the secret key directly. P-256 uses the IKM to derive a key.
+ // X25519 and X-Wing use the secret key directly. P-256 uses the IKM to
+ // derive a key.
bssl::Span<const uint8_t> secret_input = secret_key_e_;
if (kem_id_ == EVP_HPKE_DHKEM_P256_HKDF_SHA256) {
secret_input = ikm_e_;
@@ -442,6 +444,8 @@
}
// Test the auth mode.
+ // We skip X-Wing here since it does not support auth mode.
+ if (EVP_HPKE_KEM_id(kem()) != EVP_HPKE_XWING)
{
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
diff --git a/crypto/hpke/hpke_test_vectors.txt b/crypto/hpke/hpke_test_vectors.txt
index f8d3110..6bba28a 100644
--- a/crypto/hpke/hpke_test_vectors.txt
+++ b/crypto/hpke/hpke_test_vectors.txt
@@ -1038,7 +1038,7 @@
ct = 957f9800542b0b8891badb026d79cc54597cb2d225b54c00c5238c25d05c30e3fbeda97d2e0e1aba483a2df9f2
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 3853fe2b4035195a573ffc53856e77058e15d9ea064de3e59f4961d0095250ee
# exports[1]
@@ -2092,7 +2092,7 @@
ct = 42fa248a0e67ccca688f2b1d13ba4ba84755acf764bd797c8f7ba3b9b1dc3330326f8d172fef6003c79ec72319
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 28c70088017d70c896a8420f04702c5a321d9cbf0279fba899b59e51bac72c85
# exports[1]
@@ -3144,7 +3144,7 @@
ct = 53624f4f9f173453b14e633b45390ff54cacaa4428d44baee1bff8133fab1ab3afe60f88e4634b525c54e92eda
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = ded6cffafaea6b812cbf3e241e88332adbc077aca81512914213810ee291770a
# exports[1]
@@ -4198,7 +4198,7 @@
ct = 16bc024eb0af9037260c822d45fa786e3c259aab1b7a4a196a72c3e794e78446440ba42b531da44d3d36d0a042
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 8890c5615e5d6b0e1b212e26d80a7e8c0d03e796377f09e9377aa0497ccf89c9
# exports[1]
@@ -5250,7 +5250,7 @@
ct = 7a4a13e9ef23978e2c520fd4d2e757514ae160cd0cd05e556ef692370ca53076214c0c40d4c728d6ed9e727a5b
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 4bbd6243b8bb54cec311fac9df81841b6fd61f56538a775e7c80a9f40160606e
# exports[1]
@@ -6304,7 +6304,7 @@
ct = 3be14e8b3bbd1028cf2b7d0a691dbbeff71321e7dec92d3c2cfb30a0994ab246af76168480285a60037b4ba13a
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 070cffafd89b67b7f0eeb800235303a223e6ff9d1e774dce8eac585c8688c872
# exports[1]
@@ -7358,7 +7358,7 @@
ct = 28e874512f8940fafc7d06135e7589f6b4198bc0f3a1c64702e72c9e6abaf9f05cb0d2f11b03a517898815c934
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 837e49c3ff629250c8d80d3c3fb957725ed481e59e2feb57afd9fe9a8c7c4497
# exports[1]
@@ -8410,7 +8410,7 @@
ct = 10f179686aa2caec1758c8e554513f16472bd0a11e2a907dde0b212cbe87d74f367f8ffe5e41cd3e9962a6afb2
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 5e9bc3d236e1911d95e65b576a8a86d478fb827e8bdfe77b741b289890490d4d
# exports[1]
@@ -9462,7 +9462,7 @@
ct = fcc4c798b73d45d4a241f4d05886befed63b8bdf0252454072c9f6170f6e262f2738cf2ea290053b2181ad46d6
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 7a4c2b89e1909fb0e3ca42d5040f4c2d8346dc0643d787b8474e804f8f72798e
# exports[1]
@@ -10516,7 +10516,7 @@
ct = df400deaab08719cdc7b278b9d2daf898e6aec30e0b1746552d53a20397c519c409a8b73e5e6672985a09c0942
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 6c0386ae15b1b834a5247ca5595b4e102347cbcdc65de64832f36008ce9c9483
# exports[1]
@@ -11568,7 +11568,7 @@
ct = b45b69d419a9be7219d8c94365b89ad6951caf4576ea4774ea40e9b7047a09d6537d1aa2f7c12d6ae4b729b4d0
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 9b13c510416ac977b553bf1741018809c246a695f45eff6d3b0356dbefe1e660
# exports[1]
@@ -12622,7 +12622,7 @@
ct = e2276ec5047bc4b6ed57d6da7da2fb47a77502f0a30f17d040247c73da336d722bc6c89adf68396a0912c6d152
pt = 4265617574792069732074727574682c20747275746820626561757479
# exports[0]
-exporter_context =
+exporter_context =
L = 32
exported_value = 56c4d6c1d3a46c70fd8f4ecda5d27c70886e348efb51bd5edeaa39ff6ce34389
# exports[1]
@@ -12633,3 +12633,95 @@
exporter_context = 54657374436f6e74657874
L = 32
exported_value = eb0d312b6263995b4c7761e64b688c215ffd6043ff3bad2368c862784cbe6eff
+
+mode = 0
+kem_id = 25722
+kdf_id = 1
+aead_id = 1
+info = 4f6465206f6e2061204772656369616e2055726e
+skRm = 7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26
+skEm = 7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df32347268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234
+pkRm = e2236b35a8c24b39b10aa1323a96a919a2ced88400633a7b07131713fc14b2b5b19cfc3da5fa1a92c49f25513e0fd30d6b1611c9ab9635d7086727a4b7d21d34244e66969cf15b3b2a785329f61b096b277ea037383479a6b556de7231fe4b7fa9c9ac24c0699a0018a5253401bacfa905ca816573e56a2d2e067e9b7287533ba13a937dedb31fa44baced40769923610034ae31e619a170245199b3c5c39864859fe1b4c9717a07c30495bdfb98a0a002ccf56c1286cef5041dede3c44cf16bf562c7448518026b3d8b9940680abd38a1575fd27b58da063bfac32c39c30869374c05c1aeb1898b6b303cc68be455346ee0af699636224a148ca2aea10463111c709f69b69c70ce8538746698c4c60a9aef0030c7924ceec42a5d36816f545eae13293460b3acb37ea0e13d70e4aa78686da398a8397c08eaf96882113fe4f7bad4da40b0501e1c753efe73053c87014e8661c33099afe8bede414a5b1aa27d8392b3e131e9a70c1055878240cad0f40d5fe3cdf85236ead97e2a97448363b2808caafd516cd25052c5c362543c2517e4acd0e60ec07163009b6425fc32277acee71c24bab53ed9f29e74c66a0a3564955998d76b96a9a8b50d1635a4d7a67eb42df5644d330457293a8042f53cc7a69288f17ed55827e82b28e82665a86a14fbd96645eca8172c044f83bc0d8c0b4c8626985631ca87af829068f1358963cb333664ca482763ba3b3bb208577f9ba6ac62c25f76592743b64be519317714cb4102cb7b2f9a25b2b4f0615de31decd9ca55026d6da0b65111b16fe52feed8a487e144462a6dba93728f500b6ffc49e515569ef25fed17aff520507368253525860f58be3be61c964604a6ac814e6935596402a520a4670b3d284318866593d15a4bb01c35e3e587ee0c67d2880d6f2407fb7a70712b838deb96c5d7bf2b44bcf6038ccbe33fbcf51a54a584fe90083c91c7a6d43d4fb15f48c60c2fd66e0a8aad4ad64e5c42bb8877c0ebec2b5e387c8a988fdc23beb9e16c8757781e0a1499c61e138c21f216c29d076979871caa6942bafc090544bee99b54b16cb9a9a364d6246d9f42cce53c66b59c45c8f9ae9299a75d15180c3c952151a91b7a10772429dc4cbae6fcc622fa8018c63439f890630b9928db6bb7f9438ae4065ed34d73d486f3f52f90f0807dc88dfdd8c728e954f1ac35c06c000ce41a0582580e3bb57b672972890ac5e7988e7850657116f1b57d0809aaedec0bede1ae148148311c6f7e317346e5189fb8cd635b986f8c0bdd27641c584b778b3a911a80be1c9692ab8e1bbb12839573cce19df183b45835bbb55052f9fc66a1678ef2a36dea78411e6c8d60501b4e60592d13698a943b509185db912e2ea10be06171236b327c71716094c964a68b03377f513a05bcd99c1f346583bb052977a10a12adfc758034e5617da4c1276585e5774e1f3b9978b09d0e9c44d3bc86151c43aad185712717340223ac381d21150a04294e97bb13bbda21b5a182b6da969e19a7fd072737fa8e880a53c2428e3d049b7d2197405296ddb361912a7bcf4827ced611d0c7a7da104dde4322095339f64a61d5bb108ff0bf4d780cae509fb22c256914193ff7349042581237d522828824ee3bdfd07fb03f1f942d2ea179fe722f06cc03de5b69859edb06eff389b27dce59844570216223593d4ba32d9abac8cd049040ef6534
+pkEm = 3829125bd65c4e3612e520ff3cd77938d11c7fa6445fe440a77ee7354b178b71018427144fb2ebcb0aab44f4456251d3885181e0bae0509793f7c160116630ecd898af82d557e5b8aa313672c785e40a8c4b401ecc3d13300591933fe46f7061eaac318f4ab9277174c6282b2f1cc7b7c6dfe57e34f0a325732d58cce71a33fef826419f9c033e31001d8db456a4818563b0754530a855cde822c38643a73c19bb0a9552df2f36c9b00020b3a32d4130dd073ed9eddcea046364bd25ca1ba99865e3aed169c338042fbd31dab9387ed9f5c6d6117bd320b6e3f7092fbab7e2ddceceb81907fcbea6986444836f86004e946ed1c0236dbc760fa06c1ec191d9c92b07e90d243715975af3422980287fc7a57e120b604c8a598e8f1aac5d430e2b2801ff3b36da7640fdbc1fe41fc49fd04320ec86e9dc104aa88f7e346a950c0f2dc1c423fbde5adbd360b66079523795a9e351d17e5b2e943c6381b07c16612960aa682ddc7093e510a7f2b0f24761ab0564c926049dc330f3ed6c4ec23a6cf0f51fd99edae518fdb7615060931c3c0b58f34a7a8aa647368a8bed78ee7b5213bb730170320ccb218e42d7c06b4a5d9088acf3ea9d7f7633203e3a66372c2a75de396f329b6c0d35e2505dcb0ff2ec07eb5ca7f4f44a2d38df047aaeb5761e36fc65537a560ed302992aa03d0b0e20e96501e70545eafbc0bcb93e3d71761f814555c94076540632509a23f2b19d632da32e86203a5232103e13707686e1c2662e50a5f3e08a730e90d4002aff2a85eda0b39c360e1618999100bc56d2c06e7c4cdd728f65a0e044ae2c0c94704b760b0d2a993483cc0636dcb7f5e1ff2453aee6804297b66b314d6158360a4f7f8dfaf70e83459a01b2a9b8e8e6b9dc69793b22940acae5ac404951358e7e31901b47ee6d12ee483e4d449bc8d59af6d56b982b4a6134e29648c54aa47e85d5eb63a98a94f53d91773bf63902057f0969719b28778881aa01504e3f8631b4091a19392bd1afe2554be79b6c61f125d78e16dec8dff31e778076ef81b4a30217b321fb714511e9d9fe87f6616572ec1b2d7dab2ed1eaab1bc8bd7f033c2a95c6426b336a24a972a3efcdaf3614d3a570ec9bea43d2a1bcc9ca10590cd473acbdb0ba86d7b6a5d24a2a4b0b8b192846d2da9f6b7f6b43c7b6953ca071a47b7025dca6d452d1964106b8e640d6af37c87462e7bbd113cedbd336da61e283483624dd7551a4e62c8f4686e4e001930ad8820962bedf2afbdd2f7cd5c79cd392e031671c349a92b4ee40271ce08cb0b83a76275a70dc56eca92a335f7584f7fa132171416b4eed2a8888edca372285fefbcfaf36646a7a45f95113f3015d190ebd7961f74960672fca13f96f8f076927baecfebc742443ff916b9331aa886718dd2a3a68703df5fb477b6d0942a55b6379e8920fede28bebdc36e7cbf56cb3d3143d1be5ddf7deac990fe41db417dc62f297f7956e20d6fa9d2a9735b5675c256fb3c94fff37bafa16fa15e299ba47a311263f9581298172eafc6e007b6cb01a54e73f5c4bc692d5e002e9b423301a39155577991d
+ikmE =
+ikmR =
+# encryptions[0]
+aad = 436f756e742d30
+ct = a96ea59259a2893265d79052bfa8e976f6a9aaf9fb0cce901449f23c18a9e9b238e29161c2d94b5b6fefa046af
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[1]
+aad = 436f756e742d31
+ct = e564b69338613bcdb4f91ed19c3e357c969b5533f90054e708ffa386eb9b92d08aab7d2b106272f5c557167404
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[2]
+aad = 436f756e742d32
+ct = 54ffec11a44e6a015c2c162f402adf98909b44e3fa4176994411ada7934757fd08972fb07bba31d02ef5da3163
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[3]
+aad = 436f756e742d33
+ct = 882ce53fb75aec77052a31c0e64e7e5f00ab76824c9aa105efb785eacedcf2332c9330c0c359ef36ce3828ce9f
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[4]
+aad = 436f756e742d34
+ct = b7ba017c2f31bdc1ce7b69872e89445d6cb1af186b94b9756b77bc5fe780bbc5913ffce67b5c56e4ca3706051f
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[5]
+aad = 436f756e742d35
+ct = f5f867e67d50cf6a66ca6c8c4852d8edff11ba0329c8fd87dce9c678e772e137f3b18244d66617a53b9ba1f1d6
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[6]
+aad = 436f756e742d36
+ct = 53c6b51025b2b13d6375fa6ba125629aaf869b6631ff467ff710dfea74f290a2c97c2492089c07bb11d55c3d25
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[7]
+aad = 436f756e742d37
+ct = 6ed1234bee53fe5f5f40693865affac0c96960f0ff1cc531ac00a26f62d76987941853b10e6443f85551893af1
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[8]
+aad = 436f756e742d38
+ct = 9fb86baa49b26a7a11ecff55dbc8fd83defedad355c0bad3ce56e84b94dc4a5d5e591e10f7f97c6cd8ffe1e95e
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[9]
+aad = 436f756e742d39
+ct = a4ebc70dcc7aab9161e8c180552df7a53c6bf50427a3b099ae31bbd9477a96341f717985d4c794118b4371951a
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[10]
+aad = 436f756e742d3130
+ct = cd5ea01f76c86803cde939da15a3c55202c67264c4058e9d4f6706775f1aa10a5f2b799bdbddba7b5b7f4d8d72
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[11]
+aad = 436f756e742d3131
+ct = c935e4b91398689b1c776889662657a9774be90329248317fcfa45273354903236e5912cb56792aa334e32028c
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[12]
+aad = 436f756e742d3132
+ct = ef7e85eed0b2d2107b8121d2d989c0d2f2a44852f6d7078a10fc500c7b2c48e9c7b9c19d65473b64abe63e8afd
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[13]
+aad = 436f756e742d3133
+ct = 65367f871e9200a87722f259afdee533285e00e879f61d1ce90ad9d4d288b9afb091d2f366afb65737524ea420
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[14]
+aad = 436f756e742d3134
+ct = 10cc0347e05181c5efd1702f694632def82559f8fde72485cbcd8e1477554acac7dfa0d337ce6755dbd714e5bb
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[15]
+aad = 436f756e742d3135
+ct = 0122276c11bc4ca37358f64e277e1027e89f66f0c57e5df071b4ca46bb5826be1f220a0e3884323404eec509f9
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# encryptions[16]
+aad = 436f756e742d3136
+ct = ab9be3a0b6384b7c73f097c519df408e6d42f6d8c479b11c66bbe432d890008d74fbd4d7e51c8978b559ba5a46
+pt = 4265617574792069732074727574682c20747275746820626561757479
+# exports[0]
+exporter_context =
+L = 32
+exported_value = c78ebc7a3064b7274dd5c316d62bb05114a7578b0af79cd856a38d6bcdde72a9
+# exports[1]
+exporter_context = 00
+L = 32
+exported_value = a5d3e6562b1d9cf928620d51a1d5c141045e0ab91af77d2b5d4f9cf9d85813d9
+# exports[2]
+exporter_context = 54657374436f6e74657874
+L = 32
+exported_value = 5fd0d16475885903b6c533a789e2dbe1f8a6088b8424534f9b0922314dd2ae4e
diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h
index ca10731..7ccc6c6 100644
--- a/include/openssl/hpke.h
+++ b/include/openssl/hpke.h
@@ -16,7 +16,7 @@
#define OPENSSL_HEADER_HPKE_H
#include <openssl/aead.h>
-#include <openssl/base.h> // IWYU pragma: export
+#include <openssl/base.h> // IWYU pragma: export
#include <openssl/curve25519.h>
#include <openssl/digest.h>
@@ -42,12 +42,14 @@
// The following constants are KEM identifiers.
#define EVP_HPKE_DHKEM_P256_HKDF_SHA256 0x0010
#define EVP_HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
+#define EVP_HPKE_XWING 0x647a
// 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_p256_hkdf_sha256(void);
+OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_xwing(void);
// EVP_HPKE_KEM_id returns the HPKE KEM identifier for |kem|, which
// will be one of the |EVP_HPKE_KEM_*| constants.
@@ -55,7 +57,7 @@
// 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 65
+#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 1216
// 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|.
@@ -71,7 +73,7 @@
// 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 65
+#define EVP_HPKE_MAX_ENC_LENGTH 1120
// 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|.