import pytest from app import crypto def test_round_trip(): data = '{"привет": "мир"}'.encode("utf-8") blob = crypto.encrypt(data, "пароль123") assert crypto.decrypt(blob, "пароль123") == data def test_wrong_password(): blob = crypto.encrypt(b"secret", "правильный") with pytest.raises(crypto.WrongPassword): crypto.decrypt(blob, "неправильный") def test_empty_password_still_works(): blob = crypto.encrypt(b"secret", "") assert crypto.decrypt(blob, "") == b"secret" def test_same_data_gives_different_bytes(): """Соль и nonce случайны, поэтому шифртекст не детерминирован. Это причина, по которой storage сравнивает хеш открытого JSON, а не байты файла — иначе git получал бы новый коммит на каждое сохранение. """ a = crypto.encrypt(b"same", "pw") b = crypto.encrypt(b"same", "pw") assert a != b assert crypto.decrypt(a, "pw") == crypto.decrypt(b, "pw") def test_header_is_authenticated(): """Подмена соли в заголовке ловится как ошибка, а не молча меняет ключ.""" blob = bytearray(crypto.encrypt(b"secret", "pw")) blob[9] ^= 0xFF # первый байт соли with pytest.raises(crypto.WrongPassword): crypto.decrypt(bytes(blob), "pw") def test_tampered_ciphertext_rejected(): blob = bytearray(crypto.encrypt(b"secret", "pw")) blob[-1] ^= 0xFF with pytest.raises(crypto.WrongPassword): crypto.decrypt(bytes(blob), "pw") def test_not_a_vault_file(): with pytest.raises(crypto.UnsupportedFormat): crypto.decrypt(b"\x00" * 100, "pw") def test_truncated_file(): with pytest.raises(crypto.UnsupportedFormat): crypto.decrypt(b"FMDB\x01", "pw") def test_future_format_version_reports_clearly(): blob = bytearray(crypto.encrypt(b"secret", "pw")) blob[4] = 99 with pytest.raises(crypto.UnsupportedFormat, match="новой версией"): crypto.decrypt(bytes(blob), "pw") def test_absurd_scrypt_params_rejected_without_allocating(): """Чужой файл не должен заставить нас выделить гигабайты под scrypt.""" blob = bytearray(crypto.encrypt(b"secret", "pw")) blob[6] = 40 # log2(n) = 40 with pytest.raises(crypto.UnsupportedFormat): crypto.decrypt(bytes(blob), "pw") def test_compression_actually_helps(): data = b'{"bun": "poppy"}' * 500 blob = crypto.encrypt(data, "pw") assert len(blob) < len(data) // 4