Files
llm-api-keygen/tests/test_core_enhanced.py
drd_vic 0e20e4375a fix: 增强密钥强度检测逻辑并修复解密异常处理
增强API密钥强度检测算法,综合评估字符集熵值和实际字符多样性,避免低复杂度密钥通过验证。同时改进解密功能的错误处理,统一异常类型。

主要改进:
- 新增字符多样性检测,防止全重复字符的弱密钥通过验证
- 修正熵值计算逻辑,基于原始字符集而非密钥实际字符分布
- 增强解密函数异常处理,统一抛出InvalidToken异常类型
- 更新测试用例以匹配新的强校验逻辑

技术细节:
- check_key_strength函数新增min_diversity、charset、exclude_ambiguous参数
- 解密时捕获UnicodeDecodeError并转换为InvalidToken
- 测试代码配合新逻辑调整断言和参数传递
2025-11-30 20:48:34 +08:00

121 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import pytest
import string
from llmapikeygen import (
generate_api_key, generate_batch, check_key_strength,
encrypt_key, decrypt_key, PYDANTIC_AVAILABLE, CRYPTOGRAPHY_AVAILABLE
)
# 跳过整个文件(如果依赖未安装)
pytestmark = [
pytest.mark.skipif(not PYDANTIC_AVAILABLE, reason="Pydantic not installed"),
pytest.mark.skipif(not CRYPTOGRAPHY_AVAILABLE, reason="Cryptography not installed"),
]
def test_generate_api_key_pydantic_validation():
"""测试 pydantic 参数校验"""
# 长度小于最小值8
with pytest.raises(ValueError) as excinfo:
generate_api_key(length=7)
assert "Length must be ≥ 8" in str(excinfo.value) or "至少8个字符" in str(excinfo.value)
# 前缀为空字符串
with pytest.raises(ValueError) as excinfo:
generate_api_key(prefix="")
assert "Prefix cannot be empty" in str(excinfo.value) or "前缀不能为空" in str(excinfo.value)
# 前缀仅含空格
with pytest.raises(ValueError) as excinfo:
generate_api_key(prefix=" ")
assert "Prefix cannot be empty" in str(excinfo.value) or "前缀不能为空" in str(excinfo.value)
def test_generate_api_key_use_crypto():
"""测试使用 cryptography 增强随机性"""
# 单密钥生成
key1 = generate_api_key(length=32, use_crypto=True)
assert len(key1) == len("sk-") + 32
# 批量生成(确保不重复)
batch = generate_batch(count=10, use_crypto=True)
assert len(set(batch)) == 10
# 不同字符集下的兼容性
key_charset = generate_api_key(charset=string.ascii_lowercase, use_crypto=True)
assert all(c in string.ascii_lowercase for c in key_charset[3:])
def test_check_key_strength_crypto_enhanced():
"""测试 cryptography 增强的密钥强度检测"""
# 生成高强度密钥
key = generate_api_key(length=64, use_crypto=True)
is_secure, msg = check_key_strength(key)
assert is_secure
assert "合格" in msg
# 边缘情况熵值刚好达标修改部分传递charset和exclude_ambiguous参数
charset = string.ascii_letters[:16] # 原始字符集a-p16种
# 生成时关闭exclude_ambiguous避免排除o字符确保字符集大小=16
key_marginal = generate_api_key(
charset=charset,
exclude_ambiguous=False, # 关闭易混淆字符排除
length=32
)
is_secure, msg = check_key_strength(
key_marginal,
min_entropy=4.0,
charset=charset, # 传递原始字符集
exclude_ambiguous=False # 与生成时一致
)
assert is_secure
def test_encrypt_decrypt_key_basic():
"""测试密钥加密和解密"""
# 普通密钥加密解密
key = generate_api_key()
encrypted_key, secret_key = encrypt_key(key)
# 断言加密后的数据非空
assert isinstance(encrypted_key, bytes) and len(encrypted_key) > 0
assert isinstance(secret_key, bytes) and len(secret_key) > 0
# 解密后与原密钥一致
decrypted_key = decrypt_key(encrypted_key, secret_key)
assert decrypted_key == key
def test_encrypt_decrypt_custom_secret_key():
"""测试自定义加密密钥"""
from cryptography.fernet import Fernet
# 自定义 secret_key需符合 Fernet 格式)
custom_secret_key = Fernet.generate_key()
key = "sk-custom-1234567890abcdef"
# 用自定义密钥加密
encrypted_key, secret_key = encrypt_key(key, secret_key=custom_secret_key)
assert secret_key == custom_secret_key # 返回的密钥与自定义一致
# 解密
decrypted_key = decrypt_key(encrypted_key, custom_secret_key)
assert decrypted_key == key
def test_encrypt_decrypt_special_key():
"""测试含特殊字符的密钥加密解密"""
# 含特殊符号的密钥
special_key = "sk-!@#$%^&*()_+-=[]{}|;:,.?~`1234"
encrypted_key, secret_key = encrypt_key(special_key)
decrypted_key = decrypt_key(encrypted_key, secret_key)
assert decrypted_key == special_key
# 长密钥128位主体
long_key = generate_api_key(length=128)
encrypted_long, secret_long = encrypt_key(long_key)
decrypted_long = decrypt_key(encrypted_long, secret_long)
assert decrypted_long == long_key
def test_generate_batch_use_crypto():
"""测试批量生成(启用 cryptography"""
batch = generate_batch(count=5, length=24, use_crypto=True)
assert len(batch) == 5
for key in batch:
assert len(key) == len("sk-") + 24
# 强度检测合格
is_secure, _ = check_key_strength(key)
assert is_secure