Recipe 14.5 Verifying that a String Is Uncorrupted During Transmission
Problem
You have some text that will be
sent across a network to another machine for processing. It is
critical that you are able to verify that this text remains intact
and unmodified when it arrives at its destination.
Solution
Calculate a hash value from
this 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:
public class HashOps
{
public static string CreateStringHash(string unHashedString)
{
byte[] encodedUnHashedString = Encoding.Unicode.GetBytes(unHashedString);
SHA256Managed hashingObj = new SHA256Managed( );
byte[] hashCode = hashingObj.ComputeHash(encodedUnHashedString);
string hashBase64 = Convert.ToBase64String(hashCode);
string stringWithHash = unHashedString + hashBase64;
hashingObj.Clear( );
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 < 45)
{
originalStr = null;
return (true);
}
string hashCodeString =
stringWithHash.Substring(stringWithHash.Length - 44);
string unHashedString =
stringWithHash.Substring(0, stringWithHash.Length - 44);
byte[] hashCode = Convert.FromBase64String(hashCodeString);
byte[] encodedUnHashedString = Encoding.Unicode.GetBytes(unHashedString);
SHA256Managed hashingObj = new SHA256Managed( );
byte[] receivedHashCode = hashingObj.ComputeHash(encodedUnHashedString);
bool hasBeenTamperedWith = false;
for (int counter = 0; counter < receivedHashCode.Length; counter++)
{
if (receivedHashCode[counter] != hashCode[counter])
{
hasBeenTamperedWith = true;
break;
}
}
if (!hasBeenTamperedWith)
{
originalStr = unHashedString;
}
else
{
originalStr = null;
}
hashingObj.Clear( );
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, we 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.");
}
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 value
can be sent to its 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 into 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 both in this method and the
CreateStringHash method. You must also change the
numeric literal 44 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.
|