web-dev-qa-db-fra.com

Cryptage / décryptage de fichiers volumineux (.NET)

Je dois crypter, stocker puis décrypter plus tard de gros fichiers. Quelle est la meilleure façon de procéder? J'ai entendu dire que le chiffrement RSA coûte cher et il m'a été conseillé d'utiliser RSA pour chiffrer une clé AES, puis d'utiliser la clé AES pour chiffrer les gros fichiers. Toutes les suggestions avec exemple seront excellentes.

24
kalrashi

Un grand organisme est petit d'un autre, bien que nous sachions tous cher quand nous le voyons. Clin d'oeil clin d'oeil.

Essayez de comparer quelque chose comme ce qui suit dans votre environnement et voyez où vous en êtes:

EDIT 13/02/2012: Le code a été mis à jour car je suis devenu (imperceptiblement) plus intelligent et j'ai également remarqué quelques erreurs de découpage qui s'étaient glissées. 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);
                }
            }
        }
    }
14
HABO

Cela peut aider

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

    }
}

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

13
Muhammad Alaa

Généralement, la stratégie que vous avez décrite est utilisée lorsque les données seront cryptées sur une machine (comme un serveur) puis décryptées par une autre machine (client). Le serveur chiffrera les données en utilisant le chiffrement à clé symétrique (pour les performances) avec une clé nouvellement générée et chiffrera cette clé symétrique avec une clé publique (correspondant à la clé privée d'un client). Le serveur envoie au client à la fois les données chiffrées et la clé symétrique chiffrée. Le client peut déchiffrer la clé symétrique avec sa clé privée, puis utiliser cette clé symétrique pour déchiffrer les données. Si vous chiffrez et déchiffrez les données sur la même machine, il peut ne pas être judicieux d'utiliser à la fois RSA et AES, car vous n'essaieriez pas de transmettre la clé de chiffrement à une autre machine.

10
Matt Dearing

Comme vous l'avez entendu, la cryptographie asymétrique, comme RSA, est beaucoup plus lente que la cryptographie symétrique (par exemple AES) mais elle a ses avantages (gestion de clé plus simple, par exemple un clé privée unique à protéger).

La clé (jeu de mots destiné) est d'utiliser les avantages des deux (clé privée asymétrique et vitesse symétrique) tout en ignorant les inconvénients de l'autre (nombreuses clés secrètes et vitesse lente).

Vous pouvez le faire en utilisant RSA une fois par fichier (sans impact énorme sur les performances) pour crypter une clé secrète (symétrique) utilisée pour crypter (beaucoup plus rapidement) votre gros fichier. Ce * wrapping de la clé symétrique vous permet de gérer uniquement une seule clé privée.

Voici un lien vers mon ancien (mais toujours vrai) article de blog qui donne un exemple pour le faire en utilisant C # et le framework .NET (Microsoft of Mono).

4
poupou