Python与JavaScript AES加密结果不一致的问题及解决方法
JS与Python AES-CBC加密结果不一致的解决办法
你这两段代码结果不一致的核心原因很明确,直接看问题和修复方案:
问题根源
- JS代码搞反了加密和解密:你定义的是
encryptSeed加密函数,但内部却使用了crypto.createDecipheriv(这是解密专用函数),完全颠倒了操作逻辑,自然不可能和Python的加密结果匹配。 - 密文处理方式错误:两段代码最后都尝试将二进制密文直接用UTF-8解码,这大概率会失败——密文是随机二进制数据,无法直接转成合法的UTF-8字符串,通常用十六进制或Base64编码输出才是正确做法。
修复后的代码
修正后的JavaScript代码
import crypto from 'crypto'; function encryptSeed(text, key, iv) { const keyBuffer = Buffer.from(key, "utf8"); console.log("key:" + keyBuffer.toString("hex")); const ivBuffer = Buffer.from(iv, "utf8"); console.log("iv:" + ivBuffer.toString("hex")); // 若text是明文,替换为Buffer.from(text, "utf8"),此处保留原代码的十六进制输入逻辑 const textBuffer = Buffer.from(text, "hex"); console.log("text:" + textBuffer.toString("hex")); // 替换为加密专用的createCipheriv,算法保持aes-128-cbc const cipher = crypto.createCipheriv("aes-128-cbc", keyBuffer, ivBuffer); let encrypted = cipher.update(textBuffer); encrypted = Buffer.concat([encrypted, cipher.final()]); console.log("result:" + encrypted.toString("hex")); // 返回十六进制编码的密文,避免UTF-8解码失败 return encrypted.toString("hex"); }
修正后的Python代码
from Crypto.Cipher import AES from Crypto.Util.Padding import pad def encrypt_seed(text, key, iv): key_bytes = key.encode("utf8") print("key:" + key_bytes.hex()) iv_bytes = iv.encode("utf8") print("iv:" + iv_bytes.hex()) text_bytes = bytes.fromhex(text) print("text:" + text_bytes.hex()) cryptor = AES.new(key_bytes, AES.MODE_CBC, iv_bytes) # 显式执行PKCS7填充,和Node.js默认行为对齐,避免版本差异 padded_text = pad(text_bytes, AES.block_size) ciphertext = cryptor.encrypt(padded_text) print("result:" + ciphertext.hex()) # 返回十六进制编码的密文 return ciphertext.hex()
额外注意事项
- 密钥长度要求:aes-128-cbc要求密钥必须是16字节(128位),确保传入的
key字符串转成UTF-8后正好是16字节——否则Node.js会自动截断密钥,PyCryptodome则会直接抛出错误。 - IV长度要求:CBC模式的IV必须与块大小一致(16字节),两段代码均使用UTF-8转码,要保证
iv字符串转成字节后长度为16字节。 - 填充一致性:Node.js的
createCipheriv默认使用PKCS7填充,PyCryptodome的encrypt在明文长度非块倍数时也默认使用PKCS7,但显式调用pad函数可以避免不同版本的行为差异。 - 输出编码规范:密文属于二进制数据,不要直接尝试用UTF-8解码,推荐用十六进制或Base64编码后返回,这样在不同语言间传递更可靠。
内容的提问来源于stack exchange,提问作者Singun
相关产品推荐
相关产品推荐

