How to calculate md5 checksum of blob using CryptoJS
Asked Answered
F

1

10

Uploading file in chunks using Blob API. Here I want to check the md5 checksum of the blob. When I tried the below code it is working fine for text files, but it is returning different value for binary files.

var reader = new FileReader();
reader.readAsBinaryString(blob);
reader.onloadend = function () {
    var mdsum = CryptoJS.MD5(reader.result);
    console.log("MD5 Checksum",mdsum.toString());
};

How to calculate the md5 checksum of blob correctly for all types of files ?

Felicitous answered 28/12, 2015 at 11:25 Comment(4)
#17820320Darvon
You're using CryptoJS. This question have nothing to do with jQuery.Whiteley
Please be aware that MD5 is considered "cryptographically broken and unsuitable for further use". Unless you have to use it for compatibility with an externally provided service, consider switching to SHA-2 (SHA-256 etc.).Carlton
https://mcmap.net/q/919966/-calculate-the-hash-of-blob-using-javascriptTuberous
B
17

Use the following code to create a correct md5 hash:

  function calculateMd5(blob, callback) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(blob);
    reader.onloadend = function () {
      var wordArray = CryptoJS.lib.WordArray.create(reader.result),
          hash = CryptoJS.MD5(wordArray).toString();
      // or CryptoJS.SHA256(wordArray).toString(); for SHA-2
      console.log("MD5 Checksum", hash);
      callback(hash);
    };
  }

Update (a bit simpler):

 function calculateMd5(blob, callback) {
    var reader = new FileReader();
    reader.readAsBinaryString(blob);
    reader.onloadend = function () {
      var  hash = CryptoJS.MD5(reader.result).toString();
      // or CryptoJS.SHA256(reader.result).toString(); for SHA-2
      console.log("MD5 Checksum", hash);
      callback(hash);
    };
  }

Be sure to include core.js, lib-typedarrays.js (important) and md5.js components from CryptoJS library.
Please see this fiddle for a complete example (because of origin access control it won't work on fiddle, try it on your local server).

Bandurria answered 28/12, 2015 at 12:21 Comment(11)
you sould define the onloadend method before the call to readAsBinaryString or readAsArrayBuffer : otherwise, with a small enough buffer, you might get the onloadend event handler registered after the event was triggered.Bigelow
@Bigelow Can you show a demo of that? The readAsBinaryString method initiates a new task in the queue, which is not executed in the same stack when reader.onloadend is setup (as an effect of JavaScript's event loop). So the order of reader.readAsBinaryString and reader.onloadend doesn't matter.Bandurria
Well, it happened to me this afternoon when using this code. The method that is triggering the call to onloadend is readAsBinaryString (from mozilla : When the read operation is finished, the readyState becomes DONE, and the loadend is triggered) and in your code, you register the event handler after the method that will trigger it. Perhaps it will work 99% of the time, but it will fail sometime too. Inverting both operations will be working in every case.Bigelow
@Bigelow Can you simply show me a demo to demonstrate the problem? It doesn't matter in which order these lines are executed, because the read operation starts a new task in the queue. The specification says: Initiate an annotated task read operation using the blob argument as input and handle tasks queued on the file reading task source per below.Bandurria
It is a race condition. Demonstrating it in every case on a platform with good multithreading is often hard without using Thread.sleep. But this is javascript, mutlithreading behavior will depend on the browser used, and there is no Thread.sleep. But race condition can also be uncovered with a debugger, and stepping in the code. Here is a jsfiddle : jsfiddle.net/k73va9ob/2 . Open it, open the dev console (F12), run it, click the button, and click the 'play' button once the breakpoint is hit. You'll see that the onloadend method is not called.Bigelow
@Bigelow Thank you for providing the demo. I tried both simple run and with the debugger and it works as expected (Chrome v57). JavaScript is single threaded, no race conditions can happen. Maybe the problem is in the way a specific engine implements the API.Bandurria
Indeed. I've just tested with chrome, and it is working as expected. Firefox is showing the issue. A firefox bug perhap's ?Bigelow
@Bigelow It could be.Bandurria
Not sure why, but the "update" version of the code is not returning me correct MD5 hash on blob (with img data). The original one is returning the right one.Bouquet
could you explain, why the author's code is wrong. Why cant just CryptoJS.MD5(reader.result);Assisi
for me using this produced the right result var hash = CryptoJS.MD5(CryptoJS.enc.Latin1.parse(reader.result)).toString();Bracteate

© 2022 - 2024 — McMap. All rights reserved.