通过 System.Net.Socket 发送后使用 Rijndael 解密数据的问题

Posted

技术标签:

【中文标题】通过 System.Net.Socket 发送后使用 Rijndael 解密数据的问题【英文标题】:Issues with decrypting data with Rijndael after sending through System.Net.Socket 【发布时间】:2015-01-05 22:51:30 【问题描述】:

我遵循了来自 YouTube 的教程 http://tinyurl.com/ljvzjqk 和 http://tinyurl.com/os7vlgr,并尝试在我正在处理的客户端/服务器项目中实现这一点。 我可以很好地在客户端程序中加密和解密字符串,但是当服务器接收到数据时,它并没有正确解密。

在调试的时候可以看到携带数据的byte[]两端是完全一样的。

在这两个程序中,这是在类中声明的:

static SymmetricAlgorithm rjnObj;
static byte[] Key =  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 ;

服务器:

static void Main(string[] args)
    
        rjnObj = Rijndael.Create();
        rjnObj.Padding = PaddingMode.Zeros;
        rjnObj.Key = Key;

        Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1980);

        serverSocket.Bind(localEP);
        serverSocket.Listen(10);
        serverSocket = serverSocket.Accept();
        while(true)
        
            byte[] dataReceived = new byte[1024];
            int lengthOfData = serverSocket.Receive(dataReceived);
            byte[] dataReceived2 = new byte[lengthOfData];
            for (int i = 0; i < lengthOfData; i++)
            
                dataReceived2[i] = dataReceived[i];
            
            Console.WriteLine("Received: 0", Encoding.UTF8.GetString(dataReceived2));
            Console.WriteLine("Decrypted: 0", Decrypt(dataReceived2));
        
    
    public static string Decrypt(byte[] cipherbytes)
    
        System.IO.MemoryStream ms = new System.IO.MemoryStream(cipherbytes);
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateDecryptor(), CryptoStreamMode.Read);

        cs.Read(cipherbytes, 0, cipherbytes.Length);
        byte[] plainBytes = ms.ToArray();
        cs.Close();
        ms.Close();

        return Encoding.UTF8.GetString(plainBytes);
    

客户:

static void Main(string[] args)
    
        rjnObj = Rijndael.Create();
        rjnObj.Padding = PaddingMode.Zeros;
        rjnObj.Key = Key;

        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1980);

        try
        
            clientSocket.Connect(serverEP);
            Console.WriteLine("Connected to 0.", clientSocket.RemoteEndPoint);

            while(true)
            
                Console.Write("String to send: ");
                byte[] dataToSend = Encrypt(Console.ReadLine());
                clientSocket.Send(dataToSend);

                Console.WriteLine("Encrypted string: 0", Encoding.UTF8.GetString(dataToSend));
                Console.WriteLine("Decrypted string: 0", Decrypt(dataToSend));
            
        
        catch (Exception e)
        
            Console.WriteLine("Something went wrong...");
            Console.WriteLine(e.ToString());
            Console.ReadKey();
        
    
    public static byte[] Encrypt(string s)
    
        byte[] plainBytes = Encoding.UTF8.GetBytes(s);
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateEncryptor(), CryptoStreamMode.Write);

        cs.Write(plainBytes, 0, plainBytes.Length);
        cs.Close();
        byte[] cipherbytes = ms.ToArray();
        ms.Close();

        return cipherbytes;
    
    public static string Decrypt(byte[] cipherbytes)
    
        System.IO.MemoryStream ms = new System.IO.MemoryStream(cipherbytes);
        CryptoStream cs = new CryptoStream(ms, rjnObj.CreateDecryptor(), CryptoStreamMode.Read);

        cs.Read(cipherbytes, 0, cipherbytes.Length);
        byte[] plainBytes = ms.ToArray();
        cs.Close();
        ms.Close();

        return Encoding.UTF8.GetString(plainBytes);
    

客户端程序的输出:

Connected to 127.0.0.1:1980.
String to send: Hello server!
Encrypted string: ?*?8?2?HfG▲z  ?K
Decrypted string: Hello server!
String to send:

服务器程序的输出:

Received: ?*?8?2?HfG▲z  ?K
Decrypted: E??diQ♣?ZX??♂?z

如你所见,服务端的加密字符串和客户端的加密字符串是相等的,所以我猜是和rjnObj有关,而且这个对象两端并不完全相同。

这里给出的代码是我为提出这个问题而创建的新解决方案。 我用过PaddingMode.Zeros,因为我在尝试PKCS7的时候遇到了异常。

在服务器代码中,我将另一个 byte[] dataReceived2 设置为接收到的 byte[] 的确切长度。 我发现了其他通过网络发送加密数据的代码示例,但这些示例使用 TcpClient 和 NetworkStream。 在我正在为一个学校项目开发的解决方案中,我正在使用 Sockets,我真的不想重写该解决方案。

如果有人能帮我解决这个问题,那就太好了!谢谢!

【问题讨论】:

【参考方案1】:

尝试使用相同的 IV。我相信当你创建Rijndael.Create()的新实例时,Key和IV会随机生成。您只设置了 Key,但要完成这项工作,您还需要使用相同的 IV。

在客户端上,您使用Rijndael 的相同实例,因此加密和解密工作正常。

您可能想查看Rijndael 类用法here 的文档和示例。我喜欢它的是使用语句。它看起来更干净,因为流一旦不再使用就会关闭。

【讨论】:

【参考方案2】:

您在服务器中的 Decrypt 方法根本没有任何意义。正如你现在所做的那样,你应该从 中读取 cs Stream into 明文数组。或者,您可以对流进行不同的分层并将密文写入到 cs 流中,然后从底层内存流中检索明文。我认为后一种方法更干净,更容易。

【讨论】:

以上是关于通过 System.Net.Socket 发送后使用 Rijndael 解密数据的问题的主要内容,如果未能解决你的问题,请参考以下文章

Gmail:如何以编程方式发送电子邮件

MPMoviePlayerController 在全屏模式后使 App 的方向不正确

获取本机IPV4地址

在Android中单击后使标记可拖动

我们可以在 MFP 上注销后使旧的访问令牌失效吗?

添加属性文件后使eclipse更快