txt 以外的文件的 MD5 校验和计算不正确?

MD5 checksum not calculated properly for files other than txt?

我正在使用 crypto-js 在上传之前为我的文件计算 MD5 校验和,下面是我的代码。

import CryptoJS from "crypto-js";

const getMd5 = async (fileObject) => {
  let md5 = "";
  try {
    const fileObjectUrl = URL.createObjectURL(fileObject);
    const blobText = await fetch(fileObjectUrl)
      .then((res) => res.blob())
      .then((res) => new Response(res).text());

    const hash = CryptoJS.MD5(CryptoJS.enc.Latin1.parse(blobText));
    md5 = hash.toString(CryptoJS.enc.Hex);
  } catch (err) {
    console.log("Error occured getMd5:", err);
  }
  return md5;
};

以上代码仅适用于文本文件,但适用于非文本文件文件图像、视频等,校验和计算错误

任何 help/input 表示赞赏。 谢谢!

只需将 .then((res) => res.blob()) 的结果直接输入 MD5 函数即可。

编码为 text() 可能是有损的(and/or 使用替换字符),并且 Latin1 也没有涵盖所有可能的字节值范围 - 至少官方是这样。只是不需要先转换为文本再转换回二进制。

需要转换为 CryptoJS 可以接受的二进制表示形式 - 已实现 。然而,这需要是二进制到二进制的转换,而不是二进制 -> 文本 -> 二进制转换。

Response.text() 读取响应流并使用 UTF-8 编码将其转换为字符串。不符合 UTF-8 标准的任意二进制数据将在此过程中损坏(例如图像、视频等),s。还有另一个答案。
这是通过使用 Response.arrayBuffer() 来防止的,它只是将数据不变地存储在 ArrayBuffer.
中 由于 CryptoJS 在内部使用 WordArrays,因此需要将 ArrayBuffer 进一步转换为 WordArray

以下修复适用于我的机器:

(async () => {
            
    const getMd5 = async(fileObject) => {
        let md5 = "";
        try {
            const fileObjectUrl = URL.createObjectURL(blob);
            const blobText = await fetch(fileObjectUrl)
                .then((res) => res.blob())
                .then((res) => new Response(res).arrayBuffer());                    // Convert to ArrayBuffer       
            const hash = CryptoJS.MD5(CryptoJS.lib.WordArray.create(blobText)); // Import as WordArray
            md5 = hash.toString(CryptoJS.enc.Hex);
        } catch (err) {
            console.log("Error occured getMd5:", err);
        }
        return md5;
    };
        
    const blob = new Blob([new Uint8Array([0x01, 0x02, 0x03, 0x7f, 0x80, 0x81, 0xfd, 0xfe, 0xff])]);
    console.log(await(getMd5(blob)));
        
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

为简单起见,我没有使用文件对象进行测试,而是使用不符合 UTF8 标准的数据的 blob 对象。 生成的哈希是正确的,可以在线验证,例如here