The Advanced Encryption Standard or AES was originally called the Rijndael cipher, based off a combination of the two Belgian author's names Joan Daemen and Vincent Rijmen . After the cipher was accepted in 2002 to replace the aging DES cipher, it became the governments choice for top secret information. With keys of length 128, 192, or 256 bits (depending on your preference, the default being 256) and corresponding rounds of 10,12, or 14 this is a pretty nice cipher.

AES is a symmetric cipher. Some of you may be wondering, what does that mean? Well, a symetric cipher is one that typically uses one key for both encryption and decryption. Basically you need to "share" the key with the other party, which is why sometimes symmetric ciphers are called shared key ciphers. I would love to do a tutorial on public key cryptography or one comparing both symmetric and public key if this tutorial turns out good and people would want one.

Ok enough history and background, if you would like to learn more specifically about AES check this out Here.

For this (my first tutorial) I really think a basic start is appropriate.

What we are going to accomplish with this? I plan on writing here a simple program that takes in a message from a user to encrypt and decrypt then display that back. So lets get started.

First create a C# console app. Then we are going to need to include just three things.

using System;
//System.IO we include for the access to the memory stream
using System.IO;
//The big using here, this includes everything you could want to do with cryptography.
//Including hashing and public key or semetric key cryptography.
//Gives us acess to cryptostream, the crypto transforms and the rijndael class.
using System.Security.Cryptography;

Little explanation here, when the RijndaelManaged constructor is called it creates both the key and the Initialization Vector(IV). (For the purposes of this tutorial I am using the generated IV and Key.) The key is like a password built in when you encrypt, and checked when you decrypt. I am going to let wikipedia explain IV's "In cryptography, an initialization vector (IV) is a block of bits that is required to allow a stream cipher or a block cipher to be executed in any of several streaming modes of operation to produce a unique stream independent from other streams produced by the same encryption key, without having to go through a (usually lengthy) re-keying process." Basically it keeps track of your bits and allows you to use the same key for multiple encrypts and decrypts.

//This class here the Rijndael is what will have most all of the methods we need to do aes encryption.
//When this is called it will create both a key and Initialization Vector to use.
RijndaelManaged Crypto = new RijndaelManaged();

I will talk about things that are commented so forgive the repeats.
Let us go over the encrypt function, which returns a byte array holding the encrypted data.
The first thing to make sure is that you have both the original IV and Key. Use the RijndaelManaged.Key or RijndaelManaged.IV property to pass them around.

The big things to pay attention to are the BIG THREE the RijndaelManaged, ICryptoTransform and the CryptoStream.

The ICryptoTransform is used to encrypt and decrypt, it is created with either the encrypt method or decrypt method of the RijndaelManaged class, which take the key and IV as parameters.

// Just here so you can see RijndaelManaged Crypto = new RijndaelManaged();
ICryptoTransform Encryptor = Crypto.CreateEncryptor(Crypto.Key, Crypto.IV);

Next is the CryptoStream. The CryptoStream allows for encryption in memory and even inherits from MemoryStream. CryptoStream is passed three parameters a memory stream, the type of transformation and the Cryptographic mode to work through which can be Write ( for encryption) or read ( for decryption).

The last thing that really needs mentioning is the CryptoStream.Write method, where you will be actually writing to the stream. The method takes three parameters the first (and here is a big point) needs to be in bytes, in our case we need to convert the text to bytes in the function this is done by encoding and then calling the getbytes method. The next parameter is an offset unless you have a good reason leave this as zero, lastly I am using the encoded string to get its length which is passed to the stream. Really that is about it, the rest of the function is pretty self explanatory.

//The object that encodes and has getbytes as well as the length method
System.Text.UTF8Encoding Byte_Transform = new System.Text.UTF8Encoding();
Crypto_Stream.Write(PlainBytes, 0, PlainBytes.Length);
The Encrypt Function
private static byte[] encrypt_function(string Plain_Text, byte[] Key, byte[] IV)
{
RijndaelManaged Crypto = null;
MemoryStream MemStream = null;
//I crypto transform is used to perform the actual decryption vs encryption, hash function are also a version of crypto transform.
ICryptoTransform Encryptor = null;
//Crypto streams allow for encryption in memory.
CryptoStream Crypto_Stream = null;
System.Text.UTF8Encoding Byte_Transform = new System.Text.UTF8Encoding();
//Just grabbing the bytes since most crypto functions need bytes.
byte[] PlainBytes = Byte_Transform.GetBytes(Plain_Text);
try
{
Crypto = new RijndaelManaged();
Crypto.Key = Key;
Crypto.IV = IV;
MemStream = new MemoryStream();
//Calling the method create encryptor method Needs both the Key and IV these have to be from the original Rijndael call
//If these are changed nothing will work right.
Encryptor = Crypto.CreateEncryptor(Crypto.Key, Crypto.IV);
//The big parameter here is the cryptomode.write, you are writing the data to memory to perform the transformation
Crypto_Stream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
//The method write takes three params the data to be written (in bytes) the offset value (int) and the length of the stream (int)
Crypto_Stream.Write(PlainBytes, 0, PlainBytes.Length);
}
finally
{
//if the crypto blocks are not clear lets make sure the data is gone
if (Crypto != null)
Crypto.Clear();
//Close because of my need to close things when done.
Crypto_Stream.Close();
}
//Return the memory byte array
return MemStream.ToArray();
}

The decryption function is VERY similar to the encryption function, the major things that need pointing out are as follows.

Your ICryptoTransform will now be passed the decrypt method of the RijndaelManaged class.

Lastly for this I used a stream reader. As is stated in the comments this just makes it so much easier to get the data from the stream. The ReadToEnd method and the fact that the stream reader returns a string makes life easy, so use it. The StreamReader only needs to be called with the Crypto_Stream inserted.

That is really about it. Below is the full code for people who want to Copy and Paste. Thanks for the time. I really hope this tutorial proves useful and if it is please tell me I want to continue to write about using some of the things offered in the System.Security.Cryptography namespace. If it is not useful please tell me and I will try to correct the problems.

using System;
//System.IO we include for the access to the memory stream
using System.IO;
//The big using here, this includes everything you could want to do with cryptography.
//Including hashing and public key or semetric key cryptography.
//Gives us acess to cryptostream, the crypto transforms and the rijndael class.
using System.Security.Cryptography;
namespace AES_Tutuorial
{
class Crypto_tut
{
static void Main()
{
string Plain_Text;
string Decrypted;
string Encrypted_Text;
byte[] Encrypted_Bytes;
//This class here the Rijndael is what will have most all of the methods we need to do aes encryption.
//When this is called it will create both a key and Initialization Vector to use.
RijndaelManaged Crypto = new RijndaelManaged();
//This is just here to convert the Encrypted byte array to a string for viewing purposes.
System.Text.UTF8Encoding UTF = new System.Text.UTF8Encoding();
Console.WriteLine("Please put in the text to be encrypted.");
Plain_Text = Console.ReadLine();
try
{
Encrypted_Bytes = encrypt_function(Plain_Text, Crypto.Key, Crypto.IV);
Encrypted_Text = UTF.GetString(Encrypted_Bytes);
Decrypted = decrypt_function(Encrypted_Bytes, Crypto.Key, Crypto.IV);
Console.WriteLine("Start: {0}", Plain_Text);
Console.WriteLine("Encrypted: {0}", Encrypted_Text);
Console.WriteLine("Decrypted: {0}", Decrypted);
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e.Message);
}
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
private static byte[] encrypt_function(string Plain_Text, byte[] Key, byte[] IV)
{
RijndaelManaged Crypto = null;
MemoryStream MemStream = null;
//I crypto transform is used to perform the actual decryption vs encryption, hash function are a version of crypto transforms.
ICryptoTransform Encryptor = null;
//Crypto streams allow for encryption in memory.
CryptoStream Crypto_Stream = null;
System.Text.UTF8Encoding Byte_Transform = new System.Text.UTF8Encoding();
//Just grabbing the bytes since most crypto functions need bytes.
byte[] PlainBytes = Byte_Transform.GetBytes(Plain_Text);
try
{
Crypto = new RijndaelManaged();
Crypto.Key = Key;
Crypto.IV = IV;
MemStream = new MemoryStream();
//Calling the method create encryptor method Needs both the Key and IV these have to be from the original Rijndael call
//If these are changed nothing will work right.
Encryptor = Crypto.CreateEncryptor(Crypto.Key, Crypto.IV);
//The big parameter here is the cryptomode.write, you are writing the data to memory to perform the transformation
Crypto_Stream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
//The method write takes three params the data to be written (in bytes) the offset value (int) and the length of the stream (int)
Crypto_Stream.Write(PlainBytes, 0, PlainBytes.Length);
}
finally
{
//if the crypto blocks are not clear lets make sure the data is gone
if (Crypto != null)
Crypto.Clear();
//Close because of my need to close things then done.
Crypto_Stream.Close();
}
//Return the memory byte array
return MemStream.ToArray();
}
private static string decrypt_function(byte[] Cipher_Text, byte[] Key, byte[] IV)
{
RijndaelManaged Crypto = null;
MemoryStream MemStream = null;
ICryptoTransform Decryptor = null;
CryptoStream Crypto_Stream = null;
StreamReader Stream_Read = null;
string Plain_Text;
try
{
Crypto = new RijndaelManaged();
Crypto.Key = Key;
Crypto.IV = IV;
MemStream = new MemoryStream(Cipher_Text);
//Create Decryptor make sure if you are decrypting that this is here and you did not copy paste encryptor.
Decryptor = Crypto.CreateDecryptor(Crypto.Key, Crypto.IV);
//This is different from the encryption look at the mode make sure you are reading from the stream.
Crypto_Stream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);
//I used the stream reader here because the ReadToEnd method is easy and because it return a string, also easy.
Stream_Read = new StreamReader(Crypto_Stream);
Plain_Text = Stream_Read.ReadToEnd();
}
finally
{
if (Crypto != null)
Crypto.Clear();
MemStream.Flush();
MemStream.Close();
}
return Plain_Text;
}
}
}

Thank you for the update that is much shorter. this is just an example.Personally I dont use the generated keys. I take a password from the user and use the crypto classes secure random byte generator to generate a salt and hash those to get a key.

Thank you for the update that is much shorter. this is just an example.Personally I dont use the generated keys. I take a password from the user and use the crypto classes secure random byte generator to generate a salt and hash those to get a key.

Just so you know md5 is no longer secure and is not safe for encryption. Look up cryptographic hashes they are nice alternatives.

I'm do not think collisions affect this implementation. If attackers have access to my hashes, then they already have the key and IV, no need to crack the hashes. Attackers must have access to my passwords and salt before they can generate my key and IV. The hash function is merely used to create full byte arrays for the key and IV to prevent a brute force attack on the final AES encrypted string.

With that said, I have no problem replacing MD5 with something more robust out of principle.

One last update. I did a major overhaul on the previous AES class I posted after seeing how other developers implement AES when encrypting credit card numbers. The IV is randomized and stored in the final string during each encryption to completely prevent reusing IVs. I decided to use 256 bit SHA, because I need a 256 bit key for AES to comply with PCI standards.

Here are some very important concepts for implementing AES:

Generate a random IV during every encryption

The IV is a public key, so it can be stored with or at the beginning of the encrypted text

Never reuse an IV

Failure to randomize the IV will cause plaintext strings with identical substrings to have corresponding identical substrings in their encrypted strings.

One last update. I did a major overhaul on the previous AES class I posted after seeing how other developers implement AES when encrypting credit card numbers. The IV is randomized and stored in the final string during each encryption to completely prevent reusing IVs. I decided to use 256 bit SHA, because I need a 256 bit key for AES to comply with PCI standards.

Here are some very important concepts for implementing AES:

Generate a random IV during every encryption

The IV is a public key, so it can be stored with or at the beginning of the encrypted text

Never reuse an IV

Failure to randomize the IV will cause plaintext strings with identical substrings to have corresponding identical substrings in their encrypted strings.

This is a great thread and an even better resource.

Jared, are you able to post your overhauled example here? I would like to take a look.