export const helper = { typeOf(o: any) { return ({}).toString.call(o).slice(8, -1).toLowerCase(); }, isString(o: any) { return helper.typeOf(o) === 'string'; }, isObject(o: any) { return helper.typeOf(o) === 'object'; }, safetyParse(o: any) { try { return helper.isString(o) ? JSON.parse(o) : o; } catch (e) { return o; } } }; export default class ReCrypto { CryptoJS: any; ORI_16: string[]; KEYS: { // 十六位十六进制数作为密钥 SECRET: any; // 十六位十六进制数作为密钥偏移量 SECRET_IV: any; }; IS_ENCRYPTED_SIGN: { key: string; value: string; }; constructor({ CryptoJS }: any) { this.CryptoJS = CryptoJS || null; this.ORI_16 = ['q1', 'w2', 'e3', 'r4', 't5', 'y6', 'u7', 'i8']; const _reduceFn = (prev: string, item: string) => `${prev}${item}`; this.KEYS = { // 十六位十六进制数作为密钥 SECRET: this.CryptoJS.enc.Utf8.parse(this.ORI_16.reduce(_reduceFn, '')), // 十六位十六进制数作为密钥偏移量 SECRET_IV: this.CryptoJS.enc.Utf8.parse(this.ORI_16.reduceRight(_reduceFn, '')), }; this.IS_ENCRYPTED_SIGN = { key: '_', value: '_', }; if (!CryptoJS) { console.error('没有捕获到正确的 CryptoJS'); } } /** * 加密 * @param {*} oriData 源数据 * @returns {String} 加密结果 */ encrypt(oriData: any) { const data = JSON.stringify(oriData); const dataHex = this.CryptoJS.enc.Utf8.parse(data); const encrypted = this.CryptoJS.AES.encrypt(dataHex, this.KEYS.SECRET, { iv: this.KEYS.SECRET_IV, mode: this.CryptoJS.mode.CBC, padding: this.CryptoJS.pad.Pkcs7, }); return encrypted.ciphertext.toString(); } /** * 解密 * @param {String} oriStr 源数据 * @returns {*} 解密结果 */ decrypt(oriStr: unknown) { const encryptedHexStr = this.CryptoJS.enc.Hex.parse(oriStr); const str = this.CryptoJS.enc.Base64.stringify(encryptedHexStr); const decrypt = this.CryptoJS.AES.decrypt(str, this.KEYS.SECRET, { iv: this.KEYS.SECRET_IV, mode: this.CryptoJS.mode.CBC, padding: this.CryptoJS.pad.Pkcs7 }); const decryptedStr = decrypt.toString(this.CryptoJS.enc.Utf8); return helper.safetyParse(decryptedStr.toString()); } /** * 是否是加密过的固定格式 * @param {*} oriData 待验证数据 * @returns {Boolean} */ isEncrypted(oriData: any) { const data = helper.safetyParse(oriData); const isObj = helper.isObject(data); const hasKey = Object.prototype.hasOwnProperty.call(data, this.IS_ENCRYPTED_SIGN.key); const valMatched = data[this.IS_ENCRYPTED_SIGN.key] === this.IS_ENCRYPTED_SIGN.value; return isObj && hasKey && valMatched; } /** * 获取固定加密格式的加密串 * @param {*} oriData 加密格式 * @returns {String} */ getOriEncryptCont(oriData: any) { const data = helper.safetyParse(oriData); return data[data.k] || ''; } /** * 基于加密串构造固定格式的加密内容 * @param {*} cont 加密串 * @returns {String} */ makeJSONCont(cont: any) { return `{ "${this.IS_ENCRYPTED_SIGN.key}": "${this.IS_ENCRYPTED_SIGN.key}", "k": "v", "v": "${cont}" }`; } /** * 基于原始数据加密-构造固定格式的加密内容 * @param {*} cont 原始数据 * @returns {String} */ makeEncryptJSONCont(cont: any) { return this.makeJSONCont(this.encrypt(cont)); } /** * 基于固定格式加密内容解密 * @param {Object} jsonCont 固定加密格式内容 * @returns {String} */ decryptEncryptedJSON(jsonCont: any) { return this.decrypt(this.getOriEncryptCont(jsonCont)); } /** * 获取真实数据 - 尝试 parse,失败返回原始的 * @param data * @returns {*} */ getRealData(data: any) { return helper.safetyParse(this.isEncrypted(data) ? this.decryptEncryptedJSON(data) : data); } }