Search code examples
javascriptangularjssha256cryptojsng-file-upload

javascript - Different SHA256 using the same file in Angularjs app and bash


I need to get the digest of an uploaded file in my AngularJS app, but the result digest is different from the file digest I get with bash.

I started using jshashes, but when I saw that the resultant hash (on the web app) was different from the one which I get locally using bash I decided to move to CryptoJS. But the result is the same,the hash from the uploaded file is still different.

Here's my code:

var reader = new FileReader();    
reader.readAsBinaryString(controller.file);
controller.fileHash = CryptoJS.SHA256(reader.result).toString(CryptoJS.enc.Hex);

As you can see the code is quite simple, just reads the uploaded file from the variable using FileReader and convert the value into a BinaryString, hash the content and finally assign the result to another controller valriable to show it in the html.

In my shell (local environment) to get the file digest I run the following command:

$ shasum -a 256 [path/to/file]

In order to upload files, i'm using ng-file-upload

What I'm missing? If anyone can help me or guide me to see the solution I will be very greatful.

Thank you in advance.

Update 1: As @destroyer said in the comments below readAsBinaryString is deprecated and it's an asynchronous method, so here's my actual code:

var reader = new FileReader();
reader.onload = function() {
    controller.fileHash = CryptoJS.SHA256(reader.result).toString(CryptoJS.enc.Hex);
};
reader.readAsArrayBuffer(controller.file);

I tried this solution in order to convert the ArrayBuffer object into a BinaryString. But the result is still wrong.

Update 2: Here's an image of a console log og the object I want to hash File object console.log


Solution

  • readAsBinaryString is deprecated, you should use readAsArrayBuffer.

    Either way, those functions start an asynchronous operation, the result of which you read inside the FileReader instance's load event.

    var reader = new FileReader();    
    reader.onload = function(){
      controller.fileHash = CryptoJS.SHA256(reader.result).toString(CryptoJS.enc.Hex);
    };
    reader.readAsArrayBuffer(controller.file);
    

    Reflecting on our conversation in comments: the problem was that crypto-js does not operate on binary files, but on strings.

    You can get a SHA256 implementation that supports ArrayBuffers directly in js-sha256.