Files
7z-encrypt/tests/test_crypto.py
T

97 lines
3.1 KiB
Python

"""crypto 模块行为测试 (真实加密/解密/篡改, 非 mock)
运行: cd /home/lou/文档/7z-encrypt && .venv/bin/python -m unittest discover -v
"""
import io
import os
import sys
import tempfile
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from crypto import CryptoEngine, CryptoError, IntegrityError, KeyNotFoundError
class TestKeyring(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
self.kr = os.path.join(self._td.name, 'keyring.json')
self.eng = CryptoEngine(self.kr)
def test_generate_and_persist(self):
k1 = self.eng.generate_key('k')
self.assertEqual(len(k1), 32)
self.assertTrue(os.path.exists(self.kr))
self.assertEqual(oct(os.stat(self.kr).st_mode & 0o777), '0o600')
# 重新实例化读回同一密钥 (持久化)
eng2 = CryptoEngine(self.kr)
self.assertEqual(eng2.get_key('k'), k1)
def test_no_overwrite(self):
self.eng.generate_key('k')
with self.assertRaises(CryptoError):
self.eng.generate_key('k')
def test_unknown_key(self):
with self.assertRaises(KeyNotFoundError):
self.eng.get_key('nope')
class TestRoundTrip(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
self.eng = CryptoEngine(os.path.join(self._td.name, 'keyring.json'))
self.eng.generate_key('k')
def _roundtrip(self, data: bytes):
enc = io.BytesIO()
params = self.eng.encrypt_stream(io.BytesIO(data), enc, 'k')
enc.seek(0)
dec = io.BytesIO()
self.eng.decrypt_stream(enc, dec, 'k')
self.assertEqual(dec.getvalue(), data)
return params
def test_empty(self):
self._roundtrip(b'')
def test_small(self):
self._roundtrip(b'hello')
def test_cross_block(self):
# 跨 16KiB 块边界
self._roundtrip(b'x' * 16385)
def test_multi_mb_random(self):
self._roundtrip(os.urandom(5 << 20))
def test_params(self):
params = self._roundtrip(b'z')
self.assertEqual(params['alg'], 'cobblestone-aes256gcm')
self.assertEqual(params['key_id'], 'k')
self.assertEqual(params['context'], '7z-encrypt:v1')
class TestTamper(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory(prefix='hermes-test-')
self.addCleanup(self._td.cleanup)
self.eng = CryptoEngine(os.path.join(self._td.name, 'keyring.json'))
self.eng.generate_key('k')
def test_tamper_detected(self):
data = b'y' * 100000
enc = io.BytesIO()
self.eng.encrypt_stream(io.BytesIO(data), enc, 'k')
bad = bytearray(enc.getvalue())
bad[len(bad) // 2] ^= 0xFF
with self.assertRaises(IntegrityError):
self.eng.decrypt_stream(io.BytesIO(bytes(bad)), io.BytesIO(), 'k')
if __name__ == '__main__':
unittest.main()