Unexplained CryptographicException : Padding is invalid...
I wrote the following functions to encrypt and decrypt a file, and they seemed to work perfectly. However, once I modify the data being saved 2-3 times, I get the following error:
System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(...)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(...)
at System.Security.Cryptography.CryptoStream.Read(...)
at Decrypt(String cipher, String password)public static string Encrypt(string plaintext, string password)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();byte[] plaintextByte = System.Text.Encoding.Unicode.GetBytes(plaintext);
byte[] saltByte = Encoding.ASCII.GetBytes(password.Length.ToString());PasswordDeriveBytes secretKey = new PasswordDeriveBytes(password, saltByte);
ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);cryptoStream.Write(plaintextByte, 0, plaintextByte.Length);
cryptoStream.FlushFinalBlock();byte[] cipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
encryptor.Dispose();return Convert.ToBase64String(cipherBytes);
}public static string Decrypt(string cipher, string password)
{
string ciphertext;
using (StreamReader fsin = new StreamReader(cipher))
{
ciphertext = fsin.ReadToEnd();
}
try
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();byte[] ciphertextByte = Convert.FromBase64String(ciphertext);
byte[] saltByte = Encoding.ASCII.GetBytes(password.Length.ToString());PasswordDeriveBytes secretKey = new PasswordDeriveBytes(password, saltByte);
ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(ciphertextByte);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);byte[] plainText = new byte[ciphertextByte.Length];
int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
memoryStream.Close();
cryptoStream.Close();return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
}
catch (Exception e)
{
throw new InvalidDataException("[" + e.ToString() + " : " + e.Message + "] Data corrupt");
}
}public static void Encrypt(string plaintext, string password, string fout)
{
using (StreamWriter fsout = new StreamWriter(fout))
{
fsout.Write(Encrypt(plaintext, password));
}
}Thanks a ton guys!
Answers
- I had the same problem, but when I added this line
rijndael.Padding = PaddingMode.None;
when crypting and encrypting I never saw it again.
Hope it will be help you. - I searched everywhere for a solution to this problem and nothing I tried worked. Finally it occured to me that I had one program which was reading the entire contents of the encrypted file just fine, but the program that didn't read the entire contents of the file would throw the error you specified. I solved the error by making sure I read to the end of the file when decrypting, even if I didn't need all of the data. Since then, I was able to close my CryptoStream just fine without throwing the error.
All Replies
- I had the same problem, but when I added this line
rijndael.Padding = PaddingMode.None;
when crypting and encrypting I never saw it again.
Hope it will be help you. I tried setting Padding = PaddingMode.None, but now when I try to encrypt any string, I get the error - "Invalid length of string to encrypt". Do you know why that is?
- I searched everywhere for a solution to this problem and nothing I tried worked. Finally it occured to me that I had one program which was reading the entire contents of the encrypted file just fine, but the program that didn't read the entire contents of the file would throw the error you specified. I solved the error by making sure I read to the end of the file when decrypting, even if I didn't need all of the data. Since then, I was able to close my CryptoStream just fine without throwing the error.
I, too, had that problem, until I hit on the explanation at http://www.codeproject.com/dotnet/Cryptor.asp.
The suggestions in other replys will sometimes work, by chance, but what you really need to do is set RijndaelAlg.Padding to PaddingMode.ISO10126, PaddingMode.PKCS7, or PaddingMode.ANSIX923. Any one of these 3 values should work, provided that you use the same value when encrypting and decrypting. Other values will work with some data, but not with all data. The above URL explains why.
What I don't understand is the reason Microsoft provides options that sometimes don't work, or at least why they don't default to a reliable option.
Excellent reply. Thanks, was looking all over and as you said, the solutions were random, your solution was the only one that actually made sense and worked.
I did find one other issue with me code in case anyone else has this issue, I was trying to read directly from a file into a cryptostream and that doesn't work because you are giving the length as the file size, and that doesn't leave room for the padding.
You can read or write to/from the crypto stream on either encrypting or decrypting, but one will result in the number of bytes you specify from your source (in my case the file) as the size of the end result of bytes[] and the other does not. If you read half a block and specify the length rather than just output it into a stream, then it will ignore the padding half to make a full block anyway since the length came from the original source's size and you get the error. Yah that sounds confusing but if you are doing what I was, you will know what I’m saying.
Thanks again Steve.
I've got the same exception but my problem was resolved differently.
The file I was writing to was open as OpenOrCreate and I didn't set stream's length back to 0, so if the new encoded stream is shorter then the part of the previous data remains at the end of the file. In such case you are kind of padding the data that's why the exception was thrown.
- I see your message but you do not explain how you read the whole file in at once. I have a Doc.Load("myxml.xml"); where the Doc object is of type XmlDocument. Any ideas on how to get passed the end of the file would be welcome.
Thanks
Rod@bergren.net - Sorry for the late comment, but I want to mention that my solution for this problem was to add
after I declared the CryptoServiceProvider (before using it). I did this for both the encryption and decryption. Previously I had no PaddingMode set for either, which does make me wonder about wacky defaults.MyRijandaelManaged.Padding = PaddingMode.None Fshad
I think I'm having the problem you are describing about block sizes but I don't understand the solution. Could you show us your solution in code please?Thanks
- I have done some Research & development work in encryption. this exception is happening
because of the reasons. I will explain u more about it.
1) u r using different paddingmode format while encrypting & decrypting. & u must use same padding format in both process
for eg:- rjdl.Padding = PaddingMode.PKCS7;
if u r using the above PaddingMode format then use the same thing while decryption
2) u r using the differnet format of Encdoing format's while encryption & decryption
for eg: incase u r using this format of encdoing while encryption
byte[] sbyte = Encoding.ASCII.GetBytes(key.Length.ToString());
then don't change it while decrypting
here I am using ASCII format
don't forget to call the same key when u used for encryption
for better guidence store the key while u r using for encrytpion somewhere in database or somewhere else
& call the same key when u r decrypting. if u have any problem then let me know
I will solve your issue
don't forget to check my website www.bestpals.co.in
I implemented secuirty in this website beyond imagination level
if u want help in coding then mail me sandeepms@bestpals.co.in
sdpms- Proposed As Answer bySandeep M S Saturday, September 13, 2008 4:04 AM
- Edited bySandeep M S Saturday, September 13, 2008 9:07 AMgrammatical errors
- Edited bySandeep M S Saturday, September 13, 2008 5:08 AMI want to help all this regard
- Edited bySandeep M S Saturday, September 13, 2008 5:06 AM
I know this is several years later but I recently ran into the issue and it was all because I didn't do "FlushFinalBlock()" which is basically the same as not writing everything. Now the padding and stuff now works no matter which one I choose.
so yeah, I hope this helps anyone else searching for the answers I was.- Proposed As Answer byKarl Wessels Monday, November 03, 2008 9:01 PM
- I get the same error, but when encrypting and decrypting with a different Key and IV.
- I think that "MemoryStream" should be avoided! "CryptoStream" uses the "buffer" as work area, that later is clean with zeros. Try to use "IsolatedStorageFileStream" or "FileStream." I think that it is not necessary to change the values default of "Rijndael", for most of the situations.
The following sample has three "TextBox" and two "Button", inputTextBox, outputTextBox, resultTextBox, encryptButton, and decryptButton.public partial class Window1 : Window { public Window1() { InitializeComponent(); setupAlgorithm("mypas5w@rd"); } private void encryptButton_Click(object sender, RoutedEventArgs e) { byte[] input = Encoding.Unicode.GetBytes(inputTextBox.Text); using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream("out.dat", FileMode.Create, FileAccess.Write)) { ICryptoTransform encrypto = alg.CreateEncryptor(); using (CryptoStream cStream = new CryptoStream(isoStream, encrypto, CryptoStreamMode.Write)) { cStream.Write(input, 0, input.Length); cStream.FlushFinalBlock(); } } using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream("out.dat", FileMode.Open, FileAccess.Read)) { outputTextBox.Clear(); byte[] bytesRead = new byte[(int)isoStream.Length]; isoStream.Read(bytesRead, 0, bytesRead.Length); foreach (byte b in bytesRead) outputTextBox.AppendText(string.Format("{0:x}", b)); outputTextBox.AppendText("\r\nEncrypted data successfully generated !"); } } private void decryptButton_Click(object sender, RoutedEventArgs e) { try { using (IsolatedStorageFileStream isoFile = new IsolatedStorageFileStream("out.dat", FileMode.Open, FileAccess.Read)) { ICryptoTransform decrypto = alg.CreateDecryptor(); using (CryptoStream eStream = new CryptoStream(isoFile, decrypto, CryptoStreamMode.Read)) { using (StreamReader sr = new StreamReader(eStream, <strong>Encoding.Unicode</strong>)) { resultTextBox.Text = sr.ReadToEnd(); } } } } catch (Exception err) { MessageBox.Show(err.Message); } } Rijndael alg = null; private void setupAlgorithm(string p) { try { alg = Rijndael.Create(); byte[] salt = Encoding.Unicode.GetBytes("thismys@lt"); Rfc2898DeriveBytes passwordKey = new Rfc2898DeriveBytes(p, salt); alg.Key = passwordKey.GetBytes(alg.KeySize / 8); alg.IV = passwordKey.GetBytes(alg.BlockSize / 8); } catch (Exception err) { MessageBox.Show(err.Message); } } }
Obs.: The default Encoding of the "StreamReader" is Encoding.UTF8, then change for Encoding.Unicode !
antonio

