Padding is invalid and cannot be removed Exception while decrypting string using "AesManaged" C#
Asked Answered
D

2

6

Please suggest me where i need to update/refactor the code to get rid of exception. I am getting exception while I try to decrypt the encrypted string using following code.

Following line is throwing exception

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

public string EncryptAuthenticationTokenAes(string plainText)
{

    byte[] encrypted;
    // Create an AesManaged object
    // with the specified key and IV.
    using (AesManaged aesAlg = new AesManaged())
    {

        // Create a decrytor to perform the stream transform.
        ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
        aesAlg.Padding = PaddingMode.None;
        // 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 Convert.ToBase64String(encrypted);

}

public string DecryptPasswordAes(string encryptedString)
{
    //Convert cipher text back to byte array
    byte[] cipherText = Convert.FromBase64String(encryptedString);

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

    // Create an AesManaged object
    // with the specified key and IV.
    using (AesManaged aesAlg = new AesManaged())
    {
        // Create a decrytor to perform the stream transform.
        ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
        aesAlg.Padding = PaddingMode.None;
        // 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;

}
Drava answered 6/5, 2012 at 10:25 Comment(1)
I found actually the problem in calling of encryption and decryption methods, as the both are using different Key and IV. when i passed the same Key and IV the problem get resolved.Drava
S
19

Pretty standard bug when using CryptoStream, you forgot to force it to encrypt the last bytes of the stream. It keeps bytes in an internal buffer until enough of them arrive to emit a block. You must force the last few bytes out. Fix:

    using (var msEncrypt = new MemoryStream())
    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    using (var swEncrypt = new StreamWriter(csEncrypt)) {
        swEncrypt.Write(plainText);
        csEncrypt.FlushFinalBlock();
        encrypted = msEncrypt.ToArray();
    }

You got the exception when decrypting it because encrypted is missing the final padding. The real problem is caused by the using statement, you wouldn't have this problem if you waited obtaining the encrypted bytes until after the CryptoStream is closed. But that doesn't work well because the using statement on the StreamWriter also closes the CryptoStream and the MemoryStream. Explicitly using FlushFinalBlock() is the best workaround.

Spracklen answered 6/5, 2012 at 12:5 Comment(6)
For some reason that approach did not work for me in C# 4.0/4.5 - had to put curly braces after each using( ). Than no .FlushFinalBlock( ) call is needed. See stackoverflow.com/questions/29809687/#29835039.Gullah
@Astrogator: That makes no sense and was not the source/fix. Curlies are optional and do not (in this case) change the semantics.Sheriff
@EdS. Not the cause for this one, but check my linked question. I also decided that curlies {} were unnecessary - and got bitten by that. They may not change semantics, but they certainly did affect execution order because restoring them fixed my code. That's all i wanted to warn about.Gullah
@Astrogator: Oh, well sure; you moved a line of close to a completely different scope.Sheriff
@EdS. The order of execution of finalisers (and => object closures), affected by presence or absence of curlies {}, was important in my question. I asked it, answered it myself, shared my experience, and warned others who'd stumble on this Q. 4 years later you just came to this one, dissed my comment, and then downvoted my answer. Not cool, dude!Gullah
@Astrogator: I didn't "diss" your comment; the way you phrased it was vague and didn't make much sense on it's face. If you had said "I moved use of the variable outside the enclosing scope of the other stream" I wouldn't have said anything. You didn't say that though, you said "I had to put curly braces after each using block." That does not imply you moved use after Dispose had been called on the stream, so I stand by "that makes no sense". "Curly braces" had nothing to do with it; you changed the order of operations.Sheriff
M
0
    swEncrypt.Write(plainText);
    swEncrypt.Flush();
    csEncrypt.FlushFinalBlock();
    encrypted = msEncrypt.ToArray();

Calling swEncrypt.Flush() before csEncrypt.FlushFinalBlock() solved my problem.

Merrileemerrili answered 17/5, 2023 at 5:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.