2010-12-28 6 views
6

C#でAES暗号化コードを書きましたが、暗号化と復号化に問題があります。パスフレーズとして「test」と入力し、「このデータは誰でも秘密にしておく必要があります!.NETでAES暗号化を使用しています - 埋め込みが無効であり、削除できないと言うCryptographicException

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. 
    at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) 
    at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) 
    at System.Security.Cryptography.CryptoStream.FlushFinalBlock() 
    at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) 
    at System.IO.Stream.Close() 
    at System.IO.Stream.Dispose() 
    ... 

そして、16文字未満のものを入力した場合は出力されません。

AESはブロック暗号であるため、私は暗号化に特別な処理が必要だと思っていますが、それが何であるかはわかりませんし、Web上でどのように例を見つけることもできませんでした。ここに私のコードは次のとおりです。CBCのような詰め物を、必要とするモードでAESなどのブロック暗号を使用している場合

using System; 
using System.IO; 
using System.Security.Cryptography; 
using System.Text; 

public static class DatabaseCrypto 
{ 
    public static EncryptedData Encrypt(string password, string data) 
    { 
     return DatabaseCrypto.Transform(true, password, data, null, null) as EncryptedData; 
    } 

    public static string Decrypt(string password, EncryptedData data) 
    { 
     return DatabaseCrypto.Transform(false, password, data.DataString, data.SaltString, data.MACString) as string; 
    } 

    private static object Transform(bool encrypt, string password, string data, string saltString, string macString) 
    { 
     using (AesManaged aes = new AesManaged()) 
     { 
      aes.Mode = CipherMode.CBC; 
      aes.Padding = PaddingMode.PKCS7; 
      int key_len = aes.KeySize/8; 
      int iv_len = aes.BlockSize/8; 
      const int salt_size = 8; 
      const int iterations = 8192; 

      byte[] salt = encrypt ? new byte[salt_size] : Convert.FromBase64String(saltString); 
      if (encrypt) 
      { 
       new RNGCryptoServiceProvider().GetBytes(salt); 
      } 

      byte[] bc_key = new Rfc2898DeriveBytes("BLK" + password, salt, iterations).GetBytes(key_len); 
      byte[] iv = new Rfc2898DeriveBytes("IV" + password, salt, iterations).GetBytes(iv_len); 
      byte[] mac_key = new Rfc2898DeriveBytes("MAC" + password, salt, iterations).GetBytes(16); 

      aes.Key = bc_key; 
      aes.IV = iv; 

      byte[] rawData = encrypt ? Encoding.UTF8.GetBytes(data) : Convert.FromBase64String(data); 

      using (ICryptoTransform transform = encrypt ? aes.CreateEncryptor() : aes.CreateDecryptor()) 
      using (MemoryStream memoryStream = encrypt ? new MemoryStream() : new MemoryStream(rawData)) 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, encrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read)) 
      { 
       if (encrypt) 
       { 
        cryptoStream.Write(rawData, 0, rawData.Length); 

        return new EncryptedData(salt, mac_key, memoryStream.ToArray()); 
       } 
       else 
       { 
        byte[] originalData = new byte[rawData.Length]; 
        int count = cryptoStream.Read(originalData, 0, originalData.Length); 

        return Encoding.UTF8.GetString(originalData, 0, count); 
       } 
      } 
     } 
    } 
} 

public class EncryptedData 
{ 
    public EncryptedData() 
    { 
    } 

    public EncryptedData(byte[] salt, byte[] mac, byte[] data) 
    { 
     this.Salt = salt; 
     this.MAC = mac; 
     this.Data = data; 
    } 

    public EncryptedData(string salt, string mac, string data) 
    { 
     this.SaltString = salt; 
     this.MACString = mac; 
     this.DataString = data; 
    } 

    public byte[] Salt 
    { 
     get; 
     set; 
    } 

    public string SaltString 
    { 
     get { return Convert.ToBase64String(this.Salt); } 
     set { this.Salt = Convert.FromBase64String(value); } 
    } 

    public byte[] MAC 
    { 
     get; 
     set; 
    } 

    public string MACString 
    { 
     get { return Convert.ToBase64String(this.MAC); } 
     set { this.MAC = Convert.FromBase64String(value); } 
    } 

    public byte[] Data 
    { 
     get; 
     set; 
    } 

    public string DataString 
    { 
     get { return Convert.ToBase64String(this.Data); } 
     set { this.Data = Convert.FromBase64String(value); } 
    } 
} 

    static void ReadTest() 
    { 
     Console.WriteLine("Enter password: "); 
     string password = Console.ReadLine(); 

     using (StreamReader reader = new StreamReader("aes.cs.txt")) 
     { 
      EncryptedData enc = new EncryptedData(); 
      enc.SaltString = reader.ReadLine(); 
      enc.MACString = reader.ReadLine(); 
      enc.DataString = reader.ReadLine(); 

      Console.WriteLine("The decrypted data was: " + DatabaseCrypto.Decrypt(password, enc)); 
     } 
    } 

    static void WriteTest() 
    { 
     Console.WriteLine("Enter data: "); 
     string data = Console.ReadLine(); 
     Console.WriteLine("Enter password: "); 
     string password = Console.ReadLine(); 

     EncryptedData enc = DatabaseCrypto.Encrypt(password, data); 

     using (StreamWriter stream = new StreamWriter("aes.cs.txt")) 
     { 
      stream.WriteLine(enc.SaltString); 
      stream.WriteLine(enc.MACString); 
      stream.WriteLine(enc.DataString); 

      Console.WriteLine("The encrypted data was: " + enc.DataString); 
     } 
    } 

答えて

13

、あなたは出力は常にブロックサイズの倍数になることを認識しなければなりません。これを達成するために、PKCS7のようなパディングモードでは、暗号化プロセスの最後に暗号にいくつかのバイトを追加します。しかし、暗号が終わった時点を暗号化装置に知らせなければなりません。そのためには、すべてあなたがしなければならない

cryptoStream.Write(rawData, 0, rawData.Length); 

後にPS

cryptoStream.FlushFinalBlock(); 

文を挿入している:

おそらくそれは単なるデバッグ用ですが、あなたの塩の生成方法はまったく同じを生成し、たびに塩。

+0

うわー、それでは、簡単?私はそれがFlushFinalBlockと何か関係があるかもしれないと思ったが、わからなかった。前に追加したと思うけど、間違ったパスワードを入力しただけかもしれない。いくつかランダムなユニットテストを生成する必要があります。 :)また、私は塩が同じであることを知っています - 私はまだランダムなものを生成する方法がわかりませんでしたが、そのコードを書いた後に 'RNGCryptoServiceProvider'を見つけました。しかし、それを指摘してくれてありがとう。 –

+0

msdnとstackoverflowの多くの例はそれほど健康ではありません。 FlushFinalBlock()。ワオ。 – ZZZ

+0

StreamWriterでCryptoStreamをラップしていました...「cryptoStream.FlushFinalBlock();」は、関係なく呼び出される必要があります。ありがとう - これは時間を大幅に節約しました! – trousyt

関連する問題