Шифрование/Расшифровка больших файлов (.NET)
Мне нужно зашифровать, сохранить и затем расшифровать большие файлы. Каков наилучший способ сделать это? Я слышал, что шифрование RSA дорогое, и было рекомендовано использовать RSA для шифрования ключа AES, а затем использовать ключ AES для шифрования больших файлов. Любые предложения с примером будут замечательными.
Ответы
Ответ 1
Как правило, описанная вами стратегия используется, когда данные будут зашифрованы на одном компьютере (например, на сервере), а затем дешифрованы другой машиной (клиентом). Сервер будет шифровать данные с помощью симметричного шифрования ключа (для повышения производительности) с вновь созданным ключом и зашифровать этот симметричный ключ с открытым ключом (соответствующий закрытому ключу клиента). Сервер отправляет клиенту как зашифрованные данные, так и зашифрованный симметричный ключ. Клиент может расшифровать симметричный ключ с помощью закрытого ключа, а затем использовать этот симметричный ключ для дешифрования данных.
Если вы шифруете и дешифруете данные на одном компьютере, может не иметь смысла использовать RSA и AES, поскольку вы не пытаетесь передать ключ шифрования на другой компьютер.
Ответ 2
Это может помочь
/// 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
Ответ 3
Один большой организм - еще один маленький, хотя мы все знаем дорого, когда видим его. Подвинь, подмигивай.
Попробуйте сравнить в своей среде что-то вроде следующего:
РЕДАКТИРОВАТЬ 2/13/2012: Код был обновлен, так как я стал (незаметно) умнее, а также заметил несколько ошибок с ошибкой cut'n'paste, которые вписались. 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);
}
}
}
}
Ответ 4
Как вы слышали, асимметричная криптография, такая как RSA, намного медленнее симметричной криптографии (например, AES), но она имеет преимущества (более простое управление ключами, например, один закрытый ключ для защиты).
Ключ (предназначенный для каламбура) - использовать преимущества обоих (закрытый ключ асимметричного и скорость симметричного), игнорируя при этом неудобства другого (многие секретные ключи и медленная скорость).
Вы можете сделать это, используя RSA один раз для каждого файла (без огромного влияния на производительность) для шифрования (симметричного) секретного ключа, который используется для шифрования (намного быстрее) вашего большого файла. Эта * упаковка симметричного ключа позволяет вам управлять только одним закрытым ключом.
Здесь ссылка на мой старый (но все еще верный) пост в блоге, который дает пример для этого, используя С# и .NET framework ( Microsoft из Mono).