要点说明:
密钥:RSA 2048,公钥加密,私钥解密;私钥签名,公钥验签
加密填充:
RSA/ECB/OAEPWithSHA-256AndMGF1Padding(推荐,安全,替代不安全的 PKCS1v1.5)签名算法:
SHA256withRSA(先对原文做 SHA256 哈希,再 RSA 私钥签名)因为 RSA 加密长度有限,示例只加密短文本;生产中大文件用「AES 加密内容 + RSA 加密 AES 密钥」
JDK 原生
java.security,无需引入第三方包
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaDemo {
// RSA 密钥长度
private static final int KEY_SIZE = 2048;
// 加密算法
private static final String RSA_ALGORITHM = "RSA";
// 加密模式填充
private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
// 签名算法
private static final String SIGN_ALGORITHM = "SHA256withRSA";
public static void main(String[] args) throws Exception {
// 1. 生成RSA密钥对(公钥、私钥)
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 转Base64字符串,方便网络传输/存储
String pubKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String priKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println("=== 公钥(Base64) ===");
System.out.println(pubKeyBase64);
System.out.println("=== 私钥(Base64) ===");
System.out.println(priKeyBase64);
// 原始明文
String originText = "Hello RSA,测试RSA加密+数字签名!";
System.out.println("\n原始明文:" + originText);
// ========== RSA 加密解密演示 ==========
// 公钥加密
String encryptBase64 = encrypt(originText, pubKeyBase64);
System.out.println("\n公钥加密结果(Base64):" + encryptBase64);
// 私钥解密
String decryptText = decrypt(encryptBase64, priKeyBase64);
System.out.println("私钥解密结果:" + decryptText);
// ========== RSA 签名验签演示 ==========
// 私钥签名
String signBase64 = sign(originText, priKeyBase64);
System.out.println("\n私钥签名结果(Base64):" + signBase64);
// 公钥验签
boolean verifyResult = verify(originText, signBase64, pubKeyBase64);
System.out.println("公钥验签结果:" + verifyResult);
// 篡改原文测试:验签失败
String tamperText = "Hello RSA,【被篡改】测试RSA加密+数字签名!";
boolean verifyTamper = verify(tamperText, signBase64, pubKeyBase64);
System.out.println("篡改后原文验签:" + verifyTamper);
}
/**
* 生成RSA密钥对
*/
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
generator.initialize(KEY_SIZE, new SecureRandom());
return generator.generateKeyPair();
}
/**
* 公钥加密
* @param plainText 明文
* @param publicKeyBase64 base64公钥
* @return base64密文
*/
public static String encrypt(String plainText, String publicKeyBase64) throws Exception {
// 还原公钥对象
byte[] pubBytes = Base64.getDecoder().decode(publicKeyBase64);
X509EncodedKeySpec spec = new X509EncodedKeySpec(pubBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(spec);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptBytes = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encryptBytes);
}
/**
* 私钥解密
* @param cipherBase64 base64密文
* @param privateKeyBase64 base64私钥
* @return 明文
*/
public static String decrypt(String cipherBase64, String privateKeyBase64) throws Exception {
byte[] priBytes = Base64.getDecoder().decode(privateKeyBase64);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(priBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(spec);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainBytes = cipher.doFinal(Base64.getDecoder().decode(cipherBase64));
return new String(plainBytes);
}
/**
* 私钥签名
* @param content 原文
* @param privateKeyBase64 base64私钥
* @return base64签名串
*/
public static String sign(String content, String privateKeyBase64) throws Exception {
byte[] priBytes = Base64.getDecoder().decode(privateKeyBase64);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(priBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(spec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initSign(privateKey);
signature.update(content.getBytes());
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
}
/**
* 公钥验签
* @param content 原文
* @param signBase64 base64签名
* @param publicKeyBase64 base64公钥
* @return true=合法,false=篡改/签名不对
*/
public static boolean verify(String content, String signBase64, String publicKeyBase64) throws Exception {
byte[] pubBytes = Base64.getDecoder().decode(publicKeyBase64);
X509EncodedKeySpec spec = new X509EncodedKeySpec(pubBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(spec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(publicKey);
signature.update(content.getBytes());
return signature.verify(Base64.getDecoder().decode(signBase64));
}
}
运行输出示例
=== 公钥(Base64) ===
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlxxxx
=== 私钥(Base64) ===
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCAlxxxx
原始明文:Hello RSA,测试RSA加密+数字签名!
公钥加密结果(Base64):K5xxxx
私钥解密结果:Hello RSA,测试RSA加密+数字签名!
私钥签名结果(Base64):D8xxxx
公钥验签结果:true
篡改后原文验签:false
生产注意事项
不要裸 RSA:必须带填充,OAEP 优于旧的 PKCS#1 v1.5
RSA 不能加密大数据:2048 位 RSA 最多加密 245 字节,业务中:AES 加密业务数据,RSA 加密 AES 密钥
私钥严禁明文硬编码,生产要密钥管理(KMS)
字符编码:代码里
getBytes()默认平台编码,生产统一指定StandardCharsets.UTF_8JDK 版本:
Base64是 JDK8+;低版本要用 commons-codec
改造:加上 UTF-8(推荐上线版本)
把所有 content.getBytes() 替换为
content.getBytes(StandardCharsets.UTF_8)
记得 import java.nio.charset.StandardCharsets;
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问