use secrecy::{ExposeSecret, SecretString};
use std::fs;
use std::io::{Read, Write};
use tempfile::tempdir;
use enc_file::{AeadAlg, EncryptOptions, decrypt_bytes, decrypt_file, encrypt_bytes, encrypt_file};
const KIB: usize = 1024;
const MIB: usize = 1024 * 1024;
#[inline]
fn kib(n: usize) -> usize {
n.saturating_mul(KIB)
}
#[inline]
fn mib(n: usize) -> usize {
n.saturating_mul(MIB)
}
fn blake3_32(data: &[u8]) -> [u8; 32] {
let mut out = [0u8; 32];
let hash = blake3::hash(data);
out.copy_from_slice(hash.as_bytes());
out
}
fn blake3_key_from_pw(context: &str, pw: &SecretString) -> [u8; 32] {
blake3::derive_key(context, pw.expose_secret().as_bytes())
}
fn blake3_32_keyed(key: &[u8; 32], data: &[u8]) -> [u8; 32] {
let mut out = [0u8; 32];
let hash = blake3::keyed_hash(key, data);
out.copy_from_slice(hash.as_bytes());
out
}
#[test]
fn keyed_hash_roundtrip_bytes_both_algs() {
let algs = [AeadAlg::XChaCha20Poly1305, AeadAlg::Aes256GcmSiv];
for &alg in &algs {
let msg = {
let mut v = vec![0u8; mib(1) + kib(3)];
for (i, b) in v.iter_mut().enumerate() {
*b = (i as u32).wrapping_mul(2246822519).wrapping_add(3266489917) as u8;
}
v
};
let pw = SecretString::new(format!("keyed-hash-bytes-{alg:?}").into_boxed_str());
let key = blake3_key_from_pw("enc_file/tests/keyed_hash_bytes", &pw);
let expected_keyed = blake3_32_keyed(&key, &msg);
let opts = EncryptOptions {
alg,
..EncryptOptions::default()
};
let ct = encrypt_bytes(&msg, pw.clone(), &opts).unwrap();
let round = decrypt_bytes(&ct, pw).unwrap();
let got_keyed = blake3_32_keyed(&key, &round);
assert_eq!(
got_keyed, expected_keyed,
"keyed blake3 mismatch: alg={alg:?}"
);
assert_eq!(
blake3_32(&round),
blake3_32(&msg),
"unkeyed blake3 mismatch: alg={alg:?}"
);
}
}
#[test]
fn keyed_hash_roundtrip_files_both_algs() {
let algs = [AeadAlg::XChaCha20Poly1305, AeadAlg::Aes256GcmSiv];
for &alg in &algs {
let dir = tempdir().unwrap();
let in_path = dir.path().join("in.bin");
let enc_path = dir.path().join("out.enc");
let back_path = dir.path().join("back.bin");
let mut data = vec![0u8; mib(1)];
for (i, b) in data.iter_mut().enumerate() {
*b = (i as u32).wrapping_mul(2654435761).wrapping_add(1013904223) as u8;
}
fs::File::create(&in_path)
.unwrap()
.write_all(&data)
.unwrap();
let pw = SecretString::new(format!("keyed-hash-bytes-{alg:?}").into_boxed_str());
let key = blake3_key_from_pw("enc_file/tests/keyed_hash_files", &pw);
let expected_keyed = blake3_32_keyed(&key, &data);
let opts = EncryptOptions {
alg,
..EncryptOptions::default()
};
encrypt_file(&in_path, Some(&enc_path), pw.clone(), opts).unwrap();
decrypt_file(&enc_path, Some(&back_path), pw).unwrap();
let mut round = Vec::new();
fs::File::open(&back_path)
.unwrap()
.read_to_end(&mut round)
.unwrap();
let got_keyed = blake3_32_keyed(&key, &round);
assert_eq!(
got_keyed, expected_keyed,
"keyed blake3 mismatch: alg={alg:?}"
);
assert_eq!(
blake3_32(&round),
blake3_32(&data),
"unkeyed blake3 mismatch: alg={alg:?}"
);
}
}