RSA工具类,这个就是网上大多数通用的代码了,无非就是生成密钥,获取公,私钥,分段加解密这些了。
注意:1、RSA默认支持最大加密的为117位,解密的为128,如果你的内容超出了就必须要进行分段加解密。刚一开始楼主报的错误就是因为这一个。
2、还有一个要提一下的,毕竟曾经掉进过坑里。1024位的密钥和2048位的密钥解密最大分别对应128和256,我下面打了注释的,多留意一下。
package com.qyq.springbootapi.util;
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;
public class RsaUtil {
/**
* 指定加密算法
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 指定生成多少位的密钥
*/
private static final int KEY_BIT = 1024;
/** *//**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/** *//**
* RSA最大解密密文大小
* 1024位密钥的要设置为128,
* 248位密钥的要改成256,不然会报错
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 生成密钥对
* @return
* @throws Exception
*/
public static Map genKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(KEY_BIT);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();//生成公钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();//生成密钥
Map map = new HashMap<>(2);
map.put("publicKey",rsaPublicKey);
map.put("privateKey",rsaPrivateKey);
return map;
}
/**
* 获取公钥
* @param map
* @return
*/
public static String getPublicKey(Map map){
Key key = (Key) map.get("publicKey");
String publicKey = Base64.getEncoder().encodeToString(key.getEncoded());
return publicKey;
}
/**
* 获取私钥
* @param map
* @return
*/
public static String getPrivate(Map map){
Key key = (Key) map.get("privateKey");
String privateKey = Base64.getEncoder().encodeToString(key.getEncoded());
return privateKey;
}
/**
* 公钥分段加密 --》公钥加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static String encrypt(String data, String publicKey) throws Exception {
byte[] bytes = Base64.getDecoder().decode(publicKey);//先把公钥进行解码
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.getBytes("UTF-8").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.getBytes("UTF-8"), offset, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data.getBytes("UTF-8"), offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
// 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
// 加密后的字符串
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* 私钥分段解密 --》私钥解密
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static String decrypt(String data, String privateKey) throws Exception {
byte[] bytes = Base64.getDecoder().decode(privateKey);//先对私钥进行解码
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
byte[] dataBytes = Base64.getDecoder().decode(data);//对要解密的数据进行解码
int inputLen = dataBytes.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(dataBytes, offset, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
// 解密后的内容
return new String(decryptedData, "UTF-8");
}
}
@GetMapping("/test")
public ResponseResult TestApiController(){
String object = restTemplate.getForObject("http://localhost:8080/get", String.class);
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMcJilCfGtsoXe/ioAqT2sh36bz2j+KmUUcaKaF+dQNQ/LKTZNyftazl44Oyl6gEGfSYkFgGiCMutv6EMHlPRV6AYL8VNo8BmcDGDfWWyL3fDIpxtD99IXLV7k0f7Hm4doEuaEEb9pY3+wpAYe2Fr41MLRv4kI9nG7/OH24/cTHdAgMBAAECgYATKFPr1qSbG5OPF10YJ4sTaJdS3NiUlDWWhmojZSyWGSF5fr5ijezKq4Xuky4NufdVl6mtD1PjLwfmD4sq4fpnJqfAuUMUGe3NC9Y6hm3VqWdXqY9UrRaQQUUsPlQlxaMYCOwjPdgvk3BRkIet1vY/63EWjrFfXXqhb+GpgKz68QJBAO4/FZI7E9lK8BMRodrT44rB1W0hV/nan0Lel2ZSoZf0QhChCtQLP6WJ3rfC1IQHmL9ZWVqD1fzndXEHyAJcUmcCQQDV3ns0lVFll76dGZ0VEB8G+vVD7L8TIpJSuCaRKf4KZXIWoOUIoefgNEEW8AGF9EwkPlUNFrSXahEeyvjFgNcbAkAvqKLyC6tezmTUC7TrB3P/L+M333Gv45H0WH7E00bMFOqaVPzLiiyDOt84t1q3xqVBsefz+Wd3Hf4aTEowXrOFAkBrPi/r00BIwEnd/z0MldPpLSiV0f6SetCC2ELGohb4YZxPCokuxfk/LRTCisFIyZLwzazabltKXe6N0VvjtdKnAkEAxxToDiKLandMMcAZjpeQS57ENSq17DVA7v3ZCl5W9wIIi7zGwcfUFZ/Uwwk55+Hrx/DmBqxQjhGanPzp9XWMVw==";
try {
String decrypt = RsaUtil.decrypt(object, privateKey);
return new ResponseResult(0,"成功",decrypt);
} catch (Exception e) {
e.printStackTrace();
return new ResponseResult(0,"失败",404);
}
}
@GetMapping("/get")
public String TestApiController1(){
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHCYpQnxrbKF3v4qAKk9rId+m89o/iplFHGimhfnUDUPyyk2Tcn7Ws5eODspeoBBn0mJBYBogjLrb+hDB5T0VegGC/FTaPAZnAxg31lsi93wyKcbQ/fSFy1e5NH+x5uHaBLmhBG/aWN/sKQGHtha+NTC0b+JCPZxu/zh9uP3Ex3QIDAQAB";
String data = "这是一个测试接口";
try {
String encrypt = RsaUtil.encrypt(data, publicKey);
return encrypt;
} catch (Exception e) {
e.printStackTrace();
return "null";
}
}
万事俱备只欠东风了,结果运行时他又给我抛出了一个错,后面还是靠度娘解决了,现在贴一下,就是下面这个错
java.lang.IllegalArgumentException: Illegal base64 character 22
狗日的,原来是因为导的包造成的。
Base64这个东西因为我导的是java.util.Base64这个包下的,jdk1.8后用的编码表不一样,不包括换行符。后面还是改成使用apache common包中的org.apache.commons.codec.binary.Base64类进行编码和解码才解决。
由于jdk1.7和jdk1.8内置的Base64遵守的RFC协议不一致,jdk1.7按照照RFC1521实现的,jdk1.8是按照rfc4648和rfc2045两个协议来实现的。具体可以从类注释中查询到。由于协议的不同可能导致jdk1.8的解码jdk1.7编码的数据时抛出java.lang.IllegalArgumentException: Illegal base64 character a异常.因此需要特别注意保持解码编码的一致性。
jdk7的编码结果包含换行;
jdk8的编码结果不包含换行;
jdk8无法解码包含换行的编码结果;