private void FileEncrypt(string inputFile, string outputFile, string password)

        {

            //http://stackoverflow.com/questions/27645527/aes-encryption-on-large-files


            //generate random salt

            byte[] salt = GenerateRandomSalt();


            FileStream fsCrypt = new FileStream(outputFile, 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);


            // 속도를 중시하면 다음 줄을 쓴다. 속도는 빠르다.

            AES.Key = Encoding.UTF8.GetBytes(password);

            AES.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };



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

            {

                Console.WriteLine("Error: " + ex.Message);

            }

            finally

            {

                cs.Close();

                fsCrypt.Close();

            }

        }



        private void FileDecrypt(string inputFile, string outputFile, string password)

        {

            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.Key = Encoding.UTF8.GetBytes(password);

            AES.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };



            AES.Padding = PaddingMode.PKCS7;

            AES.Mode = CipherMode.CFB;


            CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);


            FileStream fsOut = new FileStream(outputFile, 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 (CryptographicException ex_CryptographicException)

            {

                Console.WriteLine("CryptographicException error: " + ex_CryptographicException.Message);

            }

            catch (Exception ex)

            {

                Console.WriteLine("Error: " + ex.Message);

            }


            try

            {

                cs.Close();

            }

            catch (Exception ex)

            {

                Console.WriteLine("Error by closing CryptoStream: " + ex.Message);

            }

            finally

            {

                fsOut.Close();

                fsCrypt.Close();

            }

        }



inputFile : 암호화할 파일 디렉토리

outputFile : 암호화되어 저장하기 위한 파일 디렉토리 

password : 암호화 키


Rfc2898DeriveBytes의 GetBytes는 Key를 해쉬화하여 각 파일에 여러개의 Key를 주입한 효과를 준다. 그러나 보안성이 강화되는 만큼 너무 느리다..

var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000); 에서 50000을 100000을 넣으면 보안성이 더강화된다.




이 알고리즘을 사용하기 위해서는 사용클래스에



        [DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]

        public static extern bool ZeroMemory(IntPtr Destination, int Length);


        /// <summary>

        /// Creates a random salt that will be used to encrypt your file. This method is required on FileEncrypt.

        /// salt : randomly string of byte unit

        /// </summary>

        /// <returns></returns>

        private static byte[] GenerateRandomSalt()

        {

            byte[] data = new byte[32];


            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())

            {

                for (int i = 0; i < 10; i++)

                {

                    // Fille the buffer with the generated data

                    rng.GetBytes(data);

                }

            }


            return data;

        }


를 선언하고


public void EncryptFile(){

    //AES256의 key는 32bit

            string password = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";


            // For additional security Pin the password of your files

            GCHandle gch = GCHandle.Alloc(password, GCHandleType.Pinned);


            FileEncrypt(dirFilePath, encryptFilePath, password);


            // To increase the security of the encryption, delete the given password from the memory !

            ZeroMemory(gch.AddrOfPinnedObject(), password.Length * 2);

            gch.Free();


}


public void DecryptFile(){


    //AES256의 key는 32bit

            string password = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";


            // For additional security Pin the password of your files

            GCHandle gch = GCHandle.Alloc(password, GCHandleType.Pinned);


            FileDecrypt(dirFilePath, decryptFilePath, password);

            // To increase the security of the decryption, delete the used password from the memory !

            ZeroMemory(gch.AddrOfPinnedObject(), password.Length * 2);

            gch.Free();

}


다음과 같은 방식으로 쓰면 된다.


Posted by Lich King
,