您现在的位置是:首页 > 技术教程 正文

前端使用 crypto-js 库 aes加解密

admin 阅读: 2024-03-26
后台-插件-广告管理-内容页头部广告(手机)

前端使用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

安装

script 标签嵌入

<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>
  • 1

npm 或 yarn 安装

npm install crypto-js yarn add crypto-js
  • 1
  • 2
  • 3

CommonJS

const CryptoJS = require('crypto-js');
  • 1

ES module:

import CryptoJS from 'crypto-js';
  • 1
封装加密和解密
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(); //加密完成后,转换成字符串 } 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) }; // BASE64 const base64 = { en: (data) => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)), de: (data) => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8) }; // SHA256 const sha256 = (data) => { return CryptoJS.SHA256(data).toString(); }; // MD5 const md5 = (data) => { return CryptoJS.MD5(data).toString(); }; export { aes, md5, sha256, base64 };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
使用 JSEncrypt 生成密钥

JSEncrypt是基于JavaScript的RSA加密库,允许在浏览器端使用RSA算法进行加密和解密操作。它提供了容易使用的API,简化了在客户端上进行加密的过程。

JSEncrypt支持以下操作:

  • 生成密钥对: 可以使用JSEncrypt生成RSA密钥对,包括公钥和私钥。

  • 加密: 使用公钥加密数据,确保只有拥有私钥的服务器才能解密。

  • 解密: 使用私钥解密被公钥加密过的数据。

  • 密钥格式: JSEncrypt支持多种密钥格式,包括PEM格式(基于Base64编码)。

使用JSEncrypt进行RSA加密的基本步骤如下:

  • 引入JSEncrypt库: 在HTML页面中引入JSEncrypt库的脚本文件。

  • 创建JSEncrypt对象: 使用JSEncrypt构造函数创建一个新的JSEncrypt对象。

  • 生成密钥对: 封装getKey()方法生成RSA密钥对,并将生成的私钥加密后传给后端。

  • 加密数据: 使用encrypt.encrypt(plainText)方法,将明文数据进行加密。

  • 解密数据: 在服务器端使用私钥进行解密,获取原始数据。

需要注意的是,由于JSEncrypt是在客户端上执行的,所以密钥在传输过程中可能会存在安全风险。为了确保数据的安全性,建议在客户端和服务器之间使用安全的通信协议进行数据传输,并在服务器端进行进一步的安全验证和处理。

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)=>{ let key = JSON.parse(JSON.stringify(codeArr[aes])) delete codeArr[aes] return key }; window.getKey = getKey window.rsaEncode = rsaEncode
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

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); /// 拿到公钥加密字符串 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183

总结

加密: 使用 JSEncrypt 生成私钥 key 并将密钥 key 加密得到 code, 使用 CryptoJS.AES.encrypt() 和 key 加密请求数据,将 加密后的 code 设置在请求头,后端获取加密后 code 进行解密得到私钥 key ,再对请求数据解密得到原始数据
解密: 前端获取响应头的key,通过解密 JSEncrypt 解密得到私钥 key, 使用 CryptoJS.AES.decrypt() 方法对响应数据进行解密,得到原始数据

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索