web-dev-qa-db-ja.com

AesManagedを使用した「パディングは無効であり、削除できません」

AesManagedで簡単な暗号化/復号化を機能させようとしていますが、復号化ストリームを閉じようとすると例外が発生し続けます。ここの文字列は正しく暗号化および復号化され、Console.WriteLineが正しい文字列を出力した後、CryptographicException "パディングが無効で削除できません"が発生します。

何か案は?

MemoryStream ms = new MemoryStream();
byte[] rawPlaintext = Encoding.Unicode.GetBytes("This is annoying!");

using (Aes aes = new AesManaged())
{
  aes.Padding = PaddingMode.PKCS7;
  aes.Key = new byte[128/8];
  aes.IV = new byte[128/8];

  using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(),
                                            CryptoStreamMode.Write))
  {
    cs.Write(rawPlaintext, 0, rawPlaintext.Length);
    cs.FlushFinalBlock();
  }

  ms = new MemoryStream(ms.GetBuffer());
  using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(),
                                            CryptoStreamMode.Read))
  {
    byte[] rawData = new byte[rawPlaintext.Length];
    int len = cs.Read(rawData, 0, rawPlaintext.Length);
    string s = Encoding.Unicode.GetString(rawData);
    Console.WriteLine(s);
  }
}
29
TimK

コツはMemoryStream.ToArray()を使うことです。また、暗号化と復号化の両方でCryptoStreamを使用して書き込みを行うようにコードを変更しました。また、CryptoStream.FlushFinalBlock()ステートメント内にあり、using()でフラッシュが発生するため、Dispose()を明示的に呼び出す必要はありません。次は私のために働きます。

byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!");

using (Aes aes = new AesManaged())
{
    aes.Padding = PaddingMode.PKCS7;
    aes.KeySize = 128;          // in bits
    aes.Key = new byte[128/8];  // 16 bytes for 128 bit encryption
    aes.IV = new byte[128/8];   // AES needs a 16-byte IV
    // Should set Key and IV here.  Good approach: derive them from 
    // a password via Cryptography.Rfc2898DeriveBytes 
    byte[] cipherText= null;
    byte[] plainText= null;

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
        {
            cs.Write(rawPlaintext, 0, rawPlaintext.Length);
        }

        cipherText= ms.ToArray();
    }


    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
        {
            cs.Write(cipherText, 0, cipherText.Length);
        }

        plainText = ms.ToArray();
    }
    string s = System.Text.Encoding.Unicode.GetString(plainText);
    Console.WriteLine(s);
}

また、AesManagedインスタンスの Mode を明示的に設定し、 System.Security.Cryptography.Rfc2898DeriveBytes を使用してキーとIVをパスワードとソルト。

また見なさい:
- AesManaged

50
Cheeso

この例外は、いくつかの暗号化パラメーターのいずれか1つが一致していないことが原因である可能性があります。

Security.Cryptography.Debug インターフェイスを使用して、暗号化/復号化メソッドで使用されるすべてのパラメーターをトレースしました。

最後に、KeySizeを設定した後にKeyプロパティを設定すると、クラスがランダムなキーを再生成し、最初に設定したキーを使用しないことが問題であることがわかりました。

23
athina.bikaki

byte [] rawData = new byte [rawPlaintext.Length];

おそらく必要なパディングを含むバッファの長さを読み取る必要があります(IIRC、数年前)。

1
leppie

実際にはMemoryStream.GetBufferがこのバッファー内の実際のデータではなく、割り当てられたバッファーを返すという答えはありません。この場合、256バイトのバッファが返されますが、暗号化されたデータは32バイトしか含まれません。

1

その価値については、私が直面したことを文書化します。 CryptoStreamが閉じられる前に、暗号化メモリストリームを読み取ろうとしました。私はそれが素朴だったことを知っていて、それをデバッグするのに一日を無駄にしました。

_    public static byte[] Encrypt(byte[] buffer, byte[] sessionKey, out byte[] iv)
    {
        byte[] encrypted;
        iv = null;
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
        {
            aesAlg.Key = sessionKey;
            iv = aesAlg.IV;
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(sessionKey, iv);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    csEncrypt.Write(buffer, 0, buffer.Length);

                    //This was not closing the cryptostream and only worked if I called FlushFinalBlock()
                    //encrypted = msEncrypt.ToArray(); 
                }

                encrypted = msEncrypt.ToArray();

                return encrypted;
            }
        }
    }
_

Cyptoストリームが閉じられた後に読み込まれた暗号化メモリストリームを移動すると、問題が解決しました。チーソが言ったように。 usingブロックを使用している場合は、FlushFinalBlock()を呼び出す必要はありません。

0
Jack7