use anyhow::Context;
use philbin::{
careful::Nonce256,
easy::{AssociatedData, AuthTag256, Ciphertext, Key256, Plaintext},
};
use test_utils::AegisTestCase;
use rstest::rstest;
use similar_asserts::assert_eq;
fn extract_nonce(data: &[u8]) -> anyhow::Result<Nonce256> {
let nonce_array = data
.split_at(Nonce256::BYTES)
.0
.as_array()
.context("data must contain a 32 byte nonce")?;
Ok(Nonce256::new(*nonce_array)?)
}
fn extract_ciphertext_and_tag(data: &[u8]) -> &[u8] {
data.split_at(Nonce256::BYTES).1
}
fn assemble_encrypted_payload(test_case: &AegisTestCase) -> Vec<u8> {
let mut out = vec![
0u8;
test_case.nonce.len()
+ test_case.ciphertext.len()
+ test_case.tag256.len()
];
out[..Nonce256::BYTES].copy_from_slice(&test_case.nonce);
out[Nonce256::BYTES..Nonce256::BYTES + test_case.ciphertext.len()]
.copy_from_slice(&test_case.ciphertext);
out[Nonce256::BYTES + test_case.ciphertext.len()..]
.copy_from_slice(&test_case.tag256);
out
}
#[rstest]
fn roundtrip() -> anyhow::Result<()> {
let plaintext = b"foo bar zoo";
let associated_data = b"moo goo";
let key = Key256::generate()?;
let encrypted_payload = philbin::easy::encrypt(
Plaintext::new(plaintext),
AssociatedData::new(associated_data),
&key,
)?;
let decrypted_plaintext = philbin::easy::decrypt(
Ciphertext::new(&encrypted_payload),
AssociatedData::new(associated_data),
&key,
)?;
assert_eq!(expected: plaintext.as_slice(), actual: decrypted_plaintext);
Ok(())
}
#[rstest]
fn encrypt_basic() -> anyhow::Result<()> {
let test_case = test_utils::aegis256x4::example();
let encrypted_payload = philbin::easy::encrypt(
Plaintext::new(&test_case.plaintext),
AssociatedData::new(&test_case.associated_data),
&Key256::from_bytes(&test_case.key)?,
)?;
assert_ne!(
[0; Nonce256::BYTES],
extract_nonce(&encrypted_payload)?.into_array(),
"nonce is all-zero"
);
let ciphertext_and_tag = philbin::careful::aegis256x4::encrypt::<AuthTag256>(
Plaintext::new(&test_case.plaintext),
AssociatedData::new(&test_case.associated_data),
&Key256::from_bytes(&test_case.key)?,
extract_nonce(&encrypted_payload)?,
)?;
assert_eq!(
expected: ciphertext_and_tag,
actual: extract_ciphertext_and_tag(&encrypted_payload),
"(ciphertext || tag) is wrong");
Ok(())
}
#[rstest]
fn decrypt_basic() -> anyhow::Result<()> {
let test_case = test_utils::aegis256x4::example();
let plaintext = philbin::easy::decrypt(
Ciphertext::new(&assemble_encrypted_payload(&test_case)),
AssociatedData::new(&test_case.associated_data),
&Key256::from_bytes(&test_case.key)?,
)?;
assert_eq!(expected: test_case.plaintext, actual: plaintext);
Ok(())
}