Using HMACs to authenticate a hash in .NET

In this post we learnt about using hashing in .NET. Hashes provide a one-way encryption of a message where the hash value ideally cannot be “unhashed”, i.e. we cannot build the original string from it. A hash or message digest helps us verify whether the message has been tampered with by a third party after it was sent to us.

We can take a step further and add an extra layer of security on our hashes. After all a message and its hash could originate from anyone. How can we verify the authenticity of the message as well? That’s where Hashed Message Authentication Codes, also called HashMACs or HMACs enter the picture.

Suppose that you get the following message with its hash: “Let’s meet at 7pm in front of the cinema, John”. You examine the hash and come to the conclusion that the message hasn’t been modified. Then you get another message: “Let’s meet at 6pm instead.” Hmmm, OK, that’s unusual, John normally doesn’t change his mind so quickly, did the message really come from him?

HMACs are also hashes but they are given an extra round of calculation using a random hash key. If both parties have access to this key then the message can be verified and authenticated using the agreed key and hash algorithm. If the receiver calculates a HashMac which is different from the one sent along with the message then authentication fails.

HashMacs in .NET derive from the HMAC abstract base class in the System.Security.Cryptography namespace. There are implementations corresponding to the various hashing algorithms we saw before such as MD5 and SHA-256.

For the demo we’ll need a true random number generator that we saw in this post. Here’s a slightly modified helper class:

All concrete implementations of HMAC have a ComputeHash method that accepts a byte array. In the above code we convert the incoming message into an array of bytes and return the calculated bytes as a string for easier visualisation.

Here’s some test code that calculates the SHA-1, SHA-256 and SHA-512 HMACs with a 64-bit hash key: