Click here to Skip to main content
Click here to Skip to main content

C# AES 256 bits Encryption Library with Salt

, 9 May 2014 Public Domain
Rate this:
Please Sign up or sign in to vote.
A C# universal AES Encryption Library.

Core Encryption Code

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

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;
}

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 Base What? A Practical Introduction to Base Encoding[^]

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 I do is 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 string Encrypt(string text, string pwd)
{
    byte[] originalBytes = Encoding.UTF8.GetBytes(text);
    byte[] encryptedBytes = null;
    byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);

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

    // Generating salt bytes
    byte[] saltBytes = GetRandomBytes();

    // Appending salt bytes to original bytes
    byte[] bytesToBeEncrypted = new byte[saltBytes.Length + originalBytes.Length];
    for (int i = 0; i < saltBytes.Length; i++)
    {
        bytesToBeEncrypted[i] = saltBytes[i];
    }
    for (int i = 0; i < originalBytes.Length; i++)
    {
        bytesToBeEncrypted[i + saltBytes.Length] = originalBytes[i];
    }

    encryptedBytes = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

    return Convert.ToBase64String(encryptedBytes);
}
Example of Removing the Salt after Decryption
public string Decrypt(string decryptedText, string pwd)
{
    byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);

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

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

    // Getting the size of salt
    int _saltSize = 4;

    // Removing salt bytes, retrieving original bytes
    byte[] originalBytes = new byte[decryptedBytes.Length - _saltSize];
    for (int i = _saltSize; i < decryptedBytes.Length; i++)
    {
        originalBytes[i - _saltSize] = decryptedBytes[i];
    }

    return Encoding.UTF8.GetString(originalBytes);
}
Code for getting random bytes
public byte[] GetRandomBytes()
{
    int _saltSize = 4;
    byte[] ba = new byte[_saltSize];
    RNGCryptoServiceProvider.Create().GetBytes(ba);
    return ba;
}

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.

About Storing Password in System.String

If you are working this on a desktop pc application, you are recommended not to store the password in plain string. Strings cannot be manually disposed. It will be disposed by Garbage Collector, however, it is hard to tell how long will the string continue to stay in memory before it is completely dispose. At the time it remains in memory, it is easily retrievable. One of the suggested method is by capturing the password key strokes and store it into byte array (or list of bytes) and wipe off the byte array immediately after it is used (for example, fill the byte array with 0 (zero), etc).

Another option is by using System.Security.SecureString. System.Security.SecureString can be destroyed manually at any time. The value stored within System.Security.SecureString is encrypted.

Example of Using SecureString

using System.Security;
using System.Runtime.InteropServices; 

Storing text into SecureString:

SecureString secureString = new SecureString();
secureString.AppendChar('h');
secureString.AppendChar('e');
secureString.AppendChar('l');
secureString.AppendChar('l');
secureString.AppendChar('o'); 

Retrieving data from SecureString

byte[] secureStringBytes = null;
// Convert System.SecureString to Pointer
IntPtr unmanagedBytes = Marshal.SecureStringToGlobalAllocAnsi(secureString);
try
{
    unsafe
    {
        byte* byteArray = (byte*)unmanagedBytes.ToPointer();
        // Find the end of the string
        byte* pEnd = byteArray;
        while (*pEnd++ != 0) { }
        // Length is effectively the difference here (note we're 1 past end) 
        int length = (int)((pEnd - byteArray) - 1);
        secureStringBytes = new byte[length];
        for (int i = 0; i < length; ++i)
        {
            // Work with data in byte array as necessary, via pointers, here
            secureStringBytes[i] = *(byteArray + i);
        }
    }
}
finally
{
    // This will completely remove the data from memory
    Marshal.ZeroFreeGlobalAllocAnsi(unmanagedBytes);
} 
return secureStringBytes; 

Retriving data from SecureString involves executing unsafe code (for handling unmanaged bytes). Therefore you have to allow your project to be built with unsafe code allowed. This option is available at your project's Properties settings.

Or else you will receive error message:

Unsafe code may only appear if compiling with /unsafe 

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

Share

About the Author

adriancs
Software Developer
Malaysia Malaysia
Writing programs is an art.

Comments and Discussions

 
GeneralThis is a beauty! PinmemberMember 422552214-Oct-14 6:06 
GeneralMy vote of 5 PinprofessionalCarefulCoder10-Oct-14 23:42 
QuestionAES256-NI Vs AES-256 Pinmembersachin_nike23-Sep-14 2:13 
AnswerRe: AES256-NI Vs AES-256 Pinprofessionaladriancs23-Sep-14 3:59 
Questionwho can i add "the Marshal" code in my project ?? when i merge it with my project it's start giving error " the "Marshal" does not eist in the current context" PinmemberMember 1106327918-Sep-14 23:00 
AnswerRe: who can i add "the Marshal" code in my project ?? when i merge it with my project it's start giving error " the "Marshal" does not eist in the current context" Pinprofessionaladriancs12-Nov-14 23:50 
Generalnice writeup PinmemberMember 189862317-Sep-14 9:49 
Bug[My vote of 1] Error in Authentaction PinmemberHus_loia14-Jul-14 18:50 
GeneralRe: [My vote of 1] Error in Authentaction Pinprofessionaladriancs14-Jul-14 20:45 
QuestionCross platform applicability PinmemberKedyr24-Jun-14 5:22 
AnswerRe: Cross platform applicability Pinprofessionaladriancs24-Jun-14 16:04 
Questionthanks Pinmembers.javan27-May-14 23:43 
AnswerC# AES 256 Encryption PinmemberJohn Malcosky13-May-14 3:12 
QuestionThanks! PinmemberIvandro Ismael9-May-14 17:04 
Questionpassword byte Pinmembersaber rezaii magham8-May-14 0:35 
AnswerRe: password byte Pinprofessionaladriancs8-May-14 2:59 
AnswerRe: password byte Pinprofessionaladriancs8-May-14 3:04 
QuestionHelpful PinmemberEmre Ataseven7-May-14 12:30 
QuestionYou should use a hash function, not a two way encryption function. PinmemberJoe Gakenheimer7-May-14 8:22 
GeneralRe: You should use a hash function, not a two way encryption function. PinmemberRobTeixeira7-May-14 9:31 
GeneralRe: You should use a hash function, not a two way encryption function. [modified] Pinprofessionaladriancs8-May-14 3:51 
GeneralRe: You should use a hash function, not a two way encryption function. PinmemberRobTeixeira8-May-14 8:47 
GeneralRe: You should use a hash function, not a two way encryption function. Pinprofessionaladriancs9-May-14 17:33 
GeneralRe: You should use a hash function, not a two way encryption function. PinmemberJoe Gakenheimer8-May-14 3:55 
GeneralRe: You should use a hash function, not a two way encryption function. PinmemberRobTeixeira8-May-14 8:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 9 May 2014
Article Copyright 2014 by adriancs
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid