我对.NET CryptoStream
类的一个怪癖感到困惑:它的Dispose()
方法读取了密文的末尾,寻找不应该填充的填充,并抛出结果是CryprographicException
。
下面的C#程序加密几个字节,调整密文数组的大小,以便在密文结束后有更多(无意义)字节,然后尝试解密它。重点是:
CryptoStream
中写入6个字节并使用PaddingMode.PKCS7
(默认值),因此块中剩余的两个字节用填充值0x02填充。CryptoStream
读取了6个字节;我不要求它解密到废话部分,而我不依赖于它识别填充以找出它何时到达明文的末尾。 问题在于,当调用解密CryptoStream
的{{1}}时(自动在Dispose()
块的末尾),我会收到using
的消息“糟糕的数据”。它的堆栈跟踪显示它正在执行CryptographicException
,并且所有16个字节都已从CryptoStream.FlushFinalBlock()
消耗,而不仅仅是与实际加密数据相对应的8个字节。
如果我删除调整ciphertextStream
数组大小的行,则程序可以正常工作。如果我在解密前做ciphertext
,程序也能正常工作 - 但这基本上使填充字节成为明文的一部分,所以我宁愿不这样做。显然,问题在于与填充相关;据我所知,它被解密了第二个块,并期望在它的末尾找到有效的tripleDes.Padding = PaddingMode.None
样式填充。
因为我只是从PKCS7
读取足够的内容来要求解密一个块,并且该块是正确填充的最终块,然后我关闭CryptoStream
而不再读取,为什么流认为它需要读取另一个块并寻找更多填充?为什么它甚至试图将更多输入作为其CryptoStream
的一部分?
Dispose()
答案 0 :(得分:3)
你故意在流的末尾添加垃圾,然后想知道为什么流会在垃圾上窒息。
在加密中,必须非常仔细地检查所有,以确保攻击者不会偷偷摸摸地尝试某些事情。如果你指定了PKCS7填充,那么流是正确的,如果它在流的末尾没有找到正确的填充,则在末尾检查PKCS7填充并向右抛出异常。
流无法知道实际的密文在流的中间结束,而不是在结尾处。你怎么能指望它知道?在加密中,规则是标记任何和所有异常,并且流的(明显)末端的错误填充是文档将告诉您导致异常的内容。