Description
I am using a slightly modified security class taken straight from codeproject.com, I am using it to encrypt/decrypt aes byte arrays.
I have tested that the key generation method in these produces the same key, and they are given the same password and salt. they also have the same IV
the error is always on the line after the CryptoStream.Write
in the AES_Decrypt
function
"An unhandled exception of type 'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
Additional information: Padding is invalid and cannot be removed."
(yes i know having a static salt is bad, this is only for testing purposes)
Solutions that didn't work
Paddingmode.Zeros
Paddingmode.None
.FlushFinalBlock();
Related Questions
- "Padding is invalid and cannot be removed" using AesManaged
- Padding is invalid and cannot be removed?
- Padding is invalid and cannot be removed Exception while decrypting string using "AesManaged" C#
- Error RijndaelManaged, "Padding is invalid and cannot be removed"
Related Links
- https://social.msdn.microsoft.com/Forums/vstudio/en-US/d1788582-bf8c-43ec-a686-49647c359136/unexplained-cryptographicexception-padding-is-invalid?forum=netfxbcl
- http://www.codeproject.com/Questions/379525/Padding-is-invalid-and-cannot-be-removed-Exception
Code
using System.Security.Cryptography;
using System.IO;
using System;
namespace FinexCore
{
public class Security
{
/*
* AES encrypt and decrypt from:
* http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt
*/
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
private byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8}; //8 bytes
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.Padding = PaddingMode.PKCS7;
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.FlushFinalBlock();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.Padding = PaddingMode.PKCS7;
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.FlushFinalBlock();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
public void Wipe()
{
Array.Clear(saltBytes, 0, saltBytes.Length);
}
}
}
note: the save and load functions are called with the exact same password
The code that calls the encryption
public void Load(byte[] password)
{
Security decryptor = new Security();
byte[] bytes = decryptor.AES_Decrypt(System.IO.File.ReadAllBytes(Pathname()), password);
using (MemoryStream stream = new MemoryStream(bytes))
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Root = (Folder)binaryFormatter.Deserialize(stream);
}
Array.Clear(bytes, 0, bytes.Length);
Array.Clear(password, 0, password.Length);
decryptor.Wipe();
}
public void Save(byte[] password)
{
byte[] bytes;
using (MemoryStream stream = new MemoryStream())
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, Root);
bytes = stream.ToArray();
}
Security encryptor = new Security();
bytes = encryptor.AES_Encrypt(bytes, password);
System.IO.File.WriteAllBytes(Pathname(), bytes);
Array.Clear(bytes, 0, bytes.Length);
Array.Clear(password, 0, password.Length);
encryptor.Wipe();
}
Code for testing key generation
static void keytests()
{
byte[] passwordBytes = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] saltBytes = { 1, 2, 3, 4, 5, 6, 7, 8};
int iterations = 1000;
var key1 = new Rfc2898DeriveBytes(passwordBytes, saltBytes, iterations);
var key2 = new Rfc2898DeriveBytes(passwordBytes, saltBytes, iterations);
Console.WriteLine(BTS(key1.GetBytes(256 / 8)));
Console.WriteLine(BTS(key2.GetBytes(256 / 8)));
}
public static string BTS(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}