前端使用crypto-js庫aes加解密詳細(xì)代碼示例
前言
CryptoJS是一個JavaScript加密算法庫,用于在客戶端瀏覽器中執(zhí)行加密和解密操作。它提供了一系列常見的加密算法,如AES、DES、Triple DES、Rabbit、RC4、MD5、SHA-1等等。
AES
工作原理
AES(高級加密標(biāo)準(zhǔn))是一種對稱加密算法,即加密和解密使用相同的密鑰。它可以加密長度為128、192和256位的數(shù)據(jù)塊,并使用128位的密鑰進行加密。AES算法使用了固定的塊長度和密鑰長度,并且被廣泛應(yīng)用于許多安全協(xié)議和標(biāo)準(zhǔn)中,例如SSL/TLS、SSH、IPSec等。
在AES加密中,明文被分成128位的塊,每個塊使用相同的密鑰進行加密。加密過程包括以下步驟:
密鑰擴展:將密鑰擴展為加密算法所需的輪密鑰。
初始輪:將明文分成塊,并與第一輪密鑰進行異或。
多輪加密:將初始輪產(chǎn)生的結(jié)果反復(fù)進行多輪加密,每輪使用不同的輪密鑰進行加密。
最終輪:在最后一輪加密中,將塊進行加密,但是不再進行下一輪加密,而是直接輸出密文。
解密過程與加密過程類似,只是將加密過程中的步驟反過來。需要注意的是,解密的過程中使用的是相同的密鑰和輪密鑰。由于AES是一種塊加密算法,因此在加密過程中,需要對數(shù)據(jù)進行填充,確保數(shù)據(jù)塊大小為128位。
AES算法的優(yōu)點
安全性高:AES算法是一種可靠的加密算法,它在數(shù)據(jù)傳輸、文件加密和網(wǎng)絡(luò)安全等領(lǐng)域有著廣泛的應(yīng)用。
效率高:AES算法采用對稱加密算法進行加密和解密,使用相同的密鑰進行加密和解密。對稱加密算法比非對稱加密算法更加高效,因此AES算法具有更高的效率。
應(yīng)用廣泛:AES算法在數(shù)據(jù)傳輸、文件加密和網(wǎng)絡(luò)安全等領(lǐng)域有著廣泛的應(yīng)用。在數(shù)據(jù)傳輸過程中,AES算法可以對數(shù)據(jù)進行加密,保護數(shù)據(jù)的安全性。在文件加密過程中,AES算法可以對文件進行加密,保護文件的安全性。在網(wǎng)絡(luò)安全領(lǐng)域,AES算法可以對網(wǎng)絡(luò)數(shù)據(jù)進行加密,保護網(wǎng)絡(luò)的安全性。
github地址: https://github.com/brix/crypto-js
cryptojs文檔: https://cryptojs.gitbook.io/docs/#encoders
在線aes加密解密工具: http://tool.chacuo.net/cryptaes
安裝
script 標(biāo)簽嵌入
<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';
封裝加密和解密
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(); //加密完成后,轉(zhuǎn)換成字符串 } 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 };
使用 JSEncrypt 生成密鑰
JSEncrypt是基于JavaScript的RSA加密庫,允許在瀏覽器端使用RSA算法進行加密和解密操作。它提供了容易使用的API,簡化了在客戶端上進行加密的過程。
JSEncrypt支持以下操作:
生成密鑰對: 可以使用JSEncrypt生成RSA密鑰對,包括公鑰和私鑰。
加密: 使用公鑰加密數(shù)據(jù),確保只有擁有私鑰的服務(wù)器才能解密。
解密: 使用私鑰解密被公鑰加密過的數(shù)據(jù)。
密鑰格式: JSEncrypt支持多種密鑰格式,包括PEM格式(基于Base64編碼)。
使用JSEncrypt進行RSA加密的基本步驟如下:
引入JSEncrypt庫: 在HTML頁面中引入JSEncrypt庫的腳本文件。
創(chuàng)建JSEncrypt對象: 使用JSEncrypt構(gòu)造函數(shù)創(chuàng)建一個新的JSEncrypt對象。
生成密鑰對: 封裝getKey()方法生成RSA密鑰對,并將生成的私鑰加密后傳給后端。
加密數(shù)據(jù): 使用encrypt.encrypt(plainText)方法,將明文數(shù)據(jù)進行加密。
解密數(shù)據(jù): 在服務(wù)器端使用私鑰進行解密,獲取原始數(shù)據(jù)。
需要注意的是,由于JSEncrypt是在客戶端上執(zhí)行的,所以密鑰在傳輸過程中可能會存在安全風(fēng)險。為了確保數(shù)據(jù)的安全性,建議在客戶端和服務(wù)器之間使用安全的通信協(xié)議進行數(shù)據(jù)傳輸,并在服務(wù)器端進行進一步的安全驗證和處理。
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
publicKey 可以通過發(fā)請求后端返回,也可以自己定義,要求前后端一致
封裝 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; // 統(tǒng)一加解密 const Unify = { // 統(tǒng)一加密方法 en(data, key) { // 1.aes加密 let aesStr = aes.en(JSON.stringify(data), key); return aesStr; }, // 統(tǒng)一解密 de(aesStr, key) { // 1.aes解密 let dataStr = aes.de(aesStr, key); // 3.轉(zhuǎn)json對象 let data = JSON.parse(dataStr); return data; }, }; let loadinginstace; let cfg, msg; msg = "服務(wù)器君開小差了,請稍后再試"; 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, "加密前入?yún)?--"); 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 請根據(jù)實際情況自行修改 } const contenttype = config.headers.common["Accept"]; let types = contenttype.includes("application/json"); let key = getKey(); // 獲取密鑰 config.headers["aes"] = key.code; // 將 aes 的 code 設(shè)置到請求頭,傳給后端解密 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 請求參數(shù) 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("系統(tǒng)異常:" + 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('服務(wù)授權(quán)失敗,請聯(lián)系管理添加權(quán)限!', "error"); } else { message(resMsg, "error"); } let flg = res.data.msg.includes('當(dāng)前登錄狀態(tài)已失效') 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) { //服務(wù)異常 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 : "服務(wù)或網(wǎng)絡(luò)異常!" Message({ message: t, type: type, duration: 30 * 1000, center: true, showClose: true }); } export default axios;
總結(jié)
加密: 使用 JSEncrypt 生成私鑰 key
并將密鑰 key
加密得到 code
, 使用 CryptoJS.AES.encrypt()
和 key 加密請求數(shù)據(jù),將 加密后的 code
設(shè)置在請求頭,后端獲取加密后 code
進行解密得到私鑰 key
,再對請求數(shù)據(jù)解密得到原始數(shù)據(jù)
解密: 前端獲取響應(yīng)頭的key,通過解密 JSEncrypt 解密得到私鑰 key
, 使用 CryptoJS.AES.decrypt()
方法對響應(yīng)數(shù)據(jù)進行解密,得到原始數(shù)據(jù)
到此這篇關(guān)于前端使用crypto-js庫aes加解密的文章就介紹到這了,更多相關(guān)前端crypto-js庫aes加解密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于javascript canvas實現(xiàn)五子棋游戲
這篇文章主要介紹了基于javascript canvas實現(xiàn)的五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-07-07排序算法的javascript實現(xiàn)與講解(99js手記)
這篇文章主要介紹了排序算法的javascript實現(xiàn)與講解,需要的朋友可以參考下2014-09-09Bootstrap字體圖標(biāo)無法正常顯示的解決方法
這篇文章主要為大家詳細(xì)介紹了Bootstrap字體圖標(biāo)無法正常顯示的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10