我觉得这是一个奇葩的问题,但是我现在有这样的需求,文件上传前,先在浏览器上进行 AES 加密,在文件下载时,先进行 AES 解密再存储本地。我该如何操作,我目前正在 VUE 项目中尝试这些操作,我使用https://github.com/brix/crypto-js 来进行操作,感觉它非常流行,但是发现我只能对文本文件进行处理,对于图片之类的文件我无法操作。 附上我的部分代码
Encode() {
if (this.file === null) {
console.log('file not exist!')
}
var CryptoJS = require('crypto-js');
this.file_mime = this.file.type;
this.file_name = this.file.name;
//读取本地文件
var reader = new FileReader();
//读取完毕后触发
reader.onload = () => {
let key = '1234567887654321';
var encrypted = CryptoJS.AES.encrypt(reader.result,key).ciphertext.toString();
this.file2 = new Blob([encrypted], {type: 'application/octet-stream'});
const a = document.createElement("a");
const url = window.URL.createObjectURL(this.file2);
const filename = this.file_name;
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
};
reader.readAsDataURL(this.file);
},
Decode() {
if (this.file === null) {
console.log('file not exist!')
}
var CryptoJS = require('crypto-js');
//读取本地文件
var reader = new FileReader();
//读取完毕后触发
reader.onload = () => {
let key = '1234567887654321';
var decrypted = CryptoJS.AES.decrypt(reader.result,key).toString(CryptoJS.enc.Utf8);
//Blob 生成
this.file2 = new Blob([decrypted], {type: this.file_mime});
const a = document.createElement("a");
const url = window.URL.createObjectURL(this.file2);
const filename = this.file_name;
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
};
reader.readAsText(this.file);
}
1
ysc3839 2020-02-23 19:54:54 +08:00 via Android
找支持 Blob 的加密库?
|
2
also24 2020-02-23 19:58:25 +08:00 via Android
CryptoJS 可以解密 bin 的吧…
// 不信你看电子工业出版社的 pdf |
4
tealover007 2020-02-23 20:05:19 +08:00
加密是一个很费 CPU 计算的操作。
加密图片的意义在什么地方,是为了防止没有权限的人获取? 换一个思路:如果远程服务器可以存放未加密的图片,那系统用权限控制就好。 估计上面的方案不是你想要的,那么 再换一个思路:利用离线 aes 加解密软件加密所需文件,把 aes 解密工具和加密后的文件上传到系统,对方下载 aes 加解密软件和文件,然后自己解密。文件的存放路径或者业务场景处理好,应该问题不大。 多了一个下载解密软件和解密的操作。 |
6
also24 2020-02-23 20:12:54 +08:00
另:你可能没有理解电子工业出版社的梗
你可以点击下面链接里的 『立即阅读』,它的在线阅读器里的 pdf 就是用 JS 做的 AES 解密: https://yd.51zhy.cn/ebook/web/newBook/queryNewBookById?id=64556589 |
7
xuthus OP @tealover007 这确实是最优方案。但是我在写我的毕业设计[信息安全专业],是一个关于网盘类型的项目。我有想使用访问控制的手段来隔离,但是被要求文件存储需要进行加密 /解密处理,这种用户自行加密解密显然不太合适。
|
8
xuthus OP @also24 CryptoJS.AES.encrypt(reader.result,key) 这个对象无法写入 Blob,所以我就把他 tostring 了。
|
9
also24 2020-02-23 20:17:51 +08:00
另外,我看了下,你的 AES 似乎没有指定 mode ?
你可以需要了解一下 AES 的几种 mode https://zh.wikipedia.org/zh-hans/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F |
10
xuthus OP @also24 我在正常测试时,是有指定的,CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}) 这种,CryptoJS 有提供,当然,流处理上,我会选计算器模式 CTR。
|
12
also24 2020-02-23 20:35:19 +08:00
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
我看了一下 FileReader,在读取的时候需要指定 FileReader.readAsArrayBuffer() FileReader.readAsBinaryString() FileReader.readAsDataURL() 你在 encode 方法里用的是 readAsDataURL,也就是说 reader.result 里其实是文件在 base64 编码后的字符串。 而你把这个字符串直接传进了 encrypt 方法,也就是说此时你其实是在加密这个字符串。 encrypt 方法返回的 encryptedData 直接 tostring 的话,是密文 base64 后的字符串, 但你取的是 encryptedData.ciphertext.tostring(),这个实际上是密文的 hexString 字符串。 相应的,你在 Decode 方法里使用的是 readAsText,文件内容是字符串的情况下也不算太错 但是你把这串文本直接丢进 decrypt 方法就大错特错了,应当从 hexString 转回 Blob 才对 当然,以上是针对你的程序来说的。 我来写的话,应该会选择 readAsDataURL 读到 base64 编码后的文件, 然后 base64 解码后丢进 encrypt 方法,再把 encryptedData.toString() 的字符串解码后丢进输出文件。 |
13
LuRenJiasWorld 2020-02-23 20:39:40 +08:00
有个建议,试试看 wasm 的库,比如这个:
https://github.com/flash1293/aes-wasm 这些库一般都是从成熟的 C/C++库 port 过来的,缺点是一般都要传入 ArrayBuffer,处理起来费一点代码 |
14
xuthus OP @also24 你的解读是正确的,我的思路一开始就是:先得到 base64Data->aes 加密 base64Data->存为一个文本。解密直接读取文本->aes 解密->base64Data 解码。
|
15
xuthus OP @LuRenJiasWorld 谢谢,我去研究研究。
|
16
also24 2020-02-23 20:51:07 +08:00 6
总结一下,请务必分清楚几种不同的数据格式:
一个字符串,它的内容是:『 V2EX 』 对应的 ASCII 码是: 86 50 69 88 对应的十六进制分别为: 56 32 45 58 那么在 UTF8 / ANSI 编码下,按大端序书写,它的二进制( binary )内容是: 0101 0110 0011 0010 0100 0101 0101 1000 相应的 HEX 字符串就是: 0x56324558 相应的 base64 字符串是: VjJFWA== 你的错误就在于混淆使用了 binary / b64 String / HEX String,从而导致混乱 不过确实,网上找到的很多资料都在混淆使用或者不仔细说明。 事实上,AES 的 encrypt 方法只管你输入的是 binary( byte array ) 就好了,字符串还是文件对它来说没区别。 总之,你这里只需要配合 FileReader,选择正确的编解码方式就好了。 个人不建议对 base64 String 进行加解密操作,这样会造成密文文件体积增大,徒增开销。 如果我没有理解错的话,直接使用 FileReader.readAsArrayBuffer() 应该能够避免中间 b64 编解码的开销。 |
18
tyx1703 2020-02-23 21:29:13 +08:00
正好前两天看过这个
我用的这个库 https://cryptojs.gitbook.io/docs/#encoders。 首先读取文件用 FileReader.readAsArrayBuffer(),然后把 ArrayBuffer 转成十六进制字符串。 再用 crypto-js 读取十六进制字符串进行加密。 加密过程结束之后,crypto-js 把结果转成十六进制字符串,然后转换成 ArrayBuffer,写入文件对象即可。 |
20
muzuiget 2020-02-24 00:12:11 +08:00
为何上面两人的语法像机器翻译的样子?
|
22
wizardoz 2020-02-24 10:06:43 +08:00
https 不是已经做了这个事了吗?不相信浏览器?
|