C# 要解密的数据长度无效

C# 要解密的数据长度无效,c#,cryptography,rijndaelmanaged,C#,Cryptography,Rijndaelmanaged,我试图使用RijndaelManaged通过套接字对文件流进行加密和解密,但我一直遇到异常 CryptographicException: Length of the data to decrypt is invalid. at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)

我试图使用RijndaelManaged通过套接字对文件流进行加密和解密,但我一直遇到异常

CryptographicException: Length of the data to decrypt is invalid. at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.CryptoStream.FlushFinalBlock() at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
有人知道我可能做错了什么吗?

在我看来,你没有正确地发送最后一个区块。您至少需要
FlushFinalBlock()
发送
加密流
,以确保发送最终块(接收流正在寻找)

顺便说一句,就你所做的安全而言。至少使用
CipherMode.CBC
(密码块链接),它实际使用IV并使每个块依赖于前一个块

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

还有一点需要注意:您不能假设字节输入等于字节输出。分组密码处理的块大小固定,除非您使用的是将分组密码转换为流密码的密码模式,否则会有填充,使密文比明文长

cipher.Mode = CipherMode.ECB;

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

在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;
    }
}
瞧,她工作得很好(因为我以前根本不在乎这种填充物)。我不确定如果Available返回0会发生什么,即使所有数据都没有被传输,但在这种情况下,我将在稍后讨论。谢谢你的帮助,杰弗里


问候。

我的,我刚取下了填充物,效果很好


注释掉这个-cipher.Padding=PaddingMode.ISO10126

""?????呵呵?他在用Rijndael?这不是“自己滚”。不过,有一点值得注意,即开发人员需要小心如何使用加密。ECB在这里失败,因为每个块都是独立加密的。无论我使用哪种密码,我仍然可以得到“数据长度…”例外…@Cheeso:你不必制定自己的加密算法(甚至实现)来实现自己的安全性。在这种情况下,看起来Patrick试图通过网络发送文件-有很多好方法可以做到这一点。通过自己的方式,他几乎在应用程序中留下了一个巨大的安全漏洞,这不是通过良好的分析(就像一个像样的库)发现的,而是通过在StackOverflow上发布一个无关的问题发现的->FlushFinalBlock()我将更改密码模式,我只是作为一个示例输入它,这样您就知道我不会以任何“奇怪”的方式初始化密码。sendFile()中的readBytes尚未使用,我忘记将其删除。我读到了文件的末尾,所以这不应该是这里的问题。我认为cipher.Padding=PaddingMode.ISO10126;是在处理填充物吗?我可以改变什么使其工作?如果加密流处于读取模式,如果您处理它,最后的块将丢失;它必须从底层源流中实际读取文件的结尾以生成最后一个块。Jeffrey:如果我尝试调用stream.FlushFinalBlock(),它会说不支持异常:不能在同一个流上调用两次FlushFinalBlock。这是否意味着文件的结尾已经被读取(并发送)?不一定。由于流处于读取模式,您不能自己调用FlushFinalBlock,否则您将遇到一个问题:您需要确保EOF条件“读取”加密流。在接收端,您的代码似乎假设连线上的字节与文件中的字节之间存在字节对字节的对应关系,这实际上更可能是导致异常的原因。为了读取填充,您必须从套接字读取比文件大小允许的更多的字节。啊,当然,我不是从加密流读取,而是从套接字读取!愚蠢的我。。。
cipher.Mode = CipherMode.ECB;
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;
        }
    }
}