Как ускорить этот метод шифрования C# Filestream

У меня есть метод шифрования, который работает невероятно медленно. Для шифрования нескольких сотен МБ данных требуется около 20 минут. Я не уверен, правильно ли я выбрал подход. Любая помощь, мысли, советы будут с благодарностью.

    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();
}

Спасибо за вашу помощь!

3 ответа

Решение

Хотя шифрование может быть медленным, я бы не ожидал, что это будет проблемой здесь. Я подозреваю, что побайтовый ввод-вывод вызывает ненужные издержки. Самый простой способ исправить это с помощью разумного Stream.CopyTo - и пока вы на это, вы должны использовать using заявления для очистки соответствующим образом:

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);
            }
        }
    }
}

Как отмечалось в других ответах, это не хороший способ создания IV. В общем, я бы предпочел использовать Rijndael.Create() вместо указания RijndaelManaged - и вы, вероятно, захотите использовать using Заявление об этом тоже.

Вы читаете ровно один байт за раз. Это создает много накладных расходов.

Чтобы ускорить обработку, начните использовать больше байтов одновременно или вызовите функцию внутреннего копирования:

fsIn.CopyTo(cs);

MSDN

Чтение одного байта за раз - ужасная идея. Используйте встроенный Stream.CopyTo метод:

fsIn.CopyTo(cs);

Также обратите внимание, что получение IV из того же материала, из которого вы получаете ключ, является плохой практикой и может привести к уязвимостям безопасности. В некоторых случаях он может даже позволить злоумышленнику получить доступ к открытому тексту. Вы должны случайным образом генерировать IV для каждой операции шифрования.

Другие вопросы по тегам