12

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

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

当整个文件已被传输时,在 receiveFile 中的 using 语句结束时会引发异常。

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

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

4

4 回答 4

6

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

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

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

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

于 2009-06-02T22:21:08.490 回答
1

在 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 会发生什么,即使所有数据都没有传输,但我会在这种情况下稍后处理。感谢您的帮助杰弗里!

问候。

于 2009-06-04T16:41:38.700 回答
0
cipher.Mode = CipherMode.ECB;

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

于 2009-06-02T23:40:59.077 回答
0

我的我刚刚删除了填充,它可以工作

对此进行了注释 - cipher.Padding = PaddingMode.ISO10126;

于 2016-07-08T01:02:16.317 回答