第一步:在本地安装OpenSSL(安装步骤省略),打开/bin目录下的openssl.exe文件。输入一下命令。
1.生成RSA私钥
genrsa -out rsa_private_key.pem 1024
2.把RSA私钥转换成PKCS8格式
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
3.生成公钥
rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
第二步:将pkcs8.pem文件和rsa_public_key.pem文件的绝对路径取到。
第三步:在Controller层新建2个方法。
1.对返回值进行加密(公钥)。@Encrypt :对返回值进行加密的注解
//对返回的字符串进行加密
@Encrypt
@GetMapping("/encryption")
public String encryption() {
return "成功";
//对返回的实体类进行加密
@Encrypt
@GetMapping("/encryption")
public 实体ShiTi encryption() {
ShiTi shiTi = new ShiTi ();
shiTi.setvalue("值");
return shiTi;
2.对请求参数进行解密(私钥)。@Decrypt:对接收数据进行解密的注解
@Decrypt
@PostMapping("/decryption")
public String Decryption(@RequestBody String a(上一个方法加密之后的数据)){
return a(解密之后的数据);
}
第四步:在一个项目同级目录下新建文件夹存放2个注解文件。
//解密
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Decrypt {
}
//加密
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Encrypt {
}
第五步:三个加解密的工具类。
/**
* 私钥加解密【服务器使用】
*/
@Component
public class PrivateKeyUtils {
/**
* 服务端:私钥加密
* @param privatePath
* @param plainText
*/
public static String encrypt(String privatePath, String plainText) throws Exception {
try {
RSAPrivateKey privateKey = RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadKeyByFile(privatePath));
byte[] cipherData = RSAEncrypt.encrypt(privateKey, plainText.getBytes());
Base64 base64 = new Base64();
String cipher = new String(base64.encode(cipherData));
return cipher;
} catch (Exception e) {
e.printStackTrace();
//return "error";
throw new Exception(e.getMessage());
}
}
/**
* 服务端:私钥解密
*/
public static String decrypt(String privatePath, String cipherText) {
try {
Base64 base64 = new Base64();
RSAPrivateKey privateKey = RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadKeyByFile(privatePath));
byte[] res = RSAEncrypt.decrypt(privateKey, base64.decode(cipherText));
String plain = new String(res);
return plain;
} catch (Exception e) {
e.printStackTrace();
return "error";
}
}
}
/**
* 公钥加解密【客户端使用】
*/
public class PublicKeyUtils {
/**
* 客户端:公钥加密
* @param publicPath
* @param plainText
*/
public static String encrypt(String publicPath, String plainText){
if (StringUtils.isEmpty(publicPath)) {
throw new IllegalArgumentException("公钥为空");
}
if (new File(publicPath).exists() == false) {
throw new IllegalArgumentException("公钥不存在");
}
if (StringUtils.isEmpty(plainText)) {
throw new IllegalArgumentException("数据为空");
}
try {
RSAPublicKey publicKey = RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadKeyByFile(publicPath));
byte[] cipherData = RSAEncrypt.encrypt(publicKey, plainText.getBytes());
Base64 base64 = new Base64();
String cipher = new String(base64.encode(cipherData));
return cipher;
} catch (Exception e) {
e.printStackTrace();
return "error";
}
}
/**
* 客户端:公钥解密
* @param publicPath
* @param cipherText
* @return
*/
public static String decrypt(String publicPath, String cipherText) {
try {
Base64 base64 = new Base64();
RSAPublicKey publicKey = RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadKeyByFile(publicPath));
byte[] res = RSAEncrypt.decrypt(publicKey, base64.decode(cipherText));
String plain = new String(res);
return plain;
} catch (Exception e) {
e.printStackTrace();
return "error";
}
}
}
/**
* RSA加密组件
*/
public class RSAEncrypt {
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// RSA最大加密明文大小
private static final int MAX_ENCRYPT_BLOCK = 117;
// RSA最大解密密文大小
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 随机生成密钥对
* @param filePath 密钥存放路径
* @param filePrefix 密钥名称前缀
*/
public static void genKeyPair(String filePath, String filePrefix) {
KeyPairGenerator keyPairGen = null;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
try {
// 得到公钥字符串
Encoder base64 = Base64.getEncoder();
String publicKeyString = new String(base64.encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(base64.encode(privateKey.getEncoded()));
// 将密钥对写入到文件
StringBuffer publicKeyName = new StringBuffer();
publicKeyName.append(filePath).append("/").append(filePrefix).append("_public_key.pem");
StringBuffer privateKeyName = new StringBuffer();
privateKeyName.append(filePath).append("/").append(filePrefix).append("_private_key.pem");
FileWriter pubfw = new FileWriter(new String(publicKeyName));
FileWriter prifw = new FileWriter(new String(privateKeyName));
BufferedWriter pubbw = new BufferedWriter(pubfw);
BufferedWriter pribw = new BufferedWriter(prifw);
pubbw.write(publicKeyString);
pribw.write(privateKeyString);
pubbw.flush();
pubbw.close();
pubfw.close();
pribw.flush();
pribw.close();
prifw.close();
System.out.println("公钥是:" + publicKeyName + "私钥是:" + privateKeyName);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从文件中输入流中加载密钥
* @param path 公钥输入流
* @throws Exception 加载公钥时产生的异常
*/
public static String loadKeyByFile(String path) throws Exception {
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
br.close();
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("密钥数据流读取错误");
} catch (NullPointerException e) {
throw new Exception("密钥输入流为空");
}
}
/**
* 从字符串中加载公钥
* @param publicKeyStr 公钥数据字符串
* @throws Exception 加载公钥时产生的异常
*/
public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
throws Exception {
try {
Decoder decoder = Base64.getMimeDecoder();//注不要使用.getDecoder();
byte[] buffer = decoder.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 从字符串中加载私钥
*/
public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
throws Exception {
try {
Decoder base64Decoder = Base64.getMimeDecoder();
byte[] buffer = base64Decoder.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
e.printStackTrace();
throw new Exception("私钥非法");
} catch (NullPointerException e) {
e.printStackTrace();
throw new Exception("私钥数据为空");
}
}
/**
* 公钥加密过程
* @param publicKey 公钥
* @param plainTextData 明文数据
* @throws Exception 加密过程中的异常信息
*/
public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
throws Exception {
if (publicKey == null) {
throw new Exception("加密公钥为空, 请设置");
}
Cipher cipher = null;
try {
// 使用默认RSA
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 明文数据的长度
int inputLen = plainTextData.length;
int offSet = 0;
int i = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] output = null;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
output = cipher.doFinal(plainTextData, offSet, MAX_ENCRYPT_BLOCK);
} else {
output = cipher.doFinal(plainTextData, offSet, inputLen - offSet);
}
out.write(output, 0, output.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
//return output;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此加密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("加密公钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("明文长度非法");
} catch (BadPaddingException e) {
throw new Exception("明文数据已损坏");
}
}
/**
* 私钥加密过程
*
* @param privateKey 私钥
* @param plainTextData 明文数据
* @return
* @throws Exception 加密过程中的异常信息
*/
public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
throws Exception {
if (privateKey == null) {
throw new Exception("加密私钥为空, 请设置");
}
Cipher cipher = null;
try {
// 使用默认RSA
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
// 明文数据的长度
int inputLen = plainTextData.length;
int offSet = 0;
int i = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] output = null;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
output = cipher.doFinal(plainTextData, offSet, MAX_ENCRYPT_BLOCK);
} else {
output = cipher.doFinal(plainTextData, offSet, inputLen - offSet);
}
out.write(output, 0, output.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此加密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("加密私钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("明文长度非法");
} catch (BadPaddingException 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("解密私钥为空, 请设置");
}
Cipher cipher = null;
try {
// 使用默认RSA
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 密文的长度
int inputLen = cipherData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] output;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
output = cipher.doFinal(cipherData, offSet, MAX_DECRYPT_BLOCK);
} else {
output = cipher.doFinal(cipherData, offSet, inputLen - offSet);
}
out.write(output, 0, output.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此解密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
e.printStackTrace();
throw new Exception("解密私钥非法,请检查");
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
throw new Exception("密文长度非法");
} catch (BadPaddingException e) {
e.printStackTrace();
throw new Exception("密文数据已损坏");
}
}
/**
* 公钥解密过程
* @param publicKey 公钥
* @param cipherData 密文数据
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
throws Exception {
if (publicKey == null) {
throw new Exception("解密公钥为空, 请设置");
}
Cipher cipher = null;
try {
// 使用默认RSA
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// 密文的长度
int inputLen = cipherData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] output;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
output = cipher.doFinal(cipherData, offSet, MAX_DECRYPT_BLOCK);
} else {
output = cipher.doFinal(cipherData, offSet, inputLen - offSet);
}
out.write(output, 0, output.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此解密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("解密公钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("密文长度非法");
} catch (BadPaddingException e) {
throw new Exception("密文数据已损坏");
}
}
/**
* 字节数据转十六进制字符串
* @param data 输入数据
* @return 十六进制内容
*/
public static String byteArrayToString(byte[] data) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < data.length; i++) {
// 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
// 取出字节的低四位 作为索引得到相应的十六进制标识符
stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
if (i < data.length - 1) {
stringBuilder.append(' ');
}
}
return stringBuilder.toString();
}
}
第六步:三个加解密的通知类。
public class DecryptHttpInputMessage implements HttpInputMessage {
private InputStream body;
public DecryptHttpInputMessage(HttpInputMessage inputMessage, boolean showLog) throws Exception {
String privatePath = 私钥证书的绝对地址;
if (StringUtils.isEmpty(privatePath)) {
throw new IllegalArgumentException("私钥为空");
}
String content = new BufferedReader(new InputStreamReader(inputMessage.getBody()))
.lines().collect(Collectors.joining(System.lineSeparator()));
String decryptBody;
if (content.startsWith("{")) {
logger.info("Unencrypted without decryption:{}", content);
decryptBody = content;
} else {
content = content.replaceAll(" ", "+");
// 私钥解密
decryptBody = PrivateKeyUtils.decrypt(privatePath, content);
logger.info("decryptBody=" + decryptBody);
if (showLog) {
logger.info("Encrypted data received:{},After decryption:{}", content, decryptBody);
}
}
this.body = new ByteArrayInputStream(decryptBody.getBytes());
}
@Override
public InputStream getBody() {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}
@ControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
// 是否使用"解密"注解
private boolean encrypt;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
// 判断方法 是否使用"解密"注解
if (methodParameter.getMethod().isAnnotationPresent(Decrypt.class)) {
encrypt = true;
}
return encrypt;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType){
if (encrypt) {
logger.info("--START--");
logger.info("-DecryptRequestBodyAdvice-");
try {
return new DecryptHttpInputMessage(inputMessage,false);
} catch (Exception e) {
e.printStackTrace();
logger.error("Decryption failed", e);
}
}
return inputMessage;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Autowired
private BocommMerchantService bocommMerchantService;
// 是否使用"加密"注解
private boolean encrypt;
private static ThreadLocal<Boolean> encryptLocal = new ThreadLocal<>();
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// 判断方法 是否使用"加密"注解
if (returnType.getMethod().isAnnotationPresent(Encrypt.class)) {
encrypt = true;
}
return encrypt;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Boolean status = encryptLocal.get();
if (null != status && !status) {
encryptLocal.remove();
return body;
}
if (encrypt) {
try {
String publicPath = 公钥证书的绝对路径;
if (StringUtils.isEmpty(publicPath)){
throw new IllegalArgumentException("公钥为空");
}
// 响应数据转成JSON字符串
String content = JSON.toJSONString(body);
//公钥加密
String result = PublicKeyUtils.encrypt(publicPath, content);
return result;
} catch (Exception e) {
throw new CustomException(e.getMessage(), 11);
}
}
return body;
}
}
第七步:在需要加解密的方法或接口根据需求上添加@Decrypt和@Encrypt注解即可。