#![allow(missing_docs)]
extern crate alloc;
use alloc::vec::Vec;
mod aead;
mod kdf;
mod kem;
mod labeled;
mod schedule;
mod suite;
#[cfg(test)]
mod tests;
pub use aead::HpkeAead;
pub use kdf::HpkeKdf;
pub use kem::HpkeKem;
pub use schedule::Mode;
pub use suite::CipherSuite;
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum Error {
InvalidKey,
InvalidDhOutput,
DeriveKeyPair,
AeadError,
MessageLimitReached,
ExportOnly,
InvalidEnc,
PskInputsInconsistent,
ExportLengthExceeded,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::InvalidKey => f.write_str("invalid HPKE key"),
Error::InvalidDhOutput => f.write_str("DH output was zero / low-order"),
Error::DeriveKeyPair => f.write_str("DeriveKeyPair exhausted 256 tries"),
Error::AeadError => f.write_str("HPKE AEAD seal/open failed"),
Error::MessageLimitReached => f.write_str("HPKE per-suite message limit reached"),
Error::ExportOnly => f.write_str("HPKE suite is export-only"),
Error::InvalidEnc => f.write_str("HPKE encapsulated key has wrong length"),
Error::PskInputsInconsistent => f.write_str("HPKE psk / psk_id inputs inconsistent"),
Error::ExportLengthExceeded => f.write_str("HPKE export length exceeds KDF maximum"),
}
}
}
impl core::error::Error for Error {}
pub use schedule::{ReceiverContext, SenderContext};
pub fn setup_sender<R: crate::rng::RngCore>(
rng: &mut R,
suite: CipherSuite,
pk_r: &[u8],
info: &[u8],
) -> Result<(Vec<u8>, SenderContext), Error> {
let (shared_secret, enc) = suite.kem.encap(rng, pk_r)?;
let ctx = SenderContext::new(suite, Mode::Base, &shared_secret, info, &[], &[])?;
Ok((enc, ctx))
}
pub fn setup_receiver(
suite: CipherSuite,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
) -> Result<ReceiverContext, Error> {
let shared_secret = suite.kem.decap(enc, sk_r)?;
ReceiverContext::new(suite, Mode::Base, &shared_secret, info, &[], &[])
}
pub fn setup_sender_psk<R: crate::rng::RngCore>(
rng: &mut R,
suite: CipherSuite,
pk_r: &[u8],
info: &[u8],
psk: &[u8],
psk_id: &[u8],
) -> Result<(Vec<u8>, SenderContext), Error> {
let (shared_secret, enc) = suite.kem.encap(rng, pk_r)?;
let ctx = SenderContext::new(suite, Mode::Psk, &shared_secret, info, psk, psk_id)?;
Ok((enc, ctx))
}
pub fn setup_receiver_psk(
suite: CipherSuite,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
psk: &[u8],
psk_id: &[u8],
) -> Result<ReceiverContext, Error> {
let shared_secret = suite.kem.decap(enc, sk_r)?;
ReceiverContext::new(suite, Mode::Psk, &shared_secret, info, psk, psk_id)
}
pub fn setup_sender_auth<R: crate::rng::RngCore>(
rng: &mut R,
suite: CipherSuite,
pk_r: &[u8],
info: &[u8],
sk_s: &[u8],
) -> Result<(Vec<u8>, SenderContext), Error> {
let (shared_secret, enc) = suite.kem.auth_encap(rng, pk_r, sk_s)?;
let ctx = SenderContext::new(suite, Mode::Auth, &shared_secret, info, &[], &[])?;
Ok((enc, ctx))
}
pub fn setup_receiver_auth(
suite: CipherSuite,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
pk_s: &[u8],
) -> Result<ReceiverContext, Error> {
let shared_secret = suite.kem.auth_decap(enc, sk_r, pk_s)?;
ReceiverContext::new(suite, Mode::Auth, &shared_secret, info, &[], &[])
}
#[allow(clippy::too_many_arguments)]
pub fn setup_sender_auth_psk<R: crate::rng::RngCore>(
rng: &mut R,
suite: CipherSuite,
pk_r: &[u8],
info: &[u8],
psk: &[u8],
psk_id: &[u8],
sk_s: &[u8],
) -> Result<(Vec<u8>, SenderContext), Error> {
let (shared_secret, enc) = suite.kem.auth_encap(rng, pk_r, sk_s)?;
let ctx = SenderContext::new(suite, Mode::AuthPsk, &shared_secret, info, psk, psk_id)?;
Ok((enc, ctx))
}
#[allow(clippy::too_many_arguments)]
pub fn setup_receiver_auth_psk(
suite: CipherSuite,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
psk: &[u8],
psk_id: &[u8],
pk_s: &[u8],
) -> Result<ReceiverContext, Error> {
let shared_secret = suite.kem.auth_decap(enc, sk_r, pk_s)?;
ReceiverContext::new(suite, Mode::AuthPsk, &shared_secret, info, psk, psk_id)
}
pub fn seal<R: crate::rng::RngCore>(
rng: &mut R,
suite: CipherSuite,
pk_r: &[u8],
info: &[u8],
aad: &[u8],
pt: &[u8],
) -> Result<(Vec<u8>, Vec<u8>), Error> {
let (enc, mut ctx) = setup_sender(rng, suite, pk_r, info)?;
let ct = ctx.seal(aad, pt)?;
Ok((enc, ct))
}
pub fn open(
suite: CipherSuite,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
aad: &[u8],
ct: &[u8],
) -> Result<Vec<u8>, Error> {
let mut ctx = setup_receiver(suite, enc, sk_r, info)?;
ctx.open(aad, ct)
}