使用BouncyCastle解密AES/SIC/PKCS7Padding加密数据时触发BadPaddingException问题排查
问题分析与修复方案
嘿,我一眼就看到你代码里的核心问题了——IV(初始化向量)的处理完全错误,这也是导致BadPaddingException的主要原因!
问题根源
AES/SIC本质是CTR流加密模式,这类模式的核心要求是:解密时必须使用和加密阶段完全相同的IV。而你现在的decrypt方法每次都会调用generateIv()生成一个全新的随机IV,这就导致解密的起始计数器和加密完全对不上,解密出来的字节流完全混乱,PKCS7填充的验证自然会失败,抛出BadPaddingException。
另外还有个小问题:你每次解密都调用Security.addProvider(new BouncyCastleProvider()),重复添加Provider是没必要的,应该只初始化一次。
修复后的代码方案
要解决这个问题,你需要保证解密时使用加密时的原始IV。通常的做法是把IV和密文一起传输(比如拼接在密文前面,再一起Base64编码),解密时先分离出IV再进行解密。以下是完整的修正代码:
import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import java.security.Security; import java.security.SecureRandom; import java.util.Base64; public class AesEncryption { // 只初始化一次BouncyCastleProvider,避免重复添加 static { Security.addProvider(new BouncyCastleProvider()); } // 配套的加密方法示例:将IV拼接在密文前16字节后再Base64编码 public static String encrypt(String aesKey, String plainText) throws Exception { SecretKey key = new SecretKeySpec(Base64.getDecoder().decode(aesKey), "AES"); Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); // 生成加密用的随机IV byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); byte[] encryptedBytes = cipher.doFinal(plainText.getBytes("UTF-8")); // 拼接IV和密文:前16字节是IV,后面是实际密文 byte[] combinedData = new byte[iv.length + encryptedBytes.length]; System.arraycopy(iv, 0, combinedData, 0, iv.length); System.arraycopy(encryptedBytes, 0, combinedData, iv.length, encryptedBytes.length); return Base64.getEncoder().encodeToString(combinedData); } public static String decrypt(String aesKey, String cipherText) { try { SecretKey key = new SecretKeySpec(Base64.getDecoder().decode(aesKey), "AES"); Cipher dcipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); // 解码密文,分离出IV和实际加密内容 byte[] combinedData = Base64.getDecoder().decode(cipherText); byte[] iv = new byte[16]; byte[] encryptedBytes = new byte[combinedData.length - 16]; System.arraycopy(combinedData, 0, iv, 0, iv.length); System.arraycopy(combinedData, 16, encryptedBytes, 0, encryptedBytes.length); // 使用加密时的原始IV初始化解密器 IvParameterSpec ivSpec = new IvParameterSpec(iv); dcipher.init(Cipher.DECRYPT_MODE, key, ivSpec); byte[] decryptedBytes = dcipher.doFinal(encryptedBytes); return new String(decryptedBytes, "UTF-8"); } catch (Exception e) { e.printStackTrace(); return null; } } }
关键注意点
- 如果加密操作不是你实现的,那你必须从加密方获取加密时使用的原始IV,而不是自己生成——这是解密成功的核心前提。
- SIC模式的IV不需要保密,但必须保证唯一性(同一个密钥下不能重复使用同一个IV),所以加密时用随机IV是正确的做法。
内容的提问来源于stack exchange,提问作者user0365873
相关产品推荐
相关产品推荐

