AES/CBC/PKCS5Padding Encryption/Decryption in C#

by zebsadiq 1. July 2013 13:33

I’ve recently been asked to write some code to decrypt some data using C# which was originally encrypted in Java. While I managed to get this to work, I had to piece information together from many different sources on the web. Therefore I have decided to simplify the procedure for the next person who comes looking by putting this into one place.

I was provided with the following piece of information by the Java developer (obviously the values here are created to be used for demo purposes):

Cyphered data (base64) r/w1xZb85PokABCycED5Tw==
Deciphered data I am Zeb
Encryption key (hex) 142eb4a7ab52dbfb971e18daed7056488446b4b2167cf61187f4bbc60fc9d96d
Initialisation Vector (hex) 26744a68b53dd87bb395584c00f7290a
Cipher method AES/CBC/PKCS5Padding

Though what needed to be done was straight forward, I faced the following difficulties when discovering how to code my solution:

  • Almost all examples I came across were discussing the use of the Rfc2898DeriveBytes class to salt a password which is very specific to the security around passwords.
  • No on example pointed out the difference between a Base32 encoding , a Hexadecimal string and a Base64 string.
  • When you are working with decryption, your result is either going to be right or wrong. If you algorithm doesn’t work, then you do not exactly what is going wrong. There doesn’t seem to be an online tool to ensure that the data that you are working with is valid.
  • Since my data was coming from Java, I was not sure whether Java has a slightly different algorithm for the cipher method used which was causing my decoding to fail. (Obviously this was just a doubt).

In our scenario, we will not be working to encrypt passwords. For that, I would recommend the use of Rfc2898DeriveBytes. There are plenty of examples of this on the web.

Here is my code

MyCryptoClass.cs:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace CypherExample
{

    public sealed class MyCryptoClass
    {
        protected RijndaelManaged myRijndael;

        private static string encryptionKey = "142eb4a7ab52dbfb971e18daed7056488446b4b2167cf61187f4bbc60fc9d96d";
        private static string initialisationVector = "26744a68b53dd87bb395584c00f7290a";

        // Singleton pattern used here with ensured thread safety
        protected static readonly MyCryptoClass _instance = new MyCryptoClass();
        public static MyCryptoClass Instance
        {
            get { return _instance; }
        }

        public MyCryptoClass()
        {
            
        }

        public string DecryptText(string encryptedString)
        {
            using (myRijndael = new RijndaelManaged())
            {

                myRijndael.Key = HexStringToByte(encryptionKey);
                myRijndael.IV = HexStringToByte(initialisationVector);
                myRijndael.Mode = CipherMode.CBC;
                myRijndael.Padding = PaddingMode.PKCS7;

                Byte[] ourEnc = Convert.FromBase64String(encryptedString);
                string ourDec = DecryptStringFromBytes(ourEnc, myRijndael.Key, myRijndael.IV);

                return ourDec;
            }
        }


        public string EncryptText(string plainText)
        {
            using (myRijndael = new RijndaelManaged())
            {

                myRijndael.Key = HexStringToByte(encryptionKey);
                myRijndael.IV = HexStringToByte(initialisationVector);
                myRijndael.Mode = CipherMode.CBC;
                myRijndael.Padding = PaddingMode.PKCS7;

                byte[] encrypted = EncryptStringToBytes(plainText, myRijndael.Key, myRijndael.IV);
                string encString = Convert.ToBase64String(encrypted);

                return encString;
            }
        }


        protected byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");
            byte[] encrypted;
            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption. 
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream. 
            return encrypted;

        }

        protected string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");

            // Declare the string used to hold 
            // the decrypted text. 
            string plaintext = null;

            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for decryption. 
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {

                            // Read the decrypted bytes from the decrypting stream 
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }

            }

            return plaintext;

        }

        public static void GenerateKeyAndIV()
        {
            // This code is only here for an example
            RijndaelManaged myRijndaelManaged = new RijndaelManaged();
            myRijndaelManaged.Mode = CipherMode.CBC;
            myRijndaelManaged.Padding = PaddingMode.PKCS7;

            myRijndaelManaged.GenerateIV();
            myRijndaelManaged.GenerateKey();
            string newKey = ByteArrayToHexString(myRijndaelManaged.Key);
            string newinitVector = ByteArrayToHexString(myRijndaelManaged.IV);
        }

        protected static byte[] HexStringToByte(string hexString)
        {
            try
            {
                int bytesCount = (hexString.Length) / 2;
                byte[] bytes = new byte[bytesCount];
                for (int x = 0; x < bytesCount; ++x)
                {
                    bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
                }
                return bytes;
            }
            catch
            {
                throw;
            }
        }

        public static string ByteArrayToHexString(byte[] ba)
        {
            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }
    }
}

To be able to test our Cipher, the following is a Console Application which would output the results of our Encryption / Decryption.

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CypherExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("********************Encryption Example******************");
            MyCryptoClass crypto = MyCryptoClass.Instance;
            string inputText = "I am Zeb";
            Console.WriteLine("Plain text is: '{0}'", inputText);
            string encryptedText = crypto.EncryptText(inputText);
            Console.WriteLine("Encrypted text is '{0}'", encryptedText);

            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("********************Decryption Example******************");
            string inputEncryptedText = "r/w1xZb85PokABCycED5Tw==";
            Console.WriteLine("Input Encrypted text is '{0}'", inputEncryptedText);
            string decryptedText = crypto.DecryptText(inputEncryptedText);
            Console.WriteLine("Decrypted text is: '{0}'", decryptedText);

            


            Console.ReadLine();
        }
    }
}

This is what this code outputs:

********************Encryption Example******************
Plain text is: 'I am Zeb'
Encrypted text is 'r/w1xZb85PokABCycED5Tw=='


********************Decryption Example******************
Input Encrypted text is 'r/w1xZb85PokABCycED5Tw=='
Decrypted text is: 'I am Zeb'

Key notes about the code above:

  • The cypher data is a Base64 string. This is why we use the Convert.FromBase64String() method on line 38.
  • Method HexStringToByte() converts hex strings to bytes. Remember that these strings are different to Base64 strings.
  • Method ByteArrayToHexString() on line 182 is the reverse process for HexStringToByte().
  • Notice, line 33 to 36 in MyCryptoClass.cs. This is where i am defining the Cipher method.
  • Notice that the encrypted data is base64 and the key and initialisation vector is a hex value. If you get these mixed up, your solution will not work.
  • PaddingMode.PKCS7 accommodates PKCS5Padding.

Hope this helps!

Tags: , ,

C# | Security | Encryption/Decryption

Comments

12/14/2014 1:39:39 PM #

Pingback from birvanswers.org

Objective-C decrypt AES 128 cbc hex string | Yeaton Answers

birvanswers.org | Reply

9/20/2016 7:24:13 AM #

Pingback from csharptutorial.xyz

How to convert this routine from Java into C# – C# Tutorial

csharptutorial.xyz | Reply

5/17/2018 2:58:49 PM #

Pingback from topfreelancertips.com

Need an equivalent c# program for this JAVA Program - Upwork - Top Freelancing Tips

topfreelancertips.com | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Calendar

<<  December 2024  >>
MoTuWeThFrSaSu
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

View posts in large calendar