要解密的数据长度无效

我正在尝试使用RijndaelManaged通过套接字加密和解密文件流,但我一直在碰到exception

  CryptographicException:要解密的数据长度无效。
    在System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount)
    在System.Security.Cryptography.CryptoStream.FlushFinalBlock()
    在System.Security.Cryptography.CryptoStream.Dispose(布尔处理)

当整个文件被传输时,在receiveFile中的using语句结束时抛出exception。

我尝试在网上搜索,但只找到了在加密和解密单个字符串时使用编码时出现的问题的答案。 我使用FileStream,所以我没有指定要使用的任何编码,所以这不应该是问题。 这些是我的方法:

private void transferFile(FileInfo file, long position, long readBytes) { // transfer on socket stream Stream stream = new FileStream(file.FullName, FileMode.Open); if (position > 0) { stream.Seek(position, SeekOrigin.Begin); } // if this should be encrypted, wrap the encryptor stream if (UseCipher) { stream = new CryptoStream(stream, streamEncryptor, CryptoStreamMode.Read); } using (stream) { int read; byte[] array = new byte[8096]; while ((read = stream.Read(array, 0, array.Length)) > 0) { streamSocket.Send(array, 0, read, SocketFlags.None); position += read; } } } private void receiveFile(FileInfo transferFile) { byte[] array = new byte[8096]; // receive file Stream stream = new FileStream(transferFile.FullName, FileMode.Append); if (UseCipher) { stream = new CryptoStream(stream, streamDecryptor, CryptoStreamMode.Write); } using (stream) { long position = new FileInfo(transferFile.Path).Length; while (position < transferFile.Length) { int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); int read = position < array.Length ? streamSocket.Receive(array, maxRead, SocketFlags.None) : streamSocket.Receive(array, SocketFlags.None); stream.Write(array, 0, read); position += read; } } } 

这是我用来设置密码的方法。 byte [] init是生成的字节数组。

 private void setupStreamCipher(byte[] init) { RijndaelManaged cipher = new RijndaelManaged(); cipher.KeySize = cipher.BlockSize = 256; // bit size cipher.Mode = CipherMode.ECB; cipher.Padding = PaddingMode.ISO10126; byte[] keyBytes = new byte[32]; byte[] ivBytes = new byte[32]; Array.Copy(init, keyBytes, 32); Array.Copy(init, 32, ivBytes, 0, 32); streamEncryptor = cipher.CreateEncryptor(keyBytes, ivBytes); streamDecryptor = cipher.CreateDecryptor(keyBytes, ivBytes); } 

任何人都知道我可能做错了什么?

它看起来像你没有正确发送最后一块。 您需要至少FlushFinalBlock()发送CryptoStream ,以确保发送最终块(接收流正在查找)。

顺便说一句, CipherMode.ECB很可能是你正在做的安全方面的史诗般的失败 。 至少使用CipherMode.CBC (密码块链接),它实际上使用IV并使每个块依赖于前一个。

编辑:哎呀,加密流处于读取模式。 在这种情况下,您需要确保读取EOF,以便CryptoStream可以处理最终块,而不是在readBytes之后停止。 如果在写入模式下运行加密流,则可能更容易控制。

还有一点需要注意:你不能假设字节数等于字节数。 分组密码具有它们处理的固定块大小,除非您使用将分组密码转换为流密码的密码模式,否则将存在使密文长于明文的填充。

在Jeffrey Hantin的评论之后,我将receiveFile中的一些行更改为

 using (stream) { FileInfo finfo = new FileInfo(transferFile.Path); long position = finfo.Length; while (position < transferFile.Length) { int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); int read = position < array.Length ? streamSocket.Receive(array, maxRead, SocketFlags.None) : streamSocket.Receive(array, SocketFlags.None); stream.Write(array, 0, read); position += read; } } 

->

 using (stream) { int read = array.Length; while ((read = streamSocket.Receive(array, read, SocketFlags.None)) > 0) { stream.Write(array, 0, read); if ((read = streamSocket.Available) == 0) { break; } } } 

瞧,她的工作(因为我之前并不在乎打扰的那种填充物)。 即使所有数据都没有被传输,我也不确定如果Available返回0会发生什么,但在那种情况下我会倾向于那样。 谢谢你的帮助杰弗里!

问候。

 cipher.Mode = CipherMode.ECB; 

哎呀! 滚动自己的安全代码几乎总是一个坏主意。

我只是删除了填充,它的工作原理

评论出来了 – cipher.Padding = PaddingMode.ISO10126;