Page 1 of 1

AES Encryption and C# A very basic intro to Cryptography in C#

#1 Smurphy  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 35
  • View blog
  • Posts: 367
  • Joined: 07-July 08

Posted 18 February 2010 - 08:58 PM

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).
Crypto_Stream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);


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.
Decryptor = Crypto.CreateDecryptor(Crypto.Key, Crypto.IV);


The CryptoStream will now be called with the Read method.
Crypto_Stream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);


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.
 Stream_Read = new StreamReader(Crypto_Stream);
 //Store the text and return.
 Plain_Text = Stream_Read.ReadToEnd();


The decryption function.
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;
        }


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.

Attached Image

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

    }
}


Is This A Good Question/Topic? 4
  • +

Replies To: AES Encryption and C#

#2 Adkins  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 66
  • View blog
  • Posts: 560
  • Joined: 27-October 09

Posted 01 March 2010 - 05:57 AM

Very well done tutorial in my opinion. Fits my needs perfectly!
Was This Post Helpful? 1
  • +
  • -

#3 jared.deckard  Icon User is offline

  • New D.I.C Head

Reputation: 18
  • View blog
  • Posts: 46
  • Joined: 11-July 12

Posted 11 July 2012 - 03:53 PM

Based on what I have read, RijndaelManaged is not the final AES implementation. AesCryptoServiceProvider uses Microsoft's RSAENH.DLL and has better compatibility across platforms.

Crypto.CreateEncryptor() uses the implicit key/iv and randomly generates them if they are null.

The MSDN page for CreateEncryptor() provides a simpler example: http://ideone.com/RPFXC
using System;
using System.Security.Cryptography;
using System.Text;

class EncryptorExample
{
     private static string quote =
         "Things may come to those who wait, but only the " +
         "things left by those who hustle. -- Abraham Lincoln";

     public static void Main()
     {
         AesCryptoServiceProvider aesCSP = new AesCryptoServiceProvider();

         aesCSP.GenerateKey();
         aesCSP.GenerateIV();
         byte[] encQuote = EncryptString(aesCSP, quote);

         Console.WriteLine("Encrypted Quote:\n");
         Console.WriteLine(Convert.ToBase64String(encQuote));

         Console.WriteLine("\nDecrypted Quote:\n");
         Console.WriteLine(DecryptBytes(aesCSP, encQuote));
     }

     public static byte[] EncryptString(SymmetricAlgorithm symAlg, string inString)
     {
         byte[] inBlock = UnicodeEncoding.Unicode.GetBytes(inString);
         ICryptoTransform xfrm = symAlg.CreateEncryptor();
         byte[] outBlock = xfrm.TransformFinalBlock(inBlock, 0, inBlock.Length);

         return outBlock;
     }

     public static string DecryptBytes(SymmetricAlgorithm symAlg, byte[] inBytes)
     {
         ICryptoTransform xfrm = symAlg.CreateDecryptor();
         byte[] outBlock = xfrm.TransformFinalBlock(inBytes, 0, inBytes.Length);

         return UnicodeEncoding.Unicode.GetString(outBlock);
     }
}


Was This Post Helpful? 2
  • +
  • -

#4 Smurphy  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 35
  • View blog
  • Posts: 367
  • Joined: 07-July 08

Posted 11 July 2012 - 05:02 PM

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.
Was This Post Helpful? 0
  • +
  • -

#5 jared.deckard  Icon User is offline

  • New D.I.C Head

Reputation: 18
  • View blog
  • Posts: 46
  • Joined: 11-July 12

Posted 13 July 2012 - 04:05 PM

View PostSmurphy, on 11 July 2012 - 05:02 PM, said:

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.


Good idea.

Here is my AES class:
using System;
using System.Text;
using System.Security.Cryptography;

/// <summary>
/// AES class is derived from the MSDN .NET CreateEncryptor() example
/// http://msdn.microsoft.com/en-us/library/09d0kyb3.aspx
/// </summary>
class AES
{
    // Symmetric algorithm interface is used to store the AES service provider
    private SymmetricAlgorithm AESProvider;

    // Crytographic transformers are used to encrypt and decrypt byte arrays
    private ICryptoTransform encryptor;
    private ICryptoTransform decryptor;

    /// <summary>
    /// Constructor for AES class that takes byte arrays for the key and IV
    /// </summary>
    /// <param name="key">Cryptographic key</param>
    /// <param name="IV">Cryptographic initialization vector</param>
    public AES(byte[] key, byte[] IV)
    {
        // Initialize AESProvider with AES service provider
        AESProvider = new AesCryptoServiceProvider();

        // Set the key and IV for AESProvider
        AESProvider.Key = key;
        AESProvider.IV = IV;

        // Initialize cryptographic transformers from AESProvider
        encryptor = AESProvider.CreateEncryptor();
        decryptor = AESProvider.CreateDecryptor();
    }

    /// <summary>
    /// Constructor for AES class that generates the key and IV from salted passwords
    /// </summary>
    /// <param name="keyPassword">Password used to generate the key</param>
    /// <param name="IVPassword">Password used to generate the IV</param>
    /// <param name="salt">Salt used to secure the passwords</param>
    public AES(string keyPassword, string IVPassword, string salt)
    {
        // Initialize AESProvider with AES service provider
        AESProvider = new AesCryptoServiceProvider();

        // Initialize a hasher with the default MD5 algorithm
        MD5 md5 = System.Security.Cryptography.MD5.Create();

        // Generate the key and IV for AESProvider from hashed, salted passwords
        AESProvider.Key = md5.ComputeHash(UnicodeEncoding.Unicode.GetBytes(keyPassword + salt));
        AESProvider.IV = md5.ComputeHash(UnicodeEncoding.Unicode.GetBytes(IVPassword + salt));

        // Initialize cryptographic transformers from AESProvider
        encryptor = AESProvider.CreateEncryptor();
        decryptor = AESProvider.CreateDecryptor();
    }

    /// <summary>
    /// Encrypts a string with AES
    /// </summary>
    /// <param name="plainText">String to encrypt</param>
    /// <returns>Encrypted string</returns>
    public string Encrypt(string plainText)
    {
        // Convert string to bytes
        byte[] plainBytes = UnicodeEncoding.Unicode.GetBytes(plainText);

        // Encrypt bytes
        byte[] secureBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

        // Return encrypted bytes as a string
        return UnicodeEncoding.Unicode.GetString(secureBytes);
    }

    /// <summary>
    /// Decrypts a string with AES
    /// </summary>
    /// <param name="secureText">Encrypted string to decrypt</param>
    /// <returns>Decrypted string</returns>
    public string Decrypt(string secureText)
    {
        // Convert encrypted string to bytes
        byte[] secureBytes = UnicodeEncoding.Unicode.GetBytes(secureText);

        // Decrypt bytes
        byte[] plainBytes = decryptor.TransformFinalBlock(secureBytes, 0, secureBytes.Length);

        // Return decrypted bytes as a string
        return UnicodeEncoding.Unicode.GetString(plainBytes);
    }

}


Was This Post Helpful? 0
  • +
  • -

#6 Smurphy  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 35
  • View blog
  • Posts: 367
  • Joined: 07-July 08

Posted 13 July 2012 - 04:27 PM

Just so you know md5 is no longer secure and is not safe for encryption. Look up cryptographic hashes they are nice alternatives.
Was This Post Helpful? 0
  • +
  • -

#7 jared.deckard  Icon User is offline

  • New D.I.C Head

Reputation: 18
  • View blog
  • Posts: 46
  • Joined: 11-July 12

Posted 14 July 2012 - 12:41 PM

View PostSmurphy, on 13 July 2012 - 04:27 PM, said:

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.
Was This Post Helpful? 0
  • +
  • -

#8 jared.deckard  Icon User is offline

  • New D.I.C Head

Reputation: 18
  • View blog
  • Posts: 46
  • Joined: 11-July 12

Posted 20 July 2012 - 10:16 AM

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.
Was This Post Helpful? 0
  • +
  • -

#9 dolsson  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 13-September 12

Posted 13 September 2012 - 06:44 AM

View Postjared.deckard, on 20 July 2012 - 10:16 AM, said:

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.

Thanks!
Was This Post Helpful? 0
  • +
  • -

#10 jared.deckard  Icon User is offline

  • New D.I.C Head

Reputation: 18
  • View blog
  • Posts: 46
  • Joined: 11-July 12

Posted 22 September 2012 - 11:18 AM

AES256 class with comments:
http://ideone.com/xQJME
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1