Return to HomePage




Generate a Message Authentication Code MAC (C#)



Applies to

* ASP.NET 2.0
* C#

Summary

To create a cryptographically secure message authentication code or integrity
check of a portion of data.

Message Authentication Codes or MACs are used by two parties to validate that a message hadn't been altered in transit. Only the nodes which posses the keys may compute the MAC and validate the MAC against an input text. This code sample demonstrates the use of an HMAC.


Objectives

* Provide a method to detect message modification and tampering, this method should not allow an attacker to easily generate and modify the MAC in transit.
* Generate a cryptographically strong key which appears random in value for use as an HMAC signing key



Scenarios

* Two entities are communicating over a sockets interface (clear-text or encrypted communications) and wish to detect message modification for data in transit
* Two entities wish to prevent message modification for data in transit via a sockets interface (clear-text or encrypted communications)

Solution Example

		        public static string GenerateHMAC(string input, string secret)
		        {
		            // Instantiate the HMAC class
		            HMACSHA256 hmac = new HMACSHA256();
	

		            try
		            {
		                // We pass in a user supplied password to generate a strong key to be used in our HMAC
		                // since people tend to use weak and potentially dictionary values for keys.  
		                // Using the [PasswordDerivedBytes] helps to mitigate the risk of dictionary attacks
		                // on our HMAC key
	

		                // In the current implementation, regardless of the salt passed to the [PasswordDeriveBytes]
		                // constructor the same derived password will be generated.
		                [PasswordDeriveBytes] pdb = new [PasswordDeriveBytes(secret,] null);
	

		                byte[] pbytes = pdb.CryptDeriveKey("TripleDES", "SHA1", 192, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
	

		                hmac.Key = pbytes;
	

		            }
	

		            catch (Exception e)
		            {
		                [Console.Error.WriteLine(e.ToString());]
		            }
		            return [ASCIIEncoding.ASCII.GetString(hmac.ComputeHash(ASCIIEncoding.ASCII.GetBytes(input)));]
		        }
	


Problem Example

The following code sample demonstrates the use of a message authenticating
code prone to tampering because it simply uses a publicly know hashing mechanism
with no shared secret:

		        public static string [GenerateDigest(string] input)
		        {
	

		            // Instantiate the SHA1 Digest
		            SHA1 sha = new [SHA1CryptoServiceProvider();]
		            return [ASCIIEncoding.ASCII.GetString(sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(input)));]
		        }
	

Test Case

The following classes must be included in any project making use of the sample code provided above:

using System.Security.Cryptography;

Execute a test encryption and comparison of a two iterations of our plaintext, one which is unaltered and a second which emulates being altered in transit:

		        static void Main(string[] args)
		        {
		            string secret = "thisisaweaksecretkeywhichweuseinourhmac";
	

		            [CodeSample] cs = new [CodeSample();]
		            string text = "the quick brown fox jumped over the lazy dog";
		            // Generate the SHA256 HMAC for the given value based on the keys setup in our constructor
	

		            string strHmac = GenerateHMAC(text, secret);
	

		            // Append the HMAC to the original text to be sent on the wire. The HMAC serves the purpose
		            // of validating the integrity of the original message
		            string msg1 = text + strHmac;
		            bool isValid = ValidateHMAC(msg1, secret);
	

		            Console.Out.WriteLine("Validating MSG1 (Unaltered in transit): " + [isValid.ToString());]
	

		            // Test a variation of the original message with the original HMAC to test validation of the
		            // HMAC and message.
		            string msg2 = "the quick brown dog jumped over the lazy fox" + strHmac;
		            isValid = ValidateHMAC(msg2, secret);
		            Console.Out.WriteLine("Validating MSG2 (Altered in transit / text rearranged): " + [isValid.ToString());]
	

		            // Show our problem example
		            //Console.Out.WriteLine("Digest of '{0}': {1}", msg2, [GenerateDigest(msg1));]
		        }
	

The ValidateHMAC method is shown below for the purposes of validating the
HMAC:

		        public static bool ValidateHMAC(string input, string secret)
		        {
		            bool isValid = false;
		            try
		            {
		                // Instantiate the HMAC class
		                HMACSHA256 hmac = new HMACSHA256();
	

		                // Since we're using SHA256, we'll take the last 32 bytes from the message,
		                // recompute the hmac on the first half and compare the two [HMACs]
	

		                string strOrigHMAC = input.Remove(0, input.Length - 32);
		                string strMsg = input.Substring(0, input.Length - 32);
		                if (strOrigHMAC == GenerateHMAC(strMsg, secret))
		                {
		                    isValid = true;
		                }
		                else
		                {
		                    isValid = false;
		                }
	

		            }
		            catch
		            {
		                isValid = false;
		            }
		            return isValid;
		        }
	

Expected Result

Validating MSG1 (Unaltered in transit): True
Validating MSG2 (Altered in transit / text rearranged): False


More Information
* An HMAC consists of taking a secret known only to entities wishing to communicate, concatenating this value to the front of a message to be sent. Next, this value is digested with a secure hash function, after which the secret is prepended to the resulting digest and performs a second digest using the secure hash function.
* The .NET framework provides several HMAC providers. In this example, we've demonstrated the use of creation and validation of an HMAC using the SHA256 hash function.
* Another goal in choosing a key for the HMAC process is to ensure that keys are strongly generated. Assuming two entities share a weak password it is possible to generate a derived key which resembles a strong and random key to an eavesdropper.


Additional Resources

* Cryptopgraphy (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_cryptography
* HMAC definition: http://en.wikipedia.org/wiki/HMAC
* HMAC class: http://msdn2.microsoft.com/en-US/library/system.security.cryptography.hmac.aspx
* Protecting keys using the DPAPI: http://msdn.microsoft.com/library/en-us/dnpag2/html/paght000005.asp
* Generating a key from a password: http://blogs.msdn.com/shawnfa/archive/2004/04/14/113514.aspx

Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Cryptography
* Author: George Gal




Return to HomePage
Microsoft Communities