CryptoJS AES-CBC加盐解密转Python后解密失败问题排查
CryptoJS AES-CBC加盐解密转Python的问题排查与解决
问题背景
现有一段基于CryptoJS的JavaScript AES-CBC加盐解密逻辑,需要改写为Python版本,但Python代码处理密钥时得到错误的解密结果,且无法修改原有加密方式,只能调整Python解密逻辑。
原代码对比
JavaScript代码
// y is array with all data var decryptjson = {"ct": y[0].substr(2), "iv": y[1], "s": y[2]} var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(decryptjson.ct) }); if (decryptjson.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(decryptjson.iv); if (decryptjson.s) cipherParams.salt = CryptoJS.enc.Hex.parse(decryptjson.s); var a = CryptoJS.AES.decrypt(cipherParams, key).toString(CryptoJS.enc.Utf8)
原Python代码
decryptdict = {"ct":y[0], "iv": y[1], "s": y[2]} ct = b64decode(decryptdict["ct"]) iv = bytes.fromhex(decryptdict["iv"]) salt = bytes.fromhex(decryptdict["s"]) key = pbkdf2.PBKDF2(key, salt).read(32) cipher = AES.new(key, AES.MODE_CBC, iv) decryptedstring = cipher.decrypt(ct)
问题排查
密文预处理不一致
JS代码中对密文做了y[0].substr(2)操作(去掉前两位字符),但原Python代码直接使用y[0],导致密文数据不匹配。密钥派生算法错误
CryptoJS的AES.decrypt在传入salt时,默认使用OpenSSL的EVP_BytesToKey算法(基于MD5哈希、1次迭代),而非PBKDF2。原Python代码误用PBKDF2生成密钥,导致密钥与JS端不一致,这是解密失败的核心原因。填充未处理
CryptoJS默认使用PKCS7填充,原Python代码解密后未去除填充字节,会导致结果末尾出现多余的乱码字符。
修正后的Python代码
from base64 import b64decode from Crypto.Cipher import AES from Crypto.Hash import MD5 from Crypto.Util.Padding import unpad # 替换为实际的y数组数据 y = ["你的密文字符串", "IV的十六进制值", "盐的十六进制值"] # 密文需去掉前两位,和JS逻辑对齐 decryptdict = {"ct": y[0][2:], "iv": y[1], "s": y[2]} # 替换为JS端使用的原始密钥 password = b"your_original_key" ct = b64decode(decryptdict["ct"]) iv = bytes.fromhex(decryptdict["iv"]) salt = bytes.fromhex(decryptdict["s"]) # 实现CryptoJS默认的EVP_BytesToKey密钥派生逻辑 def evp_bytes_to_key(password, salt, key_len=32, iv_len=16): buf = b"" while len(buf) < key_len + iv_len: md5_hash = MD5.new() md5_hash.update(buf + password + salt) buf += md5_hash.digest() key = buf[:key_len] return key # 生成匹配的密钥 key = evp_bytes_to_key(password, salt) # 初始化CBC解密器 cipher = AES.new(key, AES.MODE_CBC, iv) # 解密并去除PKCS7填充 decrypted_bytes = cipher.decrypt(ct) decryptedstring = unpad(decrypted_bytes, AES.block_size).decode("utf-8") print(decryptedstring)
说明
- 确保安装依赖:执行
pip install pycryptodome - 代码中需替换
y数组、password为实际业务数据 - 密钥派生逻辑严格对齐CryptoJS的默认行为,保证密钥一致性
内容的提问来源于stack exchange,提问作者cat339
相关产品推荐
相关产品推荐

