AES跨端解密报错ValueError: Padding is incorrect的排查求助
问题场景
做学校项目时,用TypeScript + CryptoJS加密前端数据,通过AES算法传输到Django + PyCryptodome后端解密。.env中存储的Base64格式密钥为:
SECRET='DfkCqKG7zAovGC/ZXdTG5SkW5rNP8AWU3FjW56xdKv4='
前端加密后的数据传到后端,在执行pt = unpad(decrypted_padded_data, AES.block_size)时触发ValueError: Padding is incorrect.错误。已确认数据传输无丢失,发现前后端密钥处理逻辑不一致:
- 前端直接将Base64密钥字符串用
CryptoJS.enc.Utf8.parse()解析 - 后端将Base64密钥解码为字节数组
核心问题
前端错误地将Base64编码的密钥当作UTF-8字符串解析,而非解码成原始字节数组,导致前后端实际使用的密钥不匹配,最终解密后的数据无法通过填充校验。
CryptoJS的Utf8.parse()会把Base64字符串的每个字符转成UTF-8字节,而正确做法是将Base64字符串解码为对应字节数组(与后端处理逻辑一致)。
修复方案
修改前端密钥处理逻辑
将前端中密钥的解析方式从CryptoJS.enc.Utf8.parse(SECRET_KEY)改为CryptoJS.enc.Base64.parse(SECRET_KEY),确保前后端使用完全相同的密钥字节数组。
修改后的前端代码:
import CryptoJS from 'crypto-js'; const SECRET_KEY = import.meta.env.VITE_SECRET export function encryptData(data: string): string { const iv = CryptoJS.lib.WordArray.random(16); // 改用Base64解析密钥 const key = CryptoJS.enc.Base64.parse(SECRET_KEY); const encrypted = CryptoJS.AES.encrypt(data, key, { iv }); const ivAndEncryptedData = iv.concat(encrypted.ciphertext); return CryptoJS.enc.Base64.stringify(ivAndEncryptedData); } export function decryptData(encryptedData: string): string { const decoded = CryptoJS.enc.Base64.parse(encryptedData); const iv = CryptoJS.lib.WordArray.create(decoded.words.slice(0, 4)); const ciphertext = CryptoJS.lib.WordArray.create(decoded.words.slice(4)); const cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext, iv }); // 改用Base64解析密钥 const key = CryptoJS.enc.Base64.parse(SECRET_KEY); const decrypted = CryptoJS.AES.decrypt(cipherParams, key); return decrypted.toString(CryptoJS.enc.Utf8); }
后端代码无需修改
后端的密钥处理逻辑是正确的:SECRET_KEY = base64.b64decode(os.getenv('SECRET'))已将Base64密钥解码为原始字节数组,和修改后的前端密钥处理逻辑一致。
验证
修改后,前端加密任意字符串(比如"test123"),将加密后的Base64字符串传给后端解密,应能正确得到原始字符串,不会再触发填充错误。
内容的提问来源于stack exchange,提问作者Dev00

