Reputation: 75
I am performing independent encrypt-decrypt (1st app performs enc 2nd decrypts) While decryption I either get "Padding invalid" or "Length of data to decrypt is invalid" error.Any help is appreciated thanks My encryption code:
static void EncryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Create))
{
fsCrypt.Write(salt, 0, salt.Length);
}
int bytesToRead = 128 * 1024 * 1024; // 128MB
byte[] buffer = new byte[bytesToRead]; // create the array that will be used encrypted
long fileOffset = 0;
int read = 0;
bool allRead = false;
while (!allRead)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
fs.Seek(fileOffset, SeekOrigin.Begin); // continue reading from where we were...
read = fs.Read(buffer, 0, bytesToRead); // read the next chunk
}
if (read == 0)
allRead = true;
else
fileOffset += read;
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Open)) // automatically dispose fsCrypt
{
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
fsCrypt.Seek(fileOffset, SeekOrigin.End);
cs.FlushFinalBlock();
cs.Write(buffer, 0, read);
}
}
}
}
and My decryption code:
public void DecryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
string extension = System.IO.Path.GetExtension(file);
string result = file.Substring(0, file.Length - extension.Length);
using (FileStream destination = new FileStream(result, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
try
{
using (FileStream source = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
catch (CryptographicException exception)
{
if (exception.Message == "Padding is invalid and cannot be removed.")
throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
else
throw;
}
}
}
}
Upvotes: 1
Views: 1804
Reputation: 93978
The following calls are executed in the wrong order:
cs.FlushFinalBlock();
and
cs.Write(buffer, 0, read);
FlushFinalBlock
should always come last (it will be automatically called when the stream is closed though, so it should be OK if you don't close the underlying stream first). FlushFinalBlock
should certainly never be called in a (while
) loop.
The buffer handling is not correct: the streams should not be closed and opened all the time. Instead a block of bytes should be read, then written to the crypto stream. The using
statements should be outside the while
loop.
For CFB mode PaddingMode.PKCS7
should be set. Padding is not required at all for CFB. Unfortunately .NET seems to have a buggy implementation that does require padding to be used in combination to the streams.
Upvotes: 2