Java RSA+Base64解密抛出BadPaddingException: Decryption error问题
问题定位
你的代码触发javax.crypto.BadPaddingException: Decryption error有3个核心错误,按影响优先级排序:
- 密钥对不匹配:你在类的构造方法中每次实例化都会生成全新的RSA密钥对。如果加密操作和解密操作使用的不是同一个
EncryptionUtil实例,加密用的公钥和解密用的私钥完全不属于同一对密钥,RSA算法无法正常解密,必然抛出padding错误。这是此类报错最常见的触发原因。 - Cipher实例线程不安全:你把
Cipher定义为类成员变量全局共享,而Cipher本身是有状态的对象。多线程并发调用加解密方法时,会出现Cipher的工作模式(加密/解密)、密钥被其他线程覆盖的问题,导致传入的解密数据和当前Cipher的状态不匹配,触发异常。 - 编解码未指定字符集:代码中所有字符串和字节数组的转换都没有指定字符集,程序运行在不同操作系统、不同语言环境下时,会因为默认字符集差异导致Base64编解码、明文转码出错,间接触发解密异常。
修复方案
按照以下规则调整代码即可解决问题:
- 不要在工具类构造时动态生成密钥对:RSA密钥对应提前生成后持久化存储(比如配置文件、密钥库),加解密时统一加载匹配的公钥、私钥;如果是临时内存使用场景,必须保证加解密操作调用的是同一个持有固定密钥对的实例。
- 不要全局共享Cipher实例:每次执行加解密操作时单独初始化Cipher对象,方法执行完后自动回收,避免多线程状态冲突。
- 所有字节、字符串转换操作统一指定
UTF-8字符集,消除环境差异带来的编解码错误。
修复后的核心参考代码:
import org.apache.commons.codec.binary.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.nio.charset.StandardCharsets; import java.security.*; public class EncryptionUtil { static final String SECRET_ALGO = "RSA"; static final String CIPHER_TOKENIZER_TRANSFORMER = "RSA/ECB/PKCS1Padding"; static final int KEY_SIZE = 1024; private final KeyPair pair; // 构造方法仅在需要临时生成密钥对时使用,生产环境建议替换为从配置加载已生成的密钥对 public EncryptionUtil(){ try{ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(SECRET_ALGO); keyPairGen.initialize(KEY_SIZE); pair = keyPairGen.generateKeyPair(); }catch (NoSuchAlgorithmException e) { throw new IllegalStateException("Cannot Build Encryption Utils with given params"); } } public String decrypt(String encrypted) { try { // 每次调用单独初始化Cipher,不共享实例 Cipher cipher = Cipher.getInstance(CIPHER_TOKENIZER_TRANSFORMER); cipher.init(Cipher.DECRYPT_MODE, pair.getPrivate()); byte[] decodeBytes = new Base64().decode(encrypted.getBytes(StandardCharsets.UTF_8)); return new String(cipher.doFinal(decodeBytes), StandardCharsets.UTF_8); } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) { throw new FiveXXServiceException(e.getMessage(), ErrorCode.DECRYPTION_EXCEPTION); } } public String encrypt(String text) { try { // 每次调用单独初始化Cipher,不共享实例 Cipher cipher = Cipher.getInstance(CIPHER_TOKENIZER_TRANSFORMER); cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic()); byte[] encryptBytes = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8)); return new String(new Base64().encode(encryptBytes), StandardCharsets.UTF_8); } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) { throw new FiveXXServiceException(e.getMessage(), ErrorCode.ENCRYPTION_EXCEPTION); } } }
注意:1024位RSA密钥安全强度已经不足,生产环境建议替换为2048位及以上长度;RSA/ECB/PKCS1Padding模式仅适合加密短数据,1024位密钥最大可加密数据长度为117字节,超过长度需要结合对称加密算法使用。
内容的提问来源于stack exchange,提问作者Abhishek Kumar
相关产品推荐
相关产品推荐

