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

Java使用BouncyCastle实现AES-256-CBC解密报pad block corrupted错误求助

问题根因

pad block corrupted报错本质是密钥或IV与加密端不匹配,导致解密后填充位校验失败。你的问题核心是PHP的hash()函数默认返回十六进制字符串而非原始二进制字节,Java侧的处理逻辑和PHP侧不匹配。

PHP侧逻辑拆解

  • hash('sha256', $input)默认返回长度为64的小写十六进制字符串(每个字符对应0-9/a-f),而非32字节的原始二进制哈希值
  • AES-256-CBC需要32字节密钥,openssl_decrypt传入64字节的十六进制字符串时,会自动截断前32字节作为有效密钥
  • IV生成时,两次哈希后得到的64位十六进制字符串取前16个字符(刚好16字节)作为有效IV

Java侧需要修改的点

  1. 新增字节数组转小写十六进制字符串的工具方法,对齐PHP的hash()默认输出
  2. 所有字符串转字节数组时明确指定UTF-8编码,避免系统默认编码差异
  3. 密钥、IV的生成逻辑对齐PHP的字符串截断规则
修改后可运行代码
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Arrays;

public class Aes {
    // 字节数组转小写十六进制字符串,对齐PHP hash()默认输出
    private static String bytesToHex(byte[] hash) {
        StringBuilder hexString = new StringBuilder(2 * hash.length);
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    public static void main(String[] args) throws Exception {
        String date = "2021-05-26 14:00:00";
        String private_key = "7X9gx9E3Qx4EiUdB63nc";
        String composite = date + private_key;

        // 生成密钥:对齐PHP逻辑,哈希后转十六进制串,取前32字节
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update(composite.getBytes(StandardCharsets.UTF_8));
        byte[] stringHash = messageDigest.digest();
        String keyHex = bytesToHex(stringHash);
        byte[] skey = Arrays.copyOf(keyHex.getBytes(StandardCharsets.UTF_8), 32);

        // 生成IV:对齐PHP逻辑,两次哈希后转十六进制串,取前16字节
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(private_key.getBytes(StandardCharsets.UTF_8));
        byte[] firstHash = md.digest();
        MessageDigest md2 = MessageDigest.getInstance("SHA-256");
        md2.update(firstHash);
        byte[] secondHash = md2.digest();
        String ivHex = bytesToHex(secondHash);
        byte[] ivec = Arrays.copyOf(ivHex.getBytes(StandardCharsets.UTF_8), 16);

        String encryptedText = "WwBOU6s8DaMWmYdctBJwfuoujFgVygBUjhsbdf8eWqQ=";
        Security.addProvider(new BouncyCastleProvider());
        byte[] encrypted = DatatypeConverter.parseBase64Binary(encryptedText);

        PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
        CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(skey), ivec);
        aes.init(false, ivAndKey);

        int minSize = aes.getOutputSize(encrypted.length);
        byte[] outBuf = new byte[minSize];
        int length1 = aes.processBytes(encrypted, 0, encrypted.length, outBuf, 0);
        int length2 = aes.doFinal(outBuf, length1);
        int actualLength = length1 + length2;
        byte[] decrypted = new byte[actualLength];
        System.arraycopy(outBuf, 0, decrypted, 0, actualLength);

        String decryptedString = new String(decrypted, StandardCharsets.UTF_8);
        System.out.println("<[" + decryptedString + "]>");
    }
}
其他注意事项
  • JDK8及以上版本默认支持AES-256,不需要额外配置无限制权限文件,如果你使用JDK7需要单独替换jce目录下的权限包
  • 如果你使用更高版本JDK,javax.xml.bind.DatatypeConverter可能被移除,可以替换为java.util.Base64的Base64解码逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 23:15:04