use crate::{cipher::Cipher, decipher::Decipher, decrypt::Decrypt, encrypt::Encrypt, IntoAad};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Element<T>(pub T);
impl<T> Element<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> From<T> for Element<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T> Encrypt for Element<T>
where
T: Encrypt,
{
fn encrypt_with_aad<'a, C, A>(self, cipher: C, aad: A) -> Result<C::Ok, C::Error>
where
C: Cipher,
A: IntoAad<'a>,
{
self.0
.encrypt_with_aad(cipher, aad.into_aad().for_sequence_element())
}
}
impl<'c, T> Decrypt<'c> for Element<T>
where
T: Decrypt<'c> + 'c,
{
fn decrypt_with_aad<'a, D, A>(decipher: D, aad: A) -> D::Ok<Self>
where
D: Decipher<'c>,
A: IntoAad<'a>,
{
D::map_ok(
T::decrypt_with_aad(decipher, aad.into_aad().for_sequence_element()),
Element,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::{MockCipher, MockDecipher};
use crate::Aad;
#[test]
fn encrypt_binds_the_sequence_element_derivation() {
let cipher = MockCipher::new();
let ct = Element("row")
.encrypt_with_aad(&cipher, "users")
.expect("encryption should succeed");
assert_eq!(ct, b"row");
let expected = Aad::from_slice(b"users").for_sequence_element();
assert_eq!(cipher.captured_aad(), expected.as_bytes());
assert_ne!(cipher.captured_aad(), b"users");
}
#[test]
fn encrypt_with_no_aad_derives_from_the_empty_aad() {
let cipher = MockCipher::new();
Element("row")
.encrypt(&cipher)
.expect("encryption should succeed");
let expected = Aad::empty().for_sequence_element();
assert_eq!(cipher.captured_aad(), expected.as_bytes());
assert_ne!(cipher.captured_aad(), Aad::empty().as_bytes());
}
#[test]
fn decrypt_binds_the_same_derivation_and_rewraps() {
let decipher = MockDecipher::new(b"row");
let got: Element<String> =
Element::decrypt_with_aad(&decipher, "users").expect("decryption should succeed");
assert_eq!(got, Element("row".to_string()));
let expected = Aad::from_slice(b"users").for_sequence_element();
assert_eq!(decipher.captured_aad(), expected.as_bytes());
}
#[test]
fn encrypt_and_decrypt_bind_identical_aad() {
let cipher = MockCipher::new();
Element("row")
.encrypt_with_aad(&cipher, "users")
.expect("encryption should succeed");
let decipher = MockDecipher::new(b"row");
let _: Element<String> =
Element::decrypt_with_aad(&decipher, "users").expect("decryption should succeed");
assert_eq!(cipher.captured_aad(), decipher.captured_aad());
}
}