Introduction
This article covers what the differences are between hashing, MAC and digital signatures. It presumes a certain level of knowledge about encryption methods especially the difference between symmetric and asymmetric encryption. The article does not cover how to perform encryption or about key management. There are some code examples on how to perform each of the technologies using C# in .NET v2.0.
Hashing; as a means to verify data integrity
The reason for performing hashing is to ensure data integrity. Hashing is simply a process whereby you calculate a hash code from some data. The generated hash code is mathematically derived and is unique and specific for the data it was derived from. If any byte changes in the data then a completely different hash code is generated. For example a hash code generated from the text “Hello” is completely different to the hash code generated for the text “hello” or “ Hello”.
This is what makes hashing extremely useful in checking if data has been modified or damaged since it was either last saved or sent over the network. If, for example, you’re sending data to someone then by sending a hash code of the data along with the data itself the receiver can check the data's integrity by generating their own hash from the data and comparing it with the hash code that was sent. If the data has been modified, even by one byte, then the two hash codes won’t match and that means the data has been altered.
Here's another practical example of the process:
Bob sends Alice some data and Alice wants a means to check if the data has been modified. Bob creates a hash code of his data and sends both the data and the hash code to Alice. Alice then creates her own hash code from Bob’s data using the same hashing algorithm used by Bob and compares her hash code against Bob’s hash code. If there is a match then the data has not been modified.
Hash codes are a means to check that data was received/read as it was sent/written, any accidental damage/modification or malicious changes are checkable using hashes.
Some hashing algorithms include MD5, SHA1, and SHA256.
Example of using SHA1 hashing algorithm in .NET.
//sha1 hashes work with bytes, need to converts text to bytes
byte[] data = Encoding.Unicode.GetBytes(this.txtOriginal.Text);
//sha1 crypto service
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] result = sha.ComputeHash(data);
Message Authentication Codes (MAC); as a means to prevent man in the middle attacks and verify data integrity.
One of the problems with hashing is its wide open to man in the middle attacks. Without doubt hashing has its uses but in terms of sending data there is nothing stopping someone from intercepting the data, modifying it, and then resending the new message with a new hash. What the receiver gets is a message where the hash code matches the data, even though the data has been modified.
Message Authentication Codes are a way to prevent this. MACs use symmetric encryption methods to protect the sent hash. Symmetric encryption uses one private session key and both the sender and receiver require to have a copy of this key.
The process is as follows. Bob sends Alice some data. He generates a hash of the data and encrypts the hash using the symmetric key. Both the data and the encrypted hash are sent to Alice.
Alice, who also has the session key, generates her own hash from the data and encrypts it using the session key. She then checks her encrypted hash against the encrypted hash Bob sent. If they match the data is unchanged. Any man in the middle attacks no longer work as the middle man does not have the session key and therefore cannot generate a valid encrypted hash for the message.
Essentially a MAC is just an encrypted hash. It’s a combination of an encryption session key and a hashing algorithm.
Some example methods available in .NET include HMACMD5 a MAC algorithm based on MD5 hashing, and HMACSHA1 a MAC algorithm based on SHA1 hashing.
Example code for generating a random session key, this key is required to encrypt the hash code.
// Create a random key using a random number generator.
// This would be the secret key shared by sender and receiver.
byte[] secretkey = new Byte[64];
// RNGCryptoServiceProvider is an implementation of
// a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// The array is now filled with random bytes.
rng.GetBytes(secretkey);
Example code for generating a MAC using HMACMD5.
//hashes work with bytes, need to converts text to bytes
byte[] data = Encoding.Unicode.GetBytes(this.txtSend.Text);
// Initialize the keyed hash object.
HMACMD5 hmacMD5 = new HMACMD5(secretkey);
byte[] macSender = hmacMD5.ComputeHash(data);
Example code to check whether a MAC is valid for the data.
//hashes work with bytes, need to converts text to bytes
byte[] data = Encoding.Unicode.GetBytes(this.txtRecieved.Text);
// Initialize the keyed hash object.
HMACMD5 hmacMD5 = new HMACMD5(secretkey);
byte[] macReciever = hmacMD5.ComputeHash(data);
bool tampered = false;
// compare the computed hash with the stored value
for (int i = 0; i < macReciever.Length; i++)
{
if (macReciever[i] != macSender[i])
{
tampered = true;
break;
}
}
MessageBox.Show("Message has been tampered with: " + tampered);
Digital Signatures; as a means to verify the data source.
Digital signatures are an adaptation of MAC that provide the same advantages but with the added ability to verify the data’s source/sender. MACs only verify that the data never changed but they cannot be used to check that the data actually came from the person who claims to have sent it.
The only real difference in MAC and digital signatures is the key used to encrypt the hash. In MACs the key is a shared symmetric session key. In digital signature the keys used are public/private asymmetric keys.
Since the two keys of asymmetric encryption are mathematically related to each other one key can be used to verify that the encryption was done with the other key. With digital signatures the sender encrypts the hash using their private key while the receiver verifies the digital signature using the sender’s public key. Of course since the public key is more freely available then anyone can verify the message’s source.
So, for example, Bob wants to send Alice some data and Alice wants to be able to check the data was unchanged and came from Bob. Bob creates the hash and encrypts it into a digital signature using his private key. He sends the data and the digital signature over to Alice.
Alice uses Bob’s public key to verify that the digital signature was created using Bob’s corresponding private key. If everything checks out then Alice knows the message hasn’t been modified and that it came from Bob.
.NET provides DSA and XML Digital Signatures for creating digital signatures. XML Digital Signatures can be used to sign data in a variety of ways (enveloping, enveloped and detached) however I have not covered them here.
Example code of generating a digital signature:
First of all a hash is created from the data being sent.
byte[] data = Encoding.Unicode.GetBytes(this.txtSend.Text);
//sha1 crypto service, digital signatures are created from the hash
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(data);
This hash is then used to create the digital signature.
//Create a new instance of DSACryptoServiceProvider.
//DSA contains asymmetric public and private key information
DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
//TODO, load the sender private key into DSACryptoService here.
//Create an DSASignatureFormatter object and pass it the
//DSACryptoServiceProvider to transfer the key information.
DSASignatureFormatter DSAFormatter = new DSASignatureFormatter(DSA);
//Set the hash algorithm to SHA1.
DSAFormatter.SetHashAlgorithm("SHA1");
//Create a signature from the hash
byte[] signature = DSAFormatter.CreateSignature(hash);
Example code of verifying a digital signature:
The hash of the received message must be generated.
byte[] data = Encoding.Unicode.GetBytes(this.txtRecieved.Text);
//sha1 crypto service, digital signatures are created from the hash
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(data);
The hash is then used with the public key to verify the signature.
//Create an DSASignatureDeformatter object and pass it the
//DSACryptoServiceProvider to transfer the key information.
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(DSA);
//Create a new instance of DSACryptoServiceProvider.
//DSA contains asymmetric public and private key information
DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
//TODO, the sender public key into DSACryptoService here.
//get the signature sent with the message
byte[] signature = GetMessageDigitalSignature();
//Verify the hash and the signature
if (DSADeformatter.VerifySignature(hash, signature))
{
MessageBox.Show("The signature was verified.");
}
else
{
MessageBox.Show("The signature was not verified.");
}
Summary
Hashes on there own are a great way to determine if data has been modified either since it was last saved or sent. The data and hash are both sent/saved together. To verify the hash matches the data a new hash is created from the data and if the two hash values match then the data hasn’t changed.
Hashes on their own are open to man in the middle attacks where a malicious person intercepts the data modifies its meaning and generates a new hash for the modified message. Checking the hash will still result in verification even though the data has been changed.
MAC can be used to prevent this by encrypting the hash using a shared symmetric session key. Both parties using the data need to have the same session key for this to work. To check the MAC the sender sends the message along with a encrypted hash code, the receiver generates their own encrypted hash code for the message using the same session key. If both encrypted hashes are the same then the message is verified. This work well but to verify that the data is unchanged and came from the correct source digital signatures are used.
Digital signatures are like MACs but instead of the hash code being encrypted with a shared symmetric key a public/private asymmetric key is used instead. With digital signatures the hash code is signed by the private key and verified with the public key.
Downloads
Download the Source Code
Top Articles in this category
Microsoft's CardSpace: Part 1 – Getting started
This article is part one in a series of articles designed to get you up and running with Microsoft's CardSpace technology. This part deals with the setup of a high assurance certificate to give you an environment where a CardSpace application can be hosted. It assumes a basic knowledge of IIS and HTML.
Microsoft’s CardSpace: Part 3 – Using a Card
This article is the final part in a series of articles designed to get you up and running with Microsoft's CardSpace technology. This part deals with the consuming a card that we created and accessing the details contained within the card. It assumes a good working knowledge of C# and ASP.NET.
Microsoft's CardSpace: Part 2 - Creating and using your first identity card
This article is part two in a series of articles designed to get you up and running with Microsoft's CardSpace technology. This part deals with the setup of a simple application that enabled users to select and submit identity cards. It assumes a basic knowledge of IIS and HTML.
Protect Code with Skater .NET Obfuscator
Application vulnerabilities, Intellectual Property theft and revenue loss are among the most serious risks facing companies today. According to Business Software Alliance statistics, four out of every ten software programs are pirated in software business, worldwide.
An inside look at Symmetric Encryption
This article describes the internal workings of symmetric encryption; also known as secret key encryption. Concentrating mostly on the older DES encryption method this article doesn't contain any code examples and intends to cover the internals in a manner that isn't technology specific.
|
|
Please login to rate or to leave a comment.