我正在尝试加密和解密文件。在MVC Web应用程序中使用AES方法。我能够加密文件并只解密一次。如果我第二次尝试它会给我"填充无效且无法删除错误。"
请在下面找到我的代码。
public class EncryptionDecryption
{
// 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);
/// <summary>
/// Creates a random salt that will be used to encrypt your file. This method is required on FileEncrypt.
/// </summary>
/// <returns></returns>
public static byte[] GenerateRandomSalt()
{
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;
}
/// <summary>
/// Encrypts a file from its path and a plain password.
/// </summary>
/// <param name="inputFile"></param>
/// <param name="password"></param>
public static void FileEncrypt(string inputFile, string password)
{
//generate random salt
byte[] salt = GenerateRandomSalt();
//create output file name
using (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
using (AesManaged AES = new AesManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Padding = PaddingMode.None;
//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.CBC;
// write salt to the begining of the output file, so in this case can be random every time
fsCrypt.Write(salt, 0, salt.Length);
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
using (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
{
if (!cs.HasFlushedFinalBlock)
cs.FlushFinalBlock();
cs.Close();
fsCrypt.Close();
}
}
}
}
}
}
/// <summary>
/// Decrypts an encrypted file with the FileEncrypt method through its path and the plain password.
/// </summary>
/// <param name="inputFile"></param>
/// <param name="outputFile"></param>
/// <param name="password"></param>
public static void FileDecrypt(string inputFile, string outputFile, string password)
{
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[32];
using (FileStream fsCrypt = new FileStream(inputFile, FileMode.Open))
{
fsCrypt.Read(salt, 0, salt.Length);
using (AesManaged AES = new AesManaged ())
{
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.CBC;
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read))
{
using (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);
//if (!cs.HasFlushedFinalBlock)
cs.FlushFinalBlock();
}
}
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();
}
}
}
}
}
}
}
调用方法 加密
string password = "ThePasswordToDecryptAndEncryptTheFile";
// For additional security Pin the password of your files
GCHandle gch = GCHandle.Alloc(password, GCHandleType.Pinned);
// Encrypt the file
EncryptionDecryption.FileEncrypt(inputFilePath, password);
// To increase the security of the encryption, delete the given password from the memory !
EncryptionDecryption.ZeroMemory(gch.AddrOfPinnedObject(), password.Length * 2);
gch.Free();
解密
GCHandle gch2 = GCHandle.Alloc(password, GCHandleType.Pinned);
// Decrypt the file
EncryptionDecryption.FileDecrypt(encryptedFilePath, outputPath, password);
// To increase the security of the decryption, delete the used password from the memory !
EncryptionDecryption.ZeroMemory(gch2.AddrOfPinnedObject(), password.Length * 2);
gch2.Free();
答案 0 :(得分:0)
我通过将所有AES属性删除为默认值并保留少量来解决问题。找到下面的代码。特别是填充字段。
public static void FileEncrypt(string inputFile, string outputFile, string password, byte[] salt)
{
try
{
using (RijndaelManaged AES = new RijndaelManaged())
{
byte[] passwordBytes = ASCIIEncoding.UTF8.GetBytes(password);
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);
/* This is for demostrating purposes only.
* Ideally you will want the IV key to be different from your key and you should always generate a new one for each encryption in other to achieve maximum security*/
//byte[] IV = ASCIIEncoding.UTF8.GetBytes(skey);
using (FileStream fsCrypt = new FileStream(outputFile, FileMode.Create))
{
using (ICryptoTransform encryptor = AES.CreateEncryptor(AES.Key, AES.IV))
{
using (CryptoStream cs = new CryptoStream(fsCrypt, encryptor, CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
}
if (!cs.HasFlushedFinalBlock)
cs.FlushFinalBlock();
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static void FileDecrypt(string inputFile, string outputFile, string password, byte[] salt)
{
try
{
using (RijndaelManaged AES = new RijndaelManaged())
{
//byte[] key = ASCIIEncoding.UTF8.GetBytes(password);
/* This is for demostrating purposes only.
* Ideally you will want the IV key to be different from your key and you should always generate a new one for each encryption in other to achieve maximum security*/
//byte[] IV = ASCIIEncoding.UTF8.GetBytes(password);
byte[] passwordBytes = ASCIIEncoding.UTF8.GetBytes(password);
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);
using (FileStream fsCrypt = new FileStream(inputFile, FileMode.Open))
{
using (FileStream fsOut = new FileStream(outputFile, FileMode.Create))
{
using (ICryptoTransform decryptor = AES.CreateDecryptor(AES.Key, AES.IV))
{
using (CryptoStream cs = new CryptoStream(fsCrypt, decryptor, CryptoStreamMode.Read))
{
int data;
while ((data = cs.ReadByte()) != -1)
{
fsOut.WriteByte((byte)data);
}
if (!cs.HasFlushedFinalBlock)
cs.FlushFinalBlock();
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
// failed to decrypt file
}
}
}