use crate::{
aead::{Aead, AeadTag},
kdf::Kdf as KdfTrait,
kem::Kem as KemTrait,
op_mode::{OpModeR, OpModeS},
setup::{setup_receiver, setup_sender},
HpkeError,
};
use rand_core::{CryptoRng, RngCore};
pub fn single_shot_seal_in_place_detached<A, Kdf, Kem, R>(
mode: &OpModeS<Kem>,
pk_recip: &Kem::PublicKey,
info: &[u8],
plaintext: &mut [u8],
aad: &[u8],
csprng: &mut R,
) -> Result<(Kem::EncappedKey, AeadTag<A>), HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
R: CryptoRng + RngCore,
{
let (encapped_key, mut aead_ctx) =
setup_sender::<A, Kdf, Kem, R>(mode, pk_recip, info, csprng)?;
let tag = aead_ctx.seal_in_place_detached(plaintext, aad)?;
Ok((encapped_key, tag))
}
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn single_shot_seal<A, Kdf, Kem, R>(
mode: &OpModeS<Kem>,
pk_recip: &Kem::PublicKey,
info: &[u8],
plaintext: &[u8],
aad: &[u8],
csprng: &mut R,
) -> Result<(Kem::EncappedKey, crate::Vec<u8>), HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
R: CryptoRng + RngCore,
{
let (encapped_key, mut aead_ctx) =
setup_sender::<A, Kdf, Kem, R>(mode, pk_recip, info, csprng)?;
let ciphertext = aead_ctx.seal(plaintext, aad)?;
Ok((encapped_key, ciphertext))
}
pub fn single_shot_open_in_place_detached<A, Kdf, Kem>(
mode: &OpModeR<Kem>,
sk_recip: &Kem::PrivateKey,
encapped_key: &Kem::EncappedKey,
info: &[u8],
ciphertext: &mut [u8],
aad: &[u8],
tag: &AeadTag<A>,
) -> Result<(), HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
{
let mut aead_ctx = setup_receiver::<A, Kdf, Kem>(mode, sk_recip, encapped_key, info)?;
aead_ctx.open_in_place_detached(ciphertext, aad, tag)
}
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn single_shot_open<A, Kdf, Kem>(
mode: &OpModeR<Kem>,
sk_recip: &Kem::PrivateKey,
encapped_key: &Kem::EncappedKey,
info: &[u8],
ciphertext: &[u8],
aad: &[u8],
) -> Result<crate::Vec<u8>, HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
{
let mut aead_ctx = setup_receiver::<A, Kdf, Kem>(mode, sk_recip, encapped_key, info)?;
aead_ctx.open(ciphertext, aad)
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[cfg(test)]
mod test {
use super::*;
use crate::{
aead::ChaCha20Poly1305,
kem::Kem as KemTrait,
op_mode::{OpModeR, OpModeS, PskBundle},
test_util::gen_rand_buf,
};
use rand::{rngs::StdRng, SeedableRng};
macro_rules! test_single_shot_correctness {
($test_name:ident, $aead:ty, $kdf:ty, $kem:ty) => {
#[test]
fn $test_name() {
type A = $aead;
type Kdf = $kdf;
type Kem = $kem;
let msg = b"Good night, a-ding ding ding ding ding";
let aad = b"Five four three two one";
let mut csprng = StdRng::from_entropy();
let info = b"why would you think in a million years that that would actually work";
let (psk, psk_id) = (gen_rand_buf(), gen_rand_buf());
let psk_bundle = PskBundle {
psk: &psk,
psk_id: &psk_id,
};
let (sk_sender_id, pk_sender_id) = Kem::gen_keypair(&mut csprng);
let (sk_recip, pk_recip) = Kem::gen_keypair(&mut csprng);
let sender_mode = OpModeS::<Kem>::AuthPsk(
(sk_sender_id, pk_sender_id.clone()),
psk_bundle.clone(),
);
let receiver_mode = OpModeR::<Kem>::AuthPsk(pk_sender_id, psk_bundle);
let (encapped_key, ciphertext) = single_shot_seal::<A, Kdf, Kem, _>(
&sender_mode,
&pk_recip,
info,
msg,
aad,
&mut csprng,
)
.expect("single_shot_seal() failed");
assert!(&ciphertext[..] != &msg[..]);
let decrypted = single_shot_open::<A, Kdf, Kem>(
&receiver_mode,
&sk_recip,
&encapped_key,
info,
&ciphertext,
aad,
)
.expect("single_shot_open() failed");
assert_eq!(&decrypted, &msg);
}
};
}
#[cfg(feature = "secp")]
test_single_shot_correctness!(
test_single_shot_correctness_secp,
ChaCha20Poly1305,
crate::kdf::HkdfSha256,
crate::kem::SecpK256HkdfSha256
);
}