gpt4 book ai didi

c# - 在 EOF 抛出异常 : Padding is invalid and cannot be removed 之前停止解密

转载 作者:太空狗 更新时间:2023-10-29 17:50:50 28 4
gpt4 key购买 nike

这是我们遇到的情况:我们有巨大的加密文件,以千兆字节为单位,如果我们读到最后就可以正确解密。当我们正在读取并检测到文件中的某些标志时,问题就出现了,然后我们停止读取并调用 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 是否为假然后捕获 CryptographicException 是否有效?或者加密/解密方法有问题?也许我们遗漏了什么。

问候!

最佳答案

此异常在 Dispose(true) 期间抛出。从 Dispose 中抛出已经是一个设计缺陷 ( https://learn.microsoft.com/en-us/visualstudio/code-quality/ca1065-do-not-raise-exceptions-in-unexpected-locations#dispose-methods ),但更糟糕的是,这个异常甚至在底层流关闭之前就被抛出。

这意味着任何接收到 可能 的 Stream 的东西都需要解决这个问题,或者在“catch” block 中自己关闭底层 Stream(本质上需要引用一些完全不相关的东西),或者以某种方式警告所有听众流可能仍处于打开状态(例如,“不要尝试删除底层文件——它仍然处于打开状态!”)。

不,在我的书中,这是一个相当大的疏忽,其他答案似乎没有解决根本问题。 CryptoStream 拥有传入流的所有权,因此它负责在控制离开 Dispose(true) 之前关闭底层流,故事结束。

理想情况下,它也不应该在并非真正异常的情况下抛出异常(例如“我们提前停止读取,因为解密数据的格式错误,继续读取是浪费时间”)。

我们的解决方案基本上是这样的 (更新:但请注意——正如 Will Krause 在评论中指出的那样,这可能会在私有(private) _InputBuffer 中留下敏感信息_OutputBuffer 可以通过反射访问的字段。.NET Framework 4.5及以上版本没有这个问题。):

internal sealed class SilentCryptoStream : CryptoStream
{
private readonly Stream underlyingStream;

public SilentCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
: base(stream, transform, mode)
{
// stream is already implicitly validated non-null in the base constructor.
this.underlyingStream = stream;
}

protected override void Dispose(bool disposing)
{
try
{
base.Dispose(disposing);
}
catch (CryptographicException)
{
if (disposing)
{
this.underlyingStream.Dispose();
}
}
}
}

关于c# - 在 EOF 抛出异常 : Padding is invalid and cannot be removed 之前停止解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15640857/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com