I have encryption method that runs incredible slowly. It takes around 20 minutes to encrypt several hundred MB of data. I'm not sure if I'm taking the right approach. Any help, thoughts, advice would be greatly appreciated.
private void AES_Encrypt(string inputFile, string outputFile, byte[] passwordBytes, byte[] saltBytes)
{
FileStream fsCrypt = new FileStream(outputFile, FileMode.Create);
RijndaelManaged AES = new RijndaelManaged();
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.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
CryptoStream cs = new CryptoStream(fsCrypt,
AES.CreateEncryptor(),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsCrypt.Flush();
cs.Flush();
fsIn.Flush();
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
Thanks for your help!
While encryption can be slow, I wouldn't expect that to be the issue here. I suspect it's the byte-by-byte IO that's causing unnecessary overhead. The simplest way to fix that is with a judicious call to Stream.CopyTo
- and while you're at it, you should use using
statements to clean up appropriately:
private void AesEncrypt(string inputFile, string outputFile, byte[] passwordBytes, byte[] saltBytes)
{
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
RijndaelManaged aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 128,
Key = key.GetBytes(AES.KeySize / 8),
IV = key.GetBytes(AES.BlockSize / 8),
Padding = PaddingMode.Zeros,
Mode = CipherMode.CBC
};
using (var output = File.Create(outputFile))
{
using (var crypto = new CryptoStream(output, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
using (var input = File.OpenRead(inputFile))
{
input.CopyTo(crypto);
}
}
}
}
As noted on other answers, this isn't a good way of generating an IV. In general I'd prefer to use Rijndael.Create()
instead of specifying RijndaelManaged
- and you'd probably want to use a using
statement for that, too.
See more on this question at Stackoverflow