C# AES 256 bits Encryption Library with Salt

Begin by adding the following using statements to import the encryption library:

using System.Security.Cryptography;
using System.IO;

Encryption

public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
    byte[] encryptedBytes = null;

    // Set your salt here, change it to meet your flavor:
    // The salt bytes must be at least 8 bytes.
    byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    using (MemoryStream ms = new MemoryStream())
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;

            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);

            AES.Mode = CipherMode.CBC;

            using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                cs.Close();
            }
            encryptedBytes = ms.ToArray();
        }
    }

    return encryptedBytes;
}

Decryption

public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
    byte[] decryptedBytes = null;

    // Set your salt here, change it to meet your flavor:
    // The salt bytes must be at least 8 bytes.
    byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    using (MemoryStream ms = new MemoryStream())
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;

            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);

            AES.Mode = CipherMode.CBC;

            using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                cs.Close();
            }
            decryptedBytes = ms.ToArray();
        }
    }

    return decryptedBytes;
}

Example of Encrypting String

You’ll notice that the encrypted string is stored in base64 encoded mode. For those who is not familiar with base64 encoding, you may want to read:

Encrypt String

public string EncryptText(string input, string password)
{
    // Get the bytes of the string
    byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

    // Hash the password with SHA256
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

    string result = Convert.ToBase64String(bytesEncrypted);

    return result;
}

Decrypt String

public string DecryptText(string input, string password)
{
    // Get the bytes of the string
    byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

    string result = Encoding.UTF8.GetString(bytesDecrypted);

    return result;
}

Example of Encrypting File

Encrypt File

public void EncryptFile()
{
    string file = "C:\\SampleFile.DLL";
    string password = "abcd1234";

    byte[] bytesToBeEncrypted = File.ReadAllBytes(file);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

    // Hash the password with SHA256
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

    string fileEncrypted = "C:\\SampleFileEncrypted.DLL";

    File.WriteAllBytes(fileEncrypted, bytesEncrypted);
}

Decrypt File

public void DecryptFile()
{
    string fileEncrypted = "C:\\SampleFileEncrypted.DLL";
    string password = "abcd1234";

    byte[] bytesToBeDecrypted = File.ReadAllBytes(fileEncrypted);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

    string file = "C:\\SampleFile.DLL";
    File.WriteAllBytes(file, bytesDecrypted);
}

Getting Randomized Encryption Result with Salt

If we encrypt the same context (i.e. string of “Hello World”) for 10 times, the encrypted results will be the same. What if we want the results different from each time it is encrypted?

What you can do is by appending a random salt bytes in front of the original bytes before encryption, and remove it after decryption.

Example of Appending Randomized Salt Before Encrypting a String

public static string EncryptString(string text, string password)
{
    byte[] baPwd = Encoding.UTF8.GetBytes(password);

    // Hash the password with SHA256
    byte[] baPwdHash = SHA256Managed.Create().ComputeHash(baPwd);

    byte[] baText = Encoding.UTF8.GetBytes(text);

    byte[] baSalt = GetRandomBytes();
    byte[] baEncrypted = new byte[baSalt.Length + baText.Length];

    // Combine Salt + Text
    for (int i = 0; i < baSalt.Length; i++)
        baEncrypted[i] = baSalt[i];
    for (int i = 0; i < baText.Length; i++)
        baEncrypted[i + baSalt.Length] = baText[i];

    baEncrypted = AES_Encrypt(baEncrypted, baPwdHash);

    string result = Convert.ToBase64String(baEncrypted);
    return result;
}

Example of Removing the Salt after Decryption

public static string DecryptString(string text, string password)
{
    byte[] baPwd = Encoding.UTF8.GetBytes(password);

    // Hash the password with SHA256
    byte[] baPwdHash = SHA256Managed.Create().ComputeHash(baPwd);

    byte[] baText = Convert.FromBase64String(text);

    byte[] baDecrypted = AES_Decrypt(baText, baPwdHash);

    // Remove salt
    int saltLength = GetSaltLength();
    byte[] baResult = new byte[baDecrypted.Length - saltLength];
    for (int i = 0; i < baResult.Length; i++)
        baResult[i] = baDecrypted[i + saltLength];

    string result = Encoding.UTF8.GetString(baResult);
    return result;
}

Code for getting random bytes

public static byte[] GetRandomBytes()
{
    int saltLength = GetSaltLength();
    byte[] ba = new byte[saltLength];
    RNGCryptoServiceProvider.Create().GetBytes(ba);
    return ba;
}

public static int GetSaltLength()
{
    return 8;
}

Another way of getting random bytes is by using System.Random. However, System.Random is strongly not recommended to be used in cryptography. This is because System.Random is not a true random. The changes of the value are following a specific sequence and pattern and it is predictable. RNGCrypto is truly randomize and the generated values does not follow a pattern and it is unpredictable.