Using Keyed Hash Functions

for RuBoard

Keyed hash functions are a subset of cryptographic hash functions that provide data authentication services in addition to integrity protection. As their name implies, keyed hash functions work by mixing a shared secret key with the to-be- hashed message to generate a hash value. That is, the hash value h = f(M, k), where f() is the keyed hash function, M is the to-be-hashed message (of arbitrary length), and k is the secret key. Changing either the message or the secret key will change the computed hash value.

Keyed hash functions are represented in the .NET Framework as subclasses of the KeyedHashAlgorithm abstract class, which itself is a subclass of HashAlgorithm . Because every KeyedHashAlgorithm is a HashAlgorithm , a KeyedHashAlgorithm object has Hash and HashSize properties and can be used as an ICryptoTransform . Additionally, a KeyedHashAlgorithm has a Key property for setting and retrieving the secret key associated with the instance object. As is the case with SymmetricAlgorithms , a random Key value will be generated when a KeyedHashAlgorithm object is constructed if you do not specify the key to use. Table 30.4 lists the keyed hash functions that are included in the .NET Framework class library; of course, additional algorithms can be added by subclassing KeyedHashAlgorithm .

Table 30.4. Keyed Hash Algorithms Included in the .NET Framework
Hash Algorithm
(Implementation Class) Legal Key Sizes (Bytes) Output Hash Size (Bytes)
HMAC-SHA1 ( HMACSHA1 )

All key sizes are legal.

Recommended size is 64 bytes.

20
MAC-3DES-CBC ( MACTripleDES ) 24 8

Keyed hash functions are often constructed from other hash algorithms or block ciphers; the two such algorithms included in the .NET Framework are representative of these construction techniques:

  • HMACSHA1 ” HMAC, short for hash-based message authentication code, is a general method for constructing a keyed hash algorithm from a hash algorithm. The HMACSHA1 class implements the HMAC construction using SHA-1 as the underlying hash function; HMAC using SHA-1 is frequently used as a keyed hash algorithm. The HMAC construction mixes a secret key with the message data, hashes the result with the hash function, mixes that hash value with the secret key again, and then applies the hash function a second time. The output hash will be 20 bytes in length ”the size of a SHA-1 hash. The secret key input to HMAC-SHA1 can be of any length, but if it is more than 64 bytes long, it will be hashed (using SHA-1) to derive a 64-byte key. (The internal construction of HMAC limits the key size to 64 bytes.)

  • MACTripleDES MACTripleDES is a keyed hash algorithm constructed from a block cipher, in this case TripleDES . MACTripleDES simply encrypts the to-be-hashed message with TripleDES using cipher block chaining (CBC) mode, zero padding for short blocks, a user -supplied secret key, and an initialization vector of all zeroes. The keyed hash of the message is the final block of the encrypted ciphertext and is 8 bytes in length. The secret key must be 24 bytes in length because it is used as a key for three-key TripleDES .

Computing a keyed hash value in the .NET Framework is almost identical to computing a non-keyed hash value, except for the additional Key property. The following code shows how you compute the HMAC-SHA1 keyed hash of an array of bytes stored in the myMessage variable with key myKey :

 HMACSHA1 hmacsha1 = new HMACSHA1(); hmacsha1.Key = myKey; byte[] hashValue = hmacsha1.ComputeHash(myMessage); 

You can also specify the key value as an argument to the object constructor:

 HMACSHA1 hmacsha1 = new HMACSHA1(myKey); byte[] hashValue = hmacsha1.ComputeHash(myMessage); 

There are also overloaded versions of ComputeHash that accept an array offset and count:

 byte[] hashValue = hmacsha1.ComputeHash(myMessage, offset, count); 

Additionally, you can use a KeyedHashAlgorithm object as an ICryptoTransform within a CryptoStream .

In the EncryptFile method of Listing 30.8, we used a "hash-and-encrypt" operation to provide authentication and integrity protection for the contents of a file. Keyed hash functions also provide authentication and integrity services; we can use an HMAC-SHA1 keyed hash to provide the same guarantees as "hash-and-encrypt" without using encryption. Listings 30.10 and 30.11 show the source code for two methods , EncodeFile and DecodeFile , which produce and consume authenticated and integrity-protected files. The EncodeFile routine takes as input three arguments: a secret key, a source filename, and a target filename. EncodeFile computes the HMACSHA1 keyed hash of the source file and then writes the concatenation of the hash value and the contents of the source file to the target file. The DecodeFile method takes two input arguments ”the secret key and the name of the encoded file ”and verifies that the file has not changed since it was written by EncodeFile .

Listing 30.10 Compute a Keyed Hash for a Source File; Create a Target File with the Keyed Hash Prepended to the Contents of the Source File
 public static void EncodeFile(byte[] key, String sourceFile, String destFile) {   // initialize the keyed hash object   HMACSHA1 hmacsha1 = new HMACSHA1(key);   FileStream inStream = new FileStream(sourceFile, FileMode.Open);   FileStream outStream = new FileStream(destFile, FileMode.Create);   // Statically compute the hash of the input file   byte[] hashValue = hmacsha1.ComputeHash(inStream);   // Reset inStream to the beginning of the file   inStream.Position = 0;   // Write the computed hash value to the output file   outStream.Write(hashValue, 0, hashValue.Length);   // copy the contents of the sourceFile to the destFile   int bytesRead;   byte[] buffer = new byte[1024]; // read 1K at a time   do {     // read from the wrapping CryptoStream!     bytesRead = inStream.Read(buffer,0,1024);     outStream.Write(buffer, 0, bytesRead);   }  while (bytesRead > 0);   // Done encrypting, close the streams   inStream.Close();   outStream.Close();   return; } 

This function is somewhat simpler than the EncryptFile method of Listing 30.8 in that it does not use any CryptoStreams . Because we chose to put the keyed hash value at the beginning of the encoded file, there is no advantage in setting up a CryptoStream to compute the keyed hash value. We will always have to read the input file twice ”once to compute the hash value and a second time to write the contents of the input file to the output file. The code for the corresponding DecodeFile method is similarly straightforward.

Listing 30.11 Verify the Integrity of a File Associated with a Keyed Hash Value
 public static bool DecodeFile(byte[] key, String sourceFile) {   // initialize the keyed hash object   HMACSHA1 hmacsha1 = new HMACSHA1(key);   // Create an array to hold the keyed hash value read from the file:   byte[] storedHash = new byte[hmacsha1.HashSize/8];   // create a FileStream for the source file   FileStream inStream = new FileStream(sourceFile, FileMode.Open);   // Read in the storedHash   inStream.Read(storedHash, 0, storedHash.Length);   // Compute the hash of the remaining contents of the file   // The stream is properly positioned at the beginning of the content,   // immediately after the stored hash value   byte[] computedHash = hmacsha1.ComputeHash(inStream);   // compare the computed hash with the stored value   for (int i=0; i< storedHash.Length; i++) {     if (computedHash[i] != storedHash[i]) {       Console.WriteLine("Hash values differ! Encoded file has been tampered with!");       return false;     }   }   Console.WriteLine("Hash values agree -- no tampering occurred.");   return true; } 

DecodeFile is implemented as a Boolean function that returns true when the keyed hash value matches the calculated hash value; a message is also displayed on the console reporting the result of the hash comparison.

This concludes our discussion of the differences between (nonkeyed) hash functions and keyed hash functions. Except for the secret key, a KeyedHashAlgorithm object behaves the same as any other HashAlgorithm object. If you have an established shared secret between two parties, a keyed hash value is often the simplest way to convey data origin authentication (that is, who hashed the file) and integrity protection (tamper-resistance).

for RuBoard


. NET Framework Security
.NET Framework Security
ISBN: 067232184X
EAN: 2147483647
Year: 2000
Pages: 235

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net