Need Quality Code? Get Silver Backed

Symmetric Encryption with AES

1stJul

0

by Gary H

It is insufficient to protect ourselves with laws; we need to protect ourselves with mathematics.

Bruce Schneier

Symmetric encryption is a method of encryption where the same key is used to encrypt and decrypt the message. This differs from asymmetric (or public-key) encryption, which uses one key to encrypt a message and another to decrypt the message.

For an overview on what encryption is I heartily recommend you read a primer. It's a broad topic and to cover it in depth would be way out of scope of this single post.

Encryption in .Net

We're going to be using AES for our chosen algorithm. The classes for this in .Net use the ciphers original name of Rijndael. The encryption classes in .Net all act on byte arrays so if you are wanting to encrypt strings you will want to look at the Encoding.GetBytes method for whichever encoding you are using (.Net defaults to unicode). If you are using other primitive types you will want to look at the BitConverter.GetBytes method. If you are encrypting objects you will want to look at some kind of serialisation before encrypting your representation.

Encryption

We begin by instantiating a new RijndaelManaged class and setting our block and padding sizes. At this point we should also take a Key and Initialisation Vector for our algorithm. Generating these securely is an article in its own right but see this Stack Overflow Article for initial pointers.

RijndaelManaged cipher = new RijndaelManaged();
cipher.BlockSize = 128;
cipher.Padding = PaddingMode.PKCS7;

Next we use a MemoryStream which will be our buffer containing encrypted data and we use a CryptoStream which will will interact with our cipher. We write our plain text into the CryptoStream which will convert it to CipherText and dump it into the MemoryStream.

using (MemoryStream msEncryptedTextBuffer = new MemoryStream())
using (CryptoStream csOut = new CryptoStream(msEncryptedTextBuffer, 
									cipher.CreateEncryptor(key, iv), 
									CryptoStreamMode.Write)) 
{
    csOut.Write(itemToEncrypt, 0, itemToEncrypt.Length);
    csOut.Flush();
    csOut.FlushFinalBlock();

    // ... 

Finally we want to cleam up our cipher, dispose of managed resources and return our cipher text. Putting all of these steps together we can create a reusable encryption method for a class library:

public static byte[] SymmetricEncrypt(byte[] itemToEncrypt, 
											byte[] key, byte[] iv)
{
    if (itemToEncrypt == null || key == null || iv == null)
        return null;

    RijndaelManaged cipher = new RijndaelManaged();
    cipher.BlockSize = 128;
    cipher.Padding = PaddingMode.PKCS7;

    using (MemoryStream msEncryptedTextBuffer = new MemoryStream())
    using (CryptoStream csOut = new CryptoStream(
    								msEncryptedTextBuffer, 
									cipher.CreateEncryptor(key, iv), 
									CryptoStreamMode.Write)) 
    {
        csOut.Write(itemToEncrypt, 0, itemToEncrypt.Length);
        csOut.Flush();
        csOut.FlushFinalBlock();

        	//Read the encrypted data from the buffer and close streams
        msEncryptedTextBuffer.Position = 0;
        byte[] data = msEncryptedTextBuffer.ToArray();
        msEncryptedTextBuffer.Close();
        csOut.Close();
        cipher.Clear();

        return data;
    }
}

Decryption

Decryption works in almost the same way. We start by reading cipher text into a MemoryStream. We prepare our cipher then create a CryptoStream from which we read the CipherText into a buffer. We clean off any padding and we're done. This gives us:

public static byte[] SymmetricDecrypt(byte[] itemToDecrypt, 
											byte[] key, byte[] iv)
{
    if (itemToDecrypt == null || key == null || iv == null)
        return null;


    using (MemoryStream msEncryptedText = new MemoryStream(
    										itemToDecrypt, 0, 
    										itemToDecrypt.Length, 
    										false)) 
    {
          //Create and prepare the cypher
        RijndaelManaged cipher = new RijndaelManaged();
        cipher.BlockSize = 128;
        cipher.Padding = PaddingMode.PKCS7;

          //Create the decryption stream and apply it to the passed data
        using (CryptoStream csOut = new CryptoStream(
        								msEncryptedText, 
        								cipher.CreateDecryptor(key, iv), 
        								CryptoStreamMode.Read)) 
        {
            byte[] decryptedData = new byte[itemToDecrypt.Length];
            int dataSize = csOut.Read(decryptedData, 0, 
            							itemToDecrypt.Length);
            csOut.Close();
            cipher.Clear();

              //Trim the excess empty elements from the array
            byte[] trimmedData = new byte[dataSize];
            Array.Copy(decryptedData, trimmedData, dataSize);

            return trimmedData;
        }
    }
}

This gives us some very reusable code that we can unit test and ensure works correctly. It makes sure we don't make any silly mistakes (like forgetting padding or failing to wipe our Cipher in memory) and gives us a set of building blocks to improve upon across the rest of your work.

Updates

Asymmetric Encryption with RSA

C# , Encryption

Comments are Locked for this Post