【问题标题】:How to read a binary file with FileReader in order to hash it with SHA-256 in CryptoJS?如何使用 FileReader 读取二进制文件以便在 CryptoJS 中使用 SHA-256 对其进行哈希处理?
【发布时间】:2023-03-11 02:45:01
【问题描述】:

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

这是我想要做的:

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

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

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

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

$('#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();
}

【问题讨论】:

  • 'bytes' 不是 Latin1 或任何其他格式。对于像(大多数)图像和声音这样的二进制文件,字符编码并不真正适用。如果您将文本从一种编码转换为另一种编码,您只会得到另一种编码的文本(可能会丢失一些字符)。如果您将二进制文件转换为另一种文本编码,您很可能会遇到损坏的文件。
  • 我很确定 CryptoJS 确实直接采用了数组缓冲区。无需关心文本编码。
  • 感谢 GolezTrol... 这是加密作者所写的:“当您将字符串传递给哈希器时,它会使用 UTF-8 转换为字节。这是为了确保不剪裁外来字符。因为您'正在处理二进制数据,您需要使用 Latin1 将字符串转换为字节。” sha256.update(CryptoJS.enc.Latin1.parse(evt.target.result));
  • 上述声明的链接:code.google.com/p/crypto-js/issues/…
  • 当我尝试使用加密方法时 sha256.update(CryptoJS.enc.Latin1.parse(evt.target.result));它返回“未定义”作为哈希值:(

标签: javascript utf-8 character-encoding cryptojs latin1


【解决方案1】:

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

您必须将 ArrayBuffer 转换为 CryptoJS 的内部 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>

您可以使用my other answer 中的技术扩展此代码,以便在不冻结浏览器的情况下对任意大小的文件进行哈希处理。

【讨论】:

  • 谢谢!你的回答给了我比我预想的更多。只是为了让您知道,我得到的“未定义”哈希值是由于奇怪的原因,有两个其他 &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/hmac-sha256.js"&gt;&lt;/script&gt; &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"&gt;&lt;/script&gt; 引用我把它们取出来了,未定义的问题就消失了。谢谢大家!
  • arrayBufferToWordArray 为我创造了奇迹。非常感谢!
  • 在 var 哈希上拍一个 .toString() 以获得实际的字符串哈希输出!
  • @MichealCWallas 你的意思是elem.value = hash; 应该改成elem.value = hash.toString(); 吗?这不应该有什么坏处,但也没有必要,因为将 WordArray 对象分配给字符串属性应该会导致自动字符串化。我用 Firefox 和 Vivaldi 对此进行了测试,没有发现问题。这可能是您正在使用的浏览器中的一个错误。
  • @ArtjomB。抱歉,我的意思是最终输出,var hash = CryptoJS.SHA256(arrayBufferToWordArray(arrayBuffer)).toString()。我认为代码不起作用,但 toString() 是获得字符串哈希输出的全部内容:)
猜你喜欢
  • 2014-05-13
  • 2020-02-02
  • 2016-08-01
  • 2018-02-22
  • 2021-12-15
  • 2013-04-26
  • 2016-01-10
  • 1970-01-01
相关资源
最近更新 更多