Java使用RSA加密和解密,使用SHA1withRSA算法进行 签名和验签
package util;
import cn.hutool.core.codec.Base64;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* RSA工具类.
*
* @author zsh
* @version 1.0
* @date 2022/12/14 17:50
*/
@Slf4j
@UtilityClass
public class RSAUtil {
/**
* 加密算法RSA.
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 签名算法.
*/
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* 密钥长度,DH算法的默认密钥长度是1024 密钥长度必须是64的倍数,在512到65536位之间.
**/
private static final int KEY_SIZE = 1024;
/**
* 随机生成密钥对.
*
* @return
*/
public static Map<String, String> genKeyPair() {
try {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(KEY_SIZE);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 得到公钥字符串
String publicKeyString = Base64.encode(publicKey.getEncoded());
// 得到私钥字符串
String privateKeyString = Base64.encode(privateKey.getEncoded());
Map<String, String> map = new HashMap<>();
map.put("publicKey", publicKeyString);
map.put("privateKey", privateKeyString);
return map;
} catch (Exception e) {
log.error("生成密钥对异常", e);
}
return null;
}
/**
* 公钥加密过程.
*
* @param publicKeyStr 公钥
* @param plainTextData 明文数据
* @return
*/
public static byte[] encryptByPublicKey(String publicKeyStr, String plainTextData) throws Exception {
if (StringUtil.isBlank(publicKeyStr)) {
throw new Exception("加密公钥为空, 请设置");
}
try {
return encryptByPublicKey(publicKeyStr, plainTextData.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("公钥加密异常", e);
throw new Exception("公钥加密异常");
}
}
/**
* 公钥加密过程.
*
* @param publicKeyStr 公钥
* @param plainTextData 明文数据
* @return
*/
public static byte[] encryptByPublicKey(String publicKeyStr, byte[] plainTextData) throws Exception {
if (StringUtil.isBlank(publicKeyStr)) {
throw new Exception("加密公钥为空, 请设置");
}
try {
return encrypt(loadPublicKeyByStr(publicKeyStr), plainTextData);
} catch (Exception e) {
log.error("公钥加密异常", e);
throw new Exception("公钥加密异常");
}
}
/**
* 公钥加密过程.
*
* @param publicKey 公钥
* @param plainTextData 明文数据
* @return
*/
public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
if (publicKey == null) {
throw new Exception("加密公钥为空, 请设置");
}
try {
// 使用默认RSA
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return processData(cipher, plainTextData, KEY_SIZE / 8 - 11);
} catch (Exception e) {
log.error("公钥加密异常", e);
throw new Exception("公钥加密异常");
}
}
/**
* 私钥解密过程.
*
* @param privateKeyStr 私钥
* @param baseData 密文数据(base64加密)
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static byte[] decryptByPrivateKey(String privateKeyStr, String baseData) throws Exception {
if (StringUtil.isBlank(privateKeyStr)) {
throw new Exception("解密私钥为空, 请设置");
}
try {
return decryptByPrivateKey(privateKeyStr, Base64.decode(baseData));
} catch (Exception e) {
log.error("私钥解密异常", e);
throw new Exception("私钥解密异常");
}
}
/**
* 私钥解密过程.
*
* @param privateKeyStr 私钥
* @param cipherData 密文数据
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static byte[] decryptByPrivateKey(String privateKeyStr, byte[] cipherData) throws Exception {
if (StringUtil.isBlank(privateKeyStr)) {
throw new Exception("解密私钥为空, 请设置");
}
try {
// 获取私钥
RSAPrivateKey privateKey = loadPrivateKeyByStr(privateKeyStr);
return decrypt(privateKey, cipherData);
} catch (Exception e) {
log.error("私钥解密异常", e);
throw new Exception("私钥解密异常");
}
}
/**
* 私钥解密过程.
*
* @param privateKey 私钥
* @param cipherData 密文数据
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
if (privateKey == null) {
throw new Exception("解密私钥为空, 请设置");
}
try {
// 使用默认RSA
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return processData(cipher, cipherData, KEY_SIZE / 8);
} catch (Exception e) {
log.error("私钥解密异常", e);
throw new Exception("私钥解密异常");
}
}
/**
* RSA签名.
*
* @param content 待签名数据
* @param privateKey 商户私钥
* @return 签名值
*/
public static String sign(byte[] content, String privateKey) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(loadPrivateKeyByStr(privateKey));
signature.update(content);
byte[] signed = signature.sign();
return Base64.encode(signed);
} catch (Exception e) {
log.error("生成签名异常", e);
}
return null;
}
/**
* RSA签名.
*
* @param content 待签名数据(base64)
* @param privateKey 商户私钥
* @return 签名值
*/
public static String sign(String content, String privateKey) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(loadPrivateKeyByStr(privateKey));
signature.update(Base64.decode(content));
byte[] signed = signature.sign();
return Base64.encode(signed);
} catch (Exception e) {
log.error("生成签名异常", e);
}
return null;
}
/**
* RSA验签名检查.
*
* @param content 待签名数据
* @param sign 签名值
* @param publicKey 分配给开发商公钥
* @return 布尔值
*/
public static boolean doCheck(byte[] content, String sign, String publicKey) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(loadPublicKeyByStr(publicKey));
signature.update(content);
return signature.verify(Base64.decode(sign));
} catch (Exception e) {
log.error("验证签名异常", e);
}
return false;
}
/**
* RSA验签名检查.
*
* @param content 待签名数据(base64)
* @param sign 签名值
* @param publicKey 分配给开发商公钥
* @return 布尔值
*/
public static boolean doCheck(String content, String sign, String publicKey) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(loadPublicKeyByStr(publicKey));
signature.update(Base64.decode(content));
return signature.verify(Base64.decode(sign));
} catch (Exception e) {
log.error("验证签名异常", e);
}
return false;
}
/**
* 从字符串中加载公钥.
*
* @param publicKeyStr 公钥数据字符串
* @return
*/
private RSAPublicKey loadPublicKeyByStr(String publicKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
log.error("公钥异常", e);
throw new Exception("公钥异常");
}
}
/**
* 获取 私钥.
*
* @param privateKeyStr 私钥数据字符串
* @throws Exception 加载私钥时产生的异常
*/
private RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
log.error("私钥异常", e);
throw new Exception("私钥异常");
}
}
/**
* 分段处理数据.
*
* @param cipher 密码算法
* @param dataes 数据
* @param segmentSize 分段大小(小于等于0不分段)
* @return
*/
private byte[] processData(Cipher cipher, byte[] dataes, int segmentSize) {
byte[] decBytes = null;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLength = dataes.length;
int offSet = 0;
for (int i = 0; inputLength - offSet > 0; offSet = i * segmentSize) {
byte[] cache;
if (inputLength - offSet > segmentSize) {
cache = cipher.doFinal(dataes, offSet, segmentSize);
} else {
cache = cipher.doFinal(dataes, offSet, inputLength - offSet);
}
out.write(cache, 0, cache.length);
++i;
}
decBytes = out.toByteArray();
out.close();
} catch (Exception e) {
log.error("分段处理数据异常", e);
}
return decBytes;
}
public static void main(String[] args) throws Exception {
// 请求端
Map<String, String> genKeyPair = genKeyPair();
// 请求端公钥
String publicKey = genKeyPair.get("publicKey");
// 请求端私钥
String privateKey = genKeyPair.get("privateKey");
// 接收端
Map<String, String> keyPair = genKeyPair();
// 接收端公钥
String toPublicKey = keyPair.get("publicKey");
// 接收端私钥
String toPrivateKey = keyPair.get("privateKey");
// -------------------------发起请求----------------------------
// 请求数据 进行数据加密 加签名
Map<String, Object> map = new HashMap<>();
map.put("username", "zsh");
map.put("age", 35);
String plainText = JsonUtils.toJsonString(map);
System.out.println("加密前数据:" + plainText);
// 接收端 公钥加密
byte[] encrypt = encryptByPublicKey(toPublicKey, plainText.getBytes(StandardCharsets.UTF_8));
System.out.println("base64加密之前数据:" + Arrays.toString(encrypt));
// base64加密
String data = Base64.encode(encrypt);
System.out.println("base64加密之后数据:" + data);
// 签名 私钥
String sign = sign(data, privateKey);
System.out.println("加密签名:" + sign);
// --------------------------收到请求---------------------------
// 收到加密数据
// 验签 请求端 公钥
String content = Arrays.toString(Base64.decode(data));
System.out.println("base64解密之后数据:" + content);
// 请求端 公钥
// 验签
boolean doCheck = doCheck(data, sign, publicKey);
System.out.println("验签:" + doCheck);
// 接收端 公钥解密
// 私钥
byte[] decrypt = decryptByPrivateKey(toPrivateKey, data);
System.out.println("解密后数据:" + new String(decrypt));
}
}