use crate::algorithm::Algorithm;
pub mod crypt;
pub mod file;
pub mod header;
pub mod key;
pub mod metadata;
pub mod stream;
pub const ALGORITHM: Algorithm = Algorithm::XChaCha20Poly1305;
#[cfg(test)]
mod tests {
use std::time::{Duration, UNIX_EPOCH};
use crate::{
file::FileMetadata,
memory::{SecureKey, SecureString},
v3::{file::EncryptedFile, key::KeyDerivationParams},
};
fn test_metadata() -> FileMetadata {
FileMetadata::new(
SecureString::new("name.txt".to_string()),
Some(UNIX_EPOCH + Duration::new(1_700_000_000, 500)),
Some(0o640),
)
}
fn derive_test_key(password: &[u8], salt: &[u8; 16]) -> SecureKey {
let (key, _) = KeyDerivationParams::test_defaults()
.derive_key(password, salt)
.unwrap();
key
}
#[test]
fn seal_decrypt_round_trip_via_bytes() {
let salt = [1u8; 16];
let key = derive_test_key(b"password", &salt);
let sealed = EncryptedFile::seal(
&test_metadata(),
b"hello streaming world",
&key,
KeyDerivationParams::test_defaults(),
salt,
[2u8; 16],
[3u8; 24],
)
.unwrap();
let parsed = EncryptedFile::from_bytes(&sealed.to_bytes()).unwrap();
let decrypted = parsed.decrypt(&key).unwrap();
assert_eq!(decrypted.filename().as_str(), "name.txt");
assert_eq!(decrypted.content().as_slice(), b"hello streaming world");
let metadata = parsed.header().decrypt_metadata(&key).unwrap();
assert_eq!(metadata.mtime(), test_metadata().mtime());
assert_eq!(metadata.mode(), Some(0o640));
}
#[test]
fn empty_content_round_trip() {
let salt = [1u8; 16];
let key = derive_test_key(b"password", &salt);
let sealed = EncryptedFile::seal(
&test_metadata(),
b"",
&key,
KeyDerivationParams::test_defaults(),
salt,
[2u8; 16],
[3u8; 24],
)
.unwrap();
let decrypted = EncryptedFile::from_bytes(&sealed.to_bytes())
.unwrap()
.decrypt(&key)
.unwrap();
assert!(decrypted.content().as_slice().is_empty());
}
#[test]
fn seal_decrypt_with_wrong_key_fails() {
let salt = [1u8; 16];
let key = derive_test_key(b"password", &salt);
let wrong_key = derive_test_key(b"wrong", &salt);
let sealed = EncryptedFile::seal(
&test_metadata(),
b"content",
&key,
KeyDerivationParams::test_defaults(),
salt,
[2u8; 16],
[3u8; 24],
)
.unwrap();
assert!(sealed.decrypt(&wrong_key).is_err());
}
#[test]
fn truncated_content_fails() {
let salt = [1u8; 16];
let key = derive_test_key(b"password", &salt);
let sealed = EncryptedFile::seal(
&test_metadata(),
b"some content",
&key,
KeyDerivationParams::test_defaults(),
salt,
[2u8; 16],
[3u8; 24],
)
.unwrap();
let mut bytes = sealed.to_bytes();
bytes.truncate(sealed.header().header_length());
let truncated = EncryptedFile::from_bytes(&bytes).unwrap();
assert!(truncated.decrypt(&key).is_err());
}
}