Encrypt and decrypt a string in C#?
Categories:
Securely Encrypt and Decrypt Strings in C#

Learn how to implement robust symmetric encryption and decryption for strings in C# using AES, ensuring data confidentiality and integrity.
In today's data-driven world, protecting sensitive information is paramount. When working with C# applications, you often encounter scenarios where you need to encrypt and decrypt strings, such as user passwords, configuration settings, or confidential messages. This article provides a comprehensive guide to implementing symmetric encryption using the Advanced Encryption Standard (AES) algorithm, a widely adopted and secure method for data protection.
Understanding Symmetric Encryption with AES
Symmetric encryption uses a single secret key for both encryption and decryption. AES is a block cipher, meaning it encrypts data in fixed-size blocks. To ensure security, it's crucial to use a strong, randomly generated key and an Initialization Vector (IV). The IV is a random number used along with the key to encrypt the first block of data, making each encryption unique even if the same plaintext is encrypted multiple times with the same key. This prevents attackers from identifying patterns.
flowchart TD A[Plaintext String] --> B{Generate Key & IV} B --> C[Encrypt with AES (Key, IV)] C --> D[Ciphertext (Base64 Encoded)] D --> E{Store/Transmit Securely} E --> F[Retrieve Ciphertext] F --> G{Use Same Key & IV} G --> H[Decrypt with AES (Key, IV)] H --> I[Original Plaintext String]
Symmetric Encryption and Decryption Process Flow
Implementing AES Encryption and Decryption in C#
C# provides robust cryptographic capabilities through the System.Security.Cryptography
namespace. We'll leverage the AesManaged
class (or Aes
in newer .NET versions) to perform our encryption and decryption operations. The key and IV should be securely stored and managed, never hardcoded directly into your application in a production environment. For demonstration purposes, we'll generate them dynamically.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static class EncryptionHelper
{
private static readonly int KeySize = 256; // AES-256
private static readonly int BlockSize = 128; // AES block size
// Generates a random AES key
public static byte[] GenerateRandomKey()
{
using (var aes = Aes.Create())
{
aes.KeySize = KeySize;
aes.GenerateKey();
return aes.Key;
}
}
// Generates a random Initialization Vector (IV)
public static byte[] GenerateRandomIV()
{
using (var aes = Aes.Create())
{
aes.BlockSize = BlockSize;
aes.GenerateIV();
return aes.IV;
}
}
public static string EncryptString(string plainText, byte[] key, byte[] iv)
{
if (string.IsNullOrEmpty(plainText))
throw new ArgumentNullException(nameof(plainText));
if (key == null || key.Length == 0)
throw new ArgumentNullException(nameof(key));
if (iv == null || iv.Length == 0)
throw new ArgumentNullException(nameof(iv));
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = iv;
aesAlg.Mode = CipherMode.CBC; // Cipher Block Chaining
aesAlg.Padding = PaddingMode.PKCS7;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Combine IV and encrypted bytes for easier storage/transmission
byte[] result = new byte[iv.Length + encrypted.Length];
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
Buffer.BlockCopy(encrypted, 0, result, iv.Length, encrypted.Length);
return Convert.ToBase64String(result);
}
public static string DecryptString(string cipherText, byte[] key)
{
if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException(nameof(cipherText));
if (key == null || key.Length == 0)
throw new ArgumentNullException(nameof(key));
byte[] fullCipher = Convert.FromBase64String(cipherText);
// Extract IV from the beginning of the fullCipher byte array
byte[] iv = new byte[BlockSize / 8]; // IV size is BlockSize in bits / 8 bits per byte
Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
// Extract encrypted bytes
byte[] encryptedBytes = new byte[fullCipher.Length - iv.Length];
Buffer.BlockCopy(fullCipher, iv.Length, encryptedBytes, 0, encryptedBytes.Length);
string plaintext = null;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = iv;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(encryptedBytes))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
C# EncryptionHelper class for AES-256
Putting It All Together: Example Usage
Here's how you can use the EncryptionHelper
class to encrypt and decrypt a string. Notice how the IV is prepended to the ciphertext before Base64 encoding, allowing the decryption method to retrieve it.
using System;
public class Program
{
public static void Main(string[] args)
{
string originalText = "This is a secret message that needs to be protected.";
Console.WriteLine($"Original Text: {originalText}");
// Generate a new key and IV for each encryption (or manage securely)
byte[] key = EncryptionHelper.GenerateRandomKey();
byte[] iv = EncryptionHelper.GenerateRandomIV(); // IV is generated per encryption
// Encrypt the string
string encryptedText = EncryptionHelper.EncryptString(originalText, key, iv);
Console.WriteLine($"Encrypted Text (Base64): {encryptedText}");
// Decrypt the string using the same key and the IV extracted from the ciphertext
string decryptedText = EncryptionHelper.DecryptString(encryptedText, key);
Console.WriteLine($"Decrypted Text: {decryptedText}");
// Verify if decryption was successful
if (originalText == decryptedText)
{
Console.WriteLine("Encryption and decryption successful!");
}
else
{
Console.WriteLine("Error: Decrypted text does not match original.");
}
// Example of incorrect key/IV usage (will fail)
Console.WriteLine("\n--- Demonstrating incorrect key/IV usage ---");
byte[] wrongKey = EncryptionHelper.GenerateRandomKey(); // A different key
try
{
string failedDecryption = EncryptionHelper.DecryptString(encryptedText, wrongKey);
Console.WriteLine($"Decrypted with wrong key: {failedDecryption}");
}
catch (CryptographicException ex)
{
Console.WriteLine($"Decryption failed with wrong key: {ex.Message}");
}
}
}
Example usage of the EncryptionHelper class
CryptographicException
or corrupted data. The IV, however, does not need to be secret but must be unique for each encryption and available during decryption.