3

我正在尝试读取服务器上的文件(以 5KB 为单位),使用 AES 加密该块并将其发送到客户端。在客户端,我解密收到的块,并附加到一个文件以取回原始文件。

但是,我在客户端收到的解密块大小与在服务器上加密的明文块不同。

例如,我有一个 15.5 KB 的 exe 文件,所以我有 15.5*1024/5*1024 = 4 个块(整数)来加密并发送给客户端(前 3 个块的长度为 5120 字节,最后一个块的长度为 512 字节) . 然而,在客户端,解密的块大小为 5057、4970、5016 和 512 字节,相当于 15.1 KB 的文件大小(小于服务器实际发送的大小)。

这是我的代码片段:

服务器(将文件发送给客户端):

FileStream fs = new FileStream("lcd.exe", FileMode.Open, FileAccess.Read);

        //block size = 5KB
        int blockSize = 5 * 1024;

        //calculate number of blocks in data
        long numberOfBlocks = fs.Length / blockSize;

        if (fs.Length % blockSize != 0) numberOfBlocks++;

        byte[] numberOfBlocksBytes = BitConverter.GetBytes(numberOfBlocks);

        //send number of blocks to client
        SendMessage(sw, numberOfBlocksBytes);

        int count = 0, offset = 0, numberOfBytesToRead=0;

        Aes objAes = new Aes();

        while (count < numberOfBlocks)
        {
            byte[] buffer;

            numberOfBytesToRead = blockSize;

            if (fs.Length < offset + blockSize)
            {
                numberOfBytesToRead = (int)(fs.Length - offset);

            }

                buffer = new byte[numberOfBytesToRead];

                fs.Read(buffer, 0, numberOfBytesToRead);

            //encrypt before sending
            byte[] encryptedBuffer = objAes.Encrypt(buffer, Encoding.Default.GetBytes(sessionKey), initVector);

            SendMessage(sw, encryptedBuffer);

            offset += numberOfBytesToRead;

            count++;

        }

        fs.Close();

接收文件的客户端代码:

byte[] numberOfBlocksBytes = ReadMessage(sr);

        long numberOfBlocks = BitConverter.ToInt64(numberOfBlocksBytes, 0);

        FileStream fs = new FileStream("lcd.exe", FileMode.Append, FileAccess.Write);

        //block size = 5KB
        int blockSize = 5 * 1024;

        Aes objAes = new Aes();

        int count = 0, offset = 0;

        while (count < numberOfBlocks)
        {

            byte[] encryptedBuffer = ReadMessage(sr);

            byte[] buffer = objAes.Decrypt(encryptedBuffer, sessionKey, initVector);

            fs.Write(buffer, 0, buffer.Length);

            offset += buffer.Length;

            count++;

        }

        fs.Close();

我的 AES 加密代码:

private const int StandardKeyLength = 16;

    public byte[] Encrypt(byte[] plainText, byte[] key, byte[] initVector)
    {
        if (key.Length != StandardKeyLength | initVector.Length != StandardKeyLength)
        {
            throw new ArgumentException("Key Length and Init Vector should be 16 bytes (128 bits) in size");
        }

        var bPlainBytes = plainText;

        var objRm = new RijndaelManaged();

        objRm.Key = key;
        objRm.IV = initVector;
        objRm.Padding = PaddingMode.PKCS7;
        objRm.BlockSize = 128;

        var ict = objRm.CreateEncryptor(objRm.Key, objRm.IV);

        var objMs = new MemoryStream();
        var objCs = new CryptoStream(objMs, ict, CryptoStreamMode.Write);

        objCs.Write(bPlainBytes, 0, bPlainBytes.Length);

        objCs.FlushFinalBlock();

        var bEncrypted = objMs.ToArray();

        return bEncrypted;
    }

我用于解密的 AES 代码:

    public byte[] Decrypt(byte[] cipherText, byte[] key, byte[] initVector)
    {
        if (key.Length != StandardKeyLength | initVector.Length != StandardKeyLength)
        {
            throw new ArgumentException("Key Length and Init Vector should be 16 bytes (128 bits) in size");
        }

        var bCipherBytes = cipherText;

        var objRm = new RijndaelManaged();
        objRm.Key = key;
        objRm.IV = initVector;
        objRm.Padding = PaddingMode.PKCS7;
        objRm.BlockSize = 128;

        var ict = objRm.CreateDecryptor(objRm.Key, objRm.IV);
        var objMs = new MemoryStream(bCipherBytes);
        var objCs = new CryptoStream(objMs, ict, CryptoStreamMode.Read);

        var streamobj = new StreamReader(objCs);

        var strDecrypted = streamobj.ReadToEnd();

        return (Encoding.Default.GetBytes(strDecrypted));
    }

这些是我在调试在服务器上发送文件块的 while 循环时得到的结果:

发送的实际文件大小:15.5 KB = 15872 字节

缓冲区大小(明文) 加密缓冲区大小(发送) 偏移计数

5120 5136 5120 0

5120 5136 10240 1

5120 5136 15360 2

 512 528 15872 3

这些是我在调试接收客户端文件块的 while 循环时得到的结果:

收到的实际文件大小:15.1 KB = 15555 字节

接收到的缓冲区大小 解密的缓冲区大小偏移计数

5136 5057 5057 0

5136 4970 10027 1

5136 5016 15043 2

 528 512 15555 3

很明显,发送和接收代码工作正常(因为发送的加密缓冲区大小 = 接收缓冲区大小)。但是,解密后的缓冲区大小与缓冲区大小(明文)完全不匹配,除了长度为 512 字节的最后一个块。

解密可能有什么问题,因为我没有在客户端完全接收文件?

4

3 回答 3

2

您被绊倒了,因为在您的 Decrypt 语句中,您将密文视为字符串。具体来说,这些行:

var streamobj = new StreamReader(objCs);
var strDecrypted = streamobj.ReadToEnd();

return (Encoding.Default.GetBytes(strDecrypted));

相反,您希望在 CryptoStream 上调用 Read 以将原始字节数组读入缓冲区。然后,您可以返回该缓冲区,而无需尝试将其强制转换为字符串(使用流阅读器正在发生这种情况)。

你应该使用更多类似的东西:

public byte[] Decrypt(byte[] cipherText, byte[] key, byte[] initVector)
{
    if (key.Length != StandardKeyLength | initVector.Length != StandardKeyLength)
    {
        throw new ArgumentException("Key Length and Init Vector should be 16 bytes (128 bits) in size");
    }

    var bCipherBytes = cipherText;

    var objRm = new RijndaelManaged();
    objRm.Key = key;
    objRm.IV = initVector;
    objRm.Padding = PaddingMode.PKCS7;
    objRm.BlockSize = 128;

    var ict = objRm.CreateDecryptor(objRm.Key, objRm.IV);
    var objMs = new MemoryStream(bCipherBytes);
    var objCs = new CryptoStream(objMs, ict, CryptoStreamMode.Read);

    var buffer = new byte[cipherText.Length];
    int readBytes = objCs.Read(buffer, 0, cipherText.Length);

    var trimmedData = new byte[readBytes];
    Array.Copy(buffer, trimmedData, readBytes);
    return trimmedData;
}

我还建议您查看我在 Snipt 上维护的加密实用程序。特别是对称加密和解密方法。就目前而言,您的代码有很多使用块丢失和一些潜在的资源泄漏。

于 2013-07-05T14:02:29.740 回答
1
    var streamobj = new StreamReader(objCs);

这不太可能运作良好。StreamReader 将假定解密的数据是 utf-8 编码的文本。从加密数据的代码中没有任何暗示实际上是这种情况,它需要一个字节[]。

请改用 FileStream,因此根本不会进行任何转换。还可以帮助您避免 Encoding.Default.GetBytes() 数据随机化器。

于 2013-07-05T14:00:45.867 回答
-1

快速观察,这可能只是我的无知: Encrypt() 方法使用默认编码来获取会话密钥字节。在接收端,Decrypt() 方法使用 sessionKey 本身作为第二个参数,即不获取字节?

于 2013-07-05T13:38:04.273 回答