use corteq::encryption::{EncryptedData, EncryptionService};
use corteq::TenantContext;
use uuid::Uuid;
fn create_tenant_context(tenant_id: Uuid, encryption_key: &str) -> TenantContext {
TenantContext::new(
tenant_id,
"test-tenant".to_string(),
encryption_key.to_string(),
)
}
#[test]
fn test_encryption_basic_round_trip() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "test-encryption-key-32-bytes!!");
let service = EncryptionService::new();
let plaintext = b"Hello, World! This is sensitive data.";
let encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encryption should succeed");
assert_ne!(encrypted.ciphertext(), plaintext);
assert!(!encrypted.ciphertext().is_empty());
let decrypted = service
.decrypt(&encrypted, &tenant_ctx)
.expect("Decryption should succeed");
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encryption_different_tenants_different_keys() {
let tenant1_id = Uuid::new_v4();
let tenant2_id = Uuid::new_v4();
let tenant1_ctx = create_tenant_context(tenant1_id, "tenant1-key-32-bytes-long!!!!");
let tenant2_ctx = create_tenant_context(tenant2_id, "tenant2-key-32-bytes-long!!!!");
let service = EncryptionService::new();
let plaintext = b"Shared secret message";
let encrypted1 = service
.encrypt(plaintext, &tenant1_ctx)
.expect("Encryption with tenant 1 key should succeed");
let encrypted2 = service
.encrypt(plaintext, &tenant2_ctx)
.expect("Encryption with tenant 2 key should succeed");
assert_ne!(encrypted1.ciphertext(), encrypted2.ciphertext());
let decrypted1 = service
.decrypt(&encrypted1, &tenant1_ctx)
.expect("Tenant 1 should decrypt their own data");
assert_eq!(decrypted1, plaintext);
let decrypted2 = service
.decrypt(&encrypted2, &tenant2_ctx)
.expect("Tenant 2 should decrypt their own data");
assert_eq!(decrypted2, plaintext);
let cross_decrypt_result = service.decrypt(&encrypted2, &tenant1_ctx);
assert!(
cross_decrypt_result.is_err(),
"Tenant 1 should NOT be able to decrypt tenant 2's data"
);
let cross_decrypt_result = service.decrypt(&encrypted1, &tenant2_ctx);
assert!(
cross_decrypt_result.is_err(),
"Tenant 2 should NOT be able to decrypt tenant 1's data"
);
}
#[test]
fn test_encryption_detects_tampering() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "test-tamper-key-32-bytes-long!");
let service = EncryptionService::new();
let plaintext = b"Original message";
let mut encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encryption should succeed");
let mut tampered_ciphertext = encrypted.ciphertext().to_vec();
if !tampered_ciphertext.is_empty() {
tampered_ciphertext[0] ^= 0xFF; }
encrypted.set_ciphertext(tampered_ciphertext);
let result = service.decrypt(&encrypted, &tenant_ctx);
assert!(result.is_err(), "Decryption of tampered data should fail");
}
#[test]
fn test_encryption_nonce_uniqueness() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "nonce-test-key-32-bytes-long!");
let service = EncryptionService::new();
let plaintext = b"Same plaintext";
let encrypted1 = service
.encrypt(plaintext, &tenant_ctx)
.expect("First encryption should succeed");
let encrypted2 = service
.encrypt(plaintext, &tenant_ctx)
.expect("Second encryption should succeed");
let encrypted3 = service
.encrypt(plaintext, &tenant_ctx)
.expect("Third encryption should succeed");
assert_ne!(encrypted1.nonce(), encrypted2.nonce());
assert_ne!(encrypted2.nonce(), encrypted3.nonce());
assert_ne!(encrypted1.nonce(), encrypted3.nonce());
assert_ne!(encrypted1.ciphertext(), encrypted2.ciphertext());
assert_ne!(encrypted2.ciphertext(), encrypted3.ciphertext());
let decrypted1 = service
.decrypt(&encrypted1, &tenant_ctx)
.expect("Decrypt 1");
let decrypted2 = service
.decrypt(&encrypted2, &tenant_ctx)
.expect("Decrypt 2");
let decrypted3 = service
.decrypt(&encrypted3, &tenant_ctx)
.expect("Decrypt 3");
assert_eq!(decrypted1, plaintext);
assert_eq!(decrypted2, plaintext);
assert_eq!(decrypted3, plaintext);
}
#[test]
fn test_encryption_empty_data() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "empty-test-key-32-bytes-long!");
let service = EncryptionService::new();
let plaintext = b"";
let encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encrypting empty data should succeed");
let decrypted = service
.decrypt(&encrypted, &tenant_ctx)
.expect("Decrypting empty data should succeed");
assert_eq!(decrypted, plaintext);
assert!(decrypted.is_empty());
}
#[test]
fn test_encryption_large_data() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "large-data-key-32-bytes-long!");
let service = EncryptionService::new();
let plaintext = vec![0xAB; 1024 * 1024];
let encrypted = service
.encrypt(&plaintext, &tenant_ctx)
.expect("Encrypting large data should succeed");
let decrypted = service
.decrypt(&encrypted, &tenant_ctx)
.expect("Decrypting large data should succeed");
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encryption_key_derivation_consistent() {
let tenant_id = Uuid::new_v4();
let encryption_key = "consistent-key-32-bytes-long!";
let tenant_ctx = create_tenant_context(tenant_id, encryption_key);
let service = EncryptionService::new();
let plaintext = b"Test message";
let encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encryption should succeed");
let service2 = EncryptionService::new();
let tenant_ctx2 = create_tenant_context(tenant_id, encryption_key);
let decrypted = service2
.decrypt(&encrypted, &tenant_ctx2)
.expect("Decryption with new service should succeed");
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encryption_invalid_nonce_length() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "invalid-nonce-key-32-bytes-lo!");
let service = EncryptionService::new();
let plaintext = b"Test";
let mut encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encryption should succeed");
let invalid_nonce = vec![0u8; 8]; encrypted.set_nonce(invalid_nonce);
let result = service.decrypt(&encrypted, &tenant_ctx);
assert!(
result.is_err(),
"Decryption with invalid nonce length should fail"
);
}
#[test]
fn test_encryption_serialization() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "serialization-key-32-bytes-lo!");
let service = EncryptionService::new();
let plaintext = b"Data to serialize";
let encrypted = service
.encrypt(plaintext, &tenant_ctx)
.expect("Encryption should succeed");
let serialized = encrypted.to_bytes();
assert!(!serialized.is_empty());
let deserialized =
EncryptedData::from_bytes(&serialized).expect("Deserialization should succeed");
assert_eq!(deserialized.nonce(), encrypted.nonce());
assert_eq!(deserialized.ciphertext(), encrypted.ciphertext());
let decrypted = service
.decrypt(&deserialized, &tenant_ctx)
.expect("Decryption after serialization should succeed");
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encryption_utf8_text() {
let tenant_id = Uuid::new_v4();
let tenant_ctx = create_tenant_context(tenant_id, "utf8-test-key-32-bytes-long!!");
let service = EncryptionService::new();
let plaintext = "Hello δΈη! π¦ Emoji and unicode ζ₯ζ¬θͺ";
let encrypted = service
.encrypt(plaintext.as_bytes(), &tenant_ctx)
.expect("Encryption should succeed");
let decrypted = service
.decrypt(&encrypted, &tenant_ctx)
.expect("Decryption should succeed");
let decrypted_text = String::from_utf8(decrypted).expect("Should be valid UTF-8");
assert_eq!(decrypted_text, plaintext);
}
#[test]
fn test_encryption_wrong_key_fails() {
let tenant_id = Uuid::new_v4();
let tenant_ctx1 = create_tenant_context(tenant_id, "correct-key-32-bytes-long!!!");
let tenant_ctx2 = create_tenant_context(tenant_id, "wrong-key-32-bytes-long!!!!!");
let service = EncryptionService::new();
let plaintext = b"Secret data";
let encrypted = service
.encrypt(plaintext, &tenant_ctx1)
.expect("Encryption should succeed");
let result = service.decrypt(&encrypted, &tenant_ctx2);
assert!(
result.is_err(),
"Decryption with wrong key should fail even for same tenant"
);
}