Sunday, July 11, 2010

Generate SHA1 File Checksum Using HTML5 File API in Javascript

JavaScript was not allow to read a file in local computer for such a long time. However, as HTML5 came out, reading files in Javascript became possible. In this post, I will demonstrate how to implement dragging and dropping a file into browser and generating its SHA1 checksum. There are three parts in this post, drag and drop handling, file reading via HTML5 File API and SHA1 JavaScript implementation.

Currently, only Firefox 3.6+ and Chrome 6+ support HTML5 File API.



DEMO


1. Drag and Drop

What we need to do is in ondrop function when user drops a file in browser. In this function, we need to transfer the dropped object as "FileList" object.

var holder = document.getElementById('holder');
holder.ondragover = function () { 
 this.className = 'hover'; 
 setHolderContent("");
 return false; 
 };

holder.ondragend = function () { 

 this.className = '';
 setHolderContent("");
  return false; 

  };

holder.ondrop = function (e) {
   e.preventDefault();

  var file = e.dataTransfer.files[0];

  processFile(file);

}


2. Reading file with HTML5 File API

The events we are interested is during reading (onprogress) and when reading finish (onloadend). And we read file content as birnary string.
function processFile(file){
 
    var reader = new FileReader();
    //update precentage while file reading 
    reader.onprogress = function (evt) {
    if (evt.lengthComputable) {
      var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
      if (percentLoaded <=100) {
       updateProgess(percentLoaded);
        }
    }
  }
    //reading finish, do sha1 calcuate.
    reader.onloadend = function (event) {
   
         
  var result = sha1Stream(event.target.result); 
   var precentIndicator = document.getElementById('holder');
    setHolderContent(result);
    updateProgess(100);
    
  };



reader.readAsBinaryString(file);
 
}

3. SHA1 JavaScript implementation

There are several JavaScript implementation available, so I just borrowed: Paul Johnston at http://pajhome.org.uk/crypt/md5/contrib/sha1_stream.js Jason Davies's stream version: http://pajhome.org.uk/crypt/md5/contrib/sha1_stream.js
function sha1Stream(input){
   
     var blocksize = 512;
     var h = naked_sha1_head();
     for (var i = 0; i < input.length; i += blocksize) {
         var len = Math.min(blocksize, input.length - i);
        var block = input.substr(i, len);
        naked_sha1(str2binb(block), len*chrsz, h);
        
     }
     var result = binb2hex(naked_sha1_tail(h));
     return result;
}
I have to thank sunetos, who help me with the stream version.

Due JavaScript's performance issues, my small SHA1 generator cannot handle large file(I suggest you try file under 2M). And It seems Chrome 6 handle large file better than firefox 3.6.



3 comments:

Matias said...

Excelent post!!

How can I do this Without HTML5??
I need to do this on IE8

Regards!

Brad G said...
This comment has been removed by the author.
Bryce Boe said...

Why are you using the streaming version? I know in principle it would be great to not have the entire file in memory, however, I'm pretty sure that by calling readAsBinaryString the entire file will be put into memory.