[Android] CryptographicException: Bad PKCS7 padding. Invalid length 0.

Sometimes (but not always) I get this exception on Android device (but not in Editor), built with Unity 5.3.6f1.

CryptographicException: Bad PKCS7 padding. Invalid length 0.
  at Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding, Int32 length, Int32 position) 
  at Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) 
  at Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
  at System.Security.Cryptography.CryptoStream.FlushFinalBlock ()
  ...

I’m using AesManaged { Mode = CipherMode.CFB, Padding = PaddingMode.PKCS7 } with properly specified key and iv for symmetric cryptography.

The code looks like:

using (var decryptor = _aes.CreateDecryptor(_aesKeyBuffer, _aesIVBuffer))
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
    cryptoStream.Write(paddedCiphertext.Array, paddedCiphertext.Offset, paddedCiphertext.Count);
    cryptoStream.Flush();
    // http://stackoverflow.com/questions/18783182/aes-encrypt-memorystream-toarray-empty
    cryptoStream.FlushFinalBlock();
    byte[] plaintextArray = memoryStream.ToArray();
    ...
}

Any ideas?

When I use another approach, still get the same exception (with another trace):

CryptographicException: Bad PKCS7 padding. Invalid length 0.
  at Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding, Int32 length, Int32 position)
  at Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
  at Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
  at System.Security.Cryptography.CryptoStream.Read (System.Byte[] buffer, Int32 offset, Int32 count)
  at System.IO.BinaryReader.ReadBytes (Int32 count)
  ...
using (var decryptor = _aes.CreateDecryptor(_aesKeyBuffer, _aesIVBuffer))
using (var memoryStream = new MemoryStream(paddedCiphertext.Array, paddedCiphertext.Offset, paddedCiphertext.Count))
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
    using (var reader = new BinaryReader(cryptoStream))
    {
        byte[] plaintextArray = reader.ReadBytes(paddedCiphertext.Count);
        ...
    }
}

Works fine in Windows Editor. Looks like a bug in Mono crypto. Can anyone confirm this?

Fixed by replacing AesManaged with equivalent Rijndael (BlockSize = 16 bytes, KeySize = 32 bytes). The error has gone. Mono cryptography is just broken.

Remind me please, why we are still stuck to out-of-date, suboptimal, and buggy version of Mono?

2 Likes

I have the same issue in 2017.3.1, works fine in 5.6.5

It appears that not every encryption mode is supported by .net 2.0 subset, switching to full .net 2.0 api compatibility or choosing a different encryption mode might work.

1 Like

Same issue, but in editor too. 2018.2.10f1. But…But… My unit tests are passes: one test encrypts, another decrypts.

AesCryptoServiceProvider not supported by .net 2.0 subset.
AesManaged supported.
I tried DES then. For DES “Bad PKCS7 padding. Invalid lengh x” exception was fixed by specifying padding in encryptor and decryptor methods for DesCryptoServiseProvider.

Nope. It is not fixed. Encrypt → Decrypt → (change some data) → Encrypt → Decrypt(Bad PKCS7 Exception).

I confirm the problem still exist in 2021.2.x.

I get the other error,when do Decrypt.
Error is : CryptographicException: Bad PKCS7 padding. Invalid length 154.
at System.Security.Cryptography.CryptoStream.Read

my code is:

some one say:
Removed the call to CryptoStream.FlushFinalBlock() in the Encrypt method.
I will try

Can anyone please share a solution? I am running into the same issue. What makes me curious is that it is a sometimes issue and doesn’t happen on the editor (or maybe not enough lucky to see it appear on the editor?). My code is pasted below:

private const string KeyString = "my-32-byte-secret-key-go-here...";

public static byte[] EncryptToByte(string plainText)
{
    byte[] cipherData;
    Aes aes = Aes.Create();
    aes.Key = Encoding.UTF8.GetBytes(KeyString);
    aes.GenerateIV();
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;
    ICryptoTransform cipher = aes.CreateEncryptor(aes.Key, aes.IV);

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, cipher, CryptoStreamMode.Write))
        {
            using (StreamWriter sw = new StreamWriter(cs))
            {
                sw.Write(plainText);
            }
        }
        cipherData = ms.ToArray();
    }

    byte[] combinedData = new byte[aes.IV.Length + cipherData.Length];
    Array.Copy(aes.IV, 0, combinedData, 0, aes.IV.Length);
    Array.Copy(cipherData, 0, combinedData, aes.IV.Length, cipherData.Length);
    return combinedData;
}

public static string DecryptFromByte(byte[] combinedData)
{
    string plainText;
    Aes aes = Aes.Create();
    aes.Key = Encoding.UTF8.GetBytes(KeyString);
    byte[] iv = new byte[aes.BlockSize / 8];
    byte[] cipherText = new byte[combinedData.Length - iv.Length];
    Array.Copy(combinedData, iv, iv.Length);
    Array.Copy(combinedData, iv.Length, cipherText, 0, cipherText.Length);
    aes.IV = iv;
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;
    ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);

    using (MemoryStream ms = new MemoryStream(cipherText))
    {
        using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                plainText = sr.ReadToEnd();
            }
        }
        return plainText;
    }
}
3 Likes