use secure_data::algorithm::{AlgorithmPolicy, CryptoAlgorithm};
use secure_data::envelope::{decrypt_for_use, encrypt_for_storage, encrypt_with_policy};
use secure_data::kms::StaticDevKeyProvider;
fn make_provider() -> StaticDevKeyProvider {
StaticDevKeyProvider::new()
}
#[tokio::test]
async fn test_default_algorithm_is_aes256gcm() {
let provider = make_provider();
let plaintext = b"default algorithm test";
let envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
assert_eq!(envelope.algorithm, "AES-256-GCM");
}
#[tokio::test]
async fn test_xchacha20_selected_via_policy() {
let provider = make_provider();
let plaintext = b"xchacha20 policy test";
let policy = AlgorithmPolicy::prefer(CryptoAlgorithm::XChaCha20Poly1305);
let envelope = encrypt_with_policy(plaintext, "test-key", &provider, &policy)
.await
.expect("encryption must succeed");
assert_eq!(envelope.algorithm, "XChaCha20-Poly1305");
}
#[tokio::test]
async fn test_decrypt_old_aes_envelope() {
let provider = make_provider();
let plaintext = b"backward compatibility test";
let envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
let decrypted = decrypt_for_use(&envelope, &provider)
.await
.expect("decryption must succeed");
assert_eq!(decrypted, plaintext);
}
#[tokio::test]
async fn test_decrypt_xchacha_envelope() {
let provider = make_provider();
let plaintext = b"xchacha decrypt test";
let policy = AlgorithmPolicy::prefer(CryptoAlgorithm::XChaCha20Poly1305);
let envelope = encrypt_with_policy(plaintext, "test-key", &provider, &policy)
.await
.expect("encryption must succeed");
let decrypted = decrypt_for_use(&envelope, &provider)
.await
.expect("decryption must succeed");
assert_eq!(decrypted, plaintext);
}
#[tokio::test]
async fn test_unknown_algorithm_rejected() {
let provider = make_provider();
let plaintext = b"unknown algorithm test";
let mut envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
envelope.algorithm = "UNKNOWN-ALGO".to_string();
let result = decrypt_for_use(&envelope, &provider).await;
assert!(result.is_err(), "must reject unknown algorithm");
let err = result.unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("unsupported") || msg.contains("algorithm"),
"error must mention unsupported algorithm, got: {msg}"
);
}
#[tokio::test]
async fn test_algorithm_downgrade_prevented() {
let provider = make_provider();
let plaintext = b"downgrade prevention test";
let policy = AlgorithmPolicy::new(
CryptoAlgorithm::Aes256Gcm,
Some(CryptoAlgorithm::XChaCha20Poly1305),
);
let result = encrypt_with_policy(plaintext, "test-key", &provider, &policy).await;
assert!(
result.is_err(),
"must reject algorithm below policy minimum"
);
let err = result.unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("below") || msg.contains("policy") || msg.contains("minimum"),
"error must indicate policy violation, got: {msg}"
);
}
#[tokio::test]
async fn test_encrypt_with_latest_key_version() {
let provider = make_provider();
let plaintext = b"key version test";
let envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
assert!(!envelope.key_version.is_empty(), "key_version must be set");
}
#[tokio::test]
async fn test_decrypt_with_old_key_version() {
let provider = make_provider();
let plaintext = b"old key version decrypt test";
let envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
let decrypted = decrypt_for_use(&envelope, &provider)
.await
.expect("decryption must succeed");
assert_eq!(decrypted, plaintext);
}
#[tokio::test]
async fn test_unknown_key_version_handled() {
let provider = make_provider();
let plaintext = b"unknown key version test";
let mut envelope = encrypt_for_storage(plaintext, "test-key", &provider)
.await
.expect("encryption must succeed");
envelope.key_version = "v99".to_string();
let result = decrypt_for_use(&envelope, &provider).await;
assert!(result.is_err(), "must reject tampered key version");
}
#[tokio::test]
async fn test_key_rotation_transparent() {
let provider = make_provider();
let plaintext1 = b"first data before rotation";
let env1 = encrypt_for_storage(plaintext1, "test-key", &provider)
.await
.expect("first encryption must succeed");
let plaintext2 = b"second data after rotation";
let env2 = encrypt_for_storage(plaintext2, "test-key", &provider)
.await
.expect("second encryption must succeed");
let dec1 = decrypt_for_use(&env1, &provider)
.await
.expect("first decryption must succeed");
let dec2 = decrypt_for_use(&env2, &provider)
.await
.expect("second decryption must succeed");
assert_eq!(dec1, plaintext1);
assert_eq!(dec2, plaintext2);
}