From d600b6a63001b749f4c060a114bed82015144df8 Mon Sep 17 00:00:00 2001 From: snowy-yang <102860110+snowy-yang@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:16:05 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20crypto=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E6=89=8B=E5=86=99=E8=BD=AE=E5=AD=90=E7=9A=84=E6=A0=87=E5=87=86?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=EF=BC=8C=E5=8E=BB=E6=8E=89=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=9A=84=E5=87=BD=E6=95=B0=E5=86=85=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 逐条比对确认无文本误伤。 --- music_api/crypto.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/music_api/crypto.py b/music_api/crypto.py index a445e9b..ca1dc7a 100644 --- a/music_api/crypto.py +++ b/music_api/crypto.py @@ -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)