MD5 Checksum for Images (Binaries) in Actionscript 3

I blogged previously about a project I was working on that needed to verify that the images downloaded were exactly what was sent. To do this I had to do an MD5 hash on the images at both ends (i.e. on the server in CF and on the client in AS3).

Luckily the hard part of the hash function for actionscript had already been written in the as3corelib which made my life significantly easier.

There is a bit of trickyness about the way Flash loads images by wrapping a swf around it which I'll save for another post - but once you have the byteArray data of the image generating the hash is pretty simple.

I just modified the corelib functions slightly and added a new function hashBinary. You can download the modified file from google code and hopefully it will get included by default in corelib.

// new function takes a byteArray
public static function hashBinary( s:ByteArray ):String

// original function takes a string
public static function hash(s:String) :String

Beneath the surface they functions use all the same code. The changes made to the code are as follows:

  • Rename hash function to be hashBinary.
  • Change parameters of hashBinary to accept a ByteArray
  • Change parameters of createBlocks to accept a ByteArray
  • Change createBlocks to use array reference instead of s.getCharCodeAt()
  • Create new hash() function which converts string to ByteArray and then call hashBinary passing in the ByteArray.

The changes should have no impact on the performance of the original hash function as it did the same conversion from a string to a binary but at a sligntly different location.

I've submitted a request to get this included in corelib so hopefully it will get added shortly.

Hope it helps Cheers, Mark

Comments
Shan's Gravatar EXACTLY what I needed... To get the MD5 of an image I was uploading via AIR. Thanks for sharing the code, and hopefully they get around to adding it to the corelib.
# Posted By Shan | 4/10/08 6:35 AM
Mark Lynch's Gravatar Hi Shan,

Glad you it was helpful to you - I've also been meaning to blog about it for a while - but I've written some code which pulls out the the jpeg data as URL Loader seems to wrap the JPG data into a swf file - probably for easier internal handling. If you need to compare the binary checksums that are generated by two different technologies - i.e. server and client side this becomes important. If you are only generating the MD5 checksums on the flash client side then you won't need to worry about it.

I'll get around to blogging about is soon but let me know if it's something you are working on and I'll publish it sooner.

Cheers,
Mark
# Posted By Mark Lynch | 4/14/08 12:44 AM
Shan's Gravatar Nope, I only need to generate the MD5 for uploading jpgs to SmugMug's upload API. Your post really came just in time... I'd been meaning to get uploads working for awhile, and only got to it last week.

I'm sure the followup post will come in handy for someone.

Thanks again!
# Posted By Shan | 4/14/08 1:13 AM
Dean's Gravatar Great article

Sorry for the N00b question, how do I get a AS file reference into a byte array so I can get the MD5 hash back.

Thanks
Dean
# Posted By Dean | 4/24/08 4:38 AM
Mark Lynch's Gravatar Hi Dean,

If you use URLLoader() and set the dataFormat to be binary, eg:

var urlReq:URLRequest =new URLRequest('http://www.example.com/image.jpg');
uLdr = new URLLoader();
uLdr.dataFormat = URLLoaderDataFormat.BINARY;            
uLdr.addEventListener(Event.COMPLETE,imageLoadHandler);
uLdr.load(urlReq);

private function imageLoadHandler(e:Event):void{
trace('Image Loaded');
var rawFile:ByteArray = e.currentTarget.data;
}

Cheers,
Mark
# Posted By Mark Lynch | 4/24/08 5:12 AM
Dean's Gravatar Thanks for the quick response.

There does not seem away to get the path of the file from the fileReference.

With the following I get
Unhandled ioError:. text=Error #2032: Stream Error. URL: file://ICS RGB.icc

I tried the object but event.target no go

I need to get the MD5 Hash of the file, I have a routine that will compare that hash with the files on the server and if this file does not exist upload, if it does exist don't upload.

The user selects the color profile from the browse(), I need to check that MD5 before uploading.

Thanks once again
private function onSelectFile(event:Event):void {
var urlReq:URLRequest =new URLRequest('file://' + event.target.name);
   var uLdr:URLLoader = new URLLoader();
   uLdr.dataFormat = URLLoaderDataFormat.BINARY;            
   uLdr.addEventListener(Event.COMPLETE,imageLoadHandler);
   uLdr.load(urlReq);
}
private function imageLoadHandler(e:Event):void{
    trace('Image Loaded');
    var rawFile:ByteArray = e.currentTarget.data;
    trace(MD5.hashBinary(rawFile))
}
# Posted By Dean | 4/24/08 1:57 PM
Mark Lynch's Gravatar Hi Dean,

I understand what you are trying to do now - is this for an app which is running in a browser as opposed to an AIR application?

If it's in a browser based app I suspect that it is not possible due to the way flash player handles the upload and download process (in order to work with the security sandboxes). The reason that I don't think it will work is that I think the Filereference class deliberately does not load the file directly into the flash play application space but passes it directly to the server.

I'd be very happy to be proved wrong as what you are trying to do would save lots of time if the files to be uploaded are large.

I haven't played with the file handling functionality in AIR yet but you may have a better chance of getting it done in AIR.

If you do figure it out please let me know.

Cheers,
Mark
# Posted By Mark Lynch | 4/24/08 3:03 PM
Jason Weed's Gravatar Thanks for the fix. You have saved me a lot of time.
# Posted By Jason Weed | 4/30/08 8:48 PM
Chris's Gravatar First off thanks for all of your effort on this project. I wouldn't have been able to do it myself.

I had a question about performance though. I have a project that generates an MD5 hash for jpg, xml, and flv files in an AIR application. The problem is that these files can get pretty large and files larger then 5mb destroy my computer when I pass them to the method.

Here is what happens to the Air process when I use the class on a 28mb flv file.

Before the file is loaded: 20mb 0%
after the file is loaded: 60mb 8% then 0%
after the file is passed to the hash method: 220mb 100% CPU
after the hash completes: 205mb 0% CPU

Maybe I'm doing something wrong or there is a way to throttle it?

Any suggestions would be greatly appreciated.
# Posted By Chris | 7/8/08 11:52 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.1.004.