前端使用crypto-js AES 加密解密
CryptoJS是一个JavaScript加密算法库,用于在客户端欣赏器中执行加密和解密操纵。它提供了一系列常见的加密算法,如AES、DES、Triple DES、Rabbit、RC4、MD5、SHA-1等等。
AES
工作原理
AES(高级加密标准)是一种对称加密算法,即加密和解密使用相同的密钥。它可以加密长度为128、192和256位的数据块,并使用128位的密钥进行加密。AES算法使用了固定的块长度和密钥长度,并且被广泛应用于许多安全协媾和标准中,例如SSL/TLS、SSH、IPSec等。
在AES加密中,明文被分成128位的块,每个块使用相同的密钥进行加密。加密过程包括以下步调:
- 密钥扩展:将密钥扩展为加密算法所需的轮密钥。
- 初始轮:将明文分成块,并与第一轮密钥进行异或。
- 多轮加密:将初始轮产生的效果反复进行多轮加密,每轮使用不同的轮密钥进行加密。
- 最终轮:在最后一轮加密中,将块进行加密,但是不再进行下一轮加密,而是直接输出密文。
解密过程与加密过程雷同,只是将加密过程中的步调反过来。必要注意的是,解密的过程中使用的是相同的密钥和轮密钥。由于AES是一种块加密算法,因此在加密过程中,必要对数据进行填充,确保数据块大小为128位。
AES算法的长处
- 安全性高:AES算法是一种可靠的加密算法,它在数据传输、文件加密和网络安全等范畴有着广泛的应用。
- 服从高:AES算法接纳对称加密算法进行加密和解密,使用相同的密钥进行加密和解密。对称加密算法比非对称加密算法更加高效,因此AES算法具有更高的服从。
- 应用广泛:AES算法在数据传输、文件加密和网络安全等范畴有着广泛的应用。在数据传输过程中,AES算法可以对数据进行加密,掩护数据的安全性。在文件加密过程中,AES算法可以对文件进行加密,掩护文件的安全性。在网络安全范畴,AES算法可以对网络数据进行加密,掩护网络的安全性。
github地址: https://github.com/brix/crypto-js
cryptojs文档: https://cryptojs.gitbook.io/docs/#encoders
在线aes加密解密工具: http://tool.chacuo.net/cryptaes
使用JSEncrypt进行RSA加密的基本步调如下:
前端:
- 初始化: 引入jsencrypt库并出始化JSEncrypt对象,使用encrypt.setPublicKey()方法设置公钥,公钥是随机恣意字符串 。
- 天生私钥和偏移量: 随机天生aes的私钥key和偏移量 iv,使用encrypt.encrypt()方法对私钥key和偏移量iv进行加密得到code,并将code传给后端, 将私钥与code存入客户端。
- 加密: 引入CryptoJS插件,使用CryptoJS.AES.encrypt()方法联合天生的私钥key和偏移量iv加密数据。
后端:
- 初始化: 使用encrypt.setPrivateKey()方法设置私钥,私钥要与前端的公钥划一。
- 解密code: 使用encryptor.decrypt()方法解密code得到eas的私钥key和偏移量iv。
- 解密数据: 引入CryptoJS插件, 使用CryptoJS.AES.decrypt()方法联合key和iv解密数据。
必要注意的是,由于JSEncrypt是在客户端上执行的,以是密钥在传输过程中可能会存在安全风险。为了确保数据的安全性,建议在客户端和服务器之间使用安全的通信协议进行数据传输,并在服务器端进行进一步的安全验证和处理。
安装
script 标签嵌入
- <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>
复制代码 npm 或 yarn 安装
- npm install crypto-js
- yarn add crypto-js
复制代码 CommonJS
- const CryptoJS = require('crypto-js');
复制代码 ES module:
- import CryptoJS from 'crypto-js';
复制代码 封装加密和解密
- // 创建key.js文件
- import JSEncrypt from 'jsencrypt'
- const encrypt = new JSEncrypt();
- let publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeCDcnFrS7DIRbvZLHreVUzaMbAFy2DYmioxBK606urY4rVR8IgLgUhnyw2/GQ99pyr8lGtqPeOoapantw1XwEVyi74MDxs4UDL8j4OZR1Es7HVGOB0GwKWobdU9cm/1iDwGyouSmijxKyAePg6KsLNgbjDPYZRS11bYEuZ8/RLQIDAQAB';
- // 设置公钥
- encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----' + publicKey + '-----END PUBLIC KEY-----')
- const random = (length) => {
- var str = Math.random().toString(36).substr(2);
- if (str.length >= length) {
- return str.substr(0, length);
- }
- str += random(length - str.length);
- return str;
- }
- export const rsaEncode = (src) => {
- // 加密数据
- let data = encrypt.encrypt(src);
- return data
- };
- export const getKey = () => {
- // 生成私钥和偏移量
- let key = { key: random(16), iv: random(16) };
- // 对私钥和偏移量加密
- let code = rsaEncode(key.key + ',' + key.iv);
- window.codeArr = window.codeArr || {};
- // 存入客户端
- codeArr[code] = key;
- return {
- key, code
- }
- };
- export const getAesKey = (aes) => {
- console.log('aes: ', aes);
- let key = JSON.parse(JSON.stringify(codeArr[aes]));
- // 从客户端获取到 key
- delete codeArr[aes];
- return key
- };
- window.getKey = getKey
- window.rsaEncode = rsaEncode
-
复制代码- // 创建 encrypt.js 文件import CryptoJS from 'crypto-js';
- // ------------AES 加密-------------function getAesString(data, key, iv) {//加密 let keys = CryptoJS.enc.Utf8.parse(key) let vis = CryptoJS.enc.Utf8.parse(iv) let encrypt = CryptoJS.AES.encrypt(data, keys, { iv: vis, //iv偏移量 CBC需加偏移量 mode: CryptoJS.mode.CBC, //CBC模式 // mode: CryptoJS.mode.ECB, //ECB模式 padding: CryptoJS.pad.Pkcs7 //padding处理 }); // debugger return encrypt.toString(); //加密完成后,转换成字符串}// ------------AES 解密-------------function getDAesString(encrypted, key, iv) { // 解密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var decrypted =CryptoJS.AES.decrypt(encrypted,key,{ iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8);}// AES 对称秘钥加密const aes = { en: (data, key) => getAesString(data, key.key, key.iv), de: (data, key) => getDAesString(data, key.key, key.iv)};export { aes };
复制代码 publicKey 可以通过发哀求后端返回,也可以自己界说,要求前后端划一
封装 axios 拦截器进行加密解密
- /**
- *
- * http配置
- *
- */
- // 引入axios以及element ui中的loading和message组件
- import { aes } from "@/util/encrypt.js";
- import { getKey, getAesKey } from "@/config/key.js";
- import axios from "axios";
- import store from "../store";
- import router from "../router/router";
- import { Loading, Message } from "element-ui";
- import { getSessStore, setSessStore } from "@/util/store";
- // 超时时间
- if (store.online) axios.defaults.timeout = 20000;
- else axios.defaults.timeout = 0;
- //跨域请求,允许保存cookie
- axios.defaults.withCredentials = true;
- // 统一加解密
- const Unify = {
- // 统一加密方法
- en(data, key) {
- // 1.aes加密
- let aesStr = aes.en(JSON.stringify(data), key);
- return aesStr;
- },
- // 统一解密
- de(aesStr, key) {
- // 1.aes解密
- let dataStr = aes.de(aesStr, key);
- // 3.转json对象
- let data = JSON.parse(dataStr);
- return data;
- },
- };
- let loadinginstace;
- let cfg, msg;
- msg = "服务器君开小差了,请稍后再试";
- function ens(data) {
- // debugger
- let src = [...data];
- src = JSON.stringify(src);
- let dataJm = aes.en(src);
- return dataJm;
- }
- function des(data) {
- // debugger
- let src = [...data];
- let dataJm = aes.de(src);
- dataJm = JSON.parse(dataJm);
- return dataJm;
- }
- const cancelToken = axios.CancelToken
- const source = cancelToken.source()
- //HTTPrequest拦截
- axios.interceptors.request.use(
- function (config) {
- console.log(config.data, "加密前入参---");
- config.cancelToken = source.token; // 全局添加cancelToken
- loadinginstace = Loading.service({
- fullscreen: true,
- });
- if (store.getters.token) {
- let info = getSessStore("token");
- // console.log("info", info);
- config.headers["Authorization"] = "Bearer " + info; // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
- }
- const contenttype = config.headers.common["Accept"];
- let types = contenttype.includes("application/json");
- let key = getKey(); // 获取密钥
- config.headers["aes"] = key.code; // 将 aes 的 code 设置到请求头,传给后端解密
- config.headers["name"] = "send";
- if (types) {
- if (config.method == "post" || config.method == "put") {
- if (config.data) {
- config.headers["crypto"] = true;
- config.headers["content-type"] = "application/json";
- let data = {
- body: config.data,
- };
- let dataJm = Unify.en(data, key.key); // 加密 post 请求参数
- config.data = dataJm;
- }
- }
- }
- return config;
- },
- (error) => {
- return Promise.reject(error);
- }
- );
- //HTTPresponse拦截
- axios.interceptors.response.use(
- (response) => {
- loadinginstace.close();
- let res = response.data || {};
- if (response.headers["date"]) {
- store.commit("setServiceTime", response.headers.date);
- }
- if (res.crypto) {
- try {
- let key = getAesKey(response.headers.aes); // 拿到加密后的key
- if (!key) {
- message("获取密钥异常", "error");
- return Promise.reject(res);
- }
- // debugger
- res = Unify.de(res.body, key); // 解密数据
- response.data = res;
- } catch (err) {
- message("系统异常:" + err.message, "error");
- return Promise.reject(err);
- }
- }
- // debugger
- if (res.code === 1) {
- message(res.msg, "error");
- return Promise.reject(res);
- }
- console.log(response, "解密后response");
- return response;
- },
- (error) => {
- console.log("错误信息", error);
- loadinginstace.close();
- const res = error.response || {};
- if (res.status === 478 || res.status === 403 || res.status === 401) {
- let resMsg = res.data.msg ? res.data.msg : res.data.data
- if (res.status === 403) {
- message('服务授权失败,请联系管理添加权限!', "error");
- } else {
- message(resMsg, "error");
- }
- let flg = res.data.msg.includes('当前登录状态已失效')
- if (res.status === 478 && flg) {
- //token失效
- source.cancel('登录信息已过期'); // 取消其他正在进行的请求
- store.dispatch("FedLogOut").then(() => {
- router.push("/login"); ///test
- });
- }
- } else if (res.status === 400) {
- message(res.data.error_description, "error");
- } else if (res.status === 202) {
- //三方未绑定
- this.$router.push({
- path: "/",
- });
- } else if (res.status === 503 || res.status === 504) {
- //服务异常
- message(res.data, "error");
- } else if (
- (res.status === 401 && res.statusText == "Unauthorized") ||
- res.data.error == "invalid_token" ||
- res.data.error == "unauthorized"
- ) {
- //token失效
- store.dispatch("FedLogOut").then(() => {
- router.push("/login"); ///test
- });
- } else {
- message(res.data.message, "error");
- }
- return Promise.reject(error);
- }
- );
- export function message(text, type) {
- let t = text ? text : "服务或网络异常!"
- Message({
- message: t,
- type: type,
- duration: 30 * 1000,
- center: true,
- showClose: true
- });
- }
- export default axios;
复制代码 总结
加密: 使用 JSEncrypt 天生私钥 key 和偏移量 iv 并将密钥 key 和 iv 加密得到 code, 使用 CryptoJS.AES.encrypt() 和 key 加密哀求数据,将 加密后的 code 设置在哀求头,后端获取加密后 code 进行解密得到私钥 key ,再对哀求数据解密得到原始数据
解密: 前端获取响应头的key,从window得到私钥 key, 使用 CryptoJS.AES.decrypt() 方法对响应数据进行解密,得到原始数据
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |