前置说明
使用 JDK 原生
java.security,不引入第三方包加密采用
RSA/ECB/OAEPWithSHA-256AndMGF1Padding(推荐,替代不安全的 PKCS1-v1.5)签名采用
SHA256withRSA(PSS 会复杂一点,这段是极简演示)密钥 2048 bit;RSA 不适合加密长明文,示例只加密短字符串;生产一定是 RSA 传 AES key
编码:Base64(JDK11+ 自带 Base64)
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaDemo {
public static void main(String[] args) throws Exception {
// 1. 生成RSA密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 转Base64方便打印、存储(实际项目可以存到配置/证书)
String pubKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String priKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println("公钥:\n" + pubKeyBase64);
System.out.println("私钥:\n" + priKeyBase64);
// 原始明文
String originText = "hello rsa test 123456";
System.out.println("\n原始明文:" + originText);
// ========== 加密:公钥加密 ==========
byte[] cipherData = encrypt(originText.getBytes(), publicKey);
String cipherBase64 = Base64.getEncoder().encodeToString(cipherData);
System.out.println("RSA加密后密文(Base64): " + cipherBase64);
// ========== 解密:私钥解密 ==========
byte[] plainData = decrypt(Base64.getDecoder().decode(cipherBase64), privateKey);
String plainText = new String(plainData);
System.out.println("RSA解密结果:" + plainText);
// ========== 签名:私钥签名 ==========
byte[] signData = sign(originText.getBytes(), privateKey);
String signBase64 = Base64.getEncoder().encodeToString(signData);
System.out.println("\n签名值(Base64): " + signBase64);
// ========== 验签:公钥验签 ==========
boolean verifyOk = verify(originText.getBytes(), signData, publicKey);
System.out.println("验签结果:" + verifyOk);
// 模拟篡改测试
String tamperText = "hello rsa test 123456 xxx";
boolean verifyFail = verify(tamperText.getBytes(), signData, publicKey);
System.out.println("篡改后验签:" + verifyFail);
// ===== 演示:从Base64字符串还原密钥(网络传输、配置读取场景)=====
PublicKey restorePub = getPublicKey(pubKeyBase64);
PrivateKey restorePri = getPrivateKey(priKeyBase64);
boolean verifyByRestoreKey = verify(originText.getBytes(), signData, restorePub);
System.out.println("使用还原后的公钥验签:" + verifyByRestoreKey);
}
/**
* RSA公钥加密 OAEP
*/
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* RSA私钥解密 OAEP
*/
public static byte[] decrypt(byte[] cipherData, PrivateKey privateKey) throws Exception {
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(cipherData);
}
/**
* SHA256withRSA 私钥签名
*/
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/**
* SHA256withRSA 公钥验签
*/
public static boolean verify(byte[] data, byte[] signBytes, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(signBytes);
}
/**
* Base64字符串 -> 公钥对象
*/
public static PublicKey getPublicKey(String pubBase64) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(pubBase64);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
}
/**
* Base64字符串 -> 私钥对象
*/
public static PrivateKey getPrivateKey(String priBase64) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(priBase64);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
}
}
重要生产提醒
JDK8 自带这套 API,但部分老国产 JDK 可能缺少 OAEP 支持,此时只能降级
RSA/ECB/PKCS1Padding(不安全,仅兼容旧系统)不要用 RSA 加密业务报文!标准方案:RSA 加密 AES 密钥 + AES 加密业务数据
签名优先推荐 RSASSA-PSS(
SHA256withRSAandMGF1),安全性更高,上面代码是 SHA256withRSA 仅做演示私钥严禁明文放配置文件,建议密钥管理服务 KMS
异常不要直接对外抛出堆栈,防止泄露密钥相关信息