c# - CryptoStream 没有像预期的那样刷新

标签 c# .net networking

我正在处理的 C# .NET Framework 4.5 代码应该允许我通过加密流将文本传输到另一个程序。我创建了两个简单的程序来演示我的问题。 EncryptionTestA 是服务器,意味着首先运行。 EncryptionTestB 是客户端,旨在第二个运行。 EncryptionTestB 连接后,它通过 CryptoStream 将文本“hello world”传输到另一个程序。至少在理论上是这样。

实际发生的是什么。我通过在内部接口(interface)上使用 Wireshark 观察数据传输来确认这一点。此代码绝对不会以其当前形式传输任何数据。我能够让它发送“hello world”的唯一方法是关闭客户端的 StreamWriter。这样做的问题是它还会关闭底层的 TCP 连接,这是我不想做的。

那么,我的问题是:如何在不关闭底层 TCP 连接的情况下刷新 StreamWriter/CryptoStream?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using System.Threading;
using System.Security;
using System.Security.Cryptography;
using System.Net;
using System.Net.Sockets;

namespace EncryptionTestA
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1892);
            listener.Start();
            TcpClient client = listener.AcceptTcpClient();
            NetworkStream ns = client.GetStream();

            Rijndael aes = RijndaelManaged.Create();
            byte[] key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
            byte[] iv = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
            CryptoStream cs = new CryptoStream(ns, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read);

            StreamReader sr = new StreamReader(cs);

            String test = sr.ReadLine();

            Console.Read();

            sr.Close();
            cs.Close();
            ns.Close();
            client.Close();
            listener.Stop();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using System.Threading;
using System.Security;
using System.Security.Cryptography;
using System.Net;
using System.Net.Sockets;

namespace EncryptionTestB
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpClient client = new TcpClient();
            client.Connect(IPAddress.Parse("127.0.0.1"), 1892);
            NetworkStream ns = client.GetStream();

            Rijndael aes = RijndaelManaged.Create();
            byte[] key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
            byte[] iv = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
            CryptoStream cs = new CryptoStream(ns, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write);

            StreamWriter sw = new StreamWriter(cs);

            sw.WriteLine("hello world");
            sw.Flush();
            //sw.Close();

            Console.Read();

            sw.Close();
            cs.Close();
            ns.Close();
            client.Close();
        }
    }
}

最佳答案

我认为问题在于您使用的是 block 密码 - 它总是以 block 为单位工作,所以直到您到达关闭流的最后一个 block (此时您有一个带有一些描述的填充的较短 block )当你有一个部分块时,什么都不能写入流。

我强烈怀疑,如果您尝试加密比“hello world”更长的内容 - 尝试至少 16 个字符,甚至更多 - 您会发现在关闭之前得到一些 block 流,但除非您碰巧碰到数据末尾的 block 边界,否则您仍然会在末尾丢失一些数据。

目前尚不清楚您的最终用例是什么:如果您尝试在同一流上发送具有某种描述的多条消息,我鼓励您制定一个方案,分别加密每条消息,然后将所有通信 channel 上的数据 - 带有长度前缀,以便您知道接收方的加密消息有多大。

请注意,在接收端,我强烈建议您避免使用DataAvailable。仅仅因为流中现在没有可用数据并不意味着您已经到达消息的末尾...这就是您需要长度前缀的原因。

关于c# - CryptoStream 没有像预期的那样刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17266902/

相关文章:

c# - 将 html 转换为 word

c# - 使用对象作为键时.Net MemoryCache Miss

.net - WCF 连接被错误中止/现有连接被远程主机强制关闭

C 套接字双栈 ss_family 始终 IPv6

networking - 你如何描述这种图表?

c# - 如何使用带有单个查询的 EF 从 MSSQL 选择 +1 记录?

c# - 如何使用.Net system.drawing.drawstring编写从右到左的字符串(项目是一个dll)?

c# - 如何对 csv 导出进行 HTML 编码

.NET ClickOnce 和 Vista 启动

android - iOS 和 Android 中的批量数据存储(10GB 以上)