10

これが私たちのシナリオです。ギガバイト単位の巨大な暗号化ファイルがあり、最後まで読み取れば正しく復号化できます。問題は、読み取り中にファイル内のフラグを検出したときに発生し、読み取りを停止して 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 をキャプチャすることは有効ですか? または、暗号化/復号化方法に問題がありますか? たぶん、何かが足りないのでしょう。

よろしく!

4

5 に答える 5

1

Closeこれは実際には最終ブロックではないため、例外をスローするDispose(true)呼び出し。FlushFinalBlock

Closeを呼び出さないようにメソッドをオーバーライドすることで、これを防ぐことができFlushFinalBlockます。

public class SilentCryptoStream : CryptoStream {
    public SilentCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) :
        base(stream, transform, mode) {
    }

    public override void Close() {
        this.Dispose(false);
        GC.SuppressFinalize(this);
    }
}

(基になるストリームを手動で閉じる必要もあります。)

reader.EndOfStream が false であるかどうかを確認してから、CryptographicException をキャプチャすることは有効ですか?

大丈夫だと思います。

于 2014-02-12T02:35:34.950 に答える
1

私が理解しているように、最後に読み取られたバイトが有効なパディングバイトではない場合、例外がスローされます。ストリームを意図的に早期に閉じると、最後に読み取られたバイトが「無効なパディング」と見なされ、例外がスローされる可能性が高くなります。意図的に終了しているので、例外を無視しても安全です。

于 2013-03-26T15:47:49.627 に答える
0

パディングをオフにできますか?

// aes.Padding = PaddingMode.PKCS7;
aes.Padding = PaddingMode.None;
于 2013-03-26T15:46:57.567 に答える