https://blog.csdn.net/ddx2019/article/details/102964182
https://www.cnblogs.com/chaoyuehedy/p/9947381.html
以上兩種方法我用得時候報錯:Uncaught Error: Malformed UTF-8 data at Object.stringify (crypto-js.js:478) at WordArray.init.toString (crypto-js.js:215) ,沒找到解決方法,就自己進行了封裝。。
以下是自己得封裝方法。
1. 安裝:
npm install crypto-js 或者yarn add crypto-js
2. 引入crypto-js,並封裝加密解密的方法
secureUtil.js
/** * Created by lijingwei on 2018/1/12. */ import CryptoJS from 'crypto-js' // SecureUtil = function () { var CONTRAST = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var DICTIONARIES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()"; var IV_TEXT = "0102030405060708"; /** * 字符串轉byte[] */ export function stringToByte(str) { var bytes = new Array(); var len, c; len = str.length; for (var i = 0; i < len; i++) { c = str.charCodeAt(i); if (c >= 0x010000 && c <= 0x10FFFF) { bytes.push(((c >> 18) & 0x07) | 0xF0); bytes.push(((c >> 12) & 0x3F) | 0x80); bytes.push(((c >> 6) & 0x3F) | 0x80); bytes.push((c & 0x3F) | 0x80); } else if (c >= 0x000800 && c <= 0x00FFFF) { bytes.push(((c >> 12) & 0x0F) | 0xE0); bytes.push(((c >> 6) & 0x3F) | 0x80); bytes.push((c & 0x3F) | 0x80); } else if (c >= 0x000080 && c <= 0x0007FF) { bytes.push(((c >> 6) & 0x1F) | 0xC0); bytes.push((c & 0x3F) | 0x80); } else { bytes.push(c & 0xFF); } } return bytes; } /** * byte[]轉字符串 */ function byteToString(arr) { if (typeof arr === 'string') { return arr; } var str = '', _arr = arr; for (var i = 0; i < _arr.length; i++) { var one = _arr[i].toString(2), v = one.match(/^1+?(?=0)/); if (v && one.length == 8) { var bytesLength = v[0].length; var store = _arr[i].toString(2).slice(7 - bytesLength); for (var st = 1; st < bytesLength; st++) { store += _arr[st + i].toString(2).slice(2); } str += String.fromCharCode(parseInt(store, 2)); i += bytesLength - 1; } else { str += String.fromCharCode(_arr[i]); } } return str; } /** * 十六進制字符串轉字節數組 */ function Str2Bytes(str) { var pos = 0; var len = str.length; if (len % 2 != 0) { return null; } len /= 2; var hexA = new Array(); for (var i = 0; i < len; i++) { var s = str.substr(pos, 2); var v = parseInt(s, 16); hexA.push(v); pos += 2; } return hexA; } /** * 字節數組轉十六進制字符串 */ function Bytes2Str(arr) { var str = ""; for (var i = 0; i < arr.length; i++) { var tmp = arr[i].toString(16); if (tmp.length == 1) { tmp = "0" + tmp; } str += tmp; } return str; } /** * 字符串插入指定位置字符 */ function insertChar(str, char, pos) { var oldstrArray = [str.substring(0, pos), str.substring(pos, str.length)]; // console.log("拆分后字符串 = %s", oldstrArray.toString()); var newstr = oldstrArray[0] + char + oldstrArray[1]; // console.log("組合后字符串 = %s", newstr); return newstr; } /** * 加密 */ export function encryption(content) { content = content.replace(/,/g, "FENGEFU"); // console.log("密前文本 = %s", content); // 根據DICTIONARIES生成16為動態密鑰 var maxPos = DICTIONARIES.length; // 密鑰字典最大長度 var LEN = 16; // 密鑰長度 var password = ''; // 動態密鑰 var array = new Array(maxPos) .fill(0) .map((v, i)=>i + 1) .sort(()=>0.5 - Math.random()) .filter((v, i)=>i < LEN); // 生成16個不同隨機數,作為字典抽取角標 for (var i = 0; i < array.length; i++) { password += DICTIONARIES.charAt(array[i] - 1); } // console.log("原始動態密鑰 = %s", password); // AES加密內容 var key = CryptoJS.enc.Utf8.parse(password); var iv = CryptoJS.enc.Utf8.parse(IV_TEXT) var encryptResult = CryptoJS.AES.encrypt(content, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 轉BASE64,增加加密強度 var encryptedStr = encryptResult.ciphertext.toString(); // // encryptedStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(encryptedStr)); // encryptedStr = Bytes2Str(stringToByte(encryptedStr)); // console.log(encryptedStr); // console.log("原始加密后密文 = %s", encryptedStr); // 密鑰干擾 var currentTimeMillis = (new Date()).valueOf().toString(); // 獲得當前時間戳 var currentTimeMillisLength = currentTimeMillis.length; if (currentTimeMillisLength < 13) { // 解決特殊機型獲取當前時間毫秒位數異常 var missingCount = 13 - currentTimeMillisLength; for (var i = 0; i < missingCount; i++) { currentTimeMillis = currentTimeMillis + i; } } else if (currentTimeMillis.length > 13) { currentTimeMillis = currentTimeMillis.substring(0, 13); } // console.log("當前時間戳 = %s", currentTimeMillis); // console.log("當前時間戳長度 = %s", currentTimeMillis.length); var h = new Array(); // 實際插入角標集合 var arrayTime = new Array(16) .fill(0) .map((v, i)=>i + 1) .sort(()=>0.5 - Math.random()) .filter((v, i)=>i < currentTimeMillis.length); // 生成16個不同隨機數,作為字典抽取角標 for (var i = 0; i < arrayTime.length; i++) { // console.log("取16位隨機數第 %s 位", arrayTime[i] - 1); h[i] = arrayTime[i] - 1; } // console.log("集合長度 = %s", h.length); var indexs = ""; // 插入角標字符串,每位是要插入的角標 //隨機選取要插入干擾字符 var arrayMix = new Array(13) .fill(0) .map((v, i)=>i + 1) .sort(()=>0.5 - Math.random()) .filter((v, i)=>i < h.length); // 生成13個不同隨機數,作為字典抽取角標 // console.log("arrayMix集合長度 = %s", arrayMix.length); for (var i = 0; i < arrayMix.length; i++) { var charAt = currentTimeMillis.charAt(arrayMix[i] - 1); //取隨機干擾字符 // console.log("干擾字符 = %s", charAt); password = insertChar(password, charAt, h[i]); // console.log("已插入干擾字符密鑰 = %s", password); indexs += CONTRAST.charAt(h[i]); // 將10進制角標映射為16進制標識方式 } // console.log("混淆插入角標索引集合字符串 = %s", indexs); // console.log("混淆后的動態密鑰 = %s", password); //將角標分成兩節(0~6)(6~13) var qian = indexs.substring(0, 6); var hou = indexs.substring(6, 13); //將分好的兩節分別拼接到角標前后 password = qian + password + hou; // console.log("最終攜帶混淆角標混淆后的動態密鑰 = %s", password); var result = password + "," + encryptedStr; // console.log("最終加密文本 = %s", result); var byteResult = stringToByte(result); // console.log("最終字節加密文本 = %s", byteResult); var hexResult = Bytes2Str(byteResult).toUpperCase(); // console.log("最終16進制加密文本 = %s", hexResult); // console.log("--------------------------"); return hexResult; } /** * 解密 * @param content */ export function decryption(content) { var btyeMessage = Str2Bytes(content); // console.log("最終16進制轉字符串加密文本Byte = %s", btyeMessage); var message = byteToString(btyeMessage); // console.log("字節轉字符串加密文本 = %s", message); var resultArray = message.split(","); // console.log("混淆密鑰 = %s", resultArray[0]); var realMessage = resultArray[1]; // console.log("實際密文 = %s", realMessage); var qian = resultArray[0].substring(0, 6); var hou = resultArray[0].substring(resultArray[0].length - 7, resultArray[0].length); var indexs16 = qian + hou; var password = resultArray[0].substring(6, resultArray[0].length - 7) // console.log("干擾字符角標 = %s", indexs16); // console.log("干擾后密鑰 = %s", password); var indexArray = indexs16.split(""); // console.log("角標數量 = %s", indexArray); for (var i = indexArray.length - 1; i >= 0; i--) { var pos = parseInt(indexArray[i], 16); // 16進制字符轉10進制字符 // console.log("干擾字符角標 = %s", pos); password = password.substring(0, pos) + password.substring(pos + 1); // console.log("刪除干擾字符后 = %s", password); } // console.log("實際密鑰 = %s", password); // AES解密內容 var key = CryptoJS.enc.Utf8.parse(password); var iv = CryptoJS.enc.Utf8.parse(IV_TEXT) // realMessage = CryptoJS.enc.Hex.parse(realMessage).toString(); var encryptedHexStr = CryptoJS.enc.Hex.parse(realMessage); var encryptedBase64Str2 = CryptoJS.enc.Base64.stringify(encryptedHexStr); var decryptedData = CryptoJS.AES.decrypt(encryptedBase64Str2, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); var decryptedStr = decryptedData.toString(CryptoJS.enc.Utf8); decryptedStr = decryptedStr.replace(/FENGEFU/g, ","); // console.log("最終文本 = %s", decryptedStr); return decryptedStr; } // }; export default { encryption, decryption }
utils.js
/** * 工具類 */ import secureUtils from './secureUtil' //加密解密 export function demoRequest(data) { var encryptMessage = secureUtils.encryption(data); return encryptMessage; } export function demoResponse(data) { var decryptMessage = secureUtils.decryption(data); return decryptMessage; } export default { demoRequest, demoResponse }
3. 在入口文件main.js中使用
import Utils from './utils/utils'
Vue.prototype.$Utils = Utils
在組件中使用
加密:
this.$Utils.demoRequest(JSON.stringify(data))
要加密得數據必須先轉為字符串
解密:
data = JSON.parse(this.$Utils.demoResponse(res.data))
解密完轉換為JSON對象