2012-02-11 17 views
15

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.Encriptación/descifrado de archivos de gran tamaño (.NET)

+0

Aquí es un ejemplo [blog anuncio] (http://www.technical-recipes.com/2013/using-rsa-to- encrypt-large-data-files-in-c /), con descargables [proyecto de Visual Studio 2010] (http://www.technical-recipes.com/Downloads/crypt.7z) que hace justamente eso. – AndyUK

Respuesta

10

Generalmente, 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.

+1

Gracias, pero mi problema es ligeramente diferente. Quiero encriptar los archivos grandes y luego almacenarlos y el cifrado (es decir, la seguridad) es necesario en caso de que el almacenamiento se vea comprometido. Para la comunicación del servidor del cliente, envío la clave AES cifrada con RSA, ¿cómo se transalta en mi escenario? ¿Guardo la clave AES como parte de los bytes pendientes o añadidos del blob cifrado de la clave simétrica? – kalrashi

+0

Un gran ejemplo se encuentra realmente en el documento X509Certificate2 de MSDN (estaba buscando en RSACryptoProvider y clases relacionadas): – kalrashi

8

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

Trate de evaluación comparativa algo como lo siguiente en su entorno y ver dónde estás en:

EDITAR 2/13/2012: El código se ha actualizado como me he vuelto (imperceptible) 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. 

    /// <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); 
       } 
      } 
     } 
    } 
+0

Este ejemplo solo encripta/descifra usando AES.¿Quiere decir que pruebe algo similar con RSA y perfil ambos? – kalrashi

+0

Depende de usted. Su pregunta no explicó la (s) amenaza (s) percibida (s) contra los datos, el tamaño de los archivos, cualquier transferencia de red o exposición involucrada, recursos de procesamiento disponibles, .... En este caso, parece que haría bien en recopilar al menos un poco de datos de referencia sobre el costo del cifrado en su entorno y trabajar desde allí. Otros han tocado la criptografía de clave pública y privada y la fuerza relativa de diferentes algoritmos. – HABO

+2

Para evitar el "Relleno no es válido y no se puede eliminar". excepción, el lado de encriptación tiene que llamar a 'source.FlushFinalBlock()' después de 'source.CopyTo (crytoStream);' de lo contrario, usted confundiría el último bloque. – DipSwitch

3

Al igual que escuchó 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 (más simple de gestión de claves, por ejemplo, una única clave privada para proteger).

La clave (juego de palabras) es utilizar las ventajas de ambas (clave privada de asimétrica y velocidad de simétrica) mientras se ignoran los inconvenientes de la otra (muchas teclas 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. Esta * envoltura de la clave simétrica le permite administrar solo una clave privada única.

Aquí hay un enlace a mi viejo (pero verdadero) blog post que da un ejemplo para hacer esto usando C# y .NET framework (Microsoft of Mono).

+0

Gracias. El ejemplo fue bastante útil. – kalrashi

10

Esto puede ayudar a

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

    } 
} 

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

+2

Este código tiene algunos problemas serios: a) No funciona si la contraseña no tiene suficiente longitud, pero el problema es que una contraseña generalmente es de baja entropía y, por lo tanto, no se puede usar directamente como clave. b) Usar la clave como el IV hace este cifrado determinista y, por lo tanto, no es semánticamente seguro. El IV debe ser generado al azar. No tiene que ser secreto, sino solo impredecible, por lo que se puede escribir simplemente en frente del texto cifrado y utilizarlo durante el descifrado. c) Sin autenticación! El texto cifrado se puede cambiar sin que el destinatario lo detecte. –

Cuestiones relacionadas