Compilation of different programming
projects I amuse myself with.
Sunday, 31 December 2023
AES Encryption with Galois Counter Mode (GCM) in C#
This article presents some helper methods for performing AES Encryption using Galois Counter Mode (GCM). AES or Advanced Encryption Standard is the most used encryption algorithm used today, having overtaken DES and Triple DES
since 2001. We will look into the GCM mode of AES in this article.
AES-GCM class AesGcm is supported in .NET Core 3.0 and newer .NET versions, plus in .NET Standard 2.1.
AES-GCM is authenticated encryption, compared to default AES-CBC (Cipher Block Chaining).
Benefits of using GCM mode of AES is the following:
Data authenticity / integrity. This is provided via a tag that is outputted by the encryption and used while decrypting
Provides support for sending additional data, used for example in newer TLS implementations to provide both encryption and a non-encrypted payload. This is called additional metadata
Here is a helper class to perform encryption and decryption using AES-GCM.
publicstaticclassAesGcmEncryption {
publicstatic (byte[], byte[]) Encrypt(byte[] dataToEncrypt, byte[] key, byte[] nonce, byte[] associatedData = null)
{
usingvar aesGcm = new AesGcm(key);
//tag and ciphertext will be filled during encryptionvar tag = newbyte[16]; //tag is a hmac (hash-based message authentication code) to check that information has not been tampered withvar cipherText = newbyte[dataToEncrypt.Length];
aesGcm.Encrypt(nonce, dataToEncrypt, cipherText, tag, associatedData);
return (cipherText, tag);
}
publicstaticbyte[] Decrypt(byte[] cipherText, byte[] key, byte[] nonce, byte[] tag, byte[] associatedData = null)
{
usingvar aesGcm = new AesGcm(key);
//tag and ciphertext will be filled during encryptionvar decryptedData = newbyte[cipherText.Length];
aesGcm.Decrypt(nonce, cipherText, tag, decryptedData, associatedData);
return decryptedData;
}
}
In the code above, the encrypt method returns a tuple with the ciperText and the tag. These are the encrypted data and the tag, both must be used while decrypting and the tag provides as mentioned a means of checking the integrity of data, i.e. that data has not been tampered with.
Note that the 16-byte tag and the ciphertext is filled after running the Encrypt method of the AesGcm class. The cipherText array must be the same length as the dataToEncrypt array inputted.
Here is sample code to use AES-GCM. Note that the metadata used here, while optional, must match in case it is set in the encryption and decryption. The nonce must be 12 bytes - 96 bits in length.The nonce is similar to a initialization vector, although it is used once for the particular encryption and decryption,
it is used to protect against replay attacks.
AES Encryption demo GCM - Galois Counter Mode:
--------------
Original Text = Text to encrypt
Encrypted Text = 9+2x0kctnRwiDDHBm0/H
Tag = sSDxsg17HFdjE4cuqRlroQ==
Decrypted Text = Text to encrypt
Use AES-GCM to provide integrity checking and allowing to send in metadata if desired to encrypt and decrypting with the AES algorithm.
We can protect the AES key using different methods, for example using the Data Protection API, this is only supported in Windows.
Let's look at a helper class for using Data Protection API.
voidEncryptAndDecryptWithProtectedKey(){
var original = "Text to encrypt";
Console.WriteLine($"Original Text = {original}");
//Create key and nnoce . Encrypt our text with AES var gcmKey = RandomNumberGenerator.GetBytes(32);
var nonce = RandomNumberGenerator.GetBytes(12);
var result = EncryptText(original, gcmKey, nonce);
//Create some entropy and protect AES keyvar entropy = RandomNumberGenerator.GetBytes(16);
var protectedKey = ProtectedData.Protect(gcmKey, entropy, DataProtectionScope.CurrentUser);
Console.WriteLine($"gcmKey = {Convert.ToBase64String(gcmKey)}, protectedKey = {Convert.ToBase64String(protectedKey)}");
// Decrypt the text with AES. the AES key has to be retrieved with DPAPI.var decryptedText = DecryptText(result.encrypted, nonce, result.tag, protectedKey, entropy);
Console.WriteLine($"Decrypted Text using AES GCM with key retrieved via Data Protection API = {decryptedText}");
}
privatestatic (byte[] encrypted, byte[] tag) EncryptText(string original, byte[] gcmKey, byte[] nonce){
return AesGcmEncryption.Encrypt(Encoding.UTF8.GetBytes(original), gcmKey, nonce, Encoding.UTF8.GetBytes("some meta"));
}
privatestaticstringDecryptText(byte[] encrypted, byte[] nonce, byte[] tag, byte[] protectedKey, byte[] entropy){
var key = DataProtectionUtil.Unprotect(protectedKey, entropy, DataProtectionScope.CurrentUser);
Console.WriteLine($"Inside DecryptText: gcmKey = {Convert.ToBase64String(key)}, protectedKey = {Convert.ToBase64String(protectedKey)}");
var decryptedText = AesGcmEncryption.Decrypt(encrypted, key, nonce, tag, Encoding.UTF8.GetBytes("some meta"));
return Encoding.UTF8.GetString(decryptedText);
}
Data Protection API is only supported on Windows platform, there are more possibilities to protect AES key but protecting your key is always a challenge when dealing with symmetric encryption algorithms such as AES.
Some more links:
No comments:
Post a Comment