Шифрование / дешифрование больших файлов (.NET) - PullRequest
24 голосов
/ 11 февраля 2012

Я должен зашифровать, сохранить, а затем расшифровать большие файлы. Каков наилучший способ сделать это? Я слышал, что шифрование RSA стоит дорого, и мне посоветовали использовать RSA для шифрования ключа AES, а затем использовать ключ AES для шифрования больших файлов. Любые предложения с примером будут отличными.

Ответы [ 4 ]

14 голосов
/ 11 февраля 2012

Один большой организм - это маленькая, хотя мы все знаем, что дорого, когда видим это.Wink, wink.

Попробуйте сравнить что-то вроде следующего в своей среде и посмотрите, где вы находитесь:

РЕДАКТИРОВАТЬ 13/02/2012: код был обновлен, как яВы стали (незаметно) умнее, а также заметили несколько ошибок резки и вставки. Mea culpa.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

...

    // Rfc2898DeriveBytes constants:
    public readonly byte[] salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Must be at least eight bytes.  MAKE THIS SALTIER!
    public const int iterations = 1042; // Recommendation is >= 1000.

    /// <summary>Decrypt a file.</summary>
    /// <remarks>NB: "Padding is invalid and cannot be removed." is the Universal CryptoServices error.  Make sure the password, salt and iterations are correct before getting nervous.</remarks>
    /// <param name="sourceFilename">The full path and name of the file to be decrypted.</param>
    /// <param name="destinationFilename">The full path and name of the file to be output.</param>
    /// <param name="password">The password for the decryption.</param>
    /// <param name="salt">The salt to be applied to the password.</param>
    /// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
    public void DecryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
    {
        AesManaged aes = new AesManaged();
        aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
        aes.KeySize = aes.LegalKeySizes[0].MaxSize;
        // NB: Rfc2898DeriveBytes initialization and subsequent calls to   GetBytes   must be eactly the same, including order, on both the encryption and decryption sides.
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
        aes.Key = key.GetBytes(aes.KeySize / 8);
        aes.IV = key.GetBytes(aes.BlockSize / 8);
        aes.Mode = CipherMode.CBC;
        ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);

        using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
        {
            using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
            {
                try
                {
                    using (FileStream source = new FileStream(sourceFilename, 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;
                }
            }
        }
    }

    /// <summary>Encrypt a file.</summary>
    /// <param name="sourceFilename">The full path and name of the file to be encrypted.</param>
    /// <param name="destinationFilename">The full path and name of the file to be output.</param>
    /// <param name="password">The password for the encryption.</param>
    /// <param name="salt">The salt to be applied to the password.</param>
    /// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
    public void EncryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
    {
        AesManaged aes = new AesManaged();
        aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
        aes.KeySize = aes.LegalKeySizes[0].MaxSize;
        // NB: Rfc2898DeriveBytes initialization and subsequent calls to   GetBytes   must be eactly the same, including order, on both the encryption and decryption sides.
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
        aes.Key = key.GetBytes(aes.KeySize / 8);
        aes.IV = key.GetBytes(aes.BlockSize / 8);
        aes.Mode = CipherMode.CBC;
        ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);

        using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
        {
            using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
            {
                using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    source.CopyTo(cryptoStream);
                }
            }
        }
    }
13 голосов
/ 20 марта 2013

Это может помочь

/// Encrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private void EncryptFile(string inputFile, string outputFile)
{

    try
    {
        string password = @"myKey123"; // Your Key Here
        UnicodeEncoding UE = new UnicodeEncoding();
        byte[] key = UE.GetBytes(password);

        string cryptFile = outputFile;
        FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);

        RijndaelManaged RMCrypto = new RijndaelManaged();

        CryptoStream cs = new CryptoStream(fsCrypt,
            RMCrypto.CreateEncryptor(key, key),
            CryptoStreamMode.Write);

        FileStream fsIn = new FileStream(inputFile, FileMode.Open);

        int data;
        while ((data = fsIn.ReadByte()) != -1)
            cs.WriteByte((byte)data);


        fsIn.Close();
        cs.Close();
        fsCrypt.Close();
    }
    catch
    {
        MessageBox.Show("Encryption failed!", "Error");
    }
}

///
/// Decrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private void DecryptFile(string inputFile, string outputFile)
{

    {
        string password = @"myKey123"; // Your Key Here

        UnicodeEncoding UE = new UnicodeEncoding();
        byte[] key = UE.GetBytes(password);

        FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);

        RijndaelManaged RMCrypto = new RijndaelManaged();

        CryptoStream cs = new CryptoStream(fsCrypt,
            RMCrypto.CreateDecryptor(key, key),
            CryptoStreamMode.Read);

        FileStream fsOut = new FileStream(outputFile, FileMode.Create);

        int data;
        while ((data = cs.ReadByte()) != -1)
            fsOut.WriteByte((byte)data);

        fsOut.Close();
        cs.Close();
        fsCrypt.Close();

    }
}

Источник: http://www.codeproject.com/Articles/26085/File-Encryption-and-Decryption-in-C

10 голосов
/ 11 февраля 2012

Обычно описанная вами стратегия используется, когда данные будут зашифрованы на одном компьютере (например, на сервере), а затем расшифрованы на другом компьютере (клиенте).Сервер зашифрует данные с использованием симметричного ключа (для повышения производительности) с помощью нового сгенерированного ключа и зашифрует этот симметричный ключ с помощью открытого ключа (соответствующего личному ключу клиента).Сервер отправляет клиенту как зашифрованные данные, так и зашифрованный симметричный ключ.Клиент может расшифровать симметричный ключ с помощью своего закрытого ключа, а затем использовать этот симметричный ключ для расшифровки данных.Если вы шифруете и дешифруете данные на одном и том же компьютере, возможно, не имеет смысла использовать как RSA, так и AES, поскольку вы не пытаетесь передать ключ шифрования на другой компьютер.

4 голосов
/ 11 февраля 2012

Как вы слышали, асимметричная криптография, такая как RSA, намного медленнее, чем симметричная криптография (например, AES), но она имеет свои преимущества (более простое управление ключами, например, один закрытый ключ для защиты).

Ключ (предназначенный для каламбура) состоит в том, чтобы использовать преимущества обоих (закрытый ключ асимметричного и симметричного быстродействия), игнорируя при этом неудобство другого (множество секретных ключей и медленную скорость).

ВыЭто можно сделать, используя RSA один раз для каждого файла (без значительного снижения производительности), чтобы зашифровать (симметричный) секретный ключ, который используется для шифрования (намного быстрее) вашего большого файла.Эта * упаковка симметричного ключа позволяет вам управлять только одним, закрытым ключом.

Вот ссылка на мой старый (но все еще верный) пост в блоге , которыйдает пример, чтобы сделать это, используя C # и .NET Framework (Microsoft of Mono).

...