Electron 使用 cryptoJs 进行加密
背景
由于 electron 开启了浏览器端可以直接使用 node 的包,所以导致了对文件加密时出现了多种类型的文件描述,node fs 读取的 Buffer 文件,浏览器的 Blob 文件
key 和 iv 构建
const key = CryptoJS.enc.Utf8.parse('1111111111')
const iv = CryptoJS.enc.Utf8.parse('11111111111')
不同格式之间转换
Buffer to ArrayBuffer
function bufferToArrayBuffer(buffer) {
const arrayBuffer = new ArrayBuffer(buffer.length)
const res = new Uint8Array(arrayBuffer)
for (let i = 0; i < buffer.length; ++i) {
res[i] = buffer[i]
}
return arrayBuffer
}
Blob to ArrayBuffer
function blobToArrayBuffer(blob) {
return new Promise((resolve, reject) => {
const file = new FileReader()
file.onload = function(result) {
resolve(file.result)
}
file.readAsArrayBuffer(blob)
})
}
wordArray To ArrayBuffer
function wordArrayToArrayBuffer(wordArray) {
const { words } = wordArray
const { sigBytes } = wordArray
const u8 = new Uint8Array(sigBytes)
for (let i = 0; i < sigBytes; i += 1) {
u8[i] = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
}
return u8
}
文件加密
对 WordArray 进行加密
function encryptFile(wordArray) {
// encrypt 函数接受的是一个 wordArray 对象
const encrypt = CryptoJS.AES.encrypt(wordArray, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
// 根据实际场景返回
return CryptoJS.enc.Base64.stringify(encrypt.ciphertext)
}
对 Buffer 文件加密
对 Buffer 加密,需要先把 Buffer 转为 ArrayBuffer,再把 ArrayBuffer 转为 WordArray
function encryptBuffer(buffer) {
const arrayBuffer = bufferToArrayBuffer(buffer)
const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)
return encryptFile(wordArray)
}
对 Blob 文件加密
对 Blob 加密,需要先把 Blob 转为 Arraybuffer,再把 ArrayBuffer 转为 WordArray
async function encryptBlob(blob) {
const arrayBuffer = await blobToArrayBuffer(blob)
const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)
return encryptFile(wordArray)
}
文件解密
对 WordArray 解密
文件解密传入的也是 WordArray 对象
function decryptFile(wordArray) {
// 后端是采用的 base64 加密,所以需要构建为 base64 的字符串,看情况变化
wordArray = CryptoJS.enc.Base64.stringify(wordArray)
const decrypt = CryptoJS.AES.decrypt(wordArray, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return wordArrayToArrayBuffer(decrypt)
}
对 Blob 解密
浏览器通过 axios 返回的是一个 Blob 文件,所以,对 Blob 文件解密需要先转为 ArrayBuffer,然后把ArrayBuffer 转为 WordArray 对象
async function decryptBlob(blob) {
const arrayBuffer = await blobToArrayBuffer(blob)
const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer)
return decryptFile(wordArray)
}
对字符串加解密
function encrypt(data) {
if (typeof data === 'object') {
// 如果传入的data是json对象,先转义为json字符串
data = JSON.stringify(data)
}
const srcs = CryptoJS.enc.Utf8.parse(data)
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv,
mode: CryptoJS.mode.CBC, // 加密模式
padding: CryptoJS.pad.Pkcs7
})
// 需要返回base64格式的加密结果
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
// 需要返回hex格式的加密结果
// return encrypted.ciphertext.toString()
}
/**
* 解密数据
* @param data 数据
* @returns {string}
*/
function decrypt(data) {
const base64 = CryptoJS.enc.Base64.parse(data)
const srcs = CryptoJS.enc.Base64.stringify(base64)
const decrypt = CryptoJS.AES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
return decryptedStr.toString()
}