2016-11-28 412 views
3

我正在嘗試編寫一個應用程序,以便在瀏覽器中使用JS對文件進行端到端加密。不過,我似乎無法正確解密所有文件。CryptoJS - 解密一個加密文件

TL; DR由於這是不切實際的加密文件超過1MB更大的作爲一個整體,我試圖用大塊它們進行加密塊。這樣做之後,我嘗試將加密的單詞(由CryptoJS的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每個字塊後(使用代碼,我在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

下面是產生斑點和獲取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

1)你爲什麼這樣做? 2)你知道這是不安全的嗎?你用這種加密實現了什麼?由於它是瀏覽器到瀏覽器 - 密鑰將可見,所以有什麼意義? – Mjh

+1

'k'是硬編碼還是通過非對稱加密檢索? –

+0

@Mjh爲了實現零知識加密,所以我們無法訪問用戶的數據。 – MahdiPOnline

回答

0

原來問題是WordArrayCryptoJS.AES.decrypt(value, key)返回有4個額外的單詞作爲填充,它不應該包含在最終結果中。 CryptoJS嘗試取消壓縮結果,但僅相應更改sigBytes,並且不更改words。所以在解密時,在寫入文件之前,文件會彈出那些額外的單詞。 4個單詞爲全塊,3個爲小塊(最後一個塊)。