ColdFusion 10 Beta - Generating Hash-Based Message Authentication Codes With Hmac()

Posted February 27, 2012 at 9:14 AM by Ben Nadel

Tags: ColdFusion

We are entering the age of APIs - Application Programming Interface(s). Many of our applications now interface with 3rd party APIs like Twilio, Twitter, EmailYak, FullContact, Face.com, and Facebook. The list goes on and on. The available functionality is simply mind-blowing; unfortunately, when we interact with 3rd party services, we do open ourselves up to another attack surface. Luckily, we can use shared private keys as a way to create Hash-based Message Authentication Codes - or, HMAC values - in order to authenticate the senders and recipients of messages. This approach used to be a rather trying feature to implement; with ColdFusion 10, however, generating HMAC values is now incredibly simple.

I don't fully understand the mechanics of generating a Hash-based Message Authentication Code. I can tell you that it works by creating a message digest with the aide of a given secure hashing algorithm. EmailYak uses the MD5 hashing algorithm; Pusher uses the Sha-256 hashing algorithm; and Twilio uses the Sha-1 hashing algorithm. In Java (and therefore in ColdFusion), the application of the given hashing algorithm is encapsulated within the classes javax.crypto.spec.SecretKeySpec and javax.crypto.Mac. And still, creating hash-based message authentication codes requires a lot of work.

In ColdFusion 10, we now have the function hmac(). hmac() fully encapsulates the selection and application of the hashing algorithm, the creation of the message digest, and the conversion of the digest into HEX format. In other words, hmac() took a complex algorithm and turned into a single function call.

To see the huge difference this has made, take a look at the following code. In this demo, I'll create an MD5-based message authentication code (HMAC) using both a custom-built, user defined ColdFusion function and the new hmac() function. The difference will become obvious.

  • <cfscript>
  •  
  •  
  • // I take an API key and a content value and generate a hashed-
  • // message authenticate code using MD5 so as to be able to
  • // authenticate that the message is from a trusted source.
  • function md5Digest( content, apiKey ){
  •  
  • // We need to hash the content using the MD5 algorithm. Let's
  • // define a key specification for the HmacMD5 alrorithm using
  • // our API key.
  • var secretKeySpec = createObject( "java", "javax.crypto.spec.SecretKeySpec" ).init(
  • toBinary( toBase64( apiKey ) ),
  • javaCast( "string", "HmacMD5" )
  • );
  •  
  • // Now, let's create our MAC (Message Authentication Code)
  • // generator to hash the actual email post content.
  • var mac = createObject( "java", "javax.crypto.Mac" ).getInstance(
  • javaCast( "string", "HmacMD5" )
  • );
  •  
  • // Initialize the MAC using our secret key.
  • mac.init( secretKeySpec );
  •  
  • // Hash the content of the message - returnes byte array.
  • var hashedBytes = mac.doFinal(
  • toBinary( toBase64( content ) )
  • );
  •  
  • // Now that we have our hashed bytes, we need to encode them
  • // as a Hexadecimal string. Create a buffer to hold the hex
  • // values as we encode each byte.
  • var hexBuffer = [];
  •  
  • // Loop over the bytes to encode them individually as HEX.
  • for (var byte in hashedBytes){
  •  
  • // Get the hex value for this byte. When converting the
  • // byte, only use the right-most 8 bits - the sign of
  • // the byte can create oddities otherwise.
  • var hexValue = formatBaseN( bitAnd( 255, byte ), 16 );
  •  
  • // When appending the HEX value, ensure that the leading
  • // zero has not been trimmed during the conversion.
  • arrayAppend(
  • hexBuffer,
  • right( "0#hexValue#", 2 )
  • );
  •  
  • }
  •  
  • // Flatten and return the Hex buffer.
  • return(
  • ucase( arrayToList( hexBuffer, "" ) )
  • );
  •  
  • }
  •  
  •  
  • // ------------------------------------------------------ //
  • // ------------------------------------------------------ //
  •  
  •  
  • // Set up our security key and our message to authenticate.
  • apiKey = "icanhazsecyouritea";
  • message = "The content to be authenticed using message digest!";
  •  
  •  
  • // Get HMAC (hashed-message authentication code) using the manual
  • // algorithm and hex conversion.
  • writeOutput(
  • md5Digest( message, apiKey )
  • );
  •  
  • writeOutput( "<br />" );
  •  
  • // Use new built-in Hmac() method.
  • writeOutput(
  • hmac( message, apiKey, "HmacMD5" )
  • );
  •  
  •  
  • </cfscript>

As you can see, the 50-line user-defined function is replaced with a single call to hmac(). And, when we run the above code, we can see that the two approaches generate the same hash-based message authentication code (HMAC):

51A2E5E7AA08926C53AAC45356ABA0C9
51A2E5E7AA08926C53AAC45356ABA0C9

The new hmac() function is so much easier!

As dealing with 3rd-party APIs becomes commonplace, message authentication becomes a fact of life. Not only do we have to authenticate where incoming messages came from, 3rd-party APIs are requiring that we authenticate who we are (when we send messages out). Many sites are using hash-based message authentication codes (HMAC) as a way to perform this security check; while this was possible before ColdFusion 10, the new beta makes this security handshake incredibly simple.


You Might Also Be Interested In:



Reader Comments

Mar 13, 2012 at 9:44 AM // reply »
158 Comments

Sixteen days have passed and no one has made your day yet? This is a good post! How can I have been the one to make your day? Seriously?!


Mar 13, 2012 at 10:50 AM // reply »
11,238 Comments

@Randall,

I guess not many people were as excited about the new hmac() method as me :D I appreciate you making my day!


Mar 28, 2012 at 7:23 PM // reply »
6 Comments

This is awesome! CF10 is going to rock


Apr 9, 2012 at 1:42 PM // reply »
46 Comments

I was reading the CF10 docs and for "algorithm" & "Encoding" it doesn't offer a list of allowable options.
http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WS932f2e4c7c04df8f744b691e1353e37d519-8000.html

Any idea regarding all of the algorithms & encoding that Hmac() supports? (Will this be further documented?)

On another note (hash related) I recently read an article recommending the use of bcrypt or BKDF2 "exclusively" to hash anything that needs to be secured:
http://www.codinghorror.com/blog/2012/04/speed-hashing.html

Here's an article on how to integrate bcrypt w/ColdFusion:
http://blog.mxunit.org/2011/02/hashing-passwords-with-bcrypt-in.html

bcrypt looks pretty nice & I was wondering if any additional security-related features, like bcrypt, may make it into CF10?


Apr 9, 2012 at 3:19 PM // reply »
11,238 Comments

@James,

I know there are licensing issues between some of the various encryption algorithms. There are some that can only be accessed via Enterprise licensing. If you look up the documentation for the encrypt() function, you can see the licensing differences in algorithm support between Standard and Enterprise.

I don't know if that applies to this particular function, or what sub-set of algorithms this supports.

I can say that in my [limited] experience, all the hashing algorithms I've come across when dealing with 3rd party APIs was MD5, Sha-1, and Sha-256.

I don't know too much about bcrypt. Honest, I don't know too much about advanced security and cryptography. I'll have to check out Marc's article on the matter, thanks!


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools