Как зашифровать и расшифровать файлы, используя алгоритм шифрования AES в C #

Если файлы ваших пользователей содержат конфиденциальную информацию, вы можете зашифровать ее, чтобы никто не мог открыть этот файл, кроме самого пользователя. Шифрование ваших файлов затрудняет доступ к ним и чтение без вашего пароля. Если вам нравится тема шифрования в вашем проекте, в этой статье мы покажем вам, как легко шифровать и дешифровать файлы с помощью алгоритма AES.

Заметка

Эта статья показывает вам способ легко и быстро шифровать и дешифровать файлы, используя простые методы, такие как шифрование и дешифрование. Они являются результатом повторного сбора информации из разных источников, таких как Stack Overflow, Security Exchange и официальный сайт MSDN.

1. Импортируйте необходимые типы

Чтобы обработать алгоритм шифрования AES в вашем проекте для шифрования и дешифрования файлов, импортируйте 2 следующих обязательных типа:

using System.Security.Cryptography;
using System.Runtime.InteropServices;

Ссылка на InteropServices в верхней части вашего класса позволит вам позже использовать DllImport метод в нашем классе.

2. Создать методы шифрования и дешифрования

Вам нужно будет добавить следующие 3 метода в ваш класс (или создать их в новом классе, а затем импортировать их в свой):

  • GenerateRandomSalt: этот метод создает случайную соль. Эта функция настраивается, и вы можете изменить ее, чтобы создать собственную соль, если вам нужно.
  • FileEncrypt: этот метод шифрует существующий файл простым паролем.
  • FileDecrypt: этот метод расшифровывает ранее зашифрованный файл с помощью метода FileEncrypt, используя простой пароль в качестве аргумента.
  • ZeroMemory: этот метод будет использоваться для удаления пароля из памяти, что повышает безопасность шифрования. Это не обязательно, однако рекомендуется к использованию.

Метод будет использован и объяснен на шаге № 3, сейчас скопируйте и включите методы в ваш проект:

//  Call this function to remove the key from memory after use for security
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
///
/// Creates a random salt that will be used to encrypt your file. This method is required on FileEncrypt.
///
///
public 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;
}
///
/// Encrypts a file from its path and a plain password.
///
///
///
private void FileEncrypt(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)
{
Console.WriteLine("Error: " + ex.Message);
}
finally
{
cs.Close();
fsCrypt.Close();
}
}
///
/// Decrypts an encrypted file with the FileEncrypt method through its path and the plain password.
///
///
///
///
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.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();
}
}

Они не обязательно идеальны, и их можно (и нужно) модифицировать для обработки большего количества исключений в случае их появления и того, как вы работаете с вашим приложением.

3. Использование методов

Из обязательных методов вам нужно будет использовать только 2 из них (FileEncrypt и FileDecrypt), очевидно, и 1 из них необязательный, четвертый (GenerateRandomSalt) используется внутренне FileEncrypt метод.

Зашифровать файл

Зашифруйте файл, используя метод FileEncrypt, который в качестве первого аргумента ожидает путь к файлу, который будет зашифрован, а в качестве второго аргумента — пароль, который будет использоваться для его шифрования. Пароль может быть использован для расшифровки файла позже. Чтобы все сделать правильно, мы рекомендуем вам удалить пароль из памяти, используя метод ZeroMemory. Вызовите эту функцию, чтобы удалить ключ из памяти после использования в целях безопасности:

string password = "ThePasswordToDecryptAndEncryptTheFile";
// For additional security Pin the password of your files
GCHandle gch = GCHandle.Alloc(password, GCHandleType.Pinned);
// Encrypt the file
FileEncrypt(@"C:\Users\username\Desktop\wordFileExample.doc", password);
// To increase the security of the encryption, delete the given password from the memory !
ZeroMemory(gch.AddrOfPinnedObject(), password.Length * 2);
gch.Free();
// You can verify it by displaying its value later on the console (the password won't appear)
Console.WriteLine("The given password is surely nothing: " + password);

FileEncrypt Метод сгенерирует файл в том же каталоге исходного файла с aes расширение (например, wordFileExample.doc).

Расшифровать файл

Чтобы расшифровать файл, мы будем следовать тому же процессу, но вместо этого будем использовать FileDecrypt. Этот метод ожидает в качестве первого аргумента путь к зашифрованному файлу, а в качестве второго аргумента — путь, куда должен быть помещен расшифрованный файл. В качестве третьего аргумента необходимо указать строку, которая использовалась для первоначального шифрования файла:

string password = "ThePasswordToDecryptAndEncryptTheFile";
// For additional security Pin the password of your files
GCHandle gch = GCHandle.Alloc(password, GCHandleType.Pinned);
// Decrypt the file
FileDecrypt(@"C:\Users\sdkca\Desktop\example.doc.aes", @"C:\Users\sdkca\Desktop\example_decrypted.doc", password);
// To increase the security of the decryption, delete the used password from the memory !
ZeroMemory(gch.AddrOfPinnedObject(), password.Length * 2);
gch.Free();
// You can verify it by displaying its value later on the console (the password won't appear)
Console.WriteLine("The given password is surely nothing: " + password);

Финальные заметки

  • Процесс шифрования / дешифрования занимает много памяти и занимает много времени, поэтому рекомендуется запускать эти задачи в другом потоке, чтобы предотвратить зависание основного интерфейса пользователя.
  • Расширение aes можно изменить на расширение, которое вы хотите.
Ссылка на основную публикацию
Adblock
detector