一、AES和RSA简单介绍
- AES:对称加解密,加密解密使用同一个秘钥。
- RSA:非对称加解密,使用公钥加密数据,只有对应的私钥才能解密,加密方和解密方各自保存秘钥对中的一个。(这里推荐一个RSA密钥对生成器,在线生成无需安装,方便快捷:传送门)
二、基本步骤
1、项目结构如下:(完整代码:传送门)
2、代码示例
- 前端页面:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AES、RSA加密</title>
<script th:src="@{/js/jquery-3.6.0.js}"></script>
<script th:src="@{/js/crypto-js.js}"></script>
<script th:src="@{/js/jsencrypt.js}"></script>
</head>
<body>
<h1>加密算法demo</h1>
<h2>AES加密,后台解密</h2>
<input id="aesValue"/>
<button onclick="encryptAes()">加密AES,返回解密后的明文</button>
<h2>RSA加密,后台解密</h2>
<input id="rsaValue"/>
<button onclick="encryptRsa()">加密RSA,返回解密后的明文</button>
</body>
<script>
/**
* AES 加密方法
*/
function encryptAes() {
// 密钥,后端也用相同的密钥解密
var secretKey = 'uBdUx82vPHkDKb284d7NkjFoNcKWBuka';
var encryptedData = CryptoJS.AES.encrypt($("#aesValue").val(), CryptoJS.enc.Utf8.parse(secretKey), {
iv: CryptoJS.enc.Utf8.parse('1234567887654321'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 加密内容要toString(),返回的才是加密的字符串
console.info(encryptedData.toString());
// 后台解密
$.ajax({
type: "get",
url: "/demo/decryptAes",
data: {value: encryptedData.toString()},
success: function(data) {
alert('解密内容是:' + data);
},
error: function() {
}
});
}
/**
* RSA 加密方法
*/
function encryptRsa() {
var encrypt = new JSEncrypt();
// 设置公钥
encrypt.setPublicKey('MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsRVQfE0mOFCBqthPyNLzJTtENgRAw2O4g7RhWQhms3P+uKHt+Kuff+YaHKpAQ6XiyPmJSAS9joaemvF5ew9k3ZGuDYnXNd3Vwxq9bTHnPAZeTLzVQ1n5iOmid1BR56ENynLkw8LSHgcHPixwvXfJNVHczip/1aXqwAmZS1GKLnJXye1+qv+WeWMcLOAYRVi1sm+nhRV+TzN3o9ykPqiEY8bmAOWo//jD68YgVRWwlnOY+euGzfWV4mhxyVSJ1jjwvM5Aox+HfABHnWPQ/3DdTmtM7NJKAYVhCZOOgQAY/os2OBf8AIC6uHmwFkJvUS4YkUPS5kRE+s1SR3iIxaAeEwIDAQAB');
// 使用公钥加密,返回加密后的数据
var encrypted = encrypt.encrypt($("#rsaValue").val());
console.info(encrypted);
// 前台解密
var decrypt = new JSEncrypt();
// 设置私钥
decrypt.setPrivateKey('MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCxFVB8TSY4UIGq2E/I0vMlO0Q2BEDDY7iDtGFZCGazc/64oe34q59/5hocqkBDpeLI+YlIBL2Ohp6a8Xl7D2Tdka4Nidc13dXDGr1tMec8Bl5MvNVDWfmI6aJ3UFHnoQ3KcuTDwtIeBwc+LHC9d8k1UdzOKn/VperACZlLUYouclfJ7X6q/5Z5Yxws4BhFWLWyb6eFFX5PM3ej3KQ+qIRjxuYA5aj/+MPrxiBVFbCWc5j564bN9ZXiaHHJVInWOPC8zkCjH4d8AEedY9D/cN1Oa0zs0koBhWEJk46BABj+izY4F/wAgLq4ebAWQm9RLhiRQ9LmRET6zVJHeIjFoB4TAgMBAAECggEAXzpSFPY8Bm6svF4k0Z83aB8t+EpjNW+r6w+WhhVxfTF0mn9iBKbuWA46no2jj31mrqMagyMheMLGChavOFE38bsEuX0VwX7xFEGN+mmqqunVzjiCCv0YptrVJoqH8SL30pXkla1v5vvqljG50vnWtxi1wBy0sATQb8L5r7pCr+SiNAlbt2X7ePyk7EkKTpon6Bl2249dZnDedOdz+wH/lQs9rGxvtqeBqbqWCj7GsxEuQysSBtnvsta/vw7M+/VvEiRh5MUrCVvJrt/thJwWMY57e01iHLuURf6xnrZqvYPrCcz5i2MVbXVawyCIq5TJAJLyeGRkXGXIvtqbkM3xAQKBgQDfYq0i4yWmnB88NehdnnTb3Tmtxtd3A+2tHzJF3dYAc1a6zAFXqTDPbt5SsqoonIbbBAzdvREHCWw4yc8XGIx18/tdxeF385V/umpPkhM+v+QYmFOLDjdODD3JByIccMMW392Zrhe6A1JA5b83XjUJs1wwFogrIY/HWElHlZ1tkwKBgQDK8Ahvl0mRnbSgA6aQ1iUzOiz7tEZRHFiep0kis8pLsePxL3UsKXP5rgssMk+hj4oLsDqRi9OXyKVFIy7N/b7DNUqnAG9y8w1ASZYvHdgJ3GndjOSESWQia83RDxaVTHP+6AQVkcSoz6HjA/JZh3FX34ogyThX/g10eEeuD/zdgQKBgDAGvQaFI3Egm66MQHrwOFuUwnPUDjruQ0k3Lc3Lldje80SR27AHFhFi2rWY5/B3Rp8LzeBWZ7TFl9jVuopSotAxNlfA1Wq+meOuJnEZDL4u71FCXqPE2KsVAquXtwO6Upc2ZiRGQ5+gWyzMuEGlJW4Ce81y6q+rNYg8OPUE+6W1AoGAXuSwvSV8BDg/PteWKoHIMVURtb0NaF4d3koQ+8YgYRbUpHHxk23qyiSlGsyHyd8pyN9l86rzjTUIevTBrRbq/bLMrpyYgKLAXoBKVsvYunuzkSKRtH3w8duBCTHJ+JQgZWCukDtyPxGf/FxbFZws1s8zcrNEwniMaBraQb0+G4ECgYANbFMZEFxZ/zy3BAiWQvGMWTKTocopmaMGhvHrqoSvsXea4HFBPfq1YF32SzamB+5xVb6ePWLK7Vl8wYSHXLkyh6kWO8FJz9Q3VmmfGhMQe17+x4/D6zPg68cKmghhnzupKRFv2pZPpNIyGZ2GRpG28+AtIvnjWFzi1NJSowKe6w==');
var uncrypted = decrypt.decrypt(encrypted);
console.info(uncrypted);
// 后台解密
$.ajax({
type: "get",
url: "/demo/decryptRsa",
data: {value: encrypted},
success: function(data) {
alert('解密内容是:' + data);
},
error: function() {
}
});
}
</script>
</html>
- AesUtils:
package com.fds.system.utils;
/**
* @author fds
* @date 2020-09-16 11:17
**/
public class AesUtils {
/**
* 密钥, 256位32个字节
*/
public static final String DEFAULT_SECRET_KEY = "uBdUx82vPHkDKb284d7NkjFoNcKWBuka";
private static final String AES = "AES";
/**
* 初始向量IV, 初始向量IV的长度规定为128位16个字节, 初始向量的来源为随机生成.
*/
private static final byte[] KEY_VI = "1234567887654321".getBytes();
/**
* 加密解密算法/加密模式/填充方式
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static java.util.Base64.Encoder base64Encoder = java.util.Base64.getEncoder();
private static java.util.Base64.Decoder base64Decoder = java.util.Base64.getDecoder();
static {
java.security.Security.setProperty("crypto.policy", "unlimited");
}
/**
* AES加密
*/
public static String encode(String key, String content) {
try {
javax.crypto.SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(key.getBytes(), AES);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, new javax.crypto.spec.IvParameterSpec(KEY_VI));
// 获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
byte[] byteEncode = content.getBytes(java.nio.charset.StandardCharsets.UTF_8);
// 根据密码器的初始化方式加密
byte[] byteAES = cipher.doFinal(byteEncode);
// 将加密后的数据转换为字符串
return base64Encoder.encodeToString(byteAES);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* AES解密
*/
public static String decode(String key, String content) {
try {
javax.crypto.SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(key.getBytes(), AES);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKey, new javax.crypto.spec.IvParameterSpec(KEY_VI));
// 将加密并编码后的内容解码成字节数组
byte[] byteContent = base64Decoder.decode(content);
// 解密
byte[] byteDecode = cipher.doFinal(byteContent);
return new String(byteDecode, java.nio.charset.StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- RsaUtils:
package com.fds.system.utils;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* @author: fds
* @date: 2021/7/13
* @description: RSA非对称加密工具类
*/
public class RsaUtils {
/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt(String str, String publicKey) throws Exception {
// base64编码的公钥
byte[] decoded = Base64.getDecoder().decode(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
// RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
}
/**
* RSA私钥解密
*
* @param str 加密字符串
* @param privateKey 私钥
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception {
// 64位解码加密后的字符串
byte[] inputByte = Base64.getDecoder().decode(str);
// base64编码的私钥
byte[] decoded = Base64.getDecoder().decode(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
// RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
return new String(cipher.doFinal(inputByte));
}
}
- DemoController:
package com.fds.system.controller;
import com.fds.system.utils.AesUtils;
import com.fds.system.utils.RsaUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Value("${rsa.secretKey}")
private String secretKey;
/**
* aes解密接口
* @param value
* @return
*/
@GetMapping("/decryptAes")
public String decryptAes(String value) {
return AesUtils.decode(AesUtils.DEFAULT_SECRET_KEY, value);
}
/**
* rsa解密接口
* @param value
* @return
*/
@GetMapping("/decryptRsa")
public String decryptRsa(String value) throws Exception {
return RsaUtils.decrypt(value, secretKey);
}
}
最后作者本人还有一个计划小程序。给自己一个计划,每天有盼头,喜欢的可以扫一扫,蟹蟹大家的支持。