You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python cryptography重写Crypto-JS的AES解密代码?

Crypto-JS AES解密代码转Python cryptography实现方案

原JS代码逻辑

const data = 'base 64 encoded encrypted data';
const salt = 'XB7sHH26Hn&FmPLxnjGccKTfPV(yk';
const pass = '.. password ..';
// CryptoJS.PBKDF2默认生成256位密钥,转十六进制字符串后拼接固定字符
const psw = `${CryptoJS.PBKDF2(pass, salt)}(tXntTbJFzh]4EuQVmjzM9GXHCth8`;
// 传入字符串密码,CryptoJS自动用EVP_BytesToKey派生密钥和IV进行解密
let plaintext = CryptoJS.AES.decrypt(data, psw).toString(CryptoJS.enc.Utf8);

你的Python代码问题分析

你目前遇到的三个问题及原因:

  • 问题1:Crypto-JS中WordArray(PBKDF2返回值)在模板字符串中会自动调用toString(),默认输出十六进制字符串,你的这个判断是正确的。
  • 问题2:Crypto-JS调用AES.decrypt(data, 字符串密码)时,不会直接用该字符串做密钥,而是通过EVP_BytesToKey算法(MD5哈希、1次迭代、无盐)生成AES密钥和IV,默认对应AES-256(32字节密钥+16字节IV)。
  • 问题3:你直接将拼接后的长字符串作为AES密钥,而AES仅支持16/24/32字节密钥(对应128/192/256位),61字节的密钥自然不符合要求。

修正后的Python代码

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import base64
import hashlib

def evp_bytes_to_key(password, key_len, iv_len):
    """实现OpenSSL EVP_BytesToKey算法,MD5哈希、1次迭代、无盐"""
    password_bytes = password.encode('utf-8')
    key = b''
    iv = b''
    tmp = b''
    while len(key) < key_len or len(iv) < iv_len:
        tmp = hashlib.md5(tmp + password_bytes).digest()
        key += tmp[:min(len(tmp), key_len - len(key))]
        if len(iv) < iv_len:
            iv += tmp[:min(len(tmp), iv_len - len(iv))]
    return key, iv

def unpad_pkcs7(data):
    """去除PKCS#7填充"""
    padding_len = data[-1]
    return data[:-padding_len]

# 配置参数
data_b64 = 'base 64 encoded encrypted data'
password = '.. password ..'
salt = 'XB7sHH26Hn&FmPLxnjGccKTfPV(yk'
fixed_str = '(tXntTbJFzh]4EuQVmjzM9GXHCth8'

# 1. 计算PBKDF2并转十六进制字符串
kdf = PBKDF2HMAC(
    algorithm=hashes.SHA1(),
    length=32,  # CryptoJS.PBKDF2默认生成256位(32字节)密钥
    salt=salt.encode('utf-8'),
    iterations=1,
    backend=default_backend()
)
pbkdf2_result = kdf.derive(password.encode('utf-8'))
pbkdf2_hex = pbkdf2_result.hex()

# 2. 拼接得到Crypto-JS中使用的密码字符串
psw_str = pbkdf2_hex + fixed_str

# 3. 用EVP_BytesToKey生成AES密钥和IV
key, iv = evp_bytes_to_key(psw_str, 32, 16)

# 4. 解密过程
cipher_data = base64.b64decode(data_b64)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
decrypted_raw = decryptor.update(cipher_data) + decryptor.finalize()

# 5. 去除填充并转明文
plaintext = unpad_pkcs7(decrypted_raw).decode('utf-8')
print(plaintext)

关键说明

  1. PBKDF2参数:CryptoJS.PBKDF2默认使用SHA1、1次迭代、生成256位密钥,所以Python中length设为32(字节)。
  2. EVP_BytesToKey:这是OpenSSL传统的密钥派生算法,Crypto-JS在传入字符串密码时默认使用该逻辑,需要手动实现。
  3. PKCS#7填充:Crypto-JS的AES默认使用PKCS#7填充,解密后需要手动去除。

内容的提问来源于stack exchange,提问作者linkedin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:45:41