This commit is contained in:
eric
2026-03-31 07:04:37 -05:00
parent 5a5b4d1beb
commit 1f7894c768
9 changed files with 705 additions and 0 deletions

62
crypto_utils.py Normal file
View File

@@ -0,0 +1,62 @@
import base64
import hashlib
from typing import Tuple
from Crypto.Cipher import AES
BLOCK_SIZE = 32 # PKCS5/PKCS7 padding 使用 32 字节块大小
def pkcs5_unpadding(data: bytes) -> bytes:
pad = data[-1]
if pad < 1 or pad > 32:
return data
return data[:-pad]
def pkcs5_padding(data: bytes) -> bytes:
amount_to_pad = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
return data + bytes([amount_to_pad]) * amount_to_pad
def get_aes_key_and_iv(encoding_aes_key: str) -> Tuple[bytes, bytes]:
"""
encoding_aes_key 是平台给的 43 位字符串,需要先补一个 '=' 再 base64 解码。
得到 32 字节 key前 16 字节为 iv。
"""
aes_key = base64.b64decode(encoding_aes_key + "=")
if len(aes_key) != 32:
raise ValueError("encodingAESKey 无效,解码后长度不是 32 字节")
iv = aes_key[:16]
return aes_key, iv
def aes_decrypt_base64(cipher_b64: str, encoding_aes_key: str) -> str:
aes_key, iv = get_aes_key_and_iv(encoding_aes_key)
cipher_bytes = base64.b64decode(cipher_b64)
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(cipher_bytes)
decrypted = pkcs5_unpadding(decrypted)
return decrypted.decode("utf-8")
def aes_encrypt_base64(plaintext: str, encoding_aes_key: str) -> str:
aes_key, iv = get_aes_key_and_iv(encoding_aes_key)
data = plaintext.encode("utf-8")
padded = pkcs5_padding(data)
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
return base64.b64encode(encrypted).decode("utf-8")
def calc_signature(token: str, timestamp: int, skill_name: str, intent_name: str, query: str) -> str:
"""
文档签名算法:
str = token + time.Now.Unix + skill_name + intent_name + query
signature = MD5(str) 小写 hex
参考https://developers.weixin.qq.com/doc/aispeech/confapi/thirdapi/thirdapi.html
"""
s = f"{token}{timestamp}{skill_name}{intent_name}{query}"
return hashlib.md5(s.encode("utf-8")).hexdigest()