1

I am attempting to test a simple class to encrypt and decrypt data in C#.

`

{  [TestFixture]
    public class CryptTest
    {
        [Test]
        public void TestMethod()
        {
            String text = "Hello World!";

            String crypt = EncryptionService.Encrypt(text, Config.KEY_STRING);
            Console.WriteLine(crypt);
            String clear = EncryptionService.Decrypt(crypt, Config.KEY_STRING);
            Console.WriteLine(clear);
            Assert.That(clear, Is.EqualTo(text));


        }

`However, I am receiving the following exception:

Message: System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.

with the stack:

        StackTrace  "   at System.Security.Cryptography.CapiSymmetricAlgorithm.DepadBlock(Byte[] block, Int32 offset, Int32 count)\r\n   at System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)\r\n   at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count)\r\n   at System.IO.StreamReader.ReadBuffer()\r\n   at System.IO.StreamReader.ReadToEnd()\r\n   at InsuranceMidAm.Services.EncryptionService.Decrypt(String cipher, String key) in C:\\Visual Studio Projects\\InsuranceMidAm\\InsuranceMidAm\\Services\\EncryptionService.cs:line 72\r\n   at InsuranceMidAm.Tests.CryptTest.TestMethod() in C:\\Visual Studio Projects\\InsuranceMidAm\\InsuranceMidAm.Tests\\CryptTest.cs:line 20" string

This is the class under test:

namespace InsuranceMidAm.Services
{
    public class EncryptionService
    {
        // Reference: https://stackoverflow.com/questions/273452/using-aes-encryption-in-c-sharp
        public static String Encrypt(String text, String key)
        {

            byte[] value = UTF8Encoding.UTF8.GetBytes(text);
            byte[] crypt;
            byte[] iv;
            using (Aes myAes = Aes.Create())
            {

                myAes.KeySize = 256;
                myAes.Mode = CipherMode.CBC;
                myAes.Key = HexToBin(key);
                myAes.GenerateIV();
                myAes.Padding = PaddingMode.PKCS7;

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, myAes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(value, 0, value.Length);
                        cs.FlushFinalBlock();
                        crypt = ms.ToArray();
                    }
                }
                iv = myAes.IV;
                myAes.Clear();
            }
            return ByteArrayToString(crypt) + ":" + ByteArrayToString(iv);

        }

        public static string Decrypt(String cipher, String key)
        {
            String outputString = "";
            byte[] ivBytes = HexToBin(getIV(cipher));
            byte[] valBytes = HexToBin(getSSN(cipher));

            using (Aes myAes = Aes.Create())
            {
                int size = valBytes.Count();

                myAes.KeySize = 256;
                myAes.Mode = CipherMode.CBC;
                myAes.Key = HexToBin(key);
                myAes.IV = ivBytes;
                myAes.Padding = PaddingMode.PKCS7;

                char[] output = new char[256];

                ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);

                using (MemoryStream memory = new MemoryStream(ivBytes))
                {
                    using (CryptoStream cryptStream = new CryptoStream(memory, myDecrypter, CryptoStreamMode.Read))
                    {
                        using (StreamReader reader = new StreamReader(cryptStream))
                        {

                            outputString = reader.ReadToEnd();
                        }

                        return outputString;
                    }
                }

            }
        }

        private static byte[] HexToBin(String hexString)
        {


            int charCount = hexString.Length;
            byte[] output = new byte[charCount / 2];
            for (int i = 0; i < charCount; i += 2)
            {
                output[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
            }


            return output;
        }

        private static String getSSN(String cipher)
        {
            int delimiterIndex = cipher.IndexOf(":");
            String SSN = cipher.Substring(0, delimiterIndex);
            return SSN;
        }


        private static String getIV(String cipher)
        {
            int delimiterIndex = cipher.IndexOf(":");
            String IV = cipher.Substring(delimiterIndex + 1);
            return IV;
        }




        // Reference: https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa
        private static string ByteArrayToString(byte[] ba)
        {
            string hex = BitConverter.ToString(ba);
            return hex.Replace("-", "");
        }

    }
}

Line 73 (where the exception is encountered) is the end of the using block for the StreamReader in the decrypt method:

    using (StreamReader reader = new StreamReader(cryptStream))
                    {

                        outputString = reader.ReadToEnd();
                    }

I referenced the following question, but could not resolve my issue.

Originally, the data was encrypted in a PHP application, and decrypted using a C# application (using nearly exactly the same decrypt method above). Now, I am wanting to both encrypt and decrypt the data using C#; however, I must still be able to properly decrypt the existing data (that was encrypted using PHP), so I would rather not modify the decrypt method too much.

Any advice would be appreciated.

KellyM
  • 2,472
  • 6
  • 46
  • 90

1 Answers1

1

You have minor mistake here:

ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);
using (MemoryStream memory = new MemoryStream(ivBytes))

You pass your IV value to decrypt, instead of actually encrypted bytes. Fix:

ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);
using (MemoryStream memory = new MemoryStream(valBytes))
Evk
  • 98,527
  • 8
  • 141
  • 191
  • Thank you so much; that solved it. Looks like diverse mistakes can cause the same exception; great observation. :) – KellyM Dec 11 '17 at 14:57
  • 1
    @Kelly Yes, any mistake that munges up the tail end of the decrypted text will give a 'Bad Padding' exception, as will using the wrong type of padding. Either way, the decrypting code cannot recognise the correct padding and throws the exception. – rossum Dec 11 '17 at 15:10
  • 1
    @KellyMarchewa since you are passing random generated value to decrypt (IV) - you could get any kind of error. If you are lucky and padding was correct - you might decrypt garbage for example. And if you are super lucky and generated IV is the same as encrypted data - it can be even decrypted correctly. – Evk Dec 11 '17 at 15:20