gpt4 book ai didi

.NET CryptoStream 在 Dispose() 中读取密文的结尾并爆炸

转载 作者:行者123 更新时间:2023-12-04 17:53:34 25 4
gpt4 key购买 nike

我对 .NET CryptoStream 类的一个怪癖感到困惑:它的 Dispose() 方法读取了密文的末尾以寻找填充它不应该,并因此抛出 CryprographicException

下面的 C# 程序加密几个字节,调整密文数组的大小,以便在密文结束后有更多(无意义的)字节,然后尝试解密它。重点是:

  • 密文为8字节,一个3DES密码 block 。因为我只将 6 个字节写入 CryptoStream 并且它使用 PaddingMode.PKCS7(默认),所以 block 中剩余的两个字节填充了填充值 0x02。
  • 密文数组随后被调整为 16 字节,两个 3DES block 。第二 block 是未初始化的废话,不是有效的密码输出。
  • 解密时,我从 CryptoStream 中读取了 6 个字节;我没有要求它解密到无意义的部分,我没有依赖它识别填充来确定它何时到达明文的末尾。

问题是当解密 CryptoStreamDispose() 被调用时(自动在 using block 的末尾),我收到一个带有消息“Bad Data”的 CryptographicException。它的堆栈跟踪显示它正在执行 CryptoStream.FlushFinalBlock(),并且 ciphertextStream 中的所有 16 个字节都已被消耗,而不仅仅是对应于实际加密数据的 8 个字节。

如果我删除调整 ciphertext 数组大小的行,程序将正常运行。如果我在解密之前执行 tripleDes.Padding = PaddingMode.None,程序也能正常工作——但这​​基本上使填充字节成为明文的一部分,所以我宁愿不这样做。显然,问题与填充有关;据我所知,它已解密第二个 block ,并期望在其末尾找到有效的 PKCS7 样式的填充。

因为我只从 CryptoStream 中读取了足够的数据来要求解密一个 block ,并且该 block 是正确填充的最后一个 block ,然后我关闭了 CryptoStream 不再读取,为什么流认为它需要读取另一个 block 并寻找更多填充?为什么它甚至试图在其 Dispose() 中消耗更多输入?


using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;

namespace Test
{
class Program
{
static void Main(string[] args)
{
byte[] plaintext = { 0, 1, 2, 3, 4 };

using (SymmetricAlgorithm tripleDes = TripleDESCryptoServiceProvider.Create())
{
// Encrypt the plaintext
byte[] ciphertext;
using (MemoryStream ciphertextStream = new MemoryStream())
{
using (ICryptoTransform encryptor = tripleDes.CreateEncryptor())
{
using (CryptoStream cryptoStream = new CryptoStream(ciphertextStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.WriteByte((byte)plaintext.Length);
cryptoStream.Write(plaintext, 0, plaintext.Length);
cryptoStream.FlushFinalBlock();
}
}

ciphertext = ciphertextStream.ToArray();
}

// *** Add some non-ciphertext garbage to the end ***
Array.Resize(ref ciphertext, ciphertext.Length + 8);

// Now decrypt it again
byte[] decryptedPlaintext;
using (MemoryStream ciphertextStream = new MemoryStream(ciphertext, false))
{
using (ICryptoTransform decryptor = tripleDes.CreateDecryptor())
{
using (CryptoStream cryptoStream = new CryptoStream(ciphertextStream, decryptor, CryptoStreamMode.Read))
{
int length = cryptoStream.ReadByte();

decryptedPlaintext = new byte[length];

int i = 0;
while (i < length)
{
int bytesRead = cryptoStream.Read(decryptedPlaintext, i, (length - i));
if (bytesRead == 0) break;
else i += bytesRead;
}
} // CryptographicException: "Bad Data"
}
}

System.Diagnostics.Debug.Assert(decryptedPlaintext.SequenceEqual(plaintext));
}
}
}
}

最佳答案

您故意将垃圾添加到流的末尾,然后想知道为什么流会因垃圾而阻塞。

在密码学中,一切 都必须非常仔细地检查,以确保攻击者没有尝试偷偷摸摸的事情。如果您指定 PKCS7 填充,则流有权在末尾检查 PKCS7 填充,如果在流末尾未找到正确的填充,则有权抛出异常。

流无法知道实际的密文在流的中间结束,而不是在末尾。你希望它怎么知道?在加密中,规则是标记任何和所有异常,并且在流的(明显的)末端的错误填充是文档会告诉你导致异常的东西。

关于.NET CryptoStream 在 Dispose() 中读取密文的结尾并爆炸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7410625/

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