【Electron 9】调试对话图片的加密处理 1.图片加解密的公共数据key、iv等// 字符串转字节数组的方法 const stringToBytes (str: string) { let ch 0 let st [] let re: any[] [] for (let i 0; i str.length; i) { ch str.charCodeAt(i) // get char st [] // set up stack do { st.push(ch 0xFF) // push byte to stack ch ch 8 // shift value down by 1 byte } while (ch) // add stack contents to result // done because chars have wrong endianness re re.concat(st.reverse()) } // return an array of bytes return re } /** * 生成加解密公共加密key、iv、 */ export const CryptoGlobal (Codekey: string) { // 将上面下载的图片转为base64编码并处理key和iv的格式 const key Codekey || xxxxxxxxxx const iv xxxxxxxxxxxxxxx // 密钥转字节数组(16位) let keyBy stringToBytes(key) let ivBy stringToBytes(iv) // 字节数组转Uint8Array let keyBv new Uint8Array(keyBy) let ivBv new Uint8Array(ivBy) // Uint8Array转WordArray let keyWA CryptoU8array.u8array.parse(keyBv) let ivWA CryptoU8array.u8array.parse(ivBv) return { key: keyWA, subtile: { iv: ivWA, // 解密方式和后端商定为为CBC模式 mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } } }2.图片插件所需的方法u8array方法注此代码我用了单独的代码管理文件名enc-u8array.tsconst CryptoJS require(‘crypto-js’);CryptoJS.enc.u8array { /** * Converts a word array to a Uint8Array. * * param {WordArray} wordArray The word array. * * return {Uint8Array} The Uint8Array. * * static * * example * * var u8arr CryptoJS.enc.u8array.stringify(wordArray); */ stringify: function (wordArray: { words: any; sigBytes: any }) { // Shortcuts var words wordArray.words var sigBytes wordArray.sigBytes // Convert var u8 new Uint8Array(sigBytes) for (var i 0; i sigBytes; i) { var byte (words[i 2] (24 - (i % 4) * 8)) 0xff u8[i] byte } return u8 }, /** * Converts a Uint8Array to a word array. * * param {string} u8Str The Uint8Array. * * return {WordArray} The word array. * * static * * example * * var wordArray CryptoJS.enc.u8array.parse(u8arr); */ parse: function (u8arr: string | any[]) { // Shortcut var len u8arr.length // Convert var words: number[] [] for (var i 0; i len; i) { words[i 2] | (u8arr[i] 0xff) (24 - (i % 4) * 8) } return CryptoJS.lib.WordArray.create(words, len) } } export default { u8array: CryptoJS.enc.u8array }3.图片加密const CryptoJS require(crypto-js); import CryptoU8array from ./enc-u8array import { CryptoGlobal } from ./cryptoGlobal /** * 图片加密 */ export function avatarEncrypt(type: string, reorganizationUrl: string, file: any, Codekey?: string, ) { const recodekey Codekey?.slice(0, 16) const { key, subtile } CryptoGlobal(recodekey) const messageWordArray CryptoU8array.u8array.parse(file); let encrypted CryptoJS.AES.encrypt(messageWordArray, key, subtile); const encryptedBytes encrypted.ciphertext; const toWordArray CryptoU8array.u8array.stringify(encryptedBytes) let blob new Blob([toWordArray], { type }); // 将加密后串转blob let blobToFile new File([blob], reorganizationUrl); return blobToFile }4.图片解密import axios from axios const CryptoJS require(crypto-js); import CryptoU8array from ./enc-u8array import { CryptoGlobal } from ./cryptoGlobal /** * base64转blob * param {*} base64 * returns */ function base64ToBlob(base64: string) { const binary atob(base64.split(,)[1]); const array []; for (let i 0; i binary.length; i) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], { type: image/jpeg }); // 这里的type可以根据实际情况进行修改 } /** * 头像解密 * param {*} buffer * returns */ function avatarDecrypt(buffer: ArrayBuffer, Codekey?: string) { let view new Uint8Array(buffer) // 将Uint8Array 转成 WordArray let contentWA CryptoU8array.u8array.parse(view) // base64字符串 let dcBase64String contentWA.toString(CryptoJS.enc.Base64) // 解密 const { key, subtile } CryptoGlobal(Codekey) let decryptedData CryptoJS.AES.decrypt(dcBase64String, key, subtile) console.log(decryptedData) // 把解密后的对象再转为base64编码,这步是关键,跟解密文字不同 let d64 decryptedData.toString(CryptoJS.enc.Base64) let encodedData data:image/png;base64, d64 // 将blob解析URL const blob base64ToBlob(encodedData); var url URL.createObjectURL(blob); return url } /** * 获取图片路径并调用头像解密方法 * param list 路径 * param key sessionId 对话图片才会需要用 * returns */ export async function decodeAvatarUrl(list: string, key?: string) { const resetList list[0] { list[list.length - 1] } ? JSON.parse(list) : list let isListType null; if(resetList ! null) { isListType typeof resetList string ? resetList : resetList?.url isListType isListType.replace(/^http:/gi, ) // 判断是否需要解密头像, 并判断图片数据是否有损坏损坏显示默认头像 try { if(isListType.includes(#%)) { const res: {data: ArrayBuffer} await axios.request({ responseType: arraybuffer, url: isListType, method: get }) if(res.data) { const reKey key?.slice(0, 16) const avatarBase64 avatarDecrypt(res.data, reKey) isListType avatarBase64 } else { isListType null } } } catch (error) { isListType null } } return isListType }5.图片加密使用/** 上传图片方法传参校验 */ type UploadFileType { /** 图片数据Uint8Array */ stream: any; /** 图片名字 */ key: string, /** 上传图片的类型: 1:头像 2:消息图片 */ updateType: number; /** sessionId */ sessionId: string } /** * 上传图片 - 七牛云 * * param stream 图片流Uint8Array * param stream 图片名称 * param updateType 1:头像 2:消息图片 * param sessionId 1:头像 2:消息图片 * */ export const uploadFile ({ stream, key, updateType, sessionId }: UploadFileType) { return new Promise(async (resolve: (res: { rescode: number, url: string, error: any }) void, reject) { const folderOs Desktop const folder updateType 1 ? avatars : conversations const folderEnd #% const reorganizationUrl ${folderOs}/${folder}/${reorganizationName()}${folderEnd} const imageType image/ key.split(.).pop() const putExtra { // 上传需要的参数 fname: , params: {}, mimeType: [imageType] }; const config { // 上传需要的参数 useCdnDomain: true, }; // token是接口获取 const { data } await updateImageToken() const { qiniuLinkUrl, token } data const decode: any await avatarEncrypt(imageType, reorganizationUrl, stream, sessionId) const observable qiniu.upload(decode, reorganizationUrl, token, putExtra, config); observable.subscribe({ next(res: any){ // console.log(res) }, error(err: any){ // 失败 // console.log(err) reject({ error: err, url: , rescode: 100 }) }, complete(res: any){ // 成功 // console.log(res) resolve({ error: null, url: qiniuLinkUrlreorganizationUrl, rescode: 200 }) } }) }) }6.图片解密使用import { decodeAvatarUrl } from /utils/decodeAvatar // src: 图片路径sessionId: 唯一key值每条对话单独的id decodeAvatarUrl(src, sessionId)参考CSDN(注仅能参考解密不够全面):https://blog.csdn.net/ningtt/article/details/118301703简书参考的这篇加密加解密都有较为全面https://www.jianshu.com/p/1f75cd571786