如何解密ArrayBuffer?

10

我一直在尝试使用CryptoJS解密一个ArrayBuffer对象,但是到目前为止它总是返回一个空的WordArray。这些文件(图片)被加密在iOS和Android应用中,发送到服务器,在这个Web应用程序中下载并进行解密显示。iOS和Android应用能够无问题地解密这些文件,因此加密过程没有问题。

文件通过XMLHttpRequest使用responseType设置为arraybuffer进行下载。以下是我的代码:

// Decrypt a Base64 encrypted string (this works perfectly)
String.prototype.aesDecrypt = function(key) {

    var nkey = CryptoJS.enc.Hex.parse(key.sha256());
    return CryptoJS.AES.decrypt(this.toString(), nkey, {
        iv: CryptoJS.enc.Hex.parse('00000000000000000000000000000000'),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);

}

// Decrypt a plain encrypted ArrayBuffer (this is the problem, it always outputs an empty WordArray)
ArrayBuffer.prototype.aesDecrypt = function(key) {

    // Get key
    if (!key) return null;
    var nkey = CryptoJS.enc.Hex.parse(key.sha256());

    // Get input (if I pass the ArrayBuffer directly to the create function, it returns
    // a WordList with sigBytes set to NaN)
    //var input = CryptoJS.lib.WordArray.create(this);
    var input = CryptoJS.lib.WordArray.create(new Uint8Array(this));

    // Decrypt
    var output = CryptoJS.AES.decrypt(input, nkey, {
        iv: CryptoJS.enc.Hex.parse('00000000000000000000000000000000'),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });

    // Output is an empty WordList
    console.log("Output: ", output);

}

我还有一个问题是如何将 WordArray 转换为 ArrayBuffer

2个回答

15

CryptoJSissue 46 中讨论了如何将 ArrayBuffer -> WordArray 进行转换。因此,添加了一个 TypedWordArray,您可以通过它传递一个 ArrayBuffer


要使用它,还需要包含以下脚本:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/lib-typedarrays.js"></script>

然后你可以简单地执行:
var wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);

/* perform decryption of `wordArray` */

为了将解密后的 decryptedWordArray 转换回 ArrayBuffer,最简单的方法可能是先将其转换为一个 Base64-String(如 这里 所讨论的),然后将该字符串解码为所需的 ArrayBuffer(参见 这里)。整个过程大致如下:

dcWordArray = ... // your decrypted WordArray
dcBase64String = dcWordArray.toString(CryptoJS.enc.Base64); // to Base64-String
dcArrayBuffer = base64DecToArr(dcBase64String).buffer; // to ArrayBuffer

编辑:

为了更高效的转换(无需中间的Base64String),请查看that问题的Aletheios答案(使用函数wordToByteArray(wordArray)并且然后执行.buffer)。


sigBytes 只有在使用 signature/MAC 时才很重要,而根据您的工作中的 String-encryption-example,您并没有使用它。如果您的文件那么大,那可能真的会成为一个问题,我会尝试找到更好的解决方案。您能否提供一些测试数据(加密的 ArrayBuffer(如果可能的话是小的)+ key + IV),这样我就可以自己尝试解密。谢谢。 - i_turo
1
抱歉,关于“sigBytes”的理解完全错误了。它们表示在“WordArray”中保存的字节数。它们不应该是“NaN”。但实际上,在本地测试时对我来说并不是这样(当包括“lib-typedarrays.js”时)。 - i_turo
我在这里制作了一个简单的JSFiddle(http://jsfiddle.net/jqfr2c99/1/),希望它有所帮助... 在那里创建的ArrayBuffer只是一个简单的文本文件(48字节),我展示了将其解密为Base64字符串的方法,这个方法可行,但是将其解密为ArrayBuffer的方法不行... - jjv360
看起来 CryptoJS 由于某些原因只能解密 Base64 字符串。(参见这个类似的问题)可能最简单的解决方案是:ArrayBuffer -> String -> decrypt() -> ArrayBuffer。我稍后会使用这些信息更新我的答案 :) - i_turo
有人提交了这个bug吗?这对我来说似乎是一个主要的性能杀手。 - Moshe Kravchik
显示剩余3条评论

-2

你可以使用Web Crypto API直接解密arrayBuffer。 无需将二进制数据转换为字符串,这样效率低下,可能会导致内存和CPU升高。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接