RSA加密Java实现完全指南:从原理到代码实战
目录导读
-
RSA加密核心原理(必懂基础)

-
Java中RSA加密的两种常见场景
-
完整代码实现:密钥生成、加密、解密
-
常见问题与避坑指南(含问答)
-
性能优化与安全建议
RSA加密核心原理(必懂基础)
RSA是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出,其核心思想是:加密和解密使用不同的密钥——公钥用于加密,私钥用于解密,安全性基于大整数分解的数学难题。
关键参数:
- 密钥长度:通常使用2048位(长度越长越安全,但性能越低)。
- 填充方式:PKCS#1 v1.5(兼容性好)或OAEP(更安全,推荐)。
适用场景:
- 数字签名(私钥签名,公钥验签)
- 加密小数据(如对称密钥、密码等,不适合加密大文件)
问题1:RSA能加密任意大小的数据吗?
答:不能,RSA加密块大小受密钥长度限制,例如2048位密钥最多加密245字节(PKCS#1 v1.5)或190字节(OAEP),大文件建议先使用AES对称加密,再用RSA加密AES密钥。
Java中RSA加密的两种常见场景
在Java中实现RSA,主要分为标准JCE(Java Cryptography Extension)和Bouncy Castle两种方式,JCE是JDK内置的,无需额外依赖;Bouncy Castle提供更多算法支持(如OAEP更灵活的哈希函数)。
| 对比维度 | JCE(javax.crypto) | Bouncy Castle |
|---|---|---|
| 依赖 | JDK自带 | 需引入bcprovjar包 |
| 填充方式 | 支持PKCS#1和OAEP | 支持更多填充 |
| 密钥长度 | 无限制 | 无限制 |
| 推荐 | 常规项目使用 | 需要特殊算法时 |
优先使用JCE(除非必须用Bouncy Castle的特定功能)。
完整代码实现:密钥生成、加密、解密
以下代码演示了如何使用JCE生成2048位RSA密钥对,并用OAEP(SHA-256)加密/解密字符串。
1 生成密钥对并保存为Base64字符串
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RSAUtil {
// 生成密钥对
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048); // 推荐2048位
return generator.generateKeyPair();
}
// 密钥转Base64字符串
public static String keyToBase64(Key key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
// 从Base64恢复密钥(示例:公钥)
public static PublicKey base64ToPublicKey(String base64) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(base64);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(new X509EncodedKeySpec(keyBytes));
}
// 私钥恢复同理,用PKCS8EncodedKeySpec
}
2 使用OAEP填充进行加密(推荐)
public static String encrypt(String plainText, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String cipherText, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(decryptedBytes, "UTF-8");
}
注意:OAEP填充默认使用SHA-1作为MGF1的哈希,显式指定
SHA-256更安全,如果兼容性问题需用PKCS#1,则改为"RSA/ECB/PKCS1Padding"。
3 完整测试示例
public static void main(String[] args) throws Exception {
// 1. 生成密钥
KeyPair keyPair = generateKeyPair();
PublicKey pubKey = keyPair.getPublic();
PrivateKey priKey = keyPair.getPrivate();
// 2. 加密
String original = "Hello, RSA! 这是一个测试。";
String encrypted = encrypt(original, pubKey);
System.out.println("加密后: " + encrypted);
// 3. 解密
String decrypted = decrypt(encrypted, priKey);
System.out.println("解密后: " + decrypted);
}
输出示例:
加密后: Kd5m8y...(Base64字符串)
解密后: Hello, RSA! 这是一个测试。
常见问题与避坑指南(含问答)
问题2:RSA加密时出现IllegalBlockSizeException怎么办?
答:这表示明文数据超过最大加密长度,2048位密钥使用OAEP+SHA-256时最大加密190字节,解决方案:将数据分块加密,或改用混合加密(AES+RSA)。
问题3:公钥和私钥如何存储?
答:推荐使用Base64字符串保存到配置文件或数据库,生产环境中私钥必须加密存储(如使用Keystore或硬件安全模块)。
问题4:OAEP和PKCS#1 v1.5选哪个?
答:OAEP更安全,能抵抗选择密文攻击,PKCS#1 v1.5主要用于兼容旧系统,新系统首选OAEP。
问题5:为什么解密后中文乱码?
答:确保加密时使用UTF-8编码,解密时同样用UTF-8,示例中已正确处理。
性能优化与安全建议
- 避免频繁生成密钥对:密钥对生成耗时长,应复用,通常使用固定密钥对,定期轮换。
- 配合对称加密:RSA效率低,适合加密少量数据,大文件先通过AES加密(速度块),再用RSA加密AES密钥。
- 使用安全随机数:Java默认使用
SecureRandom,无需额外配置。 - 禁用不安全的填充:不要使用
"RSA/ECB/NoPadding"(无填充),不加密仅用于签名场景。 - 密钥长度选择:1024位已不安全,2048位是当前基线,4096位更安全但性能下降约2~3倍。
在Java中实现RSA加密,遵循以下步骤:
- 确定算法模式:
RSA/ECB/OAEPWithSHA-256AndMGF1Padding - 生成2048位密钥对
- 使用
Cipher类完成加密/解密 - 注意数据大小限制,必要时采用混合加密
掌握这些,你就能在Java项目中安全地使用RSA加密了。实际开发中建议直接使用现成的JCE API,避免重复造轮子,但必须理解其原理才能应对异常场景。