In this tutorial, we will explore how to encrypt and decrypt strings in C# using the Advanced Encryption Standard (AES) algorithm. AES is a widely used symmetric-key block cipher that provides secure encryption and decryption of data.
Introduction to AES
The Advanced Encryption Standard (AES) is a specification for the encryption of electronic data established by the National Institute of Standards and Technology (NIST). It is a symmetric-key block cipher, which means that it uses the same key for both encryption and decryption. AES is widely used due to its high security, efficiency, and flexibility.
Key Concepts
Before we dive into the code, let’s cover some essential concepts:
- Symmetric-key: Both the sender and receiver use the same secret key for encryption and decryption.
- Block cipher: Data is divided into fixed-length blocks, and each block is encrypted independently.
- Key derivation: A process that generates a cryptographic key from a password or passphrase.
Encrypting Strings with AES
To encrypt a string using AES, we need to follow these steps:
- Generate a key from a password or passphrase using a key derivation function (KDF).
- Create an instance of the
RijndaelManaged
class, which is a .NET implementation of AES. - Set the key and initialization vector (IV) for the encryption process.
- Convert the string to be encrypted into a byte array.
- Encrypt the byte array using the
CryptoStream
class.
Here’s an example code snippet that demonstrates how to encrypt a string:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static string EncryptStringAES(string plainText, string sharedSecret)
{
if (string.IsNullOrEmpty(plainText))
throw new ArgumentNullException("plainText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");
// Generate the key from the shared secret and a salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
// Create a RijndaelManaged object
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
// Prepend the IV
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
// Write all data to the stream.
swEncrypt.Write(plainText);
}
}
return Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
Decrypting Strings with AES
To decrypt a string that was encrypted using AES, we need to follow these steps:
- Generate a key from a password or passphrase using the same KDF used for encryption.
- Create an instance of the
RijndaelManaged
class. - Set the key and IV for the decryption process.
- Convert the encrypted string into a byte array.
- Decrypt the byte array using the
CryptoStream
class.
Here’s an example code snippet that demonstrates how to decrypt a string:
public static string DecryptStringAES(string cipherText, string sharedSecret)
{
if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException("cipherText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");
// Generate the key from the shared secret and a salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
// Create a RijndaelManaged object
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
// Get the initialization vector from the encrypted stream
byte[] bytes = Convert.FromBase64String(cipherText);
using (MemoryStream msDecrypt = new MemoryStream(bytes))
{
int ivLength = BitConverter.ToInt32(msDecrypt.ToArray(), 0);
byte[] iv = new byte[ivLength];
msDecrypt.Read(iv, 0, iv.Length);
aesAlg.IV = iv;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
}
Best Practices and Security Considerations
When using AES for encryption and decryption, keep the following best practices and security considerations in mind:
- Use a secure password or passphrase to generate the key.
- Use a salt value to prevent rainbow table attacks.
- Use a sufficient work factor when generating the key to slow down the key derivation process.
- Store the encrypted data securely, such as using a secure database or file system.
- Limit access to the encryption and decryption keys.
By following these best practices and security considerations, you can ensure that your AES encryption and decryption implementation is secure and reliable.