#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
pub use crate::KP;
use crate::errors::UnknownCryptoError;
use crate::hazardous::hpke::MLKEM768_X25519_SHAKE256_CHACHA20;
use crate::hazardous::hpke::ModeBase;
use crate::hazardous::hpke::ModePsk;
pub use crate::hazardous::kem::xwing::{Ciphertext, DecapsulationKey, EncapsulationKey, KeyPair};
#[derive(Debug, PartialEq)]
pub struct HpkeBase(ModeBase<MLKEM768_X25519_SHAKE256_CHACHA20>);
impl HpkeBase {
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn new_sender(
pk_r: &EncapsulationKey,
info: &[u8],
) -> Result<(Self, Ciphertext), UnknownCryptoError> {
let (ctx, enc) = ModeBase::<MLKEM768_X25519_SHAKE256_CHACHA20>::new_sender(pk_r, info)?;
Ok((Self(ctx), enc))
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn new_recipient(
enc: &Ciphertext,
secret_key_r: &DecapsulationKey,
info: &[u8],
) -> Result<Self, UnknownCryptoError> {
Ok(Self(
ModeBase::<MLKEM768_X25519_SHAKE256_CHACHA20>::new_recipient(enc, secret_key_r, info)?,
))
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn seal(&mut self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
let mut out = vec![
0u8;
plaintext
.len()
.checked_add(MLKEM768_X25519_SHAKE256_CHACHA20::NT)
.ok_or(UnknownCryptoError)?
];
self.0.seal(plaintext, aad, &mut out)?;
Ok(out)
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn open(&mut self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
let mut out = vec![
0u8;
ciphertext
.len()
.checked_sub(MLKEM768_X25519_SHAKE256_CHACHA20::NT)
.ok_or(UnknownCryptoError)?
];
self.0.open(ciphertext, aad, &mut out)?;
Ok(out)
}
}
#[derive(Debug, PartialEq)]
pub struct HpkePsk(ModePsk<MLKEM768_X25519_SHAKE256_CHACHA20>);
impl HpkePsk {
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn new_sender(
pk_r: &EncapsulationKey,
info: &[u8],
psk: &[u8],
psk_id: &[u8],
) -> Result<(Self, Ciphertext), UnknownCryptoError> {
let (ctx, enc) =
ModePsk::<MLKEM768_X25519_SHAKE256_CHACHA20>::new_sender(pk_r, info, psk, psk_id)?;
Ok((Self(ctx), enc))
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn new_recipient(
enc: &Ciphertext,
secret_key_r: &DecapsulationKey,
info: &[u8],
psk: &[u8],
psk_id: &[u8],
) -> Result<Self, UnknownCryptoError> {
Ok(Self(
ModePsk::<MLKEM768_X25519_SHAKE256_CHACHA20>::new_recipient(
enc,
secret_key_r,
info,
psk,
psk_id,
)?,
))
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn seal(&mut self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
let mut out = vec![
0u8;
plaintext
.len()
.checked_add(MLKEM768_X25519_SHAKE256_CHACHA20::NT)
.ok_or(UnknownCryptoError)?
];
self.0.seal(plaintext, aad, &mut out)?;
Ok(out)
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn open(&mut self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
let mut out = vec![
0u8;
ciphertext
.len()
.checked_sub(MLKEM768_X25519_SHAKE256_CHACHA20::NT)
.ok_or(UnknownCryptoError)?
];
self.0.open(ciphertext, aad, &mut out)?;
Ok(out)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_basic_roundtrip() {
let recipient_kp = KeyPair::generate().unwrap();
let psk = b"any preshared secret key that is 32 bytes minimum";
let psk_id = b"identifier for psk";
let (mut hpke_sender, enc) =
HpkeBase::new_sender(recipient_kp.public(), b"info parameter").unwrap();
let ct0 = hpke_sender.seal(&[0u8; 16], b"aad parameter 0").unwrap();
let ct1 = hpke_sender.seal(&[1u8; 16], b"aad parameter 1").unwrap();
let ct2 = hpke_sender.seal(&[2u8; 16], b"aad parameter 2").unwrap();
let mut hpke_recipient =
HpkeBase::new_recipient(&enc, recipient_kp.private(), b"info parameter").unwrap();
let pt0 = hpke_recipient.open(&ct0, b"aad parameter 0").unwrap();
let pt1 = hpke_recipient.open(&ct1, b"aad parameter 1").unwrap();
let pt2 = hpke_recipient.open(&ct2, b"aad parameter 2").unwrap();
assert_eq!(&pt0, &[0u8; 16]);
assert_eq!(&pt1, &[1u8; 16]);
assert_eq!(&pt2, &[2u8; 16]);
let (mut hpke_sender, enc) =
HpkePsk::new_sender(recipient_kp.public(), b"info parameter", psk, psk_id).unwrap();
let ct0 = hpke_sender.seal(&[0u8; 16], b"aad parameter 0").unwrap();
let ct1 = hpke_sender.seal(&[1u8; 16], b"aad parameter 1").unwrap();
let ct2 = hpke_sender.seal(&[2u8; 16], b"aad parameter 2").unwrap();
let mut hpke_recipient =
HpkePsk::new_recipient(&enc, recipient_kp.private(), b"info parameter", psk, psk_id)
.unwrap();
let pt0 = hpke_recipient.open(&ct0, b"aad parameter 0").unwrap();
let pt1 = hpke_recipient.open(&ct1, b"aad parameter 1").unwrap();
let pt2 = hpke_recipient.open(&ct2, b"aad parameter 2").unwrap();
assert_eq!(&pt0, &[0u8; 16]);
assert_eq!(&pt1, &[1u8; 16]);
assert_eq!(&pt2, &[2u8; 16]);
}
}