要解密的数据长度无效

发布于 2024-07-22 03:27:29 字数 2745 浏览 3 评论 0原文

我正在尝试使用 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)

当整个文件已传输时,在 receiveFile 中的 using 语句末尾抛出异常。

我尝试在网上搜索,但只找到了在加密和解密单个字符串时使用编码时出现的问题的答案。 我使用 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);
}

有人知道我可能做错了什么吗?

I'm trying to encrypt and decrypt a file stream over a socket using RijndaelManaged, but I keep bumping into the exception

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)

The exception is thrown at the end of the using statement in receiveFile, when the whole file has been transferred.

I tried searching the web but only found answers to problems that arise when using Encoding when encrypting and decrypting a single string. I use a FileStream, so I don't specify any Encoding to be used, so that should not be the problem. These are my methods:

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;
        }
    }
}

This is the method I use to set up the ciphers. byte[] init is a generated byte array.

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);
}

Anyone have an idea in what I might be doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

舞袖。长 2024-07-29 03:27:29

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

顺便说一句, CipherMode.ECB 很可能是一次史诗般的失败 就您所做的事情的安全性而言。 至少使用 CipherMode.CBC(密码块链接),它实际上使用 IV 并使每个块依赖于前一个块。

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

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

It looks to me like you're not properly sending the final block. You need to at least FlushFinalBlock() the sending CryptoStream in order to ensure that the final block (which the receiving stream is looking for) is sent.

By the way, CipherMode.ECB is more than likely an epic fail in terms of security for what you're doing. At least use CipherMode.CBC (cipher-block chaining) which actually uses the IV and makes each block dependent on the previous one.

EDIT: Whoops, the enciphering stream is in read mode. In that case you need to make sure you read to EOF so that the CryptoStream can deal with the final block, rather than stopping after readBytes. It's probably easier to control if you run the enciphering stream in write mode.

One more note: You cannot assume that bytes in equals bytes out. Block ciphers have a fixed block size they process, and unless you are using a cipher mode that converts the block cipher to a stream cipher, there will be padding that makes the ciphertext longer than the plaintext.

已下线请稍等 2024-07-29 03:27:29

在 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 也会发生什么,但在这种情况下我稍后会倾向于这种情况。 感谢您的帮助杰弗里!

问候。

After the comment made by Jeffrey Hantin, I changed some lines in receiveFile to

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;
        }
    }
}

And voila, she works (because of the ever so kind padding that I didn't care to bother about earlier). I'm not sure what happens if Available returns 0 even though all data hasn't been transferred, but I'll tend to that later in that case. Thanks for your help Jeffrey!

Regards.

情绪操控生活 2024-07-29 03:27:29
cipher.Mode = CipherMode.ECB;

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

cipher.Mode = CipherMode.ECB;

Argh! Rolling your own security code is almost always a bad idea.

萌酱 2024-07-29 03:27:29

我的我刚刚删除了填充,它起作用了

评论了这一点 - cipher.Padding = PaddingMode.ISO10126;

Mine i just removed the padding and it works

Commented this out - cipher.Padding = PaddingMode.ISO10126;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文