2017-12-28 36 views
0

파일을 암호화하고 해독하려고합니다. MVC 웹 애플리케이션에서 AES 메소드 사용하기. 파일을 암호화하고 한 번만 해독 할 수 있습니다. 내가 두 번째 시도하면 "패딩이 유효하지 않으며 오류를 제거 할 수 없습니다."라는 메시지가 나타납니다.여백은 유효하지 않으므로 제거 할 수 없습니다. C# decrypt AES Rijndael, AES Managed

  1. 나는 거의 모든 조합을 AES 속성의 여러 속성으로 시도했습니다.
  2. 개체 삭제에 대한 문을 사용하려고했습니다.
  3. CryptoStream 쓰기 후에 FlushFinalBlock()을 사용해 보았습니다.
  4. AES.Padding to Zero를 사용하여 시도해 보았습니다. (오류는 발생하지 않지만 파일은 해독되지 않습니다.) AES.Padding을 None으로 설정하면 오류가 발생합니다 ('암호화 할 데이터 길이가 잘못되었습니다.'). PKCS7에 AES.Padding하면 오류가 발생합니다 (채우기가 잘못되었습니다.)

아래 코드를 찾으십시오.

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

제목의 오류는 일반적으로 암호화에 사용 된 키/iv 쌍이 암호 해독 시도에 사용 된 키/iv 쌍과 일치하지 않음을 나타냅니다. – Kevin

+1

나는 Encrypt에서 PaddingMode를 None으로 설정하고 Decrypt로 설정하면 PKCS7로 설정합니다. – Kevin

+0

모든 매개 변수를 설정하려고합니다. AES는 항상 CBC이고 Padding Mode는 PKCS7로 기본 설정되며 블록 크기는 항상 128이며 키 크기는 사용하는 유효한 키의 크기 (유효한 크기는 128, 192 및 256)로 설정됩니다. – Kevin

답변

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

} 
관련 문제