Cryptography in .NET : Advanced Encryption Standard (AES)

I have released an Open Source libray under the GPL 3.0 license called Block Encrypter that builds on the code discussed in this article. If you need to do reliable and secure symmedtric encryption then this library would be very useful to you.

I thought I would start a little series on using some of the cryptography primitives in .NET. Cryptography and Encryption is something that most developers working on enterprise applications will come across, especially if you work in the financial services industry.

Advanced Encryption Standard (AES)

Advanced Encryption Standard (AES)

Whilst cryptography is a fascinating subject and the design of these algorithms is very interesting, I do not recommend using an algorithm that you have designed yourself. The standard algorithms in practice today have been through lots of analysis by experts both in private industry and governments all around the world trying to find faults and weaknesses, so you are much better off using these recommended systems.

The main algorithms fall into 2 categories, Symmetric encryption and Asymmetric encryption. Symmetric encryption contains algorithms that are based solely on an encryption key. For example, if you encrypt some plaintext with Key1 you get a cipher text out the other end. If you then decrypt the cipher text with the same key (Key1) you will get back to the original plaintext.

Asymmetric encryption works by having 2 keys, a public and private key. These keys are mathematically derived from each other. The public key can be used by anyone and the private key has to be kept secret. I will talk about asymmetric encryption and more specifically RSA in another post.

For this first article I am going to look at the AES symmetric algorithm. AES stands for the Advanced Encryption Standard. This was a competition winner when the National Institute of Standards and Technology ran a contest to replace the already broken DES algorithm.

What I will show in this article is a good practical implementation of AES in .NET. We will start with the following interface. The interface contains 2 methods, Encrypt and Decrypt. They methods take cipher text/plaintext and an encryption key.

using System;

namespace CryptoLibrary
{
    public interface IAES
    {
        string Decrypt(string ciphertext, string key);
        string Encrypt(string plainText, string key);
    }
}

The following method shows the encryption process. The key is a string. This could be a password or a string of pseudo random characters. The first thing we do is run a key derivation function to generate the actual AES encryption key based on the password and a salt (which is generated in the key derivation function).

        public string Encrypt(string plainText, string key)
        {
            if (string.IsNullOrEmpty(plainText))
            {
                throw new ArgumentNullException("plainText");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key");
            }

            using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, _saltSize))
            {
                byte[] saltBytes = keyDerivationFunction.Salt;
                byte[] keyBytes = keyDerivationFunction.GetBytes(32);
                byte[] ivBytes = keyDerivationFunction.GetBytes(16);

                using (var aesManaged = new AesManaged())
                {
                    aesManaged.KeySize = 256;

                    using (var encryptor = aesManaged.CreateEncryptor(keyBytes, ivBytes))
                    {
                        MemoryStream memoryStream = null;
                        CryptoStream cryptoStream = null;

                        return WriteMemoryStream(plainText, ref saltBytes, encryptor, ref memoryStream, ref cryptoStream);
                    }
                }
            }
        }

What the key derivation function (Rfc2898DeriveBytes) does is repeatedly hash the user password along with a salt. This has multiple benefits:

Firstly, you can use arbitrarily sized passwords – AES only supports specific key sizes.

Secondly, the addition of the salt means that you can use the same passphrase to generate multiple different. This is important for key separation; reusing keys in different contexts is one of the most common ways cryptographic systems are broken.

The beauty of this is that every time you encrypt plain text P1 with the derived key, you will get a different cipher text out the other side. But those different cipher texts can all be decrypted with the same key.

I have released an Open Source libray under the GPL 3.0 license called Block Encrypter that builds on the code discussed in this article. If you need to do reliable and secure symmedtric encryption then this library would be very useful to you.

The code below shows the full use of this class based on the interface above.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;

namespace CryptoLibrary
{
    public class AES : IAES
    {
        private readonly int _saltSize = 32;

        public string Encrypt(string plainText, string key)
        {
            if (string.IsNullOrEmpty(plainText))
            {
                throw new ArgumentNullException("plainText");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key");
            }

            using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, _saltSize))
            {
                byte[] saltBytes = keyDerivationFunction.Salt;
                byte[] keyBytes = keyDerivationFunction.GetBytes(32);
                byte[] ivBytes = keyDerivationFunction.GetBytes(16);

                using (var aesManaged = new AesManaged())
                {
                    aesManaged.KeySize = 256;

                    using (var encryptor = aesManaged.CreateEncryptor(keyBytes, ivBytes))
                    {
                        MemoryStream memoryStream = null;
                        CryptoStream cryptoStream = null;

                        return WriteMemoryStream(plainText, ref saltBytes, encryptor, ref memoryStream, ref cryptoStream);
                    }
                }
            }
        }

        public string Decrypt(string ciphertext, string key)
        {
            if (string.IsNullOrEmpty(ciphertext))
            {
                throw new ArgumentNullException("ciphertext");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key");
            }

            var allTheBytes = Convert.FromBase64String(ciphertext);
            var saltBytes = allTheBytes.Take(_saltSize).ToArray();
            var ciphertextBytes = allTheBytes.Skip(_saltSize).Take(allTheBytes.Length - _saltSize).ToArray();

            using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes))
            {
                var keyBytes = keyDerivationFunction.GetBytes(32);
                var ivBytes = keyDerivationFunction.GetBytes(16);

                return DecryptWithAES(ciphertextBytes, keyBytes, ivBytes);
            }
        }

        private string WriteMemoryStream(string plainText, ref byte[] saltBytes, ICryptoTransform encryptor, ref MemoryStream memoryStream, ref CryptoStream cryptoStream)
        {
            try
            {
                memoryStream = new MemoryStream();

                try
                {
                    cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

                    using (var streamWriter = new StreamWriter(cryptoStream))
                    {
                        streamWriter.Write(plainText);
                    }
                }
                finally
                {
                    if (cryptoStream != null)
                    {
                        cryptoStream.Dispose();
                    }
                }

                var cipherTextBytes = memoryStream.ToArray();
                Array.Resize(ref saltBytes, saltBytes.Length + cipherTextBytes.Length);
                Array.Copy(cipherTextBytes, 0, saltBytes, _saltSize, cipherTextBytes.Length);

                return Convert.ToBase64String(saltBytes);
            }
            finally
            {
                if (memoryStream != null)
                {
                    memoryStream.Dispose();
                }
            }
        }

        private static string DecryptWithAES(byte[] ciphertextBytes, byte[] keyBytes, byte[] ivBytes)
        {
            using (var aesManaged = new AesManaged())
            {
                using (var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes))
                {
                    MemoryStream memoryStream = null;
                    CryptoStream cryptoStream = null;
                    StreamReader streamReader = null;

                    try
                    {
                        memoryStream = new MemoryStream(ciphertextBytes);
                        cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
                        streamReader = new StreamReader(cryptoStream);

                        return streamReader.ReadToEnd();
                    }
                    finally
                    {
                        if (memoryStream != null)
                        {
                            memoryStream.Dispose();
                            memoryStream = null;
                        }
                    }
                }
            }
        }
    }
}

 

Participate with Coding in the Trenches on Facebook

Participate with Coding in the Trenches on Facebook by Click the button above.

18 thoughts on “Cryptography in .NET : Advanced Encryption Standard (AES)

  1. Pingback: Cryptography in .NET : RSA | Stephen Haunts { Coding in the Trenches }

  2. Pingback: Cryptography in .NET : Random Numbers and Hashes | Stephen Haunts { Coding in the Trenches }

  3. Pingback: Cryptography in .NET : Hybrid Encryption Protocols | Stephen Haunts { Coding in the Trenches }

    1. hurrrr

      it is because that class doesnt implement IDisposable interface. So, if you wanna get the code right, remove using and brackets…

      Reply
  4. Pingback: Introduction to AES Encryption | Stephen Haunts { Coding in the Trenches }

  5. Pingback: Block Encrypter .NET Library | Stephen Haunts { Coding in the Trenches }

  6. Pingback: Cryptography in .NET : Digital Signatures | Stephen Haunts { Coding in the Trenches }

  7. Brian Wengel

    How secure is .Net’s AES implementation?
    I’m convinced that NSA and MS are VERY close and that it would be of NSA’s interest to have a backdoor into .Net’s AES implementation?
    I’m working on a project and considering using alternatives, although it would definitely be the easiest way to use the native .Net cryptography.
    Do you agree/disagree…..and why?

    Reply
    1. Stephen Haunts Post author

      If you use AESCryptoServiceProvider over AESManaged, then the former is FIPS compliant which should give you a good level of comfort as it is the same underlying crypto service used by the rest of windows. The FIPS compliance also helps ensure your can definitely decrypt messages implemented with another FIPS compliant AES system.

      I couldn’t tell you if anything more nefarious us going on between MS and NSA but I have always used AESCryptoServiceProvider and that has been at some very large financial and healthcare companies.

      Another alternative is to use the BouncyCastle crypto library. I have only tinkered with it, but it seems to be a popular alternative.

      http://www.bouncycastle.org/csharp/

      If you are really concerned about the implementation then you could go to the more extreme end and do all of your key management and encryption using a Hardware Security Module, but your implementation costs go up considerable then, but that may be fine in your situation.

      Reply
  8. Furiant

    Thanks for your article.

    I’m pretty new to this. How exactly do I use the example code? When I create a user, I’d pass some default password string to the plainText parameter of Encrypt(string plainText, string key), I guess. But what do I pass to the ‘key’ parameter? Would I use the same key for every new account? Where do I store it?

    Then, when the user is logging in, how do I determine if their password is correct? Could you give an example of CreateAccount(string username) and Login(string username, string password) in an MVC context?

    Sorry to be such a newb, but every article I read on this either ends with people commenting “No! Don’t do this!” or doesn’t provide enough example implementation (for me).

    Reply
    1. Stephen Haunts Post author

      You shouldn’t use AES to encrypt passwords. You should use hashing via a password based key derivation function. I recently wrote an article on this for Microsoft which should help you out.

      http://www.microsoft.com/en-gb/developers/articles/week04jun15/how-to-securely-store-passwords-and-beat-the-hackers/

      You store the hashed (with the pbkdf2 implementation) into a database. Then when the user logs in you recalculate the hash of the password on your client and compare it to what is stored in the database. If it matches let them in.

      Steve

      Reply
  9. superstringcheese

    Thanks for your article.

    I’m pretty new to this. How exactly do I use the example code? When I create a user, I’d pass some default password string to the plainText parameter of Encrypt(string plainText, string key), I guess. But what do I pass to the ‘key’ parameter? Would I use the same key for every new account? Where do I store it?

    Then, when the user is logging in, how do I determine if their password is correct? Could you give an example of CreateAccount(string username) and Login(string username, string password) in an MVC context?

    Sorry to be such a newb, but every article I read on this either ends with people commenting “No! Don’t do this!” or doesn’t provide enough example implementation (for me).

    Reply
  10. Akhilesh

    Amazing post.

    It does cover very well of how to encrypt with AES, so thanks a ton for that.

    I still need some suggestion on one important aspect to encryption using this approach or any.
    I am still puzzled at how best to handle the other big concern i.e. where to store the key used to encrypt?
    I have read about DPAPI, also storing the key in config and encrypting the config with aspnet_regiis, but DPAPI didn’t fit me as my app is load balanced, 2nd option, due to some reasons didn’t look that secure.
    Can any of you guys suggest some better ways to store the key without inventing our own key management mechanism?
    It would be great help, if i get some pointers. Thanks.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s