2

I want to encrypt/ decrypt my access token using Aes. Encryption part is successful working. But my problem is when decrypting the encrypted access token following error is occurred

Padding is invalid and cannot be removed.

Following line is throwing an exception:

 using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }

Can anyone tell me what I can do to solve this issue? (as a console application)

 class Program
    {
        private static string keyString = "E546C8DF278CD5931069B522E695D4F2";
        static void Main(string[] args)
        {
            var text = "a16df7367e9eca23ac5e071dc4449a7a";
            Console.WriteLine(EncryptString(text)); ;
            Console.WriteLine(DecryptString(EncryptString(text)));
            Console.ReadLine();
        }

        public static string EncryptString(string text)
        {
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }

                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        return Convert.ToBase64String(result);
                    }
                }
            }
        }

        public static string DecryptString(string cipherText)
        {
            var fullCipher = Convert.FromBase64String(cipherText);

            var iv = new byte[16];
            var cipher = new byte[16];

            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
        }
    }
Krishan
  • 2,356
  • 6
  • 36
  • 47
  • The iv should be the same in both encryption and decryption. – jdweng Nov 27 '17 at 07:55
  • Did you try the suggestion in [this question](https://stackoverflow.com/questions/8583112/padding-is-invalid-and-cannot-be-removed) (set padding explicitly ?) – Tewr Nov 27 '17 at 07:56
  • 1
    Notice in your encryption code how you compute the size of the final array using two existing arrays, one of who's length is only known after encryption? And how in decryption, you arbitrarily decide that the entire `cipher` is just 16 bytes? – Damien_The_Unbeliever Nov 27 '17 at 08:04
  • Side note: better not pass arbitrary key to CreateEncryptor (and CreateDecryptor), because it has bug with size validation (on full .NET at least) and will allow less than 128 bit keys. Better assign key first to `aes` instance and pass that. – Evk Nov 27 '17 at 08:34

1 Answers1

3

You should change it

        var iv = new byte[16];
        var cipher = new byte[16];

        Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
        Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);

to

        var iv = new byte[16];
        var cipher = new byte[fullCipher.Length - 16]; //Calculate correct byte size

        Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
        Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, cipher.Length);  //Change destination count of copied bytes

Cipher array size can't be 16 bytes by default you should calculate it.

lucky
  • 12,734
  • 4
  • 24
  • 46