use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::Debug;
use pki_types::FipsStatus;
use zeroize::Zeroize;
use crate::Error;
use crate::error::InvalidMessage;
use crate::msgs::{Codec, ListLength, Reader, TlsListElement};
#[expect(clippy::exhaustive_structs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct HpkeSuite {
pub kem: HpkeKem,
pub sym: HpkeSymmetricCipherSuite,
}
pub trait Hpke: Debug + Send + Sync {
fn seal(
&self,
info: &[u8],
aad: &[u8],
plaintext: &[u8],
pub_key: &HpkePublicKey,
) -> Result<(EncapsulatedSecret, Vec<u8>), Error>;
fn setup_sealer(
&self,
info: &[u8],
pub_key: &HpkePublicKey,
) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error>;
fn open(
&self,
enc: &EncapsulatedSecret,
info: &[u8],
aad: &[u8],
ciphertext: &[u8],
secret_key: &HpkePrivateKey,
) -> Result<Vec<u8>, Error>;
fn setup_opener(
&self,
enc: &EncapsulatedSecret,
info: &[u8],
secret_key: &HpkePrivateKey,
) -> Result<Box<dyn HpkeOpener + 'static>, Error>;
fn generate_key_pair(&self) -> Result<(HpkePublicKey, HpkePrivateKey), Error>;
fn fips(&self) -> FipsStatus {
FipsStatus::Unvalidated
}
fn suite(&self) -> HpkeSuite;
}
pub trait HpkeSealer: Debug + Send + Sync + 'static {
fn seal(&mut self, aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, Error>;
}
pub trait HpkeOpener: Debug + Send + Sync + 'static {
fn open(&mut self, aad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Error>;
}
#[expect(clippy::exhaustive_structs)]
#[derive(Clone, Debug)]
pub struct HpkePublicKey(pub Vec<u8>);
pub struct HpkePrivateKey(Vec<u8>);
impl HpkePrivateKey {
pub fn secret_bytes(&self) -> &[u8] {
self.0.as_slice()
}
}
impl From<Vec<u8>> for HpkePrivateKey {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}
impl Drop for HpkePrivateKey {
#[inline(never)]
fn drop(&mut self) {
self.0.zeroize();
}
}
#[expect(clippy::exhaustive_structs)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct HpkeSymmetricCipherSuite {
pub kdf_id: HpkeKdf,
pub aead_id: HpkeAead,
}
impl Codec<'_> for HpkeSymmetricCipherSuite {
fn encode(&self, bytes: &mut Vec<u8>) {
self.kdf_id.encode(bytes);
self.aead_id.encode(bytes);
}
fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> {
Ok(Self {
kdf_id: HpkeKdf::read(r)?,
aead_id: HpkeAead::read(r)?,
})
}
}
impl TlsListElement for HpkeSymmetricCipherSuite {
const SIZE_LEN: ListLength = ListLength::NonZeroU16 {
empty_error: InvalidMessage::IllegalEmptyList("HpkeSymmetricCipherSuites"),
};
}
enum_builder! {
pub struct HpkeKem(pub u16);
enum HpkeKemName {
DHKEM_P256_HKDF_SHA256 => 0x0010,
DHKEM_P384_HKDF_SHA384 => 0x0011,
DHKEM_P521_HKDF_SHA512 => 0x0012,
DHKEM_X25519_HKDF_SHA256 => 0x0020,
DHKEM_X448_HKDF_SHA512 => 0x0021,
}
}
enum_builder! {
pub struct HpkeKdf(pub u16);
enum HpkeKdfName {
HKDF_SHA256 => 0x0001,
HKDF_SHA384 => 0x0002,
HKDF_SHA512 => 0x0003,
}
}
impl Default for HpkeKdf {
fn default() -> Self {
Self::HKDF_SHA256
}
}
enum_builder! {
pub struct HpkeAead(pub u16);
enum HpkeAeadName {
AES_128_GCM => 0x0001,
AES_256_GCM => 0x0002,
CHACHA20_POLY_1305 => 0x0003,
EXPORT_ONLY => 0xFFFF,
}
}
impl Default for HpkeAead {
fn default() -> Self {
Self::AES_128_GCM
}
}
impl HpkeAead {
pub(crate) fn tag_len(&self) -> Option<usize> {
match *self {
Self::AES_128_GCM | Self::AES_256_GCM | Self::CHACHA20_POLY_1305 => Some(16),
_ => None,
}
}
}
#[expect(clippy::exhaustive_structs)]
pub struct HpkeKeyPair {
pub public_key: HpkePublicKey,
pub private_key: HpkePrivateKey,
}
#[expect(clippy::exhaustive_structs)]
#[derive(Debug)]
pub struct EncapsulatedSecret(pub Vec<u8>);