Home / Cryptography / Hybrid Encryption (RSA+AES)

Hybrid Encryption (RSA+AES)

With RSA you cannot encrypt data that is bigger than the length of the asymmetric key. If you want to encrypt a bigger block of information, what exactly would you do? Preferably, you’d wish to make use of symmetric encryption algorithm such as AES, but the issue you encounter is that of secure and reliable key trade. With AES, each recipient has to have the same key. This all seems easy in principle but how do you get that same key securely to each person? You can’t just easily send the key to them. So what you want to do is employ what is called a hybrid encryption system.

This is where you use a combination of both RSA and AES. Let’s assume we have two people involved: the sender, Nina, and the receiver, Tom. The process would look like the following for Nina sending data to Tom:

Encryption Using the Hybrid Approach

  1. Nina generates a 256-bit (32-byte) AES Key. This key is called a session key in this process.
  2. Nina generates a 128-bit (16-byte) IV.
  3. Nina encrypts the data with AES using the session key and the IV.
  4. Nina encrypts the session key with RSA and Tom’s public key.
  5. Nina stores the encrypted data, encrypted AES session key, and IV in a separate structure or file. This is the packet of data that is sent to Tom.

Decryption Using the Hybrid Approach

  1. Tom decrypts the encrypted AES session key by using RSA and Tom’s private key.
  2. Tom decrypts the encrypted data by using the decrypted AES session key and the IV.
  3. Tom reads the decrypted message.

Now, let’s look at the same process again but this time, Tom is sending a reply to Nina where Tom uses Nina’s public key and Nina uses her private key.

Encryption Using the Hybrid Approach

  1. Tom generates a 256-bit (32-byte) AES Key. This key is called a session key in this process.
  2. Tom generates a 128-bit (16-byte) IV.
  3. Tom encrypts the data with AES by using the session key and the IV.
  4. Tom encrypts the session key with RSA and Nina’s public key.
  5. Tom stores the encrypted data, encrypted AES session key, and IV in a separate structure or file. This is the packet of data that is sent to Nina.

Decryption Using the Hybrid Approach

  1. Nina decrypts the encrypted AES session key by using RSA and Nina’s private key.
  2. Nina decrypts the encrypted data by using decrypted AES session key and the IV.
  3. Nina reads the decrypted message.

Hybrid Encryption Implementation

We shall use AesEncryption class to demonstrate this hybrid encryption approach. In the AesEncryption class, there is a new method added called GenerateRandomNumber which will be used to generate our session key. For this example, we will use AES with a 256-bit (32-byte) key and we will use the algorithm in the default cipher block chaining mode with PKCS7 padding.

public class AesEncryption

{

public byte[] GenerateRandomNumber(int length)

{

using (var randomNumberGenerator = new RNGCryptoServiceProvider())

{

var randomNumber = new byte[length];

randomNumberGenerator.GetBytes(randomNumber);

return randomNumber;

}

}

public byte[] Encrypt(byte[] dataToEncrypt, byte[] key, byte[] iv)

{

using (var aes = new AesCryptoServiceProvider())

{

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

aes.Key = key;

aes.IV = iv;

using (var memoryStream = new MemoryStream())

{

var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(),

CryptoStreamMode.Write);

cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);

cryptoStream.FlushFinalBlock();

return memoryStream.ToArray();

}

}

}

public byte[] Decrypt(byte[] dataToDecrypt, byte[] key, byte[] IV)

{

using (var aes = new AesCryptoServiceProvider())

{

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

aes.Key = key;

aes.IV = IV;

using (var memoryStream = new MemoryStream())

{

var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(),

CryptoStreamMode.Write);

cryptoStream.Write(dataToDecrypt, 0, dataToDecrypt.Length);

cryptoStream.FlushFinalBlock();

var decryptBytes = memoryStream.ToArray();

return decryptBytes;

}

}

}

}

For the asymmetric encryption part of the hybrid encryption technique, we will use the same RSAWithRSAParameterKey class from our demonstration of RSA encryption. This class will store the generated RSA public and private keys as private members of the class for simplicity in this example. In a normal usage scenario, you would want to securely store your private key on a server or in a database.

public class RSAWithRSAParameterKey

{

private RSAParameters publicKey;

private RSAParameters privateKey;

public void AssignNewKey()

{

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

publicKey = rsa.ExportParameters(false);

privateKey = rsa.ExportParameters(true);

}

}

public byte[] EncryptData(byte[] dataToEncrypt)

{

byte[] cipherbytes;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false

rsa.ImportParameters(publicKey);

cipherbytes = rsa.Encrypt(dataToEncrypt, false);

}

return cipherbytes;

}

public byte[] DecryptData(byte[] dataToEncrypt)

{

byte[] plain;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

rsa.ImportParameters(privateKey);

plain = rsa.Decrypt(dataToEncrypt, false);

}

return plain;

}

}

First of all, we need a class to store our encrypted data packet. There are three parts to the packet that you will have once you have done the encryption. They are:

  • Encrypted Session Key: This is the 256-bit AES session key that is generated and then encrypted with the RSA private key.
  • Encrypted Data: This is our actual data that has been encrypted with the AES 256-bit session key.
  • Initialization Vector (IV): This is the 128-bit (16-byte) IV that is passed into the AES encryption algorithm. This does not need to be kept secret and can be stored inside our data packet.
public	class	EncryptedPacket { 

public	byte[]	EncryptedSessionKey; 

public	byte[]	EncryptedData; 

public	byte[]	Iv; 
}

The encryption process is very simple as shown in the following code example. The EncryptData method takes a string which, in this case, is our data to encrypt and the RSAWithRSAParameterKey object which contains our RSA keys.

This method first creates an instance of the AesEncryption object and generates the 256-bit (32-byte) session key. Then, the 128-bit (16-byte) IV is generated and stored in the encrypted packet object. Next, the data we want to be encrypted is encrypted with AES by using the generated session key and IV. The result is also saved in the encrypted packet object. Lastly, the generated AES session key is encrypted with the RSA public key. This encrypted session key is then saved in the encrypted packet.

This means our data is now encrypted using AES, but the key is protected using the RSA key pair.

public byte[] Encrypt(byte[] dataToEncrypt, byte[] key, byte[] iv)

{

using (var aes = new AesCryptoServiceProvider())

{

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

aes.Key = key;

aes.IV = iv;

using (var memoryStream = new MemoryStream())

{

var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(),

CryptoStreamMode.Write);

cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);

cryptoStream.FlushFinalBlock();

return memoryStream.ToArray();

}

}

}

The decryption process is just as simple. There is a method called DecryptData that takes the encrypted packet and the RSA encryption object that contains our public and private encryption keys. First, the encrypted AES session key is decrypted using the RSAWithRSAParameterKey object. This decrypts using the private key. Once the session key has been decrypted, the encrypted data is then decrypted with AES by using the session key and initialization vector. Then, the decrypted data is turned back into a string and returned to the caller.

public byte[] Decrypt(byte[] dataToDecrypt, byte[] key, byte[] IV)

{

using (var aes = new AesCryptoServiceProvider())

{

aes.Mode = CipherMode.CBC;

aes.Padding = PaddingMode.PKCS7;

aes.Key = key;

aes.IV = IV;

using (var memoryStream = new MemoryStream())

{

var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(),

CryptoStreamMode.Write);

cryptoStream.Write(dataToDecrypt, 0, dataToDecrypt.Length);

cryptoStream.FlushFinalBlock();

var decryptBytes = memoryStream.ToArray();

return decryptBytes;

}

}

}

This example shows how to get the best of both RSA and AES: You get the benefits of RSA’s asymmetric keys (which makes key exchange much easier) and you then get the benefit of AES for securely encrypting your data with the RSA- protected session key.

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 *