mod boxed;
mod error;
use std::borrow::Cow;
use snafu::ensure;
pub use boxed::{BoxedAeadDecryptor, BoxedAeadEncryptor};
pub(crate) use error::InvalidBundleSnafu;
pub use error::UnsealError;
use crate::{
crypto::KeyMatchStrength,
platform::{MaybeSend, MaybeSendSync},
};
pub struct AeadOutput {
pub nonce: Vec<u8>,
pub ciphertext: Vec<u8>,
pub tag: Vec<u8>,
}
#[derive(Debug, Clone, Copy)]
pub struct CipherMatch<'a> {
pub enc: &'a str,
pub kid: Option<&'a str>,
}
pub trait AeadEncryptor: MaybeSendSync {
type Error: crate::Error;
fn enc_algorithm(&self) -> Cow<'_, str>;
fn key_id(&self) -> Option<Cow<'_, str>>;
fn encrypt(
&self,
plaintext: &[u8],
aad: &[u8],
) -> impl Future<Output = Result<AeadOutput, Self::Error>> + MaybeSend;
}
pub trait AeadDecryptor: MaybeSendSync {
type Error: crate::Error;
fn nonce_length(&self) -> usize;
fn tag_length(&self) -> usize;
fn cipher_match(&self, m: &CipherMatch<'_>) -> Option<KeyMatchStrength>;
fn decrypt(
&self,
nonce: &[u8],
ciphertext: &[u8],
tag: &[u8],
aad: &[u8],
) -> impl Future<Output = Result<Vec<u8>, Self::Error>> + MaybeSend;
}
pub trait AeadCipherSelector: MaybeSendSync {
type Encryptor: AeadEncryptor;
fn select_cipher(&self) -> Self::Encryptor;
}
pub trait AeadSealer: AeadEncryptor {
fn seal(
&self,
plaintext: &[u8],
aad: &[u8],
) -> impl Future<Output = Result<Vec<u8>, Self::Error>> + MaybeSend;
}
pub trait AeadUnsealer: AeadDecryptor {
fn unseal(
&self,
bundle: &[u8],
aad: &[u8],
) -> impl Future<Output = Result<Vec<u8>, Self::Error>> + MaybeSend;
}
pub struct AeadV1Sealer<E: AeadEncryptor>(E);
impl<E: AeadEncryptor> AeadV1Sealer<E> {
pub fn new(encryptor: E) -> Self {
Self(encryptor)
}
}
impl<E: AeadEncryptor> AeadEncryptor for AeadV1Sealer<E> {
type Error = E::Error;
fn enc_algorithm(&self) -> Cow<'_, str> {
self.0.enc_algorithm()
}
fn key_id(&self) -> Option<Cow<'_, str>> {
self.0.key_id()
}
async fn encrypt(&self, plaintext: &[u8], aad: &[u8]) -> Result<AeadOutput, Self::Error> {
self.0.encrypt(plaintext, aad).await
}
}
impl<E: AeadEncryptor> AeadSealer for AeadV1Sealer<E> {
async fn seal(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, Self::Error> {
let output = self.encrypt(plaintext, aad).await?;
let mut bundle =
Vec::with_capacity(1 + output.nonce.len() + output.ciphertext.len() + output.tag.len());
bundle.push(0x01);
bundle.extend_from_slice(&output.nonce);
bundle.extend_from_slice(&output.ciphertext);
bundle.extend_from_slice(&output.tag);
Ok(bundle)
}
}
pub struct AeadV1Unsealer<D: AeadDecryptor>(D);
impl<D: AeadDecryptor> AeadV1Unsealer<D> {
pub fn new(decryptor: D) -> Self {
Self(decryptor)
}
}
impl<D: AeadDecryptor> AeadDecryptor for AeadV1Unsealer<D> {
type Error = UnsealError<D::Error>;
fn nonce_length(&self) -> usize {
self.0.nonce_length()
}
fn tag_length(&self) -> usize {
self.0.tag_length()
}
fn cipher_match(&self, m: &CipherMatch<'_>) -> Option<KeyMatchStrength> {
self.0.cipher_match(m)
}
async fn decrypt(
&self,
nonce: &[u8],
ciphertext: &[u8],
tag: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, Self::Error> {
self.0
.decrypt(nonce, ciphertext, tag, aad)
.await
.map_err(Into::into)
}
}
impl<D: AeadDecryptor> AeadUnsealer for AeadV1Unsealer<D> {
async fn unseal(&self, bundle: &[u8], aad: &[u8]) -> Result<Vec<u8>, Self::Error> {
let nonce_len = self.nonce_length();
let tag_len = self.tag_length();
ensure!(
bundle.len() >= 1 + nonce_len + tag_len && bundle[0] == 0x01,
InvalidBundleSnafu
);
let nonce = &bundle[1..=nonce_len];
let tag = &bundle[bundle.len() - tag_len..];
let ciphertext = &bundle[1 + nonce_len..bundle.len() - tag_len];
self.decrypt(nonce, ciphertext, tag, aad).await
}
}