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:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

namespace RandomNumberGenerator
{
    public class RNG
    {
		public string GenerateRandomCryptographicKey(int keyLength)
		{			
			return Convert.ToBase64String(GenerateRandomCryptographicBytes(keyLength));
		}

		public byte[] GenerateRandomCryptographicBytes(int keyLength)
		{
			RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
			byte[] randomBytes = new byte[keyLength];
			rngCryptoServiceProvider.GetBytes(randomBytes);
			return randomBytes;
		}
	}
}

The ComputeHmac function in the HMACService allows us to pass in any HMAC implementation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace HashingAlgos
{
	public class HMACService
	{
		public string ComputeHmac(string message, HMAC hmac)
		{
			return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(message)));
		}
	}
}

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:

private void TestHmac()
{
	RNG rng = new RNG();
	byte[] hashKey = rng.GenerateRandomCryptographicBytes(64);
	HMACService hmacService = new HMACService();

	string message = "This is another simple message";

	HMAC hmacSha1 = new HMACSHA1(hashKey);
	HMAC hmacSha256 = new HMACSHA256(hashKey);
	HMAC hmacSha512 = new HMACSHA512(hashKey);
	string messageHmacSha1 = hmacService.ComputeHmac(message, hmacSha1);
	string messageHmacSha256 = hmacService.ComputeHmac(message, hmacSha256);
	string messageHmacSha512 = hmacService.ComputeHmac(message, hmacSha512);

	Console.WriteLine(messageHmacSha1);
	Console.WriteLine(messageHmacSha256);
	Console.WriteLine(messageHmacSha512);
}

Here are the HMAC values from top to bottom:

TTz0JeJnjBnG9MVIyZXwfuHPYkM=
fsXBhiPfijlURpR1EneOPxjF4LkYAwnPUc983aeW+PE=
CiC8vIoCyB5i8qXMGTJ4lSiTSw+A4W+m7MMY/hdNcUoTdSWqkonoPh1fdJ66qX/aTSA2JxnsGNwbaurIkNBFvw==

You can view the list of posts on Security and Cryptography here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Love to use Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Ricos Blog zu Softwaredesign- und architektur

Ideen und Gedanken rund um Softwaredesign und -architektur, Domain-Driven Design, C# und Windows Azure

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: