2017-07-18 43 views
-1

tl; dr加密和解密工作正常并且正确。我检查了一切。如果我没有阅读CryptoStream的全部内容,则会出现问题。我使用RijndaelManaged类和该应用程序是为Windows Mobile 6.CryptoStream关闭时出现“填充无效且无法删除”的冲突

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

例如,这完美的作品:

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开始读取1025,1026,1027或2048字节,当关闭流时它不会崩溃。
  • 如果我从0开始读取2049,2050,...或4096字节,当关闭流时它会崩溃 。
  • 如果我从0开始读取4097个字节,当关闭流时它不会崩溃。
  • 如果我从0开始读取8192个字节,当关闭流时它将崩溃 。

IV在读取前加载。

+0

那些不在块边界上,0 - > 1023在块边界上。块边界是(对于AES)16字节的倍数。索引从0开始。 – zaph

+0

AES是一种基于块的加密算法,它一次处理一个块。因此,只要开始点位于加密过程中使用的块边界上并且长度是块大小的倍数,就不会在开始时开始解密。对于CBC模式,先前块在加密之前与数据进行异或并且解密必须再次与解密数据异或。请参阅[[CBC模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29))。 – zaph

+0

我不知道我是否明白你想说什么。我总是从0读取,第一个块是IV,来自'CryptoStream'。我并不想从中间开始。 根据我阅读的内容而出现崩溃。 1 - > 1024意味着这个:如果我读取1个字节(或者2,3,...直到包含1024),那么我关闭这个流,我会崩溃。如果我读取1025字节(或1026,1027,...直到2048年),则不会崩溃。 – eli

回答

0

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

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

这不会回答这个问题,除了读取整个加密数据之外,这是可能的。 – zaph

+0

@zaph真的吗?我只是用一种能解决问题的解决方案回答我的问题,虽然方式不好,而且你告诉我它不能回答我的问题? – eli

+0

这是“不好的方式”的一部分,在那里有一个不错的解决方案。这似乎是一个问题,如果它真的是一个隐含的答案,那就是避免阅读和解密整个文件。 – zaph

0

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

  1. 在块边界开始读取,AES为16字节。
  2. 停止读取任何块自动。
  3. 读取块大小的倍数。
  4. 解密没有填充。

注:

  • 如果模式是CBC读一个块之前,使用该作为IV。
  • 如果读到最后用填充解密。

AES是一种基于块的加密算法,它一次处理一个块。因此,只要开始点位于加密过程中使用的块边界上并且长度是块大小的倍数,就不会在开始时开始解密。

对于CBC模式,先前块与加密前的数据相异,并且解密后的数据必须与解密后的数据再次进行异或。见CBC mode

PKCS#7 padding

相关问题