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

82 lines
2.9 KiB
Python

"""
RSA 密钥校验的算法边界及失败返回合同。
"""
import base64
from itertools import product
from typing import Optional
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec, ed25519, rsa
from app.foundation.crypto import RSAUtils
@pytest.fixture(scope="module")
def key_pairs() -> dict[str, tuple[str, str]]:
"""
创建两对 RSA 和两种非 RSA 密钥,覆盖算法与身份不匹配的情况。
"""
private_keys = {
"rsa_first": rsa.generate_private_key(public_exponent=65537, key_size=1024),
"rsa_second": rsa.generate_private_key(public_exponent=65537, key_size=1024),
"ec": ec.generate_private_key(ec.SECP256R1()),
"ed25519": ed25519.Ed25519PrivateKey.generate(),
}
result = {}
for name, private_key in private_keys.items():
private_der = private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
public_der = private_key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
result[name] = (
base64.b64encode(private_der).decode("ascii"),
base64.b64encode(public_der).decode("ascii"),
)
return result
@pytest.mark.parametrize(
("private_name", "public_name"),
list(product(("rsa_first", "rsa_second", "ec", "ed25519"), repeat=2)),
)
def test_verify_rsa_keys_requires_matching_rsa_pair(key_pairs, private_name, public_name) -> None:
"""
只有对应的 RSA 公私钥通过;错配或非 RSA 算法均返回 False。
"""
private_key = key_pairs[private_name][0]
public_key = key_pairs[public_name][1]
expected = private_name == public_name and private_name.startswith("rsa_")
assert RSAUtils.verify_rsa_keys(private_key, public_key) is expected
@pytest.mark.parametrize(
("private_key", "public_key"),
[(None, None), ("", ""), ("invalid", None), (None, "invalid"), ("invalid", "invalid")],
)
def test_verify_rsa_keys_rejects_empty_or_invalid_data(
private_key: Optional[str], public_key: Optional[str],
) -> None:
"""
缺少密钥或解码失败时保留 False 返回,不向调用方泄漏解析异常。
"""
assert RSAUtils.verify_rsa_keys(private_key, public_key) is False
@pytest.mark.parametrize("invalid", ["invalid", ""])
def test_verify_rsa_keys_rejects_one_damaged_key(key_pairs, invalid: str) -> None:
"""
任一侧单独损坏时都应失败,即使另一侧仍是可解析的 RSA 密钥。
"""
private_key, public_key = key_pairs["rsa_first"]
assert RSAUtils.verify_rsa_keys(invalid, public_key) is False
assert RSAUtils.verify_rsa_keys(private_key, invalid) is False