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

JavaScript AES加密后Java解密报BadPaddingException问题排查

AES/CBC/PKCS7Padding前后端加解密报错:BadPaddingException

问题场景

前端用JavaScript(CryptoJS)实现AES/CBC/PKCS7Padding加密,后端Java解密时持续抛出javax.crypto.BadPaddingException: pad block corrupted错误。代码片段如下:

JavaScript加密代码

export const encryptPaymentData = (data) => {
  var encrypt = new JSEncrypt()
  encrypt.setPublicKey(publicKey)

  // convert the JSON object to a string
  const jsonDataString = JSON.stringify(data)

  // Create iv and secret_key
  let iv = crypto.randomBytes(16)
  let secret_key = crypto.randomBytes(32)

  // iv = Buffer.from(iv).toString("base64")
  // secret_key = Buffer.from(secret_key).toString("base64")

  iv = CryptoJS.enc.Base64.stringify(CryptoJS.lib.WordArray.create(iv))
  secret_key = CryptoJS.enc.Base64.stringify(
    CryptoJS.lib.WordArray.create(secret_key)
  )

  // Encrypt the plaintext using AES/CBC/PKCS5Padding
  console.log("iv", iv)
  console.log("Secret", secret_key)
  const ciphertext = CryptoJS.AES.encrypt(jsonDataString, secret_key, {
    iv: iv,
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC,
  })
  console.log("cipherText", ciphertext)

  // Print the ciphertext
  console.log(ciphertext.toString())
}

Java解密代码

private static final String ALGORITHM = "AES/CBC/PKCS7Padding";

public String decryptAES(String ciphertext, String secretKey, String iv) throws Exception {
        IvParameterSpec ivSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));
        SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(secretKey), "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decrypted);
    }

问题原因

  1. 密钥解析错误:CryptoJS的AES.encrypt方法接收密钥参数时,若传入字符串,会默认按UTF-8编码解析成字节。但你的secret_key是Base64编码后的字符串,直接传入会导致CryptoJS使用的密钥字节和Java端Base64解码后的原始密钥字节完全不匹配。
  2. IV格式不匹配:同样,你传给CryptoJS的iv是Base64字符串,CryptoJS会把它当作UTF-8字符串解析成WordArray,这和Java端直接Base64解码得到的原始IV字节不一致。
  3. 冗余的JSEncrypt代码:当前代码里引入了JSEncrypt但没实际使用公钥加密密钥/IV,不过这不是导致解密报错的直接原因,但属于无用代码。

修正方案

修改JavaScript加密代码,确保密钥和IV以原始字节的WordArray形式传入CryptoJS,而非Base64字符串:

export const encryptPaymentData = (data) => {
  // 转换数据为JSON字符串
  const jsonDataString = JSON.stringify(data)

  // 生成原始字节的IV和密钥(16字节IV对应AES CBC要求,32字节密钥对应AES-256)
  const ivWordArray = CryptoJS.lib.WordArray.random(16)
  const secretKeyWordArray = CryptoJS.lib.WordArray.random(32)

  // 转换为Base64字符串,用于传输给后端
  const ivBase64 = CryptoJS.enc.Base64.stringify(ivWordArray)
  const secretKeyBase64 = CryptoJS.enc.Base64.stringify(secretKeyWordArray)

  // 加密:直接传入WordArray类型的密钥和IV
  const ciphertext = CryptoJS.AES.encrypt(jsonDataString, secretKeyWordArray, {
    iv: ivWordArray,
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC,
  })

  // 输出用于后端解密的参数:密文(默认Base64)、密钥Base64、IV Base64
  console.log("iv", ivBase64)
  console.log("Secret", secretKeyBase64)
  console.log("cipherText", ciphertext.toString())
  
  // 返回这三个参数给后端
  return {
    ciphertext: ciphertext.toString(),
    secretKey: secretKeyBase64,
    iv: ivBase64
  }
}

验证说明

修正后:

  • 前端生成的secretKeyBase64和ivBase64,后端直接Base64解码就能得到和前端一致的原始密钥/IV字节。
  • CryptoJS的AES.encrypt输出的ciphertext.toString()是Base64编码的密文,后端直接Base64解码后即可解密。
  • Java端代码无需修改,保持现有逻辑即可正常解密。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:42:43