如何在二进制数据上计算MD5

JS - How to compute MD5 on binary data

本文关键字:计算 MD5 数据 二进制      更新时间:2023-09-26

EDIT:从更改标题"JS文件API -读写UTF-8数据不一致"以反映实际问题。

我有一些二进制内容,我需要计算MD5。内容是一个WARC文件,这意味着它包含文本和编码图像。为了避免文件保存中的错误,我将所有数据转换并存储在arrayBuffers中。所有数据放入UInt8Array s中转换为UTF-8。

我的第一次尝试,测试,是使用saveAs库从Chrome扩展保存文件。这意味着我使用了一个blob对象来传递给方法并创建文件。

var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
saveAs(b,'name.warc');

我没有找到一个工具来从Blob对象计算MD5,所以我正在做的是使用FileReader读取blob文件作为二进制数据,然后使用MD5工具(我使用cryptoJS以及faultylabs的工具)来计算结果。

f = new FileReader();
f.readAsBinaryString(b);
f.onloadend = function(a){
    console.log( 'Original file checksum: ', faultylabs.MD5(this.result) );
}

资源(图像)是直接以arraybuffer格式下载的,所以我不需要转换它们。

结果是错误的,这意味着从代码中检查MD5并从我保存在本地机器上的文件中检查MD5会得到2个不同的结果。作为文本阅读,显然会出现错误。

我发现的解决方案包括使用文件系统API在磁盘上写入blob对象,然后将其作为二进制数据读取,计算MD5,然后将检索到的文件保存为WARC文件(不是直接的blob对象,而是这个"刷新"版本的文件)。在这种情况下,计算的MD5是好的(我在warc文件的"刷新"版本上计算它),但是当我用"刷新"warc存档启动warc重播实例时,它会抛出错误-而原始文件我没有任何问题(但MD5不正确)。

var fd = new FormData();
// To compute the md5 hash and to have it correct on the server side, we need to write the file to the system, read it back and then calculate the md5 value.
// We need to send this version of the warc file to the server as well.
window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
function computeWARC_MD5(callback,formData) {
    window.requestFileSystem(window.TEMPORARY, b.size, onInitFs);
    function onInitFs(fs) {
        fs.root.getFile('warc.warc', {create: true}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                fileWriter.onwriteend = function(e) {
                  readAndMD5();
                };
                fileWriter.onerror = function(e) {
                  console.error('Write failed: ' + e.toString());
                };
                fileWriter.write(b);
            });
        });
        function readAndMD5() {
            fs.root.getFile('warc.warc', {}, function(fileEntry) {
                fileEntry.file( function(file) {
                    var reader = new FileReader();
                    reader.onloadend = function(e) {
                        var warcMD5 = faultylabs.MD5( this.result );
                        console.log(warcMD5);
                        var g = new Blob([this.result],{type: "text/plain;charset=utf-8"});
                        saveAs(g, o_request.file);
                        formData.append('warc_file', g)
                        formData.append('warc_checksum_md5', warcMD5.toLowerCase());
                        callback(formData);
                    };
                    reader.readAsBinaryString(file);
                });
            });
        }
    }
}
function uploadData(formData) {
    // upload
    $.ajax({
        type: 'POST',
        url: server_URL_upload,
        data: fd,
        processData: false,
        contentType: false,
        // [SPECS] fire a progress event named progress at the XMLHttpRequestUpload object about every 50ms or for every byte transmitted, whichever is least frequent
        xhrFields: {
            onprogress: function (e) {
                if (e.lengthComputable) {
                    console.log(e.loaded / e.total * 100 + '%');
                }
            }
        }
    }).done(function(data) {
       console.log('done uploading!');
       //displayMessage(port_to_page, 'Upload finished!', 'normal')
       //port_to_page.postMessage( { method:"doneUpload" } );
    });
}
computeWARC_MD5(uploadData, fd);
saveAs(b, 'warc.warc');

谁能解释一下为什么有这种差异?在处理所有我正在处理的对象作为二进制数据(存储,读取)我错过了什么?

基本上,我尝试了另一种方法,并将blob文件转换回arraybuffer并在其上计算MD5。此时,文件的MD5和arraybuffer的MD5是相同的。

var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
            var blobHtml = new Blob( [str2ab(o_request.main_page_html)], {type: "text/plain;charset=utf-8"} );
f = new FileReader();
f.readAsArrayBuffer(b);
f.onloadend = function(a){
  var warcMD5 = faultylabs.MD5(this.result);
  var fd = new FormData();
  fd.append('warc_file', b)
  fd.append('warc_checksum_md5', warcMD5.toLowerCase());
  uploadData(fd);
}

我猜从二进制字符串和从缓冲区数组的结果是不同的,这就是为什么MD5也不一致。