发布于2021-05-30 12:09 阅读(1791) 评论(0) 点赞(26) 收藏(5)
RSA与AES加密的详细介绍这里就不写了,网上很多博客,这里就只是简单说明一下:
RSA+AES的混合加密时,AES用于给传输的数据加密,然后通过RSA给AES的秘钥加密,所以接收到数据后,就需要先解密得到AES的秘钥,然后通过AES秘钥再去解密得到数据。
下面简单说下demo中加密解密的实现过程:
这里面提到的存储秘钥的方式只是在demo中作为演示使用,可以采用更合理、更安全的方式是实现!
这样,前后端都拥有的对方RSA的公钥,后面在同一个会话中具体的请求数据时,每次各自都会生成新的AES秘钥(AES的算法也需要前后端能匹配上),RSA的秘钥则在响应位置去取就可以了。
两个加密解密工具类,里面部分有使用第三方jar(hutool-all.jar)。
package com.lr.demo.util;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
public class AESUtil {
private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法
public static String getKey(int len){
if(len % 16 != 0){
System.out.println("长度要为16的整数倍");
return null;
}
char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
char[] uuid = new char[len];
if (len > 0) {
for (int i = 0; i < len; i++) {
int x = (int) (Math.random() * (len - 0 + 1) + 0);
uuid[i] = chars[x % chars.length];
}
}
return new String(uuid);
}
public static String byteToHexString(byte[] bytes){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String strHex=Integer.toHexString(bytes[i]);
if(strHex.length() > 3){
sb.append(strHex.substring(6));
} else {
if(strHex.length() < 2){
sb.append("0" + strHex);
} else {
sb.append(strHex);
}
}
}
return sb.toString();
}
/**
* AES 加密操作
*
* @param content 待加密内容
* @param key 加密密码
* @return 返回Base64转码后的加密数据
*/
public static String encrypt(String content, String key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return org.apache.commons.codec.binary.Base64.encodeBase64String(result);//通过Base64转码返回
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* AES 解密操作
*
* @param content
* @param key
* @return
*/
public static String decrypt(String content, String key) {
try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
//执行操作
byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(content));
return new String(result, "utf-8");
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
private static SecretKeySpec getSecretKey(final String key) throws UnsupportedEncodingException {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//AES 要求密钥长度为 128
kg.init(128, new SecureRandom(key.getBytes()));
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(Arrays.copyOf(key.getBytes("utf-8"), 16), KEY_ALGORITHM);// 转换为AES专用密钥
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return null;
}
}
package com.lr.demo.util;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import org.springframework.util.Base64Utils;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
public class RSAUtil {
public static final String PB_KEY = "pb_key";
public static final String PR_KEY = "pr_key";
public static final String CLI_PB_KEY = "cli_pb_key";
/**
* 获取公私秘钥对
* @return
*/
public static Map<String, Key> getRSAKey(){
KeyPair pair = SecureUtil.generateKeyPair("RSA");
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
Map<String, Key> keys = new HashMap<>();
keys.put(PR_KEY,privateKey);
keys.put(PB_KEY,publicKey);
return keys;
}
/**
* 公钥加密
* @param pbKey
* @param content
* @return
*/
public static String encByPbKey(String pbKey,String content){
try {
byte[] bytes = Base64Utils.decode(pbKey.getBytes("UTF-8"));
RSA rsa = new RSA(null,bytes);
byte[] enc = rsa.encrypt(content.getBytes("UTF-8"), KeyType.PublicKey);
String s = new String(Base64Utils.encode(enc));
return s;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 公钥加密
* @param pbKey
* @param content
* @return
*/
public static String encByPbKey(PublicKey pbKey,String content){
try {
RSA rsa = new RSA(null,pbKey);
byte[] enc = rsa.encrypt(content.getBytes("UTF-8"), KeyType.PublicKey);
String s = new String(Base64Utils.encode(enc));
return s;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 私钥解密
* @param prKey
* @param content
* @return
*/
public static String dencByPrKey(String prKey,String content){
try {
byte[] bytes = Base64Utils.decode(prKey.getBytes("UTF-8"));
RSA rsa = new RSA(bytes,null);
byte[] denc = rsa.decrypt(Base64Utils.decode(content.getBytes("UTF-8")), KeyType.PrivateKey);
String s = new String(Base64Utils.encode(denc));
return s;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 私钥解密
* @param prKey
* @param content
* @return
*/
public static String dencByPrKey(PrivateKey prKey,String content){
try {
RSA rsa = new RSA(prKey,null);
byte[] denc = rsa.decrypt(Base64Utils.decode(content.getBytes("UTF-8")), KeyType.PrivateKey);
String s = new String(denc);
return s;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
l两个Controller,一个是初始化是秘钥交换的,一个用于测试
package com.lr.demo.controller;
import com.lr.demo.commons.Result;
import com.lr.demo.util.RSAUtil;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
import java.security.Key;
import java.security.PrivateKey;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("secret")
public class SecretController {
/**
* 返回服务端的RSA公钥
* @param session
* @return
*/
@RequestMapping("getKey")
public Result getKey(HttpSession session){
Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");
if(rsaKey == null){
rsaKey = RSAUtil.getRSAKey();
session.setAttribute("keys",rsaKey);
}
byte[] encode = Base64Utils.encode(rsaKey.get(RSAUtil.PB_KEY).getEncoded());
return Result.success(new String(encode));
}
/**
* 分段解密发送过来的客户端RSA公钥
* @param map
* @param session
* @return
*/
@RequestMapping("acceptKey")
public Result acceptKey(@RequestBody Map<String,Object> map, HttpSession session){
List<String> clientKeys = (List<String>) map.get("clientKey");
System.out.println("clientKey:" + clientKeys);
Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");
String cli_key = "";
if(clientKeys != null){
for (String item : clientKeys) {
cli_key += RSAUtil.dencByPrKey((PrivateKey) rsaKey.get(RSAUtil.PR_KEY), item);
}
}
session.setAttribute(RSAUtil.CLI_PB_KEY,cli_key);
System.out.println("解密后客户端公钥:" + cli_key);
return Result.success();
}
}
package com.lr.demo.controller;
import com.alibaba.fastjson.JSON;
import com.lr.demo.commons.Constant;
import com.lr.demo.commons.Result;
import com.lr.demo.util.AESUtil;
import com.lr.demo.util.RSAUtil;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.Key;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("sys")
public class SystemController {
@RequestMapping("login")
public Result login(@RequestBody String data, HttpServletRequest request,HttpServletResponse response){
String plaintext = dencrypt(request, data);
return Result.success(encrypt("登录成功啦",response));
}
private String dencrypt(HttpServletRequest request,String data){
// 从session中获取服务端RSA的私钥
HttpSession session = request.getSession();
Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");
HashMap<String,String> hashMap = JSON.parseObject(data, HashMap.class);
// 获取客户端发送的加密数据
String enc_data = hashMap.get(Constant.ENCRYPT_DATA);
System.out.println("获取请求数据---->:" + enc_data);
// 获取发送过来的AES秘钥
String enc_aes_key = request.getHeader(Constant.ENCRYPT_AES_KEY);
// 解密AES秘钥
String aes_key = RSAUtil.dencByPrKey((PrivateKey) rsaKey.get(RSAUtil.PR_KEY), enc_aes_key);
// AES解密
String plaintext = AESUtil.decrypt(enc_data, aes_key);
System.out.println("解密数据---->:" + plaintext);
return plaintext;
}
public Map<String, String> encrypt(String data, HttpServletResponse response){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession();
String cliKey = (String) session.getAttribute(RSAUtil.CLI_PB_KEY); // 获取客户端RSA公钥
String aesKey = AESUtil.getKey(16); // 获取AES秘钥
// RSA加密AES秘钥
String encrypt_aes_key = RSAUtil.encByPbKey(cliKey, aesKey);
// AES加密返回数据
String encrypt_data = AESUtil.encrypt(data, aesKey);
// 添加响应头(AES秘钥)
response.addHeader(Constant.ENCRYPT_AES_KEY, encrypt_aes_key);
Map<String,String> map = new HashMap<>();
map.put(Constant.ENCRYPT_DATA,encrypt_data);
return map;
}
}
前端涉及的文件较多,这里就只展示下页面,其余详细代码可以下载源码后查看。
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script src="static/js/aes_v1.0.js"></script>
<script src="static/js/rsa.js"></script>
<script src="static/js/crypto-js.js"></script>
<script src="static/js/demo.js"></script>
<script src="static/js/jquery-3.5.1.js"></script>
</head>
<body>
<form action="<%=request.getContextPath()%>/sys/login" id="loginForm">
<input type="text" name="username" value="">
<input type="password" name="password" value="">
<input type="button" value="登录" id="loginBtn">
</form>
<script>
// 首页加载时,秘钥生成和交换
getRsaKeys(f)
</script>
<script>
function getFormJson(formJqueryObj) {
var o = {};
var a = formJqueryObj.serializeArray();
$.each(a, function () {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
}
$('#loginBtn').click(function () {
var json = getFormJson($('#loginForm'))
// demo.js封装的函数
request(json,'<%=request.getContextPath()%>/sys/login',function (res) {
console.log(res)
})
})
</script>
</body>
</html>
启动项目,打开首页:
服务端日志:
当交换完秘钥后,进行登录测试:
服务端就收时的日志输出:
响应后页面的输出:
以上就是一个简单的demo,源码点击下载。
作者:Jjxj
链接:http://www.qianduanheidong.com/blog/article/116124/ac0d1121eeeee2e32027/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!