Recipe17.5.Verifying that a String Remains Uncorrupted Following Transmission


Recipe 17.5. Verifying that a String Remains Uncorrupted Following Transmission

Problem

You have some text that will be sent across a network to another machine for processing. It is critical for you to verify that this text remains intact and unmodified when it arrives at its destination.

Solution

Calculate a hash value from the string and append it to the string before it is sent to its destination. Once the destination receives the string, it can remove the hash value and determine whether the string is the same one that was initially sent. The CreateStringHash method takes a string as input, adds a hash value to the end of it, and returns the new string, as shown in Example 17-8.

Example 17-8. Verifying that a string remains uncorrupted following transmission

 public class HashOps {   // The number 44 is the exact length of the base64 representation   // of the hash value, which was appended to the string.   private const int HASH_LENGTH = 44;      public static string CreateStringHash(string unHashedString)   {       byte[] encodedUnHashedString = Encoding.Unicode.GetBytes(unHashedString);       string stringWithHash = "";       using (SHA256Managed hashingObj = new SHA256Managed( ))       {         byte[] hashCode = hashingObj.ComputeHash(encodedUnHashedString);         string hashBase64 = Convert.ToBase64String(hashCode);         stringWithHash = unHashedString + hashBase64;       }       return (stringWithHash);   }                  public static bool TestReceivedStringHash(string stringWithHash,                                                   out string originalStr)         {             // Code to quickly test the handling of a tampered string.             //stringWithHash = stringWithHash.Replace('a', 'b');             if (stringWithHash.Length <= HASH_LENGTH)             {                 originalStr = null;                 return (true);             }             string hashCodeString =                 stringWithHash.Substring(stringWithHash.Length - HASH_LENGTH);             string unHashedString =                 stringWithHash.Substring(0, stringWithHash.Length - HASH_LENGTH);             byte[] hashCode = Convert.FromBase64String(hashCodeString);             byte[] encodedUnHashedString = Encoding.Unicode.GetBytes(unHashedString);             bool hasBeenTamperedWith = false;             using (SHA256Managed hashingObj = new SHA256Managed( ))             {               byte[] receivedHashCode = hashingObj.ComputeHash(encodedUnHashedString);               for (int counter = 0; counter < receivedHashCode.Length; counter++)               {                 if (receivedHashCode[counter] != hashCode[counter])                 {                     hasBeenTamperedWith = true;                     break;                 }             }             if (!hasBeenTamperedWith)             {               originalStr = unHashedString;             }             else             {               originalStr = null;             }         }         return (hasBeenTamperedWith);     } } 

The TestReceivedStringHash method is called by the code that receives a string with a hash value appended. This method removes the hash value, calculates a new hash value for the string, and checks to see whether both hash values match. If they match, both strings are exactly the same, and the method returns false. If they don't match, the string has been tampered with, and the method returns true.

Since the CreateStringHash and TestReceivedStringHash methods are static members of a class named HashOps, you can call these methods with code like the following:

 public static void VerifyNonStringCorruption( ) {     string testString = "This is the string that we'll be testing.";     string unhashedString;     string hashedString = HashOps.CreateStringHash(testString);     bool result = HashOps.TestReceivedStringHash(hashedString, out unhashedString);     Console.WriteLine(result);     if (!result)         Console.WriteLine("The string sent is: " + unhashedString);     else         Console.WriteLine("The string: " + unhashedString +             " has become corrupted."); } 

The output of this method is shown here when the string is uncorrupted:

 False The string sent is: This is the string that we'll be testing. 

The output of this method is shown here when the string is corrupted:

 False The string: This is the string that we'll #$%^(&&*2 be testing. has become corrupted. 

Discussion

You can use a hash, checksum, or cyclic redundancy check (CRC) to calculate a value based on a message. This value is then used at the destination to determine whether the message has been modified during transmission between the source and destination.

This recipe uses a hash value as a reliable method of determining whether a string has been modified. The hash value for this recipe is calculated using the SHA256Managed class. This hash value is 256 bits in size and produces greatly differing results when calculated from strings that are very similar, but not exactly the same. In fact, if a single letter is removed or even capitalized, the resulting hash value will change.

By appending this value to the string, both the string and hash values can be sent to their destination. The destination then removes the hash value and calculates a hash value of its own based on the received string. These two hash values are then compared. If they are equal, the strings are exactly the same. If they are not equal, you can be sure that somewhere between the source and destination, the string was corrupted. This technique is great for verifying that transmission succeeded without errors, but it does not guarantee against malicious tampering. To protect against malicious tampering, use an asymmetric algorithm: sign the string with a private key and verify the signature with a public key.

The CreateStringHash method first converts the unhashed string into a byte array using the GetBytes method of the UnicodeEncoding class. This byte array is then passed to the ComputeHash method of the SHA256Managed class.

Once the hash value is calculated, the byte array containing the hash code is converted to a string containing base64 digits, using the Convert.ToBase64String method. This method accepts a byte array, converts it to a string of base64 digits, and returns that string. The reason for doing this is to convert all unsigned integers in the byte array to values that can be represented in a string data type. The last thing that this method does is to append the hash value to the end of the string and return the newly hashed string.

The TestReceivedStringHash method accepts a hashed string and an out parameter that will return the unhashed string. This method returns a Boolean; as previously mentioned, true indicates that the string has been modified, false indicates that the string is unmodified.

This method first removes the hash value from the end of the StringWithHash variable. Next, a new hash is calculated using the string portion of the StringWithHash variable. These two hash values are compared. If they are the same, the string has been received, unmodified. Note that if you change the hashing algorithm used, you must change it in both this method and the CreateStringHash method. You must also change the HASH_LENGTH constant in the TestReceivedStringHash method to an appropriate size for the new hashing algorithm. This number is the exact length of the base64 representation of the hash value, which was appended to the string.

See Also

See the "SHA256Managed Class," "Convert.ToBase64String Method," and "Convert. FromBase64String Method" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

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