1

I am getting the error Padding is invalid and cannot be removed while trying to decrypt a string using AesCryptoServiceProvider. According to this question I need to specify the same padding on both the Encryption and Decryption algorithms. The problem I have is that there is already data that has been encrypted without the explicit padding. What is the default padding that was used in that case so I can explicitly set it?

Here's the code being used:

public static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
  // Check arguments. 
  if (plainText == null || plainText.Length <= 0)
    throw new ArgumentNullException("plainText");
  if (Key == null || Key.Length <= 0)
    throw new ArgumentNullException("Key");
  if (IV == null || IV.Length <= 0)
    throw new ArgumentNullException("Key");
  byte[] encrypted;
  // Create an AesCryptoServiceProvider object 
  // with the specified key and IV. 
  using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
  {
    aesAlg.Key = Key;
    aesAlg.IV = IV;
    // Create a decrytor to perform the stream transform.
    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

    // 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 encrypted;
}

public static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
  // Check arguments. 
  if (cipherText == null || cipherText.Length <= 0)
    throw new ArgumentNullException("cipherText");
  if (Key == null || Key.Length <= 0)
    throw new ArgumentNullException("Key");
  if (IV == null || IV.Length <= 0)
    throw new ArgumentNullException("Key");

  string plaintext = null;
  using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
  {
    aesAlg.Key = Key;
    aesAlg.IV = IV;

    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
    {
      using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
      {
        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
        {
          plaintext = srDecrypt.ReadToEnd();
        }
      }
    }
  }
  return plaintext;
}

The Key and the IV are being retrieved using Rfc2898DeriveBytes given a password and a salt. Bellow is the code:

public static void GetKeyAndIVFromPasswordAndSalt(string password, byte[] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv)
{
  Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);
  key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
  iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);
}
Community
  • 1
  • 1
Jonas Stawski
  • 6,682
  • 6
  • 61
  • 106
  • Not sure -- just a hunch -- but don't you need to be calling `csEncrypt.FlushFinalBlock()` before reading from your MemoryStream's buffer? – wgraham Aug 16 '13 at 19:07
  • are you storing the string in a database or somewhere that is a fixed size? the encrypted version may be longer than the storage type and thus truncating part of the padding. – dave k Aug 16 '13 at 20:19
  • @davek that's another thing I thought. I'm storing it as a binary(16) as all the tests I did had a length of 16 and since all strings will be 9 characters I figured it will always be 16. Is that correct or should I be using bigger binary? – Jonas Stawski Aug 16 '13 at 20:21
  • Just as an FYI, the root cause of the problem was the password used to generate the Key and the IV were different on the encryption than that of the decryption resulting in this error. – Jonas Stawski Oct 02 '13 at 15:34

1 Answers1

3

The default modes for symmetric algorithms can be found in the SymmetricAlgorithm Properties page on the MSDN. In this case, PaddingMode.PKCS7 is the default padding mode used.

Be aware, however, that this specific Cryptographic Exception can be thrown in different circumstances as well. If your Key and/or IV aren't the exact same ones that were used in the encryption of your data then this exception will be thrown. The second answer in the question you linked discusses this.

Community
  • 1
  • 1
Ichabod Clay
  • 1,981
  • 13
  • 17
  • I use `Rfc2898DeriveBytes` to get the `key` and `iv` and I pass in a `password` and a `salt` which should always be the same for the specific encryption/decryption. This is running as an Azure Website. Is it possible that the `key` and `iv` would be different based on which machine the user is hitting i.e. different `MachineKey`? – Jonas Stawski Aug 16 '13 at 20:05
  • Honestly, I'm not at all familiar with the workings of the Web side of C#. Although, I don't see why things would change between machines if they're all using the same way to derive the key/iv. I'd say the best way (but probably not the easiest) is to do test derivations and see if you get the same keys and ivs. – Ichabod Clay Aug 16 '13 at 20:28
  • If `Rfc2898DeriveBytes` uses the [MachineKey](http://msdn.microsoft.com/en-us/library/w8h3skw9(v=vs.100).aspx) and it is not explicitly set it could be generating different `key` and `iv` depending on the machine it is hitting. But I'm not sure that is the case. – Jonas Stawski Aug 16 '13 at 20:33
  • I've done encryption/decryption before using AES along with the derive bytes class in a simple command line program. It was done across different computers without implementing anything related to asp.net, which is why I doubt `Rfc2898DeriveBytes` implements MachineKey (although the reverse might be true, but who knows). Unfortunately, that's all I can think of off the top of my head. Your best bets are looking at the keys/ivs themselves, making sure the encrypted data isn't corrupted, or the padding mode (which I doubt is the case if everything is set at default). – Ichabod Clay Aug 16 '13 at 21:22
  • In my case, I was using the wrong Key/IV and received this error. Thank you for pointing out that this error has multiple causes! – EnterTheCode May 21 '20 at 17:24