RSA 帮助类
import lombok.extern.slf4j.Slf4j;import javax.crypto.Cipher;import java.io.ByteArrayOutputStream;import java.security.*;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.Base64;import java.util.HashMap;import java.util.Map;/*** 公私钥工具类*/@Slf4jpublic class RsaUtils {/** RSA算法标识 */public static final String RSA = "RSA";/** 算法 */public static final String ENCRYP_TYPE = "SHA256WithRSA";/** UTF-8编码 */public static final String CHARSET_UTF8 = "utf-8";/** 公钥字段名 */public static final String GEN_PUBLIC_KEY = "public_Key";/** 私钥字段名 */public static final String GEN_PRIVATE_KEY = "private_key";/*** RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024*/public static final Integer KEY_LENGTH = 512;/*** RSA最大加密明文大小*/private static final int MAX_ENCRYPT_BLOCK = 53;/*** RSA最大解密密文大小*/private static final int MAX_DECRYPT_BLOCK = 64;/*** 生成公私钥** @return 公私钥集合*/public static Map<String, String> generatorRsaKey() {Map<String, String> map = new HashMap(2);KeyPairGenerator keyPairGen;try {keyPairGen = KeyPairGenerator.getInstance(RSA);// 初始化密钥对生成器,密钥大小为1024位keyPairGen.initialize(KEY_LENGTH, new SecureRandom());// 生成一个密钥对,保存在keyPair中KeyPair keyPair = keyPairGen.generateKeyPair();// 得到私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();// 得到公钥RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();// 公钥map.put(GEN_PUBLIC_KEY, new String(Base64.getEncoder().encode(publicKey.getEncoded())));// 私钥map.put(GEN_PRIVATE_KEY, new String(Base64.getEncoder().encode(privateKey.getEncoded())));} catch (Exception e) {log.error("init rsa key error!", e);throw new GatewayRuntimeException(ResultCode.GENERATOR_KEY_ERROR);}return map;}/*** 创建私钥** @param privateKeyStr* @return*/public static PrivateKey createPrivateKey(String privateKeyStr) {try {byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr.getBytes(CHARSET_UTF8));// 生成私匙KeyFactory kf = KeyFactory.getInstance(RSA);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);return kf.generatePrivate(keySpec);} catch (Exception e) {log.error("init private key error!", e);throw new GatewayRuntimeException(ResultCode.CREATE_PRIVATE_KEY_ERROR);}}/*** 创建公钥** @param publicKeyStr* @return*/public static PublicKey createPublicKey(String publicKeyStr) {try {byte[] publickeyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(CHARSET_UTF8));X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publickeyBytes);KeyFactory keyFactory = KeyFactory.getInstance(RSA);return keyFactory.generatePublic(x509EncodedKeySpec);} catch (Exception e) {log.error("init public key error!", e);throw new GatewayRuntimeException(ResultCode.CREATE_PUBLIC_KEY_ERROR);}}/*** 加签** @param signContent 签名内容* @param privateKey 私钥* @return*/public static String doSign(String signContent, PrivateKey privateKey) {try {Signature signature = Signature.getInstance(ENCRYP_TYPE);signature.initSign(privateKey);signature.update(signContent.getBytes(CHARSET_UTF8));byte[] sign = signature.sign();return new String(Base64.getEncoder().encode(sign), CHARSET_UTF8);} catch (Exception e) {log.error("generator sign error!", e);throw new GatewayRuntimeException(ResultCode.DATA_SIGNATURE_ERROR);}}/*** 验签** @param content 内容* @param sign 签名* @param publicKey 公钥* @return*/public static boolean verifySign(String content, String sign, PublicKey publicKey) {try {Signature sig = Signature.getInstance(ENCRYP_TYPE);sig.initVerify(publicKey);byte[] signs = Base64.getDecoder().decode(sign.getBytes(CHARSET_UTF8));sig.update(content.getBytes(CHARSET_UTF8));return sig.verify(signs);} catch (Exception e) {log.error("verify sign error!", e);throw new GatewayRuntimeException(ResultCode.ILLEGAL_SIGN);}}/*** RSA加密** @param content 内容* @param publicKey 公钥* @return*/public static String encrypt(String content, PublicKey publicKey) {try {Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.ENCRYPT_MODE, publicKey);return new String(Base64.getEncoder().encode(cipher.doFinal(content.getBytes(CHARSET_UTF8))), CHARSET_UTF8);} catch (Exception e) {log.error("rsa encrypt error!", e);throw new GatewayRuntimeException(ResultCode.ENCODE_DATE_ERROR);}}/*** RSA解密** @param content 内容* @param privateKey 私钥* @return*/public static String decrypt(String content, PrivateKey privateKey) {try {//64位解码加密后的字符串byte[] inputByte = Base64.getDecoder().decode(content.getBytes(CHARSET_UTF8));//RSA解密Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.DECRYPT_MODE, privateKey);return new String(cipher.doFinal(inputByte));} catch (Exception e) {log.error("rsa decrypt error!", e);throw new GatewayRuntimeException(ResultCode.DNCODE_DATE_ERROR);}}/** *//*** <P>* 私钥解密* </p>** @param encryptedData 已加密数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] encryptedData, PrivateKey privateKey) throws Exception {/*byte[] keyBytes = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);*/Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.DECRYPT_MODE, privateKey);int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/** *//*** <p>* 公钥解密* </p>** @param encryptedData 已加密数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPublicKey(byte[] encryptedData, PublicKey publicKey) throws Exception {/*byte[] keyBytes = Base64.getDecoder().decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());*/Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.DECRYPT_MODE, publicKey);int inputLen = encryptedData.length;try(ByteArrayOutputStream out = new ByteArrayOutputStream()){int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}return out.toByteArray();}}/** *//*** <p>* 公钥加密* </p>** @param data 源数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, PublicKey publicKey) throws Exception {/*byte[] keyBytes = Base64.getDecoder().decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());*/Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.ENCRYPT_MODE, publicKey);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/** *//*** <p>* 私钥加密* </p>** @param data 源数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {/*byte[] keyBytes = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());*/Cipher cipher = Cipher.getInstance(RSA);cipher.init(Cipher.ENCRYPT_MODE, privateKey);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/*** 公钥加密(分段)** @param data* @param publicKey* @return*/public static String encryptByPublicKeyToString(String data, PublicKey publicKey) throws Exception {byte[] inputByte = data.getBytes(CHARSET_UTF8);byte[] result = encryptByPublicKey(inputByte,publicKey);return new String(Base64.getEncoder().encode(result), CHARSET_UTF8);}/*** 私钥解密(分段)** @param data* @param privateKey* @return*/public static String decryptByPrivateKeyToString(String data, PrivateKey privateKey) throws Exception {byte[] inputByte = Base64.getDecoder().decode(data.getBytes(CHARSET_UTF8));byte[] result = decryptByPrivateKey(inputByte,privateKey);return new String(result, CHARSET_UTF8);}}
AES帮助类
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESUtils {
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
public static final String AES = "AES";
public static final String CHARSET_UTF8 = "utf-8";
public AESUtils() {
}
public static String encrypt(String content, String key) throws Exception {
byte[] raw = key.getBytes(CHARSET_UTF8);
SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(1, skeySpec);
byte[] encrypted = cipher.doFinal(content.getBytes(CHARSET_UTF8));
return new String(Base64.getEncoder().encode(encrypted), CHARSET_UTF8);
}
public static String dcrypt(String content, String key) throws Exception {
byte[] raw = key.getBytes(CHARSET_UTF8);
SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(2, skeySpec);
byte[] encrypted1 = Base64.getDecoder().decode(content);
byte[] original = cipher.doFinal(encrypted1);
return new String(original, CHARSET_UTF8);
}
}

指定位数 ,128 ,192, 256
测试代码
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* @Author: Luis
* @Description:
* @Date: 2021/5/24 16:30
*/
public class PerformanceTest {
/**
* 获取随机字符串,由数字、大小写字母组成
*
* @param bytes:生成的字符串的位数
* @return
* @author
*/
public static String getRandomStr(int bytes) {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < bytes; i++) {
//随机判断判断该字符是数字还是字母
String choice = random.nextInt(2) % 2 == 0 ? "char" : "num";
if ("char".equalsIgnoreCase(choice)) {
//随机判断是大写字母还是小写字母
int start = random.nextInt(2) % 2 == 0 ? 65 : 97;
sb.append((char) (start + random.nextInt(26)));
} else if ("num".equalsIgnoreCase(choice)) {
sb.append(random.nextInt(10));
}
}
return sb.toString();
}
/**
*
// 1024 1k
// 1024 * 1024 1M
// 1024 * 1024 * 5 5M
// 1024 * 1024 * 10 10M
// 1024 * 1024 * 100 100M
// 1024 * 1024 * 1024 1G
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//testRsa();
//testPerformanceAES();
testPerformanceRSA();
}
public static void testPerformanceAES() throws Exception {
int size;
int num = 100; // 次数
System.out.println("----------验证AES算法加解密性能-----------");
size = 1024; // 1kb
performanceAES(size,num);
size = 1024 * 64; // 64 kb
performanceAES(size,num);
size = 1024 * 128; // 128 kb
performanceAES(size,num);
size = 1024 * 256; // 256 kb
performanceAES(size,num);
size = 1024 * 512; // 512 kb
performanceAES(size,num);
size = 1024 * 1024; // 1 mb
performanceAES(size,num);
size = 1024 * 1024 * 3; // 3 mb
performanceAES(size,num);
size = 1024 * 1024 * 5; // 5 mb
performanceAES(size,num);
System.out.println("------------------------------------------");
}
public static void testPerformanceRSA() throws Exception {
int size;
int num = 100; // 次数
System.out.println("----------验证AES算法加解密性能-----------");
size = 1024; // 1kb
performanceRSA(size,num);
size = 1024 * 64; // 64 kb
performanceRSA(size,num);
size = 1024 * 128; // 128 kb
performanceRSA(size,num);
size = 1024 * 256; // 256 kb
performanceRSA(size,num);
size = 1024 * 512; // 512 kb
performanceRSA(size,num);
size = 1024 * 1024; // 1 mb
performanceRSA(size,num);
size = 1024 * 1024 * 3; // 3 mb
performanceRSA(size,num);
size = 1024 * 1024 * 5; // 5 mb
performanceRSA(size,num);
System.out.println("------------------------------------------");
}
/**
* 验证AES 算法
*
* @param size
* @param num
*/
private static void performanceAES(int size, int num) throws Exception {
long encryptCostTime = 0,dcryptCostTime = 0;
String key = UUIDUtils.genReqNo().substring(0, 16);
List<String> encryptDatas = new ArrayList();
for (int i = 0; i < num; i++) {
String content = getRandomStr(size);
long encryptStartTime = System.currentTimeMillis();
String encryptStr = AESUtils.encrypt(content,key);
encryptCostTime = encryptCostTime + (System.currentTimeMillis() - encryptStartTime);
encryptDatas.add(encryptStr);
}
System.out.println(String.format("------AES加密数据大小:%s,次数:%s,总耗时:%s,平均耗时:%s ",size,num,encryptCostTime,(encryptCostTime/num)));
for(String encryptStr : encryptDatas){
long dcryptStartTime = System.currentTimeMillis();
AESUtils.dcrypt(encryptStr,key);
dcryptCostTime = dcryptCostTime + (System.currentTimeMillis() - dcryptStartTime);
}
System.out.println(String.format("------AES解密数据大小:%s,次数:%s,总耗时:%s,平均耗时:%s ",size,num,dcryptCostTime,(dcryptCostTime/num)));
}
/**
* 验证AES 算法
*
* @param size
* @param num
*/
private static void performanceRSA(int size, int num) throws Exception {
Map<String, String> rsaKeys = RsaUtils.generatorRsaKey();
PrivateKey privateKey = RsaUtils.createPrivateKey(rsaKeys.get(GEN_PRIVATE_KEY));
PublicKey publicKey = RsaUtils.createPublicKey(rsaKeys.get(GEN_PUBLIC_KEY));
long encryptCostTime = 0,dcryptCostTime = 0;
List<String> encryptDatas = new ArrayList();
for (int i = 0; i < num; i++) {
String content = getRandomStr(size);
long encryptStartTime = System.currentTimeMillis();
//RsaUtils.encrypt(content,publicKey);
String encryptStr = RsaUtils.encryptByPublicKeyToString(content,publicKey);
encryptCostTime = encryptCostTime + (System.currentTimeMillis() - encryptStartTime);
encryptDatas.add(encryptStr);
}
System.out.println(String.format("------RSA加密数据大小:%s,次数:%s,总耗时:%s,平均耗时:%s ",size,num,encryptCostTime,(encryptCostTime/num)));
for(String encryptStr : encryptDatas){
long dcryptStartTime = System.currentTimeMillis();
//RsaUtils.decrypt(encryptStr,privateKey);
RsaUtils.decryptByPrivateKeyToString(encryptStr,privateKey);
dcryptCostTime = dcryptCostTime + (System.currentTimeMillis() - dcryptStartTime);
}
System.out.println(String.format("------RSA解密数据大小:%s,次数:%s,总耗时:%s,平均耗时:%s ",size,num,dcryptCostTime,(dcryptCostTime/num)));
}
private static void testRsa() throws Exception {
Map<String, String> rsaKeys = RsaUtils.generatorRsaKey();
PrivateKey privateKey = RsaUtils.createPrivateKey(rsaKeys.get(GEN_PRIVATE_KEY));
PublicKey publicKey = RsaUtils.createPublicKey(rsaKeys.get(GEN_PUBLIC_KEY));
String content = getRandomStr(100);
System.out.println("orig message = "+ content);
String encryptStr = RsaUtils.encryptByPublicKeyToString(content,publicKey);
System.out.println("encrypt message = "+ encryptStr);
String decryptStr = RsaUtils.decryptByPrivateKeyToString(encryptStr,privateKey);
System.out.println("decrypt message = "+ decryptStr);
}
}
性能测试
AES加解密
RSA加解密

| RSA密钥长度 | 最大加密内容大小 |
|---|---|
| 512 | 53 bytes |
| 1024 | 117 bytes |
| 2048 | 245 bytes |
| 65536 | 16384 bits |
结论
- 解密要比加密耗时长,另外加密后的报文大小大于未加密的报文
- RSA默认一次加密的内容长度不太够,如果使用需要对内容进行分段加密
- AES加解密的效率明显优于RSA算法
