Encrypt and decrypt a string in C#?

Learn encrypt and decrypt a string in c#? with practical examples, diagrams, and best practices. Covers c#, .net, encryption development techniques with visual explanations.

Securely Encrypt and Decrypt Strings in C#

Hero image for Encrypt and decrypt a string 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