"""Tests for utils.crypto — AES-256-GCM encryption and key derivation.""" import os import tempfile import pytest from utils.crypto import ( CryptoEngine, KEY_SIZE, NONCE_SIZE, derive_key, encrypt_file, decrypt_file, HAS_ARGON2, ) class TestCryptoEngine: def test_encrypt_decrypt_roundtrip(self): """Encrypt then decrypt returns the original plaintext.""" key = os.urandom(KEY_SIZE) engine = CryptoEngine(key) plaintext = b"Sensitive credential data: admin:p@ssw0rd!" ciphertext = engine.encrypt(plaintext) # Ciphertext should differ from plaintext assert ciphertext != plaintext # Should include nonce prefix assert len(ciphertext) > len(plaintext) decrypted = engine.decrypt(ciphertext) assert decrypted == plaintext def test_encrypt_file_decrypt_file(self, tmp_path): """encrypt_file() and decrypt_file() round-trip a file correctly.""" src = str(tmp_path / "source.bin") enc = str(tmp_path / "encrypted.bb") dec = str(tmp_path / "decrypted.bin") original_data = os.urandom(4096) with open(src, "wb") as f: f.write(original_data) password = b"test-passphrase-42" # Use pbkdf2 to avoid argon2 dependency issues encrypt_file(src, enc, password, method="pbkdf2") decrypt_file(enc, dec, password, method="pbkdf2") with open(dec, "rb") as f: recovered = f.read() assert recovered == original_data def test_different_keys_fail(self): """Decrypting with a different key raises an error.""" key1 = os.urandom(KEY_SIZE) key2 = os.urandom(KEY_SIZE) engine1 = CryptoEngine(key1) engine2 = CryptoEngine(key2) plaintext = b"secret data" ciphertext = engine1.encrypt(plaintext) with pytest.raises(Exception): engine2.decrypt(ciphertext) def test_key_derivation_argon2(self): """derive_key with argon2id returns a 32-byte key (or falls back to pbkdf2).""" password = b"my-strong-password" salt = os.urandom(16) key = derive_key(password, salt, method="argon2id") assert isinstance(key, bytes) assert len(key) == KEY_SIZE # Same inputs produce the same key key2 = derive_key(password, salt, method="argon2id") assert key == key2 # Different salt produces a different key salt2 = os.urandom(16) key3 = derive_key(password, salt2, method="argon2id") assert key3 != key def test_key_derivation_pbkdf2(self): """derive_key with pbkdf2 returns a 32-byte key.""" password = b"another-password" salt = os.urandom(16) key = derive_key(password, salt, method="pbkdf2") assert isinstance(key, bytes) assert len(key) == KEY_SIZE # Same inputs produce the same key key2 = derive_key(password, salt, method="pbkdf2") assert key == key2 # Different password produces a different key key3 = derive_key(b"different-password", salt, method="pbkdf2") assert key3 != key