Cifrado / descifrado de archivos de gran tamaño (.NET)

Tengo que encriptar, almacenar y luego descifrar archivos de gran tamaño. ¿Cuál es la mejor manera de hacer eso? Escuché que el cifrado de RSA es caro y se me recomendó usar RSA para encriptar una clave AES y luego usar la clave AES para encriptar los archivos grandes. Cualquier sugerencia con el ejemplo será genial.

Esto puede ayudar

/// Encrypts a file using Rijndael algorithm. /// /// /// 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. /// /// /// 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(); } } 

fuente: http://www.codeproject.com/Articles/26085/File-Encryption-and-Decryption-in-C

En general, la estrategia que ha descrito se usa cuando los datos se cifran en una máquina (como un servidor) y luego se descifran en otra máquina (cliente). El servidor encriptará los datos mediante cifrado de clave simétrica (para rendimiento) con una clave generada recientemente y cifrará esta clave simétrica con una clave pública (que coincida con la clave privada de un cliente). El servidor envía al cliente tanto los datos cifrados como la clave simétrica encriptada. El cliente puede descifrar la clave simétrica con su clave privada y luego usar esta clave simétrica para descifrar los datos. Si está encriptando y descifrando los datos en la misma máquina, puede que no tenga sentido usar tanto RSA como AES ya que no estaría tratando de pasar la clave de cifrado a otra máquina.

El tamaño de un organismo es pequeño, aunque todos sabemos que es caro cuando lo vemos. Guiño guiño.

Intente realizar una evaluación comparativa de algo como lo siguiente en su entorno y vea dónde se encuentra:

EDITAR 13/2/2012: El código se ha actualizado a medida que me he vuelto (imperceptiblemente) más inteligente y también noté algunos errores cut’n’paste que se habían infiltrado. 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. /// Decrypt a file. /// 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. /// The full path and name of the file to be decrypted. /// The full path and name of the file to be output. /// The password for the decryption. /// The salt to be applied to the password. /// The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption. 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; } } } } /// Encrypt a file. /// The full path and name of the file to be encrypted. /// The full path and name of the file to be output. /// The password for the encryption. /// The salt to be applied to the password. /// The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption. 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); } } } } 

Como oíste, la criptografía asimétrica, como RSA, es mucho más lenta que la criptografía simétrica (por ejemplo, AES) pero tiene sus ventajas (gestión de claves más simple, por ejemplo, una clave privada única para proteger).

La clave (juego de palabras intencionado) es utilizar las ventajas de ambas (clave privada de asimétrica y velocidad de simétrica) mientras se ignoran las molestias de la otra (muchas claves secretas y baja velocidad).

Puede hacerlo utilizando RSA una vez por archivo (sin gran impacto en el rendimiento) para cifrar una clave secreta (simétrica) que se utiliza para encriptar (mucho más rápido) su archivo grande. Este * ajuste de la clave simétrica le permite administrar solo una clave privada única.

Aquí hay un enlace a mi antigua (pero verdadera) publicación de blog que da un ejemplo para hacer esto usando C # y .NET framework (Microsoft of Mono).