How to

encrypt/decrypt using symmetric algorithm

Published: 2. February 2012 | Updated: 2. February 2012
License: Microsoft Public License (MS-PL)
Categories: Security » Encryption
Tags: C# Security
Was this snippet helpful for you? YESYES / NONO

Class for encrypting, decrypting bytes, text or files using symmetric algorithms. Also enables generate salt and initialization vector (IV).

Import namespaces

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

Class

Methods uses optional parameters introduced in C# 4.0. For older C# versions just change "int? keySize = null" to "int? keySize" and "int passwordIterations = 1000" to " int passwordIterations".
public static class SymmetricEncryption
{
    private static readonly Random Random = new Random();

    public static byte[] GenerateSalt()
    {
        var salt = new byte[16];
        Random.NextBytes(salt);
        return salt;
    }

    public static byte[] GenerateInitializationVector(SymmetricAlgorithm algorithm)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");

        int size = algorithm.LegalBlockSizes[0].MinSize / 8;
        var iv = new byte[size];
        Random.NextBytes(iv);
        return iv;
    }

    public static void EncryptFile(SymmetricAlgorithm algorithm, string filePath, string password, string salt, string iv, int? keySize = null, int passwordIterations = 1000)
    {
        EncryptFile(algorithm, filePath, Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), Encoding.UTF8.GetBytes(iv), keySize, passwordIterations);
    }

    public static void EncryptFile(SymmetricAlgorithm algorithm, string filePath, byte[] password, byte[] salt, byte[] iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (String.IsNullOrEmpty(filePath)) throw new ArgumentException("File path is null or empty", "filePath");
        if (!File.Exists(filePath)) throw new FileNotFoundException("File does not exist", filePath);
        if (password == null || password.Length == 0) throw new ArgumentException("Password is empty", "password");
        if (salt == null || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (iv == null || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");

        var fileBytes = File.ReadAllBytes(filePath);
        var encryptedBytes = EncryptBytes(algorithm, fileBytes, password, salt, iv, keySize, passwordIterations);

        File.WriteAllBytes(filePath, encryptedBytes);
    }

    public static string EncryptText(SymmetricAlgorithm algorithm, string text, string password, string salt, string iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (String.IsNullOrEmpty(text)) throw new ArgumentException("Text is null or empty", "text");
        if (String.IsNullOrEmpty(password)) throw new ArgumentException("Password is null or empty", "password");
        if (String.IsNullOrEmpty(salt) || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (String.IsNullOrEmpty(iv) || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");

        var encryptedBytes = EncryptBytes(algorithm, Encoding.UTF8.GetBytes(text), Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), Encoding.UTF8.GetBytes(iv), keySize, passwordIterations);
        return Convert.ToBase64String(encryptedBytes);
    }

    public static byte[] EncryptBytes(SymmetricAlgorithm algorithm, byte[] data, byte[] password, byte[] salt, byte[] iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
        if (password == null || password.Length == 0) throw new ArgumentException("Password is empty", "password");
        if (salt == null || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (iv == null || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");
        if (keySize == null) keySize = algorithm.LegalKeySizes[0].MaxSize;

        byte[] keyBytes;
        using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, passwordIterations))
        {
            keyBytes = rfc2898DeriveBytes.GetBytes(keySize.Value / 8);
        }

        byte[] encrypted;
        using (var encryptor = algorithm.CreateEncryptor(keyBytes, iv))
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(data, 0, data.Length);
                    cryptoStream.FlushFinalBlock();

                    encrypted = memoryStream.ToArray();

                    memoryStream.Close();
                    cryptoStream.Close();
                }
            }
        }

        return encrypted;
    }

    public static void DecryptFile(SymmetricAlgorithm algorithm, string filePath, string password, string salt, string iv, int? keySize = null, int passwordIterations = 1000)
    {
        DecryptFile(algorithm, filePath, Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), Encoding.UTF8.GetBytes(iv), keySize, passwordIterations);
    }

    public static void DecryptFile(SymmetricAlgorithm algorithm, string filePath, byte[] password, byte[] salt, byte[] iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (String.IsNullOrEmpty(filePath)) throw new ArgumentException("File path is null or empty", "filePath");
        if (!File.Exists(filePath)) throw new FileNotFoundException("File does not exist", filePath);
        if (password == null || password.Length == 0) throw new ArgumentException("Password is empty", "password");
        if (salt == null || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (iv == null || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");

        var fileBytes = File.ReadAllBytes(filePath);
        var decryptedBytes = DecryptBytes(algorithm, fileBytes, password, salt, iv, keySize, passwordIterations);

        File.WriteAllBytes(filePath, decryptedBytes);
    }

    public static string DecryptText(SymmetricAlgorithm algorithm, string encryptedText, string password, string salt, string iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (String.IsNullOrEmpty(encryptedText)) throw new ArgumentException("Encrypted text are empty", "encryptedText");
        if (String.IsNullOrEmpty(password)) throw new ArgumentException("Password is null or empty", "password");
        if (String.IsNullOrEmpty(salt) || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (String.IsNullOrEmpty(iv) || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");

        var decrypted = DecryptBytes(algorithm, Convert.FromBase64String(encryptedText), Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), Encoding.UTF8.GetBytes(iv), keySize, passwordIterations);
        return Encoding.UTF8.GetString(decrypted);
    }

    public static byte[] DecryptBytes(SymmetricAlgorithm algorithm, byte[] encryptedData, byte[] password, byte[] salt, byte[] iv, int? keySize = null, int passwordIterations = 1000)
    {
        if (algorithm == null) throw new ArgumentNullException("algorithm");
        if (encryptedData == null || encryptedData.Length == 0) throw new ArgumentException("Encrypted data is null or empty", "encryptedData");
        if (password == null || password.Length == 0) throw new ArgumentException("Password is null or empty", "password");
        if (salt == null || salt.Length < 8) throw new ArgumentException("Salt is not at least eight bytes", "salt");
        if (iv == null || iv.Length < (algorithm.LegalBlockSizes[0].MinSize / 8)) throw new ArgumentException("Specified initialization vector (IV) does not match the block size for this algorithm", "iv");
        if (keySize == null) keySize = algorithm.LegalKeySizes[0].MaxSize;

        byte[] keyBytes;
        using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, passwordIterations))
        {
            keyBytes = rfc2898DeriveBytes.GetBytes(keySize.Value / 8);
        }

        byte[] plainTextBytes;
        int decryptedBytesCount;
        using (var decryptor = algorithm.CreateDecryptor(keyBytes, iv))
        {
            using (var memoryStream = new MemoryStream(encryptedData))
            {
                using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    plainTextBytes = new byte[encryptedData.Length];
                    decryptedBytesCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

                    memoryStream.Close();
                    cryptoStream.Close();
                }
            }
        }

        return plainTextBytes.Take(decryptedBytesCount).ToArray();
    }
}

Use

// encrypting/decrypting text
string text = "text for encryption";
string password = "my secret password";
string salt = "w9=z4]0h"; // at least 8 chars long
string iv = "fd98w7z3yupz0q41"; // have to match the algorithm block size - for all cases can be 16 chars

using (var aes = Aes.Create())
{
    string encrypted = SymmetricEncryption.EncryptText(aes, text, password, salt, iv);
    string decrypted = SymmetricEncryption.DecryptText(aes, encrypted, password, salt, iv);
    Console.WriteLine("Aes encrypted: {0}", encrypted);
    Console.WriteLine("Aes decrypted: {0}", decrypted);
}

Console.WriteLine();

using (var des = DES.Create())
{
    string encrypted = SymmetricEncryption.EncryptText(des, text, password, salt, iv);
    string decrypted = SymmetricEncryption.DecryptText(des, encrypted, password, salt, iv);
    Console.WriteLine("DES encrypted: {0}", encrypted);
    Console.WriteLine("DES decrypted: {0}", decrypted);
}

Console.WriteLine();

using (var rc2 = RC2.Create())
{
    string encrypted = SymmetricEncryption.EncryptText(rc2, text, password, salt, iv);
    string decrypted = SymmetricEncryption.DecryptText(rc2, encrypted, password, salt, iv);
    Console.WriteLine("RC2 encrypted: {0}", encrypted);
    Console.WriteLine("RC2 decrypted: {0}", decrypted);
}

Console.WriteLine();

using (var rijndael = Rijndael.Create())
{
    string encrypted = SymmetricEncryption.EncryptText(rijndael, text, password, salt, iv);
    string decrypted = SymmetricEncryption.DecryptText(rijndael, encrypted, password, salt, iv);
    Console.WriteLine("Rijndael encrypted: {0}", encrypted);
    Console.WriteLine("Rijndael decrypted: {0}", decrypted);
}

Console.WriteLine();

using (var tripleDES = TripleDES.Create())
{
    string encrypted = SymmetricEncryption.EncryptText(tripleDES, text, password, salt, iv);
    string decrypted = SymmetricEncryption.DecryptText(tripleDES, encrypted, password, salt, iv);
    Console.WriteLine("Triple DES encrypted: {0}", encrypted);
    Console.WriteLine("Triple DES decrypted: {0}", decrypted);
}


// encrypting/descrypting files
using (var rijndael = Rijndael.Create())
{
    string path = @"C:\Folder\file.jpg";
    SymmetricEncryption.EncryptFile(rijndael, path, password, salt, iv);
    SymmetricEncryption.DecryptFile(rijndael, path, password, salt, iv);
}
Console Output:
Aes encrypted: 9NIvW9WVC6QE6IYy9Q3HbxxzLc/HiIAni9okcDdsGK8=
Aes decrypted: text for encryption

DES encrypted: gUvAyi47xdNcRt0HGnO8/nqvORBfoLBp
DES decrypted: text for encryption

RC2 encrypted: SW4B1k7Cl5YCEoviM0Lo36VQcDCH9Avh
RC2 decrypted: text for encryption

Rijndael encrypted: 9NIvW9WVC6QE6IYy9Q3HbxxzLc/HiIAni9okcDdsGK8=
Rijndael decrypted: text for encryption

Triple DES encrypted: T009J1U672i53oPsP/a0nT7XmXyptdLr
Triple DES decrypted: text for encryption
Send us feedback about this snippet »



Related Snippets: