編集:解決済み - 復号化機能に問題がありました。解読関数の訂正は下記の解答で見つけることができます。c#Rijndael管理された暗号化と復号化に失敗することがある
私は、このAESの実装でどこが間違っていたかを把握しようと努力していました。私は大きなファイルを暗号化/復号化できるようにする必要があるので、ファイルストリームを使用し、ディスクに各チャンクを書き込んでいます。これは(私の知る限り承知していますようPKCS7/CBCと等価である)AES/CBC/PKCS5Paddingを使用してJavaで書かれた既存のシステムと連携する必要があるとして、AESが必要条件である
この実装は最もファイルに対して動作します。しかし、生データの最後の5バイトが欠けているファイルがいくつかあります。ファイルはエラーなしで復号化されますが、ハッシュは一致せず、欠落したバイトは実際のデータと末尾のゼロの組み合わせです。
これらのストリームは、暗号化の前後(下側のコード)にgzipされることに注意してください。
暗号化
public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = 256;
const int chunkSize = 4096;//1024 * 1024 * 10;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.Flush();
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
復号化(暗号化の前に)
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
cryptoStream.Read(buffer, 0, buffer.Length);
outStream.Write(buffer, 0, buffer.Length);
outStream.Flush();
}
//cryptoStream.FlushFinalBlock(); // Was throwing an exception
}
}
symmetricKey.Clear();
}
圧縮
public static void StreamCompress(Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
const int chunkSize = 4096;
using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
gzs.Write(buffer, 0, buffer.Length);
gzs.Flush();
}
}
}
(復号後)解凍
public static void StreamDecompress(Stream dataStream, FileStream outStream)
{
byte[] buffer = new byte[4096];
dataStream.Position = 0;
using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress))
{
for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
if (r > 0) outStream.Write(buffer, 0, r);
}
}
私はいくつかの他の質問を経ていますが、これは唯一のいくつかのファイルで発生する理由を把握することはできません。失敗するファイルサイズは46,854,144バイトです。しかし、これは大小のファイルでうまくいくようです。
ご協力いただければ幸いです。
'Stream.Read()'は読み込まれたバイト数を示す 'int'を返します。あなたの問題を解決できないかもしれませんが、実際にバッファが完全に埋まっていると仮定するのではなく、実際に読み込まれたバイト数を決定するためにこの戻り値を使用することを強く推奨します。例:var bytesRead = inStream.Read(buffer、0、buffer.Length); outStream.Write(バッファ、0、bytesRead); '。 – Iridium
または単に 'Stream.CopyTo'を使用してください – CodesInChaos
応答をありがとう!私は 'bytesRead'変数を追加して、これを既に行っていた圧縮解除メソッドを除いてすべて使用しています。残念ながら、それは問題を解決していない - 私はまだこれを見ている:( – newuser