I needed some simple string encryption, so I wrote the following code (with a great deal of "inspiration" from here):
// create and initialize a crypto algorithm private static SymmetricAlgorithm getAlgorithm(string password) { SymmetricAlgorithm algorithm = Rijndael.Create(); Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes( password, new byte[] { 0x53,0x6f,0x64,0x69,0x75,0x6d,0x20, // salty goodness 0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65 } ); algorithm.Padding = PaddingMode.ISO10126; algorithm.Key = rdb.GetBytes(32); algorithm.IV = rdb.GetBytes(16); return algorithm; } /* * encryptString * provides simple encryption of a string, with a given password */ public static string encryptString(string clearText, string password) { SymmetricAlgorithm algorithm = getAlgorithm(password); byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText); MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(clearBytes, 0, clearBytes.Length); cs.Close(); return Convert.ToBase64String(ms.ToArray()); } /* * decryptString * provides simple decryption of a string, with a given password */ public static string decryptString(string cipherText, string password) { SymmetricAlgorithm algorithm = getAlgorithm(password); byte[] cipherBytes = Convert.FromBase64String(cipherText); MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write); cs.Write(cipherBytes, 0, cipherBytes.Length); cs.Close(); return System.Text.Encoding.Unicode.GetString(ms.ToArray()); }
The code appears to work fine, except that when decrypting data with an incorrect key, I get a CryptographicException - "Padding is invalid and cannot be removed" - on the cs.Close() line in decryptString.
example code:
string password1 = "password"; string password2 = "letmein"; string startClearText = "The quick brown fox jumps over the lazy dog"; string cipherText = encryptString(startClearText, password1); string endClearText = decryptString(cipherText, password2); // exception thrown
My question is, is this to be expected? I would have thought that decrypting with the wrong password would just result in nonsense output, rather than an exception.
Padding is a way to take data that may or may not be a multiple of the block size for a cipher and extend it out so that it is. This is required for many block cipher modes as they require the data to be encrypted to be an exact multiple of the block size.
Although this have been already answered I think it would be a good idea to explain why it is to be expected.
A padding scheme is usually applied because most cryptographic filters are not semantically secure and to prevent some forms of cryptoatacks. For example, usually in RSA the OAEP padding scheme is used which prevents some sorts of attacks (such as a chosen plaintext attack or blinding).
A padding scheme appends some (usually) random garbage to the message m before the message is sent. In the OAEP method, for example, two Oracles are used (this is a simplistic explanation):
That provides you with a randomization for the messages and with a way to test if the message is garbage or not. As the padding scheme is reversible, when you decrypt the message whereas you can't say anything about the integrity of the message itself you can, in fact, make some assertion about the padding and thus you can know if the message has been correctly decrypted or you're doing something wrong (i.e someone has tampered with the message or you're using the wrong key)
I experienced a similar "Padding is invalid and cannot be removed." exception, but in my case the key IV and padding were correct.
It turned out that flushing the crypto stream is all that was missing.
Like this:
MemoryStream msr3 = new MemoryStream(); CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write); encStream.Write(bar2, 0, bar2.Length); // unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding encStream.FlushFinalBlock(); byte[] bar3 = msr3.ToArray();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With