Reputation: 361
I've been trying to learn some more about System.Security.Cryptography in c# with online docs & samples. So far I have been able to encrypt/decrypt both text and files successfully; however, i got an exception thrown when i tried to decrypt with an incorrect key.
Blockquote System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'
Encryption
private static byte[] EncryptData(SymmetricAlgorithms symmetricAlgorithm, byte[] inputBytes, byte[] key)
{
byte[] output;
using (SymmetricAlgorithm algorithm = SymmetricAlgorithmFactory(symmetricAlgorithm))
{
byte[] encrypted;
byte[] salt = new byte[PBKDF2_SaltBytes];
int maxKeySize = GetLegalKeySizes(algorithm).Max();
_rng.GetBytes(salt); //
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(key, salt, PBKDF2_Iterations))
{
algorithm.Key = pbkdf2.GetBytes(maxKeySize);
}
//algorithm.Padding = PaddingMode.PKCS7;
using (ICryptoTransform cryptoTransform = algorithm.CreateEncryptor())
{
using (MemoryStream inputStream = new MemoryStream(inputBytes), transformedStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(inputStream, cryptoTransform, CryptoStreamMode.Read))
{
cryptoStream.CopyTo(transformedStream);
}
encrypted = transformedStream.ToArray();
}
}
output = new byte[salt.Length + algorithm.IV.Length + encrypted.Length];
Buffer.BlockCopy(salt, 0, output, 0, salt.Length);
Buffer.BlockCopy(algorithm.IV, 0, output, salt.Length, algorithm.IV.Length);
Buffer.BlockCopy(encrypted, 0, output, salt.Length + algorithm.IV.Length, encrypted.Length);
}
return output;
}
Decryption
private static byte[] DecryptData(SymmetricAlgorithms symmetricAlgorithm, byte[] inputBytes, byte[] key)
{
using (SymmetricAlgorithm algorithm = SymmetricAlgorithmFactory(symmetricAlgorithm))
{
byte[] salt = new byte[PBKDF2_SaltBytes];
byte[] iv = new byte[algorithm.IV.Length];
byte[] encryptedData = new byte[inputBytes.Length - salt.Length - iv.Length];
int maxKeySize = GetLegalKeySizes(algorithm).Max();
Buffer.BlockCopy(inputBytes, 0, salt, 0, salt.Length);
Buffer.BlockCopy(inputBytes, salt.Length, iv, 0, iv.Length);
Buffer.BlockCopy(inputBytes, salt.Length + iv.Length, encryptedData, 0, encryptedData.Length);
algorithm.IV = iv;
//algorithm.Padding = PaddingMode.PKCS7;
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(key, salt, PBKDF2_Iterations))
{
algorithm.Key = pbkdf2.GetBytes(maxKeySize);
}
using(ICryptoTransform cryptoTransform = algorithm.CreateDecryptor())
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(encryptedData, 0, encryptedData.Length);
cryptoStream.FlushFinalBlock();
}
return memoryStream.ToArray();
}
}
}
}
SymmetricAlgorithmFactory returns an SymmetricAlgorithm instance
private static SymmetricAlgorithm SymmetricAlgorithmFactory(SymmetricAlgorithms symmetricAlgorithm)
{
switch (symmetricAlgorithm)
{
case SymmetricAlgorithms.AES:
return new AesCryptoServiceProvider();
case SymmetricAlgorithms.DES:
return new DESCryptoServiceProvider();
case SymmetricAlgorithms.RC2:
return new RC2CryptoServiceProvider();
case SymmetricAlgorithms.Rijndael:
return new RijndaelManaged();
case SymmetricAlgorithms.TripleDES:
return new TripleDESCryptoServiceProvider();
default:
throw new Exception("The provided Symmetric algorithm is not supported.");
}
}
public enum SymmetricAlgorithms
{
AES,
DES,
RC2,
Rijndael,
TripleDES
}
Extra Class properties
private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
private const int PBKDF2_SaltBytes = 8; //PBKDF2 recommends 64 bits minimum. 64 / 8 = 8 bytes
private const int PBKDF2_Iterations = 10000;
private static Encoding encoding = Encoding.UTF32;
Using AES to test, I then tried to change the padding property and got some different messages
PaddingMode.None
- Encryption method threw exception
Blockquote System.Security.Cryptography.CryptographicException: 'The input data is not a complete block.'
PaddingMode.PKCS7 + PaddingMode.ANSIX923 + PaddingMode.ISO10126
- Decryption method threw exception
Blockquote System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'
PaddingMode.Zeros
- This seemed to work with both a correct and incorrect key
Would anyone be able to help my understanding of the padding and why certain modes fail? Would it be a situation where different padding is needed for each of the different Symmetric Algorithms?
Upvotes: 0
Views: 1912
Reputation: 15693
Wikipedia has an article on Cryptographic padding which might help.
Block ciphers encrypt data in block sized chunks. Most messages are not an exact number of blocks, so padding is needed to fill out the last block to the right size. On decryption the padding is removed automatically.
In your case the decryption is not recognising the padding and complaining.
Possible causes are many. An incorrect key will mangle everything, including the padding. Indeed any decryption error will munge the padding, causing this problem.
Obviously if the encryption function applies one type of padding and the decryption function expects a different type then you will get this problem. Check that both sides are using the same padding. Unless you have a good reason otherwise, use PKCS#7.
When you set PaddingMode.None
the encryption method did not add padding, so the last block was unpadded and hence the wrong size. Thus the encryption side flagged it. That mode is only useful for fixed size messages that are already a whole number of blocks.
PaddingMode.Zeros
might work if there are trailing zeros on the last block. The problem is that it will lose all trailing zeros in the original message if present. Not recommended.
Using multiple padding modes is very unusual; one is sufficient. I suspect that the decryption method picked the wrong mode of the three to try first.
Upvotes: 2