|
|
|
@ -78,8 +78,10 @@ use alloc::vec::Vec; |
|
|
|
|
/// Supported KEM algorithms with values detailed in RFC 9180.
|
|
|
|
|
#[derive(Clone, Copy)] |
|
|
|
|
pub enum Kem { |
|
|
|
|
#[allow(missing_docs)] |
|
|
|
|
X25519HkdfSha256 = 32, |
|
|
|
|
/// KEM using DHKEM P-256 and HKDF-SHA256.
|
|
|
|
|
P256HkdfSha256 = 16, // 0x0010
|
|
|
|
|
/// KEM using DHKEM X25519 and HKDF-SHA256.
|
|
|
|
|
X25519HkdfSha256 = 32, // 0x0020
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Kem { |
|
|
|
@ -87,11 +89,21 @@ impl Kem { |
|
|
|
|
// Safety: this function returns a pointer to static data.
|
|
|
|
|
unsafe { |
|
|
|
|
match self { |
|
|
|
|
Kem::P256HkdfSha256 => bssl_sys::EVP_hpke_p256_hkdf_sha256(), |
|
|
|
|
Kem::X25519HkdfSha256 => bssl_sys::EVP_hpke_x25519_hkdf_sha256(), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn from_rfc_id(n: u16) -> Option<Kem> { |
|
|
|
|
match n { |
|
|
|
|
n if n == Kem::P256HkdfSha256 as u16 => Some(Self::P256HkdfSha256), |
|
|
|
|
n if n == Kem::X25519HkdfSha256 as u16 => Some(Self::X25519HkdfSha256), |
|
|
|
|
_ => None, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Generate a public and private key for this KEM.
|
|
|
|
|
pub fn generate_keypair(&self) -> (Vec<u8>, Vec<u8>) { |
|
|
|
|
let mut key = scoped::EvpHpkeKey::new(); |
|
|
|
@ -196,13 +208,12 @@ pub struct Params { |
|
|
|
|
|
|
|
|
|
impl Params { |
|
|
|
|
/// New `Params` from KEM, KDF, and AEAD enums.
|
|
|
|
|
pub fn new(_kem: Kem, _kdf: Kdf, aead: Aead) -> Self { |
|
|
|
|
// Safety: EVP_hpke_x25519_hkdf_sha256 and EVP_hpke_hkdf_sha256 just
|
|
|
|
|
// return pointers to static data.
|
|
|
|
|
pub fn new(kem: Kem, _kdf: Kdf, aead: Aead) -> Self { |
|
|
|
|
// Safety: EVP_hpke_hkdf_sha256 just returns pointer to static data.
|
|
|
|
|
unsafe { |
|
|
|
|
Self { |
|
|
|
|
// Only one KEM and KDF are supported thus far.
|
|
|
|
|
kem: bssl_sys::EVP_hpke_x25519_hkdf_sha256(), |
|
|
|
|
kem: kem.as_ffi_ptr(), |
|
|
|
|
// Only one KDF is supported thus far.
|
|
|
|
|
kdf: bssl_sys::EVP_hpke_hkdf_sha256(), |
|
|
|
|
aead: aead.as_ffi_ptr(), |
|
|
|
|
} |
|
|
|
@ -211,11 +222,11 @@ impl Params { |
|
|
|
|
|
|
|
|
|
/// New `Params` from KEM, KDF, and AEAD IDs as detailed in RFC 9180.
|
|
|
|
|
pub fn new_from_rfc_ids(kem_id: u16, kdf_id: u16, aead_id: u16) -> Option<Self> { |
|
|
|
|
let kem = Kem::X25519HkdfSha256; |
|
|
|
|
let kem = Kem::from_rfc_id(kem_id)?; |
|
|
|
|
let kdf = Kdf::HkdfSha256; |
|
|
|
|
let aead = Aead::from_rfc_id(aead_id)?; |
|
|
|
|
|
|
|
|
|
if kem_id != kem as u16 || kdf_id != kdf as u16 { |
|
|
|
|
if kdf_id != kdf as u16 { |
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
Some(Self::new(kem, kdf, aead)) |
|
|
|
@ -439,7 +450,7 @@ impl RecipientContext { |
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod test { |
|
|
|
|
use super::*; |
|
|
|
|
use crate::test_helpers::decode_hex; |
|
|
|
|
use crate::test_helpers::{decode_hex, decode_hex_into_vec}; |
|
|
|
|
|
|
|
|
|
struct TestVector { |
|
|
|
|
kem_id: u16, |
|
|
|
@ -447,9 +458,9 @@ mod test { |
|
|
|
|
aead_id: u16, |
|
|
|
|
info: [u8; 20], |
|
|
|
|
seed_for_testing: [u8; 32], // skEm
|
|
|
|
|
recipient_pub_key: [u8; 32], // pkRm
|
|
|
|
|
recipient_pub_key: Vec<u8>, // pkRm
|
|
|
|
|
recipient_priv_key: [u8; 32], // skRm
|
|
|
|
|
encapsulated_key: [u8; 32], // enc
|
|
|
|
|
encapsulated_key: Vec<u8>, // enc
|
|
|
|
|
plaintext: [u8; 29], // pt
|
|
|
|
|
associated_data: [u8; 7], // aad
|
|
|
|
|
ciphertext: [u8; 45], // ct
|
|
|
|
@ -465,9 +476,9 @@ mod test { |
|
|
|
|
aead_id: 1, |
|
|
|
|
info: decode_hex("4f6465206f6e2061204772656369616e2055726e"), |
|
|
|
|
seed_for_testing: decode_hex("52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736"), |
|
|
|
|
recipient_pub_key: decode_hex("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d"), |
|
|
|
|
recipient_pub_key: decode_hex_into_vec("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d"), |
|
|
|
|
recipient_priv_key: decode_hex("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8"), |
|
|
|
|
encapsulated_key: decode_hex("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"), |
|
|
|
|
encapsulated_key: decode_hex_into_vec("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"), |
|
|
|
|
plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"), |
|
|
|
|
associated_data: decode_hex("436f756e742d30"), |
|
|
|
|
ciphertext: decode_hex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a"), |
|
|
|
@ -484,9 +495,9 @@ mod test { |
|
|
|
|
aead_id: 3, |
|
|
|
|
info: decode_hex("4f6465206f6e2061204772656369616e2055726e"), |
|
|
|
|
seed_for_testing: decode_hex("f4ec9b33b792c372c1d2c2063507b684ef925b8c75a42dbcbf57d63ccd381600"), |
|
|
|
|
recipient_pub_key: decode_hex("4310ee97d88cc1f088a5576c77ab0cf5c3ac797f3d95139c6c84b5429c59662a"), |
|
|
|
|
recipient_pub_key: decode_hex_into_vec("4310ee97d88cc1f088a5576c77ab0cf5c3ac797f3d95139c6c84b5429c59662a"), |
|
|
|
|
recipient_priv_key: decode_hex("8057991eef8f1f1af18f4a9491d16a1ce333f695d4db8e38da75975c4478e0fb"), |
|
|
|
|
encapsulated_key: decode_hex("1afa08d3dec047a643885163f1180476fa7ddb54c6a8029ea33f95796bf2ac4a"), |
|
|
|
|
encapsulated_key: decode_hex_into_vec("1afa08d3dec047a643885163f1180476fa7ddb54c6a8029ea33f95796bf2ac4a"), |
|
|
|
|
plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"), |
|
|
|
|
associated_data: decode_hex("436f756e742d30"), |
|
|
|
|
ciphertext: decode_hex("1c5250d8034ec2b784ba2cfd69dbdb8af406cfe3ff938e131f0def8c8b60b4db21993c62ce81883d2dd1b51a28"), |
|
|
|
@ -495,9 +506,28 @@ mod test { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.3
|
|
|
|
|
fn p256_hkdf_sha256_hkdf_sha256_aes_128_gcm() -> TestVector { |
|
|
|
|
TestVector { |
|
|
|
|
kem_id: 16, |
|
|
|
|
kdf_id: 1, |
|
|
|
|
aead_id: 1, |
|
|
|
|
info: decode_hex("4f6465206f6e2061204772656369616e2055726e"), |
|
|
|
|
seed_for_testing: decode_hex("4270e54ffd08d79d5928020af4686d8f6b7d35dbe470265f1f5aa22816ce860e"), |
|
|
|
|
recipient_pub_key: decode_hex_into_vec("04fe8c19ce0905191ebc298a9245792531f26f0cece2460639e8bc39cb7f706a826a779b4cf969b8a0e539c7f62fb3d30ad6aa8f80e30f1d128aafd68a2ce72ea0"), |
|
|
|
|
recipient_priv_key: decode_hex("f3ce7fdae57e1a310d87f1ebbde6f328be0a99cdbcadf4d6589cf29de4b8ffd2"), |
|
|
|
|
encapsulated_key: decode_hex_into_vec("04a92719c6195d5085104f469a8b9814d5838ff72b60501e2c4466e5e67b325ac98536d7b61a1af4b78e5b7f951c0900be863c403ce65c9bfcb9382657222d18c4"), |
|
|
|
|
plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"), |
|
|
|
|
associated_data: decode_hex("436f756e742d30"),
|
|
|
|
|
ciphertext: decode_hex("5ad590bb8baa577f8619db35a36311226a896e7342a6d836d8b7bcd2f20b6c7f9076ac232e3ab2523f39513434"),
|
|
|
|
|
exporter_context: decode_hex("54657374436f6e74657874"),
|
|
|
|
|
exported_value: decode_hex("d8f1ea7942adbba7412c6d431c62d01371ea476b823eb697e1f6e6cae1dab85a"),
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn all_algorithms() { |
|
|
|
|
let kems = vec![Kem::X25519HkdfSha256]; |
|
|
|
|
let kems = vec![Kem::X25519HkdfSha256, Kem::P256HkdfSha256]; |
|
|
|
|
let kdfs = vec![Kdf::HkdfSha256]; |
|
|
|
|
let aeads = vec![Aead::Aes128Gcm, Aead::Aes256Gcm, Aead::Chacha20Poly1305]; |
|
|
|
|
let plaintext: &[u8] = b"plaintext"; |
|
|
|
@ -579,6 +609,7 @@ mod test { |
|
|
|
|
for test in vec![ |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(), |
|
|
|
|
p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
] { |
|
|
|
|
let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap(); |
|
|
|
|
|
|
|
|
@ -601,6 +632,7 @@ mod test { |
|
|
|
|
for test in vec![ |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(), |
|
|
|
|
p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
] { |
|
|
|
|
let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap(); |
|
|
|
|
|
|
|
|
@ -622,6 +654,7 @@ mod test { |
|
|
|
|
for test in vec![ |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(), |
|
|
|
|
p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(), |
|
|
|
|
] { |
|
|
|
|
let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap(); |
|
|
|
|
|
|
|
|
@ -641,7 +674,8 @@ mod test { |
|
|
|
|
&test.recipient_priv_key, |
|
|
|
|
&test.encapsulated_key, |
|
|
|
|
&test.info, |
|
|
|
|
).unwrap(); |
|
|
|
|
) |
|
|
|
|
.unwrap(); |
|
|
|
|
assert_eq!( |
|
|
|
|
test.exported_value.as_ref(), |
|
|
|
|
recipient_ctx.export(&test.exporter_context, test.exported_value.len()) |
|
|
|
|