0

インメモリ AESManaged 暗号化/復号化を実装しようとしています。ここでのコードはこれに基づいています。

大きなファイルの暗号化/復号化 (.NET)

暗号化部分は機能しているようです。つまり、例外はありません。しかし、復号化部分は「インデックスが配列の境界外でした」というエラーをスローします。

以前のコードでは、変換は次のように初期化されます。

 aes = new AesManaged();
 aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
 aes.KeySize = aes.LegalKeySizes[0].MaxSize;            
 Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(Key, salt, 1);
 aes.Key = key.GetBytes(aes.KeySize / 8);
 aes.IV = key.GetBytes(aes.BlockSize / 8);
 aes.Mode = CipherMode.CBC;
 transform = aes.CreateDecryptor(aes.Key, aes.IV);


void AESDecrypt(ref byte[] inB)
{
    using (MemoryStream destination = new MemoryStream(inB, 0, inB.Length))
    {
        using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
            {
                try
                {
                    using (MemoryStream source = new MemoryStream(inB, 0, inB.Length))
                    {
                        if (source.CanWrite==true)
                        {
                            source.Write(inB, 0, inB.Length);
                            source.Flush(); //<<inB is unchanged by the write
                        }
                    }
                }
                catch (CryptographicException exception)
                {
                    if (exception.Message == "Padding is invalid and cannot be removed.")
                        throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
                    else
                        throw;
                }
            }
        } <====At this point I get an IndexOutofBounds exception.
    }
}

問題のある行は次のようです: using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))

4

1 に答える 1

1

CryptoStream にデータを供給していません。パディングを削除しようとしているため、データが必要です。ソースの try/catch ブロック全体をコメントアウトしてみてください。同じエラーが発生します。

CryptoStream は空のままですが、パディングを読み取るように要求しています。「new AesManaged()」行の後に、次を追加しますaes.Padding = PaddingMode.None。これでコードは機能しますが、何も復号化されません。CryptoStream に何も供給せず、パディングを読み取るように要求していないため、もはや文句を言いません。それは何もしません。CryptoStream に暗号文を渡していないというバグがあります。

ソースの MemoryStream の代わりにこれを試してください。

using (BinaryWriter source = new BinaryWriter(cryptoStream))
{
    source.Write(inB, 0, inB.Length);
}

現在、CryptoStream が関与しており、復号化するために inB を受け取ります。

パディングの取り扱いに問題がある可能性があります。コードが書かれているので (中かっこのタイプミスを修正)、デクリプターにパディングを削除するように要求していますが、出力配列 (ref byte[] inB) をトリミングしていません。常に入力と同じ長さを返しますが、復号化された量を上書きしただけです。

サンプルデータは次のとおりです。

32 ゼロ バイトのキーと 16 ゼロ バイトの IV を試してください。

aes.Key = new byte[32];
aes.IV = new byte[16];

この暗号文を inB として復号化します。

byte[] inB = { 0xf9, 0x14, 0x32, 0x2a, 0x7a, 0x35, 0xf9, 0xef, 0x27, 0x98, 0x1a, 0x86, 0xe2, 0x80, 0x5e, 0x9b };

Padding.None を設定しないと、元のプレーンテキスト "Hello" が inB の最初の 5 バイトだけを上書きすることがわかります残りの 11 バイトは変更されません。パディングは削除され (デフォルト)、宛先ストリームには書き込まれませんでした。

Padding.None を設定して試してみてください。データをパディングしたので、destination には "Hello" とそれに続く 11 バイトの値 11 (パディング) が含まれていることがわかります。今回はパディングが削除されていないため、出力に書き込まれていることがわかります。

また、usr がコメントしたように、IV はキーで暗号化するたびに一意である必要があります。毎回同じ IV とキーを導出しています。このキーが 1 回だけ使用される場合は問題ありません。同じキーが複数回使用されている場合、これは誤りです。IV は一意である必要があります。平文で送信できます。秘密にしておく必要はありません。

于 2014-03-13T22:39:43.130 に答える