【发布时间】:2016-11-28 16:10:25
【问题描述】:
我正在尝试编写一个应用程序来对浏览器中带有 JS 的文件进行端到端加密。但是我似乎无法正确解密所有文件。
TL;DR 由于整体上对大于 1MB 的文件进行加密是不切实际的,因此我正在尝试逐块加密它们。这样做之后,我尝试将加密的单词(由CryptoJS's WordArray 产生)写入一个blob。至于解密,我读取文件并根据加密块时生成的映射将它们拆分为块并尝试解密它们。问题是解密结果是0位!
我想我在正确解密时没有读取数据块。请看下面的代码,函数getBlob(将数据写入blob)和decryptFile的最后一部分用于读取块。
更多解释
我正在使用默认设置的 CryptoJS AES。
现在我的代码如下所示:
function encryptFile (file, options, resolve, reject) {
if (!options.encrypt) {
return resolve(file)
}
if (!options.processor || !options.context) {
return reject('No encryption method.')
}
function encryptBlob (file, optStart, optEnd) {
const start = optStart || 0
let stop = optEnd || CHUNK_SIZE
if (stop > file.size - 1) {
stop = file.size
}
const blob = file.slice(start, stop)
const fileReader = new FileReader()
fileReader.onloadend = function () {
if (this.readyState !== FileReader.DONE) return
const index = Math.ceil(optStart / CHUNK_SIZE)
const result = CryptoJS.lib.WordArray.create(this.result)
encryptedFile[index] = encrypt(result)
chunksResolved++
if (chunksResolved === count) {
const {sigBytes, sigBytesMap, words} = getCipherInfo(encryptedFile)
const blob = getBlob(sigBytes, words)
resolve(blob, Object.keys(sigBytesMap))
}
}
fileReader.readAsArrayBuffer(blob)
}
let chunksResolved = 0
const encryptedFile = []
const CHUNK_SIZE = 1024*1024
const count = Math.ceil(file.size / CHUNK_SIZE)
const encrypt = value => options.processor.call(
options.context, value, 'file',
(v, k) => CryptoJS.AES.encrypt(v, k))
for (let start = 0; (start + CHUNK_SIZE) / CHUNK_SIZE <= count; start+= CHUNK_SIZE) {
encryptBlob(file, start, start + CHUNK_SIZE - 1)
}
}
如您所见,我正在尝试逐块读取文件块(每个块为 1MB 或 fileSize % 1MB)作为 ArrayBuffer,将其转换为 WordArray 以供 CryptoJS 理解和加密。
加密所有块后,我尝试将它们必须的每个单词写入一个 blob(使用我在 Google Code 中的 CryptoJS 问题中找到的代码,如下所述)并且 我想这是出了问题 .我还为加密块的结束位置生成了一个映射,以便以后可以使用它从二进制文件中取出块进行解密。
这是我解密文件的方法:
function decryptFile (file, sigBytesMap, filename, options, resolve, reject) {
if (!options.decrypt) {
return resolve(file)
}
if (!options.processor || !options.context) {
return reject('No decryption method.')
}
function decryptBlob (file, index, start, stop) {
const blob = file.slice(start, stop)
const fileReader = new FileReader()
fileReader.onloadend = function () {
if (this.readyState !== FileReader.DONE) return
const result = CryptoJS.lib.WordArray.create(this.result)
decryptedFile[index] = decrypt(result)
chunksResolved++
if (chunksResolved === count) {
const {sigBytes, words} = getCipherInfo(decryptedFile)
const finalFile = getBlob(sigBytes, words)
resolve(finalFile, filename)
}
}
fileReader.readAsArrayBuffer(blob)
}
let chunksResolved = 0
const count = sigBytesMap.length
const decryptedFile = []
const decrypt = value => options.processor.call(
options.context, value, 'file',
(v, k) => CryptoJS.AES.decrypt(v, k))
for (let i = 0; i < count; i++) {
decryptBlob(file, i, parseInt(sigBytesMap[i - 1]) || 0, parseInt(sigBytesMap[i]) - 1)
}
}
解密与加密完全相同,但不起作用。虽然块不再是 1MB,但它们仅限于地图中提到的 sigBytes。解密没有结果! sigBytes: 0.
这是生成 blob 和获取 sigbytesMap 的代码:
function getCipherInfo (ciphers) {
const sigBytesMap = []
const sigBytes = ciphers.reduce((tmp, cipher) => {
tmp += cipher.sigBytes || cipher.ciphertext.sigBytes
sigBytesMap.push(tmp)
return tmp
}, 0)
const words = ciphers.reduce((tmp, cipher) => {
return tmp.concat(cipher.words || cipher.ciphertext.words)
}, [])
return {sigBytes, sigBytesMap, words}
}
function getBlob (sigBytes, words) {
const bytes = new Uint8Array(sigBytes)
for (var i = 0; i < sigBytes; i++) {
const byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
bytes[i] = byte
}
return new Blob([ new Uint8Array(bytes) ])
}
我猜问题是我用来读取加密块的方法。或者写它们!
我还应该提到,以前我为加密做了一些不同的事情。我使用toString 方法和默认编码(我相信是CryptoJS.enc.Hex)对我得到的CryptoJS.AES.encrypt 的结果进行字符串化,但有些文件没有正确解密。它与原始文件的大小没有任何关系,而不是它们的类型。再说一次,我猜!
【问题讨论】:
-
1) 你为什么要这样做? 2)你知道那是不安全的吗?你到底用这种加密实现了什么?既然是浏览器到浏览器 - 键是可见的,那有什么意义呢?
-
k是硬编码的还是通过非对称加密检索的? -
@Mjh 实现零知识加密,这样我们就无法访问用户的数据了。
-
如果你有密钥,你就有了关于数据的知识。既然你有钥匙,这个零知识原则就被打破了。 SSL/TLS 有什么问题?
-
对,你用什么加密数据?用户的公钥?公钥加密对它可以加密的数据量有限制。您的系统的整个前提听起来完全不合时宜 - 您有一个可以查看其内容的文件。如果您看不到内容,则无需对其进行加密。您可以将损坏的 blob 交付给其他人,后者将通过向所有者询问密钥来解密它。您在这里有太多错误的决定,如果我确切知道您提供的是哪种服务,我将永远不会注册。没有难过的感觉,这里的“错误”太多了。
标签: javascript file encryption cryptojs