Home / Cryptography / Hybrid Encryption with Integrity

Hybrid Encryption with Integrity

In this article, we will build on the previous hybrid encryption example by adding message integrity. This will mean that, once the encrypted data block has been created, you can check whether or not it has been tampered with or corrupted while in transit to its recipient. Before looking at this extra layer of integrity checking, it is important to go over byte array comparisons.

Comparing Byte Arrays

When dealing with byte arrays, it is common to want to check if one array is the same as another. Typically, you might have an implementation like the following.

private static bool CompareUnSecure(byte[] array1, byte[] array2)

{

if (array1.Length != array2.Length)

{

return false;

}

for (int i = 0; i array1.Length; ++i)

{

if (array1[i] != array2[i])

{

return false ;

}

}

return true;

}

In this example, the Compare method requires two byte arrays and returns true if they are equal and false otherwise. This works by first checking if the array lengths are the same. If they are not, the method returns false. It then goes through the first array and checks each element of the array against the second array. If it finds an element that is not equal, it will return false.

On its surface, this seems like a acceptable implementation and effective, too, as it will abort immediately after detecting that the arrays are different. However, when dealing with cryptographic processes, this isn’t such a good idea. The reason is a potential attacker can use this type of comparison as a vulnerability and perform what is called a side channel timing attack.

This is where an attacker can glean information from the method because it will execute with different timings based on the arrays being fed into it. Ideally, what you need is a Compare method that will execute in the same time no matter how equal (or not) the arrays are. A better implementation would be to use something like the following.

private static bool Compare(byte[] array1, byte[] array2)

{

var result = array1.Length == array2.Length;

for(var i = 0; i array1.Length i array2.Length; ++i)

{

result = array1[i] == array2[i];

}

return result;

}

This version of Compare has the exact same method signature as the previous example. First, there is a length equality check done against the length of the two byte arrays. This will set the result field to either True or False. Even if the result is False, the method will still continue to run. Next, the method will iterate through the arrays and check each element. If any element is not equal, then the result gets set to False and the method carries on checking. This means that no matter whether the arrays are equal or not, the method will take the same length of time to execute and, therefore, will not leak information to an attacker.

Adding Integrity to the Hybrid Encryption Example

The first thing you need to do to add integrity to the hybrid encryption example is add a new field to the EncryptedPacket class. This new field will be used to store an HMAC of the encrypted data.

 public class EncryptedPacket

{

public byte[] EncryptedSessionKey;

public byte[] EncryptedData;

public byte[] Iv;

public byte[] Hmac;

}

HMAC may be used to simultaneously verify both the data integrity and the authentication of a message by combining a one- way hash function with a secret cryptographic key.

With this in mind, our new EncryptData method looks like the following.

private static EncryptedPacket EncryptData(string originalText,

RSAWithRSAParameterKey rsaParams)

{

var aes = new AesEncryption();

var sessionKey = aes.GenerateRandomNumber(32);

var encryptedPacket = new EncryptedPacket {Iv =

aes.GenerateRandomNumber(16)};

// Encrypt data with AES and AES key with RSA.

encryptedPacket.EncryptedData =

aes.Encrypt(Encoding.UTF8.GetBytes(originalText), sessionKey, encryptedPacket.Iv);

encryptedPacket.EncryptedSessionKey =

rsaParams.EncryptData(sessionKey);

using (var hmac = new HMACSHA256(sessionKey))

{

encryptedPacket.Hmac =

hmac.ComputeHash(encryptedPacket.EncryptedData);

}

return encryptedPacket;

}

This version is the same as the previous version except for the HMAC calculated using the generated session key as input at the bottom of the method. The HMAC is calculated against the data that was encrypted with the session key. It`s very important to use the non-encrypted session key to calculate the HMAC since this will mean that no one can regenerate the HMAC without having first successfully decrypted the session key with the RSA private key.

Now that EncryptData has been changed to support the generation of an HMAC for the encrypted packet, the DecryptData method needs to be changed to check the HMAC. This can be demonstrated with the following code.

private static string DecryptData(EncryptedPacket encryptedPacket,

RSAWithRSAParameterKey rsaParams)

{

var aes = new AesEncryption();

// Decrypt AES key with RSA and then decrypt data with AES.

var decryptedSessionKey =

rsaParams.DecryptData(encryptedPacket.EncryptedSessionKey);

using (var hmac = new HMACSHA256(decryptedSessionKey))

{

var hmacToCheck = hmac.ComputeHash(encryptedPacket.EncryptedData);

if (!Compare(encryptedPacket.Hmac, hmacToCheck))

{

throw new CryptographicException(“HMAC for decryption does not match

encrypted packet.”);

}

}

var decryptedData = aes.Decrypt(encryptedPacket.EncryptedData,

decryptedSessionKey, encryptedPacket.Iv);

return Encoding.UTF8.GetString(decryptedData);

}

In this version of DecryptData, once the session key has been decrypted with the RSA private key, it is fed into the constructor of the HMACSHA256 object. Next, an HMAC of the encrypted data in the packet is calculated, and then this newly calculated HMAC is compared to the HMAC in the original data packet using our more secure, time-independent Compare function. If the hashes match, then the encrypted data is decrypted with the session key. If the hashes do not match, then a CryptographicException is thrown.

 

Check Also

digital signature

Digital Signature

An essential purpose of cryptography would be  to ensure nonrepudiation of a delivered message. This …

Leave a Reply

Your email address will not be published. Required fields are marked *