refactor: crypto 改用手写轮子的标准替代,去掉重复的函数内 import

- hex_digest:`"".join([hex(d)[2:].zfill(2) for d in data])` → `data.hex()`。
  前者每字节做一次 hex()+zfill 再拼接,后者是 C 实现;两者输出相同。
- hash_hex_digest:绕道 digest() → hex_digest() 两步,直接 hexdigest()。
- _aes_encrypt / encrypt 里的函数内 import 删除:模块顶部已导入
  Cipher/algorithms/modes/padding,函数内又导一遍纯属冗余;
  base64、secrets 则提到模块顶部(原来每次调用都要走一次 import 查找)。
- PKCS7(128) 保留字面量并加注释:**不要**改写成 algorithms.AES.block_size
  ——它在类型存根里声明为 property 而非 int,pyright 会报 reportArgumentType
  (本次实测踩到,门禁拦下)。

等价性验证:encrypt_params 对固定 payload 的输出 sha1 保持
76e3738f8eab61fcfd1145164ba8e1f91d40ee4f 不变;hex_digest/hash_hex_digest
的输出逐字符相同;并做了 docstring 逐条比对确认无文本误伤。
This commit is contained in:
snowy-yang committed 2026-09-26 14:16:05 +08:00
1 parent bd3a4ac70b
commit d600b6a630
1 file changed
+10 -9
+10 -9
View File
@@ -4,7 +4,9 @@
(自 music_api.py 拆出,行为与原实现一致。)
"""
import base64
import json
import secrets
import urllib.parse
from hashlib import md5
from typing import Any
@@ -22,7 +24,7 @@ class CryptoUtils:
@staticmethod
def hex_digest(data: bytes) -> str:
"""将字节数据转换为十六进制字符串"""
return "".join([hex(d)[2:].zfill(2) for d in data])
return data.hex()
@staticmethod
def hash_digest(text: str) -> bytes:
@@ -32,7 +34,7 @@ class CryptoUtils:
@staticmethod
def hash_hex_digest(text: str) -> str:
"""计算MD5哈希值并转换为十六进制字符串"""
return CryptoUtils.hex_digest(CryptoUtils.hash_digest(text))
return md5(text.encode("utf-8")).hexdigest()
@staticmethod
def encrypt_params(url: str, payload: dict[str, Any]) -> str:
@@ -66,9 +68,11 @@ class WeapiCrypto:
@staticmethod
def _aes_encrypt(text: bytes, key: bytes) -> bytes:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.padding import PKCS7
padder = PKCS7(128).padder()
"""单层 AES-CBC + PKCS7 填充(密钥/IV 由官方 weapi 协议固定)。"""
# PKCS7 以**比特**为单位:AES 分组固定 128 比特(=16 字节)。
# 不要写 algorithms.AES.block_size——它在类型存根里声明为 property 而非 int,
# pyright 会报 reportArgumentType。
padder = padding.PKCS7(128).padder()
padded = padder.update(text) + padder.finalize()
cipher = Cipher(algorithms.AES(key), modes.CBC(WeapiCrypto.AES_IV))
encryptor = cipher.encryptor()
@@ -84,11 +88,8 @@ class WeapiCrypto:
官方协议第二层加密的输入是第一层密文的
**base64 字符串**(两次 AES 各自输出 base64)——93 条版本漏了中间那次
base64,服务端解 params 第一层得到二进制、b64 解码必失败。"""
import base64
import secrets as _secrets
text = json.dumps(payload).encode("utf-8")
secret_key = ''.join(_secrets.choice(WeapiCrypto.SEC_KEY_CHARSET) for _ in range(16))
secret_key = ''.join(secrets.choice(WeapiCrypto.SEC_KEY_CHARSET) for _ in range(16))
first = base64.b64encode(
WeapiCrypto._aes_encrypt(text, WeapiCrypto.AES_KEY)