如何使用FileReader读取二进制文件,以便在CryptoJS中使用SHA-256进行哈希

How to read a binary file with FileReader in order to hash it with SHA-256 in CryptoJS?

本文关键字:SHA-256 哈希 CryptoJS 读取 FileReader 何使用 二进制文件      更新时间:2023-09-26

如何使用javascript将UTF-8字符串转换为Latin1编码的字符串?

以下是我要做的:

  1. 我得到一个文件,通过读作为数组缓冲区将其分成块
  2. 然后,我将数组缓冲区解析为字符串
  3. 并使用以下代码将其传递给cryptoJS进行哈希计算:

    cryptosha256 = CryptoJS.algo.SHA256.create();
    cryptosha256.update(text);
    hash = cryptosha256.finalize();
    

这一切都适用于文本文件。我在使用哈希非文本文件(image/.wmv文件)的代码时遇到了问题。我在另一个博客中看到,CryptoJS的作者要求使用Latin1格式而不是UTF-8发送字节,这就是我遇到的问题。

不确定,如何使用Latin1格式从javascript中的arraybuffer生成字节(或字符串)?

$('#btnHash').click(function () {
    var fr = new FileReader(), 
        file = document.getElementById("fileName").files[0];
    fr.onload = function (e) {
        calcHash(e.target.result, file);
    };
    fr.readAsArrayBuffer(file);
});
function calcHash(dataArray, file) {
    cryptosha256 = CryptoJS.algo.SHA256.create();
    text = CryptoJS.enc.Latin1.parse(dataArray);
    cryptosha256.update(text);
    hash = cryptosha256.finalize();
}

CryptoJS不了解ArrayBuffer是什么,如果您使用Latin1或UTF-8等文本编码,您将不可避免地丢失一些字节。并不是每个可能的字节值在其中一个文本编码中都有有效的编码。

您必须将ArrayBuffer转换为CryptoJS的内部WordArray,该内部WordArray将字节保存为单词数组(32位整数)。我们可以将ArrayBuffer视为无符号8位整数的数组,并将它们放在一起构建WordArray(请参见arrayBufferToWordArray)。

以下代码显示了一个完整的示例:

function arrayBufferToWordArray(ab) {
  var i8a = new Uint8Array(ab);
  var a = [];
  for (var i = 0; i < i8a.length; i += 4) {
    a.push(i8a[i] << 24 | i8a[i + 1] << 16 | i8a[i + 2] << 8 | i8a[i + 3]);
  }
  return CryptoJS.lib.WordArray.create(a, i8a.length);
}
function handleFileSelect(evt) {
  var files = evt.target.files; // FileList object
  // Loop through the FileList and render image files as thumbnails.
  for (var i = 0, f; f = files[i]; i++) {
    var reader = new FileReader();
    // Closure to capture the file information.
    reader.onloadend = (function(theFile) {
      return function(e) {
        var arrayBuffer = e.target.result;
        var hash = CryptoJS.SHA256(arrayBufferToWordArray(arrayBuffer));
        var elem = document.getElementById("hashValue");
        elem.value = hash;
      };
    })(f);
    reader.onerror = function(e) {
      console.error(e);
    };
    // Read in the image file as a data URL.
    reader.readAsArrayBuffer(f);
  }
}
document.getElementById('upload').addEventListener('change', handleFileSelect, false);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/sha256.js"></script>
<form method="post" enctype="multipart/form-data">
  Select image to upload:
  <input type="file" name="upload" id="upload">
  <input type="text" name="hashValue" id="hashValue">
</form>

您可以使用我的另一个答案中的技术扩展此代码,以便在不冻结浏览器的情况下哈希任意大小的文件。