C# 与“碰撞”;填充无效,无法删除“;当加密流关闭时

C# 与“碰撞”;填充无效,无法删除“;当加密流关闭时,c#,encryption,windows-mobile,C#,Encryption,Windows Mobile,tl;dr加密和解密工作正常且正确。我检查了一切。当我没有从加密流读取全部内容时,就会出现问题。我使用RijndaelManaged类,该应用程序适用于Windows Mobile 6 此应用程序使用XMLs,必须加密写入磁盘的所有内容。在获取XML(内存中)后,它会将内容直接加密到文件中。稍后,应用程序必须将所有这些小XML组合成一个大XML,但与此同时,我们可能需要XML中的一些信息。为了优化内存使用,我没有在内存中加载整个XML,我使用了一个XmlReader,它只从加密流中读取它需要的内

tl;dr加密和解密工作正常且正确。我检查了一切。当我没有从
加密流
读取全部内容时,就会出现问题。我使用
RijndaelManaged
类,该应用程序适用于Windows Mobile 6

此应用程序使用XMLs,必须加密写入磁盘的所有内容。在获取XML(内存中)后,它会将内容直接加密到文件中。稍后,应用程序必须将所有这些小XML组合成一个大XML,但与此同时,我们可能需要XML中的一些信息。为了优化内存使用,我没有在内存中加载整个XML,我使用了一个
XmlReader
,它只从
加密流中读取它需要的内容。但这会导致“填充无效且无法删除”崩溃

例如,这非常有效:

using (var fileStream = new FileStream(ResponsePath, FileMode.Open))
using (var crpytoStream = new CryptoStream(fileStream, key.CreateDecryptor(), CryptoStreamMode.Read))
using (var reader = StreamReader.Create(crpytoStream, settings))
{
    reader.ReadToEnd();
}
这不是:

using (var fileStream = new FileStream(ResponsePath, FileMode.Open))
using (var crpytoStream = new CryptoStream(fileStream, key.CreateDecryptor(), CryptoStreamMode.Read))
using (var reader = StreamReader.Create(crpytoStream, settings))
{
    var buffer = new char[1024];
    reader.ReadBlock(buffer , 0, 1024);
}
我有一个解决方案,但它看起来像一个可怕的黑客,它不适合大型XML。如果你知道更清洁的解决方案,我将不胜感激

编辑: 我测试了从流中读取不同数量的字节

  • 如果我从0开始读1,2,3。。。或者1024字节,当我关闭流时它会崩溃
  • 如果我从0开始读102510261027。。。或者2048字节,当我关闭流时它不会崩溃
  • 如果我从0开始读20492050。。。或者4096字节,它将崩溃 当我关闭小溪时
  • 如果我从0开始读取4097字节,当我关闭流时它不会崩溃
  • 如果我从0开始读取8192字节,它将崩溃 当我关闭小溪时

IV在读取之前加载。

解决方案是创建另一个流以读取到最后。从XML中获取所需的所有数据后,我创建一个
StreamReader
,并读取所有内容。如果XML是巨大的,这显然是不好的

using (var workaroundStream = new StreamReader(crpytoStream))
{
    var workaroundBuffer = new char[1024];
    while (workaroundStream.ReadBlock(workaroundBuffer, 0, 1024) != 0)
    {
    }
}

可以从加密数据的中间读取和解密

  • 在块边界上开始读取,AES为16字节
  • 停止在任何块bounbdry上读取
  • 读取块大小的倍数
  • 无填充解密
  • 注:

    • 如果模式为CBC,则先读取一个块,然后将其用作IV
    • 如果读取到最后,请使用填充进行解密

    AES是一种基于块的加密算法,它一次处理一个块。因此,只要起始点位于加密过程中使用的块边界上,并且长度是块大小的倍数,那么从起始点开始解密就没有问题

    对于CBC模式,在加密之前,前一块与数据异或,解密时必须再次与解密数据异或。看


    请参阅。

    这并不能回答问题,可能只是读取整个加密数据。@zaph真的吗?我只是用一个有效的解决方案回答了我的问题,解决了我的问题,尽管是以一种不好的方式,而你却告诉我,它并没有回答我的问题?这是“尽管是以一种不好的方式”的部分,其中有一个不坏的解决方案。如果这真的是一个有隐含答案的问题,那么问题似乎是关于避免读取和解密整个文件。这些文件不在块边界上,0->1023在块边界上。块边界是(对于AES)16字节的倍数。索引从0开始。AES是一种基于块的加密算法,它一次处理一个块。因此,只要起始点位于加密过程中使用的块边界上,并且长度是块大小的倍数,那么从起始点开始解密就没有问题。对于CBC模式,在加密之前,前一块与数据异或,解密时必须再次与解密数据异或。看,我不知道我是否明白你想说什么。我总是从
    加密流
    读取0,第一个块是IV。我不想从中间开始。崩溃的程度取决于我的阅读量。1->1024意味着:如果我读取1个字节(或2,3,…直到1024个字节,包括1024个字节),那么我关闭流,我就会崩溃。如果我读取了1025个字节(或10261027,…直到2048年),则没有崩溃。更新:如果不读取最后一个块,则必须指定没有填充作为解密选项,填充仅在最后一个块上。请参阅我的答案和中的第(4)点。必须始终读取块大小的精确倍数。如果您使用的是CBC模式,并且没有在第一个区块开始阅读,您必须提供上一个区块作为IV,请参阅我答案中的第一个注释。如果你把方块、IV和填充选项弄对了,答案就行了。好的,我来检查一下。再次感谢!