これが私たちのシナリオです。ギガバイト単位の巨大な暗号化ファイルがあり、最後まで読み取れば正しく復号化できます。問題は、読み取り中にファイル内のフラグを検出したときに発生し、読み取りを停止して reader.Close() を呼び出すと、CryptographicException: "パディングが無効であり、削除できません" が発生します。投げられます。私はこの動作を再現するこの小さなコンソール アプリを持っています。テストするには、実行するだけです。C:\ ドライブにファイルを作成し、任意のキーを押すと行ごとに読み取り、「q」を押すと停止します。 .
using System;
using System.IO;
using System.Security.Cryptography;
namespace encryptSample
{
class Program
{
static void Main(string[] args)
{
var transform = CreateCryptoTransform(true);
// first create encrypted file
using (FileStream destination = new FileStream("c:\\test_enc.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
using (StreamWriter source = new StreamWriter(cryptoStream))
{
for (int i = 0; i < 1000; i++)
{
source.WriteLine("This is just random text to fill the file and show what happens when I stop reading in the middle - " + i);
}
// Also tried this line, but is the same with or without it
cryptoStream.FlushFinalBlock();
}
}
}
StreamReader reader;
ICryptoTransform transformDec;
CryptoStream cryptoStreamReader;
transformDec = CreateCryptoTransform(false);
FileStream fileStream = new FileStream("c:\\test_enc.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
cryptoStreamReader = new CryptoStream(fileStream, transformDec, CryptoStreamMode.Read);
reader = new StreamReader(cryptoStreamReader);
while (Console.In.ReadLine() != "q")
{
Console.WriteLine(reader.ReadLine());
}
try
{
cryptoStreamReader.Close();
reader.Close();
reader.Dispose();
}
catch (CryptographicException ex)
{
if (reader.EndOfStream)
throw;
}
}
private static ICryptoTransform CreateCryptoTransform(bool encrypt)
{
byte[] salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Must be at least eight bytes. MAKE THIS SALTIER!
const int iterations = 1042; // Recommendation is >= 1000.
const string password = "123456";
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
// NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = encrypt ? aes.CreateEncryptor(aes.Key, aes.IV) : aes.CreateDecryptor(aes.Key, aes.IV);
return transform;
}
}
}
元のクラスでは、Dispose() 中に reader.Close を実行します。私の質問は、reader.EndOfStream が false であるかどうかを確認してから、CryptographicException をキャプチャすることは有効ですか? または、暗号化/復号化方法に問題がありますか? たぶん、何かが足りないのでしょう。
よろしく!