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

时间:2011-09-14 02:25:59

标签: .net encryption padding cryptostream

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

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

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

问题在于,当调用解密CryptoStream的{​​{1}}时(自动在Dispose()块的末尾),我会收到using的消息“糟糕的数据”。它的堆栈跟踪显示它正在执行CryptographicException,并且所有16个字节都已从CryptoStream.FlushFinalBlock()消耗,而不仅仅是与实际加密数据相对应的8个字节。

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

因为我只是从PKCS7读取足够的内容来要求解密一个块,并且该块是正确填充的最终块,然后我关闭CryptoStream而不再读取,为什么流认为它需要读取另一个块并寻找更多填充?为什么它甚至试图将更多输入作为其CryptoStream的一部分?


Dispose()

1 个答案:

答案 0 :(得分:3)

你故意在流的末尾添加垃圾,然后想知道为什么流会在垃圾上窒息。

在加密中,必须非常仔细地检查所有,以确保攻击者不会偷偷摸摸地尝试某些事情。如果你指定了PKCS7填充,那么流是正确的,如果它在流的末尾没有找到正确的填充,则在末尾检查PKCS7填充并向右抛出异常。

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