AES encryption on large files

后端 未结 3 808
情深已故
情深已故 2020-12-05 05:56

I need to encrypt and decrypt large file (~1GB). I tried using this example: http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt But my p

相关标签:
3条回答
  • 2020-12-05 06:07

    So I created a fairly fast and low memory consumption version:
    I use a "temporary buffer" and also "use a random salt and store it with the ciphertext".
    To encrypt:

    private void AES_Encrypt(string inputFile, string password)
        {
            //http://stackoverflow.com/questions/27645527/aes-encryption-on-large-files
    
            //generate random salt
            byte[] salt = GenerateRandomSalt();
    
            //create output file name
            FileStream fsCrypt = new FileStream(inputFile + ".aes", FileMode.Create);
    
            //convert password string to byte arrray
            byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
    
            //Set Rijndael symmetric encryption algorithm
            RijndaelManaged AES = new RijndaelManaged();
            AES.KeySize = 256;
            AES.BlockSize = 128;
            AES.Padding = PaddingMode.PKCS7;
    
            //http://stackoverflow.com/questions/2659214/why-do-i-need-to-use-the-rfc2898derivebytes-class-in-net-instead-of-directly
            //"What it does is repeatedly hash the user password along with the salt." High iteration counts.
            var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
    
            //Cipher modes: http://security.stackexchange.com/questions/52665/which-is-the-best-cipher-mode-and-padding-mode-for-aes-encryption
            AES.Mode = CipherMode.CFB;
    
            //write salt to the begining of the output file, so in this case can be random every time
            fsCrypt.Write(salt, 0, salt.Length);
    
            CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
    
            FileStream fsIn = new FileStream(inputFile, FileMode.Open);
    
            //create a buffer (1mb) so only this amount will allocate in the memory and not the whole file
            byte[] buffer = new byte[1048576];
            int read;
    
            try
            {
                while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
                {
                    Application.DoEvents(); // -> for responsive GUI, using Task will be better!
                    cs.Write(buffer, 0, read);
                }
    
                //close up
                fsIn.Close();
    
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
            }
            finally
            {
                cs.Close();
                fsCrypt.Close();
            }
        }
    

    To decrypt:

    private void AES_Decrypt(string inputFile, string password)
        {
            //todo:
            // - create error message on wrong password
            // - on cancel: close and delete file
            // - on wrong password: close and delete file!
            // - create a better filen name
            // - could be check md5 hash on the files but it make this slow
    
            byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
            byte[] salt = new byte[32];
    
            FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
            fsCrypt.Read(salt, 0, salt.Length);
    
            RijndaelManaged AES = new RijndaelManaged();
            AES.KeySize = 256;
            AES.BlockSize = 128;
            var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            AES.Padding = PaddingMode.PKCS7;
            AES.Mode = CipherMode.CFB;
    
            CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);
    
            FileStream fsOut = new FileStream(inputFile + ".decrypted", FileMode.Create);
    
            int read;
            byte[] buffer = new byte[1048576];
    
            try
            {
                while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    Application.DoEvents();
                    fsOut.Write(buffer, 0, read);
                }
            }
            catch (System.Security.Cryptography.CryptographicException ex_CryptographicException)
            {
                Debug.WriteLine("CryptographicException error: " + ex_CryptographicException.Message);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
            }
    
            try
            {
                cs.Close();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error by closing CryptoStream: " + ex.Message);
            }
            finally
            {
                fsOut.Close();
                fsCrypt.Close();
            }
        }
    

    To generate random salt:

            public static byte[] GenerateRandomSalt()
        {
            //Source: http://www.dotnetperls.com/rngcryptoserviceprovider
            byte[] data = new byte[32];
    
            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
            {
                // Ten iterations.
                for (int i = 0; i < 10; i++)
                {
                    // Fill buffer.
                    rng.GetBytes(data);
                }
            }
            return data;
        }
    
    0 讨论(0)
  • 2020-12-05 06:18

    Since you are reading from a file and writing to a file just replace the memory streams by IOStream or FileStream.

    You'll have to refactor the procedures a bit so they don't expect/return byte arrays.

    0 讨论(0)
  • 2020-12-05 06:30

    Eventually, this is the code that worked for me:

     private static void AES_Encrypt(string inputFile, string outputFile, byte[] passwordBytes)
     {
            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};
            string cryptFile = outputFile;
            FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
    
            RijndaelManaged AES = new RijndaelManaged();
    
            AES.KeySize = 256;
            AES.BlockSize = 128;
    
    
            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            AES.Padding = PaddingMode.Zeros;
    
            AES.Mode = CipherMode.CBC;
    
            CryptoStream cs = new CryptoStream(fsCrypt,
                 AES.CreateEncryptor(),
                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();
    
        }
    
        private static void AES_Decrypt(string inputFile, string outputFile, byte[] passwordBytes)
        {
    
    
    
            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};
            FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
    
            RijndaelManaged AES = new RijndaelManaged();
    
            AES.KeySize = 256;
            AES.BlockSize = 128;
    
    
            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            AES.Padding = PaddingMode.Zeros;
    
            AES.Mode = CipherMode.CBC;
    
            CryptoStream cs = new CryptoStream(fsCrypt,
                AES.CreateDecryptor(),
                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();
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题