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侧需要修改的点
- 新增字节数组转小写十六进制字符串的工具方法,对齐PHP的
hash()默认输出 - 所有字符串转字节数组时明确指定UTF-8编码,避免系统默认编码差异
- 密钥、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
相关产品推荐
相关产品推荐

