Quantcast
Viewing all articles
Browse latest Browse all 28

.Net implementation of AES CRT

AesCryptoServiceProvider in .Net has not provided CRT implementation and also I have not found any examples about this from internet, so I decided to code one myself, and it turns out quite simple.

My initial thought was to find AES block cypher first in .Net, then work out the multi blocks cipher based on AES block cipher, here is the catch, in .Net AesCryptoServiceProvider is intended for multi blocks already, because when you looked at the AesCryptoServiceProvider, it has a mode setting like CBC which is only meaning for blocks cipher, bad news is the CRT mode is not implemented, good news is when AesCryptoServiceProvider is used in ECB mode, and the size of single message is the same as AES message size which is 16 bytes (128 bit), the AesCryptoServiceProvider can be used as a general AES block cipher.
Here is the code

private static byte[] AESEnrypt(byte[] key, byte[] plainBytes)
        {
            using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
            {
                myAes.Key = key;
                myAes.Mode = CipherMode.ECB; // no iv
                myAes.Padding = PaddingMode.None;

                // Create a cryptor to perform the stream transform.
                ICryptoTransform decryptor = myAes.CreateEncryptor(myAes.Key, null);

                var outputBuffer = new Byte[16];

                // Create the streams used for decryption. 
                decryptor.TransformBlock(plainBytes, 0, 16, outputBuffer, 0);


                return outputBuffer;

            }

        }

As we use AesCryptoServiceProvider as a generic AES cipher, so no IV is needed, IV is only needed when one key is used many times to avoid plain text attack, so no IV is passed in CreateEncryptor, PaddingMode.None must be set, otherwise all the encrypted bytes will be mysteriously 0.

This is general AES block cipher, the message which is plainBytes must be in size of 16 bytes, no IV involved, given a key and a message block it will output an encrypted same size block.
It is not using any stream classes, as my message is not big.

Another interesting thing is for CRT, both encryption and decryption of CRT messages use AES encrypt cipher, there is no decryption cipher needed by CRT, the key point of CRT is using AES to encrypt different IVs then XOR with plain text or cipher text to get the opposite.

So the other half of code is performing AES cipher of IVs in a parallel way defined by CRT

// decrypt using the same function
        private static byte[] CRTEncryptBytes(byte[] plainBytes, byte[] key, byte[] iv)
        {
            // divid it into blocks then start to do CTR
            var cipheredBytes = new byte[plainBytes.Length];

            for (int i = 0; i < plainBytes.Length; i += 16)
            {


                if (i + 16 <= plainBytes.Length)
                {
                    // get the encryptuion of iv
                    var plainBlockBytes = new byte[16];

                    Buffer.BlockCopy(plainBytes, i, plainBlockBytes, 0, 16);

                    var encryptedBytes = AESEnrypt(key, iv);

                    // increase iv
                    IncrementAtIndex(iv, 15);

                    var xoredBytes = XOR(plainBlockBytes, encryptedBytes);

                    Buffer.BlockCopy(xoredBytes, 0, cipheredBytes, i, 16);

                }
                else
                {
                    // get the encryption of iv
                    var cipherBlockBytes = new byte[plainBytes.Length - i];

                    Buffer.BlockCopy(plainBytes, i, cipherBlockBytes, 0, plainBytes.Length - i);

                    var decryptedBytes = AESEnrypt(key, iv);

                    var xoredBytes = XOR(cipherBlockBytes, decryptedBytes);

                    Buffer.BlockCopy(xoredBytes, 0, cipheredBytes, i, plainBytes.Length - i);
                }



            }

            return cipheredBytes;

        }

What it does is to divide plainbytes into 16 bytes blocks, for this function plainbytes can be of any size, iv is the seed (16 bytes too), for every block iv will be simply increased by value of one.

This function can be used for decryption as well.

To complete the example there are two other functions.

Function to perform increment

//Call it with higher bound
        private static void IncrementAtIndex(byte[] array, int index)
        {

            if (array[index] == byte.MaxValue)
            {
                array[index] = 0;
                if (index > 0)
                    IncrementAtIndex(array, index - 1);
            }
            else
            {
                array[index]++;
            }
        }

Function to perform XOR

    //truncate to the shortest
        private static byte[] XOR(byte[] buffer1, byte[] buffer2)
        {
            var length = buffer1.Length <= buffer2.Length
                ? buffer1.Length
                : buffer2.Length;

            var result = new byte[length];

            for (int i = 0; i < length; i++)
            {
                result[i] = (byte)(buffer1[i] ^ buffer2[i]);
            }
            return result;

        }

Viewing all articles
Browse latest Browse all 28

Trending Articles