food-records/tests/test_crypto.py

79 lines
2.6 KiB
Python
Raw Normal View History

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