Search code examples
javascriptajaxsha1cryptojs

SHA1 calculation returns wrong value


I am trying to calculate SHA1 value of a file using javascript. The file is located on the same directory as index.html and it is loaded using ajax by the name given as a query param.

for example, calling http://localhost:7070/index.html?file=file.zip should calculate SHA1 for file.zip

The following code calculates SHA1 but the result is different than what i get using this online tool with SHA1 and uploading the file http://onlinemd5.com/

$(document).ready(function(){
   var file = utils.getUrlVars() && utils.getUrlVars().file;

   if (!file) throw "error - no URL was found. set 'file' in query string.";

   $.ajax({

       url: file,
       success: function(data){
           var sha1= CryptoJS.SHA1(data).toString();
           console.log('sha1 - success', sha1);
       },
       error: function(error){
           console.log('ERROR');
       }

   })
});

What is the difference? i guess that the online tool calculates it right (and it also gives me the exact result i get when calculating using Java code), so something in this JS code does it slightly different.

The problem is definitely not in the CryptoJS package since when calculating the string 'hello' using the script generates the following output:

sha1 - success aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d

And using the online tool you get the same (in uppercase):

AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D

The problem is definitely in the format of the data after loading it or the way of using it.

When i use Java to calculate SHA1 i get the same result by calculating it on the files byte array, so it points to the fact that the bytearray i get using this script is somehow different / partial.


Solution

  • We managed to solve this eventually, the solution is pure JS with no Ajax involved:

    $(document).ready(function(){
    
    var url = utils.getUrlVars() && utils.getUrlVars().url;
    
    if (!url) throw "error - no URL was found. set 'url' in query string.";
    
    var oReq = new XMLHttpRequest();
    oReq.open("GET", url, true);
    oReq.responseType = "blob";
    
    oReq.onreadystatechange = function(e) {
    
        if (oReq.readyState == 4 && oReq.status == 200) {
            console.log('xhr success');
            success(e);
        } else if (oReq.readyState == 4 && oReq.status != 200){
            console.log('xhr error');
            error(e);
        }
    }
    
    var success = function() {
        var blob = oReq.response; 
        var sha1 = CryptoJS.algo.SHA1.create(); 
        var reader = new FileReader();
        reader.readAsArrayBuffer(blob);
    
        reader.onload = function(e) {
            var arrbuffer = e.target.result.slice(0, e.target.result.byteLength);
            var bytes = CryptoJS.enc.u8array.parse(new Uint8Array(arrbuffer));
            sha1.update(bytes);
            var sha1res = sha1.finalize().toString(CryptoJS.enc.Hex);
            // print results
            console.log('sha1 - success', sha1res);
        }
    };
    
    var error = function(){
        IJavaScriptImplementer.onError(JSON.stringify(error));
        IJavaScriptImplementer.log(JSON.stringify(error));
    }
    
    oReq.send(null);
    });
    

    As you cam see, the file is requested as a blob and is being read as one slice (you can also do it slice by slice but in my case the files are small), then the bytes are read and calculated into the SHA1 value.