Rijndael padding or length is invalid

折月煮酒 提交于 2019-12-13 01:37:51

问题


I am trying to encrypt/decrypt a string using eith Rijndael or Aes and the code below.

public class Crypto
{
    private const string defaultVector = "asdfg123456789";
    private const CipherMode cipherMode = CipherMode.CBC;
    //Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7
    private const PaddingMode paddingMode = PaddingMode.ISO10126;
    private const int iterations = 2;
    private static Rijndael GetCrypto(string passphrase)
    {
        var crypt = Rijndael.Create();
        crypt.Mode = cipherMode;
        crypt.Padding = paddingMode;
        crypt.BlockSize = 256;
        crypt.KeySize = 256;
        crypt.Key =
            new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        return crypt;
    }
    public static string Encrypt(string plainText, string passphrase)
    {
        byte[] clearData = Encoding.Unicode.GetBytes(plainText);
        byte[] encryptedData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearData, 0, clearData.Length);
                //cs.FlushFinalBlock(); //Have tried this active and commented with no change.
            }
            encryptedData = ms.ToArray();
        }
        //Changed per Xint0's answer.
        return Convert.ToBase64String(encryptedData);
    }
    public static string Decrypt(string cipherText, string passphrase)
    {
        //Changed per Xint0's answer.
        byte[] encryptedData = Convert.FromBase64String(cipherText);
        byte[] clearData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
                using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(encryptedData, 0, encryptedData.Length);
                    //I have tried adding a cs.FlushFinalBlock(); here as well.
                }
                clearData = ms.ToArray();
        }
        return Encoding.Unicode.GetString(clearData);
    }
}

//Edits: I have changed over the Unicode calls to Convert.ToBase64String per Xint0's answer below.

On the cs.Write in Decrypt method, I am getting the error that "Padding is invalid and cannot be removed."

I have tried setting the padding to PaddingMode.None but I get "Length of the data to encrypt is invalid." on the cs.Write in the Encrypt method.

I've looked at these and nothing they've said seems to work.

Padding is invalid and cannot be removed

Padding is invalid and cannot be removed?

Stack trace shows System.Security.CryptographicException is coming from RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast).


回答1:


I see two problems:

  1. You are not flushing and closing the streams before calling ms.ToArray(). Change it to:

    ...
    using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
    {
        cs.Write(clearData, 0, clearData.Length);
        cs.FlushFinalBlock();
        cs.Close();
    }
    
    ms.Close();
    encryptedData = ms.ToArray();
    ...
    
  2. In Encrypt the resulting byte array encryptedData is NOT a Unicode string, yet you are using a Unicode encoder to get a string from the byte array. Instead of that use System.Convert.ToBase64String() in Encrypt and System.Convert.FromBase64String() in Decrypt.

In Encrypt do:

return System.Convert.ToBase64String(encryptedData);

In Decrypt do:

byte[] encryptedData = System.Convert.FromBase64String(cipherText);

EDIT

The biggest problem is the return value of Encrypt. The result of encrypting the byte representation of a Unicode string is NOT a byte representation of a Unicode string. You should not use the value of encryptedData with Encoding.Unicode.GetString() to get a string representation of the encrypted data. Use System.Convert.ToBase64String() to get a string representation of the encrypted data. Please see the Remarks section in the Encoding Class MSDN Documentation.

EDIT 2

Note that Rijndael is not exactly AES, if you are interoperating with AES the block size should always be 128-bits, independent of the key size. For details you can read about it here.




回答2:


I have spend a lot of my time for finding what was causing CryptographicException and I was googling too including Stackoverflow.
It was a stupid mistake (as often when programming with copy-paste) as follow:

It was throwing on method FlushFinalBlock() from instance of CryptoStream.

Look at WRONG code:

CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);

I used it to encrypt so you can see CryptoStreamMode.Write but in the same instruction I was creating decryptor instead of encryptor (see second parameter in the constructor).

Be careful and check it to avoid wasting your precious time ;)

Regards
Bronek




回答3:


I had a similar problem, the issue in decrypt method was initializing an empty memory stream. when it worked when I initialized it with the cipher text byte array like this:

MemoryStream ms = new MemoryStream(cipherText);


来源:https://stackoverflow.com/questions/9574850/rijndael-padding-or-length-is-invalid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!