Files
MoviePilot/tests/test_token_encryption.py
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

68 lines
2.3 KiB
Python

"""
AES 文本加密的 UTF-8 字节填充与既有密文兼容契约。
"""
import base64
import pytest
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from app.application.security.token import aes_decrypt, aes_encrypt
# 公开固定测试材料,不用于真实账户或生产加密。
TEST_KEY = "0123456789abcdef0123456789abcdef"
TEST_IV = b"public-test-iv!!"
@pytest.mark.parametrize("key", [TEST_KEY[:16], TEST_KEY[:24], TEST_KEY])
@pytest.mark.parametrize("text", ["中文", "a中", "中文123", "🎵电影", "é", "中" * 16])
def test_aes_encrypt_uses_utf8_byte_padding(key, text):
"""
多字节文本必须可被既有解密器和独立的 PKCS7 解填充还原。
"""
encrypted = aes_encrypt(text, key)
raw = base64.b64decode(encrypted)
assert aes_decrypt(encrypted, key) == text
assert len(raw[16:]) % AES.block_size == 0
plaintext = AES.new(key.encode(), AES.MODE_CBC, raw[:16]).decrypt(raw[16:])
assert unpad(plaintext, AES.block_size).decode("utf-8") == text
@pytest.mark.parametrize(
("text", "expected"),
[
("MoviePilot", "cHVibGljLXRlc3QtaXYhIZgnVmGhRmHez6IkIjC3wxM="),
("a" * 15, "cHVibGljLXRlc3QtaXYhIaAx+T1J80WDWJTHAY/KalA="),
("a" * 16, "cHVibGljLXRlc3QtaXYhIaSOoHnQHNvUDkzvBGls2ZBLZ/17cnQTjeyp4aiVZKwK"),
("a" * 17, "cHVibGljLXRlc3QtaXYhIaSOoHnQHNvUDkzvBGls2ZCha8byuNUxqZhv6tTohAr4"),
],
)
def test_aes_ascii_ciphertext_matches_legacy_vectors(monkeypatch, text, expected):
"""
固定 IV 后与修复前的 ASCII 密文逐字节对照,覆盖整块前后边界。
"""
monkeypatch.setattr("Crypto.Cipher._mode_cbc.get_random_bytes", lambda _size: TEST_IV)
assert aes_encrypt(text, TEST_KEY) == expected
assert aes_decrypt(expected, TEST_KEY) == text
@pytest.mark.parametrize("key", [TEST_KEY, "invalid"])
def test_empty_aes_text_preserves_early_return(key):
"""
空文本继续直接返回空值,不先校验密钥或创建加密器。
"""
assert aes_encrypt("", key) == ""
assert aes_decrypt("", key) == ""
@pytest.mark.parametrize("text", ["ASCII", "中文"])
def test_aes_invalid_key_still_raises(text):
"""
非空文本使用非法长度密钥时仍向调用方报告错误。
"""
with pytest.raises(ValueError, match="Incorrect AES key length"):
aes_encrypt(text, "invalid")