可以在解密之前确定CryptoStream的长度吗?

时间:2014-10-07 15:18:39

标签: c# asp.net encryption

在解密之前是否可以获得解密数据的最终长度?这是一个例子:

RijndaelManaged RMCrypto = new RijndaelManaged();
RMCrypto.Padding = PaddingMode.ISO10126;
Response.Buffer = false;
Response.ClearHeaders();
Response.ClearContent();
Response.AddHeader("Content-length", ??????);
CryptoStream crypto = new CryptoStream(Response.OutputStream, RMCrypto.CreateDecryptor(Key, IV), CryptoStreamMode.Write);
using (Stream orig = GetDataStream())
{
    int bufferSize = 100000;
    int bytesReceived = bufferSize;
    byte[] buffer = new byte[bufferSize];
    while (bytesReceived == bufferSize)
    {
        bytesReceived = orig.Read(buffer, 0, bufferSize);
        crypto.Write(buffer, 0, bytesReceived);
    }
    crypto.FlushFinalBlock();
}
Response.End();

此代码已简化。源数据已加密,并从Stream方法检索为GetDataStream()。如果未包含content-length标头,则浏览器将无法提供下载文件的完成百分比或时间估算。提前解密流是不可能的,因为流可能在千兆字节大小范围内并通过网络读取。

2 个答案:

答案 0 :(得分:1)

如果您知道正在使用分组密码模式和填充模式,那么可以提前确定长度。 (例如,如果你正在使用CBC,那么你可以使用倒数第二个密文块作为IV,最后的密文块作为实际的密文,然后计算出存在多少填充字节。)

大多数开发者只是去“???”在上面并以更容易的方式解决问题:在初始加密过程中将明文长度存储在某处。

答案 1 :(得分:0)

不,由于用于CBC的最后加密块,即使在收到后,也无法确切知道 。此外,CBC加密不会在任何地方存储密文的大小。 您确实知道内部的明文与密文相同,但对于AES,减去一个 15个字节(blocksize - 1),不包括IV大小。在您之后我们收到了最后一个两个块,您可以使用倒数第一个块作为IV来检查精确的明文长度,然后解密最后一个块(与Levi的答案相同)。

内容标题用于正文中的整个内容,因此这将是密文:

  

Content-Length entity-header字段表示实体主体的大小,   在十进制数的OCTET中,发送给收件人,或者在HEAD的情况下   方法,本已发送的实体主体的大小有请求   是一个GET。

所以??????在您的问题中,应该是明文的大小,而是密文的大小(包括IV,身份验证标记和其他开销,如果存在的话)。

如果您想事先知道确切的纯文本大小(以字节为单位),只需在密文前面存储一个64位(大端)整数。它与密文大小密切相关,所以我认为它不是很保密。

另一个巧妙的技巧是使用CTR或GCM模式加密。 CTR的密文是 - 禁止IV大小 - 正好是明文的大小。 GCM添加​​了身份验证标记,但在其中使用CTR进行加密。请注意,对于这些模式中的任何一种,都不应对相同的键重复IV。