use oxidize_pdf::encryption::{EncryptionKey, StandardSecurityHandler};
use oxidize_pdf::objects::ObjectId;
#[test]
fn test_compute_object_key_simple() {
let handler = StandardSecurityHandler::rc4_40bit();
let base_key = EncryptionKey::new(vec![0x01, 0x02, 0x03, 0x04, 0x05]); let obj_id = ObjectId::new(1, 0);
let obj_key = handler.compute_object_key(&base_key, &obj_id);
assert_eq!(
obj_key.len(),
10,
"Object key should be 10 bytes for RC4-40"
);
let obj_key2 = handler.compute_object_key(&base_key, &obj_id);
assert_eq!(
obj_key, obj_key2,
"Object key computation should be deterministic"
);
}
#[test]
fn test_compute_object_key_different_objects() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xAA; 16]); let obj_id1 = ObjectId::new(5, 0);
let obj_id2 = ObjectId::new(10, 0);
let key1 = handler.compute_object_key(&base_key, &obj_id1);
let key2 = handler.compute_object_key(&base_key, &obj_id2);
assert_ne!(key1, key2, "Different objects should have different keys");
}
#[test]
fn test_compute_object_key_with_generation_number() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xBB; 16]);
let obj_id = ObjectId::new(10, 5);
let obj_key = handler.compute_object_key(&base_key, &obj_id);
let obj_id_gen0 = ObjectId::new(10, 0);
let key_gen0 = handler.compute_object_key(&base_key, &obj_id_gen0);
assert_ne!(
obj_key, key_gen0,
"Generation number should affect object key"
);
assert_eq!(
obj_key.len(),
16,
"RC4-128 object key should be 16 bytes (capped at 16)"
);
}
#[test]
fn test_decrypt_string_rc4_40bit() {
let handler = StandardSecurityHandler::rc4_40bit();
let base_key = EncryptionKey::new(vec![0x12, 0x34, 0x56, 0x78, 0x9A]);
let obj_id = ObjectId::new(1, 0);
let plaintext = b"Hello PDF";
let encrypted = handler.encrypt_string(plaintext, &base_key, &obj_id);
assert_ne!(
encrypted.as_slice(),
plaintext,
"Encrypted should differ from plaintext"
);
let decrypted = handler.decrypt_string(&encrypted, &base_key, &obj_id);
assert_eq!(
decrypted.as_slice(),
plaintext,
"Decryption should recover plaintext"
);
}
#[test]
fn test_decrypt_string_rc4_128bit() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xFF; 16]);
let obj_id = ObjectId::new(5, 0);
let plaintext = b"This is a longer PDF string with special chars: \xE9\xE8\xE7";
let encrypted = handler.encrypt_string(plaintext, &base_key, &obj_id);
let decrypted = handler.decrypt_string(&encrypted, &base_key, &obj_id);
assert_eq!(decrypted.as_slice(), plaintext);
}
#[test]
fn test_decrypt_empty_string() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xAA; 16]);
let obj_id = ObjectId::new(1, 0);
let encrypted = handler.encrypt_string(b"", &base_key, &obj_id);
let decrypted = handler.decrypt_string(&encrypted, &base_key, &obj_id);
assert_eq!(decrypted.len(), 0, "Empty string should decrypt to empty");
}
#[test]
fn test_decrypt_stream_rc4_128bit() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0x33; 16]);
let obj_id = ObjectId::new(10, 0);
let stream_data = b"BT /F1 12 Tf 100 700 Td (Hello World) Tj ET";
let encrypted = handler.encrypt_stream(stream_data, &base_key, &obj_id);
assert_ne!(encrypted.as_slice(), stream_data);
let decrypted = handler.decrypt_stream(&encrypted, &base_key, &obj_id);
assert_eq!(decrypted.as_slice(), stream_data);
}
#[test]
fn test_decrypt_large_stream() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0x55; 16]);
let obj_id = ObjectId::new(20, 1);
let large_data = vec![0x42; 10000]; let encrypted = handler.encrypt_stream(&large_data, &base_key, &obj_id);
let decrypted = handler.decrypt_stream(&encrypted, &base_key, &obj_id);
assert_eq!(decrypted, large_data);
}
#[test]
fn test_decrypt_indirect_string() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0x77; 16]);
let obj_id = ObjectId::new(5, 0);
let plaintext = b"This is an indirect string object";
let encrypted = handler.encrypt_string(plaintext, &base_key, &obj_id);
let decrypted = handler.decrypt_string(&encrypted, &base_key, &obj_id);
assert_eq!(decrypted.as_slice(), plaintext);
let wrong_obj_id = ObjectId::new(6, 0);
let wrong_decrypt = handler.decrypt_string(&encrypted, &base_key, &wrong_obj_id);
assert_ne!(
wrong_decrypt.as_slice(),
plaintext,
"Wrong object ID should fail"
);
}
#[test]
fn test_do_not_decrypt_stream_with_identity_filter() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xAA; 16]);
let obj_id = ObjectId::new(15, 0);
let stream_data = b"Unencrypted stream data";
let filter_name = "Identity";
let result = if filter_name == "Identity" {
stream_data.to_vec()
} else {
handler.decrypt_stream(stream_data, &base_key, &obj_id)
};
assert_eq!(
result.as_slice(),
stream_data,
"Identity filter should not decrypt"
);
}
#[test]
fn test_rc4_encryption_is_symmetric() {
let handler = StandardSecurityHandler::rc4_128bit();
let base_key = EncryptionKey::new(vec![0xCC; 16]);
let obj_id = ObjectId::new(1, 0);
let plaintext = b"RC4 encryption is symmetric";
let encrypted = handler.encrypt_string(plaintext, &base_key, &obj_id);
let double_encrypted = handler.encrypt_string(&encrypted, &base_key, &obj_id);
assert_eq!(
double_encrypted.as_slice(),
plaintext,
"RC4 is symmetric - double encryption = decryption"
);
}