Update: Source code is available on github.
I've just released version 0.2.0 of nano-hmac. It's the Haskell bindings to openssl HMAC and can be found on Hackage. With this new version there is now support for MD5, SHA, SHA1, SHA224, SHA256, SHA384 and SHA512. Also, new testcases now verify conformance with RFC's 2104 and 2202.
Hackage is not using haddock 2.0 yet so I'm not sure if the docs will build up there. If not, I've made the 0.2.0 docs available online.
If you don't already know what an HMAC is good for, here's a quick overview of their usefulness.
Many are familiar with MD5 hashes. They're commonly used to ensure file integrity of open source files you've downloaded off of the net. Download some file, run md5 on it and compare the hash against what's published on the website. If they match, then you can generally assume that the file hasn't been altered with respect to the provider of the hash.
% curl -O http://openssl.org/source/openssl-0.9.8g.tar.gz % curl -O http://openssl.org/source/openssl-0.9.8g.tar.gz.md5 % cat openssl-0.9.8g.tar.gz.md5 acf70a16359bf3658bdfb74bda1c4419 % md5 openssl-0.9.8g.tar.gz MD5 (openssl-0.9.8g.tar.gz) = acf70a16359bf3658bdfb74bda1c4419 % openssl dgst -md5 openssl-0.9.8g.tar.gz MD5(openssl-0.9.8g.tar.gz)= acf70a16359bf3658bdfb74bda1c4419
So a hash is basically like a checksum, it's a quick way to see if some data has been altered. Given how easy this is some thought it would be a good idea for use with the cookie session store in Rails. By providing a hash along with the cookie data, the thinking was the web application would be able to ensure that the cookie data wasn't altered/forged on subsequent requests.
However, hashes by themselves are open to attack. An attacker, if successful, can generate a matching hash or more likely a new hash (depending on how you've secured the original hash) such that you are unaware the message has been tampered with.
Message Integrity and Authenticity
An alternate approach is to use a keyed Hashing Message Authentication Code or HMAC. A HMAC adds a secret key in addition to the hashing function which enables it to guarantee both message integrity and authenticity. Only someone who has the secret key can generate the MAC. The addition of the secret key makes it much harder for the attacker to mount a preimage attack and makes it infeasible for them to generate a valid new hash without your knowledge.
The Rails guys are smart and they quickly updated the cookie session store to use HMAC's instead of just plain hashes. Furthermore, the new CSRF protection that Rails provides also uses HMAC's to generate the authenticity token used in hidden form fields.
So if you're doing any web development in Haskell, you may want to consider using HMAC's wherever you were using plain hashes for security.
Using nano-hmac is fairly straightforward. Here we'll generate a couple of MAC's using ghci. We'll generate two MAC's using the same key and message, but we'll use md5 as the first hashing algorithm and sha256 as the second.
% ghci Prelude> :module + Data.ByteString.Char8 Prelude Data.ByteString.Char8> :module + Data.Digest.OpenSSL.HMAC ...HMAC> unsafeHMAC md5 (pack "mykey") (pack "this is my message.") "b9cb782fa38b7bbae2792635fe487dd8" ...HMAC> unsafeHMAC sha256 (pack "mykey") (pack "this is my message.") "5bf1789f944e7e2f3c2dcb3516eb02dea7e01cd78cda0c374de571b71ab244cb"
And then in a shell, we can verify the MAC's using openssl directly.
% echo -n "this is my message." | openssl dgst -md5 -hmac "mykey" b9cb782fa38b7bbae2792635fe487dd8 % echo -n "this is my message." | openssl dgst -sha256 -hmac "mykey" 5bf1789f944e7e2f3c2dcb3516eb02dea7e01cd78cda0c374de571b71ab244cb
In real applications, the strength of the HMAC is a function of the key (length and guessability), the hashing algorithm and size of the resulting hash so you'll want to make sure to use a decently long key and one of the better hashing functions.
Hi, it would be very useful if you could expose the hash functions to the caller, in addition to the hmac interface, e.g.
sha1 :: ByteString -> String etc.
how do use ghci and hmac extension in such a way to use hexadecimal values for keys and message instead of strings ? It's not really clear to me.
What is format needed for keys and messages to be in hexadecimal format when using the nanohmac extension to ghc ?