填充无效,无法删除。 c#decrypt AES Rijndael,AES管理

时间:2017-12-28 20:46:04

标签: c# security encryption cryptography aes

我正在尝试加密和解密文件。在MVC Web应用程序中使用AES方法。我能够加密文件并只解密一次。如果我第二次尝试它会给我"填充无效且无法删除错误。"

  1. 我尝试过几乎所有具有AES属性的不同属性的组合。
  2. 我尝试过使用statement来处理对象。
  3. 我在CryptoStream写入后尝试使用FlushFinalBlock()。
  4. 我尝试过使用AES.Padding to Zero(没有错误,但文件没有解密),AES.Padding to None给我错误('要加密的数据长度无效。&#39 )。 AES.Padding到PKCS7给我错误(填充无效。)
  5. 请在下面找到我的代码。

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

1 个答案:

答案 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
        }
    }

}