服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 利用C#实现SSLSocket加密通讯的方法详解

利用C#实现SSLSocket加密通讯的方法详解

2022-09-27 14:08小y C#

这篇文章主要给大家介绍了关于如何利用C#实现SSLSocket加密通讯的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

SSL Socket通讯是对socket的扩展,增加Socket通讯的数据安全性,SSL认证分为单向和双向认证。单向认证只认证服务器端的合法性而不认证客户端的合法性。双向认证是同时认证服务端和客户端。下面我分别说说使用C#实现单向认证和双向认证的过程,并用代码实现。

一、 单向认证

第1步:准备一个数字证书,可以使用如下脚本生成

先进入到vs2005的命令行状态,即:

开始–>程序–>Microsoft Visual Studio 2005–>Visual Studio Tools–>Visual Studio 2005 命令提示

键入: makecert -r -pe -n “CN=TestServer” -ss Root -sky exchange

说明:上面的指令将在创建一个受信任的根证书,

第2步创建服务器端程序,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using System;
using System.ServiceModel;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Text;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.IdentityModel.Tokens;
using System.IdentityModel.Selectors;
 
namespace ConsoleApp
{
public class Program
{
static X509Certificate serverCertificate = null;
 public static void RunServer()
  {
    TcpListener listener = new TcpListener(IPAddress.Parse("192.168.1.25"), 901);
    listener.Start();
    while (true)
    {
      try
      {
        Console.WriteLine("Waiting for a client to connect...");
        TcpClient client = listener.AcceptTcpClient();
        ProcessClient(client);
      }
      catch
      {
      }
    }
  }
 
  static void ProcessClient(TcpClient client)
  {
    SslStream sslStream = new SslStream(client.GetStream(), false);
    try
    {
      sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);
      DisplaySecurityLevel(sslStream);
      DisplaySecurityServices(sslStream);
      DisplayCertificateInformation(sslStream);
      DisplayStreamProperties(sslStream);
 
      sslStream.ReadTimeout = 5000;
      sslStream.WriteTimeout = 5000;
      byte[] message = Encoding.UTF8.GetBytes("Hello from the server.");
      Console.WriteLine("Sending hello message.");
      sslStream.Write(message);
      Console.WriteLine("Waiting for client message...");
      while (true)
      {
        string messageData = ReadMessage(sslStream);
        Console.WriteLine("Received: {0}", messageData);
        if (messageData.ToUpper() == "EXIT")
          break;
      }
    }
    catch (AuthenticationException e)
    {
      Console.WriteLine("Exception: {0}", e.Message);
      if (e.InnerException != null)
      {
        Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
      }
      Console.WriteLine("Authentication failed - closing the connection.");
      sslStream.Close();
      client.Close();
      return;
    }
    finally
    {
      sslStream.Close();
      client.Close();
    }
  }
 
  static string ReadMessage(SslStream sslStream)
  {
    byte[] buffer = new byte[2048];
    StringBuilder messageData = new StringBuilder();
    int bytes = -1;
    do
    {
      bytes = sslStream.Read(buffer, 0, buffer.Length);
      Decoder decoder = Encoding.UTF8.GetDecoder();
      char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
      decoder.GetChars(buffer, 0, bytes, chars, 0);
      messageData.Append(chars);
      if (messageData.ToString().IndexOf("") != -1)
      {
        break;
      }
    }
    while (bytes != 0);
 
    return messageData.ToString();
  }
 
  static void DisplaySecurityLevel(SslStream stream)
  {
    Console.WriteLine("Cipher: {0} strength {1}", stream.CipherAlgorithm, stream.CipherStrength);
    Console.WriteLine("Hash: {0} strength {1}", stream.HashAlgorithm, stream.HashStrength);
    Console.WriteLine("Key exchange: {0} strength {1}", stream.KeyExchangeAlgorithm, stream.KeyExchangeStrength);
    Console.WriteLine("Protocol: {0}", stream.SslProtocol);
  }
 
  static void DisplaySecurityServices(SslStream stream)
  {
    Console.WriteLine("Is authenticated: {0} as server? {1}", stream.IsAuthenticated, stream.IsServer);
    Console.WriteLine("IsSigned: {0}", stream.IsSigned);
    Console.WriteLine("Is Encrypted: {0}", stream.IsEncrypted);
  }
 
  static void DisplayStreamProperties(SslStream stream)
  {
    Console.WriteLine("Can read: {0}, write {1}", stream.CanRead, stream.CanWrite);
    Console.WriteLine("Can timeout: {0}", stream.CanTimeout);
  }
 
  static void DisplayCertificateInformation(SslStream stream)
  {
    Console.WriteLine("Certificate revocation list checked: {0}", stream.CheckCertRevocationStatus);
 
    X509Certificate localCertificate = stream.LocalCertificate;
    if (stream.LocalCertificate != null)
    {
      Console.WriteLine("Local cert was issued to {0} and is valid from {1} until {2}.",
      localCertificate.Subject,
        localCertificate.GetEffectiveDateString(),
        localCertificate.GetExpirationDateString());
    }
    else
    {
      Console.WriteLine("Local certificate is null.");
    }
    X509Certificate remoteCertificate = stream.RemoteCertificate;
    if (stream.RemoteCertificate != null)
    {
      Console.WriteLine("Remote cert was issued to {0} and is valid from {1} until {2}.",
        remoteCertificate.Subject,
        remoteCertificate.GetEffectiveDateString(),
        remoteCertificate.GetExpirationDateString());
    }
    else
    {
      Console.WriteLine("Remote certificate is null.");
    }
  }
 
  private static void DisplayUsage()
  {
    Console.WriteLine("To start the server specify:");
    Console.WriteLine("serverSync certificateFile.cer");
  }
 
  public static void Main(string[] args)
  {
    try
    {
      X509Store store = new X509Store(StoreName.Root);
      store.Open(OpenFlags.ReadWrite);
      // 检索证书
      X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName, "TestServer", false); // vaildOnly = true时搜索无结果。
      if (certs.Count == 0) return;
 
      serverCertificate = certs[0];
      RunServer();
      store.Close(); // 关闭存储区。
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.Message);
    }
    Console.ReadLine();
  }
}
}

第3步,创建客户端代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
namespace ConsoleAppClient
{
using System;
using System.Collections;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
namespace Examples.System.Net
{
  public class SslTcpClient
  {
    private static Hashtable certificateErrors = new Hashtable();
    // The following method is invoked by the RemoteCertificateValidationDelegate.
    public static bool ValidateServerCertificate(
       object sender,
       X509Certificate certificate,
       X509Chain chain,
       SslPolicyErrors sslPolicyErrors)
    {
      if (sslPolicyErrors == SslPolicyErrors.None)
        return true;
      Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
      // Do not allow this client to communicate with unauthenticated servers.
      return false;
    }
 
    public static void RunClient(string machineName)
    {
      // Create a TCP/IP client socket.
      // machineName is the host running the server application.
      TcpClient client = new TcpClient(machineName, 901);
      Console.WriteLine("Client connected.");
      // Create an SSL stream that will close the client's stream.
      SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
      try
      {
        sslStream.AuthenticateAsClient("TestServer");
      }
      catch (AuthenticationException e)
      {
        Console.WriteLine("Exception: {0}", e.Message);
        if (e.InnerException != null)
        {
          Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
        }
        Console.WriteLine("Authentication failed - closing the connection.");
        client.Close();
        return;
      }
      // Encode a test message into a byte array.
      // Signal the end of the message using the "<EOF>".
      byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
      // Send hello message to the server.
      sslStream.Write(messsage);
      sslStream.Flush();
      // Read message from the server.
      string serverMessage = ReadMessage(sslStream);
      Console.WriteLine("Server says: {0}", serverMessage);
 
      messsage = Encoding.UTF8.GetBytes("exit");
      sslStream.Write(messsage);
      sslStream.Flush();
      // Close the client connection.
      client.Close();
      Console.WriteLine("Client closed.");
    }
 
    static string ReadMessage(SslStream sslStream)
    {
      // Read the message sent by the server.
      // The end of the message is signaled using the
      // "<EOF>" marker.
      byte[] buffer = new byte[2048];
      StringBuilder messageData = new StringBuilder();
      int bytes = -1;
      do
      {
        bytes = sslStream.Read(buffer, 0, buffer.Length);
 
        // Use Decoder class to convert from bytes to UTF8
        // in case a character spans two buffers.
        Decoder decoder = Encoding.UTF8.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
        decoder.GetChars(buffer, 0, bytes, chars, 0);
        messageData.Append(chars);
        // Check for EOF.
        if (messageData.ToString().IndexOf("<EOF>") != -1)
        {
          break;
        }
      } while (bytes != 0);
 
      return messageData.ToString();
    }
 
    private static void DisplayUsage()
    {
      Console.WriteLine("To start the client specify:");
      Console.WriteLine("clientSync machineName [serverName]");
      Environment.Exit(1);
    }
 
    public static void Main(string[] args)
    {
      string machineName = null;
      machineName = "192.168.1.25";
      try
      {
        RunClient(machineName);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
      Console.ReadLine();
    }
  }
}
}

运行效果如下图:

利用C#实现SSLSocket加密通讯的方法详解

导致通讯失败可能问题如下:

1)证书没有导入到受信任的根证书列表中;2)证书失效;3)客户端在使用AuthenticateAsClient注册时没有正确使用服务器端证书名称。

二、 双向认证

第1步:创建所需证书,服务器端所需证书同单向认证中的创建过程

先进入到vs2005的命令行状态,即:

开始–>程序–>Microsoft Visual Studio 2005–>Visual Studio Tools–>Visual Studio 2005 命令提示

键入:

makecert -r -pe -n “CN=TestClient” -ss Root -sky exchange

第2步:创建服务端程序

服务端的程序同单向认证的服务器端代码

第3步:创建客户端程序

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
namespace ConsoleAppClient
{
using System;
using System.Collections;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
namespace Examples.System.Net
{
  public class SslTcpClient
  {
    private static Hashtable certificateErrors = new Hashtable();
    // The following method is invoked by the RemoteCertificateValidationDelegate.
    public static bool ValidateServerCertificate(
       object sender,
       X509Certificate certificate,
       X509Chain chain,
       SslPolicyErrors sslPolicyErrors)
    {
      if (sslPolicyErrors == SslPolicyErrors.None)
        return true;
 
      Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
 
      // Do not allow this client to communicate with unauthenticated servers.
      return false;
    }
 
    public static void RunClient(string machineName)
    {
      // Create a TCP/IP client socket.
      // machineName is the host running the server application.
      TcpClient client = new TcpClient(machineName, 901);
      Console.WriteLine("Client connected.");
      // Create an SSL stream that will close the client's stream.
      SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
      // The server name must match the name on the server certificate.
 
      X509Store store = new X509Store(StoreName.Root);
      store.Open(OpenFlags.ReadWrite);
 
      //// 检索证书
      X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName, "TestClient", false);       
      try
      {
        sslStream.AuthenticateAsClient("TestServer", certs, SslProtocols.Tls, false);
      }
      catch (AuthenticationException e)
      {
        Console.WriteLine("Exception: {0}", e.Message);
        if (e.InnerException != null)
        {
          Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
        }
        Console.WriteLine("Authentication failed - closing the connection.");
        client.Close();
        return;
      }
      // Encode a test message into a byte array.
      // Signal the end of the message using the "<EOF>".
      byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
      // Send hello message to the server.
      sslStream.Write(messsage);
      sslStream.Flush();
      // Read message from the server.
      string serverMessage = ReadMessage(sslStream);
      Console.WriteLine("Server says: {0}", serverMessage);
 
      messsage = Encoding.UTF8.GetBytes("exit");
      sslStream.Write(messsage);
      sslStream.Flush();
 
      // Close the client connection.
      client.Close();
      Console.WriteLine("Client closed.");
    }
 
    static string ReadMessage(SslStream sslStream)
    {
      // Read the message sent by the server.
      // The end of the message is signaled using the
      // "<EOF>" marker.
      byte[] buffer = new byte[2048];
      StringBuilder messageData = new StringBuilder();
      int bytes = -1;
      do
      {
        bytes = sslStream.Read(buffer, 0, buffer.Length);
 
        // Use Decoder class to convert from bytes to UTF8
        // in case a character spans two buffers.
        Decoder decoder = Encoding.UTF8.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
        decoder.GetChars(buffer, 0, bytes, chars, 0);
        messageData.Append(chars);
        // Check for EOF.
        if (messageData.ToString().IndexOf("<EOF>") != -1)
        {
          break;
        }
      } while (bytes != 0);
 
      return messageData.ToString();
    }
 
    private static void DisplayUsage()
    {
      Console.WriteLine("To start the client specify:");
      Console.WriteLine("clientSync machineName [serverName]");
      Environment.Exit(1);
    }
 
    public static void Main(string[] args)
    {
      string machineName = null;
      machineName = "192.168.1.25";
      try
      {
        RunClient(machineName);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
      Console.ReadLine();
    }
  }
}
}

总结

到此这篇关于利用C#实现SSLSocket加密通讯的文章就介绍到这了,更多相关C#实现SSLSocket加密通讯内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/tuyile006/p/13341033.html

延伸 · 阅读

精彩推荐
  • C#c#检测文本文件编码的方法

    c#检测文本文件编码的方法

    这篇文章主要介绍了c#检测文本文件编码的方法...

    C#教程网4112021-11-15
  • C#积累Visual Studio 常用快捷键的动画演示

    积累Visual Studio 常用快捷键的动画演示

    在代码开发过程中,频繁的使用键盘、鼠标操作非常麻烦,影响程序的开发效率。如何操作能用键盘来操作,那就节省时间了。下面小编把我平时积累的有...

    C#教程网7532021-10-29
  • C#C#中的Internal关键字小结

    C#中的Internal关键字小结

    这篇文章主要介绍了C#中的Internal关键字小结的相关资料,需要的朋友可以参考下...

    C#教程网7392022-01-04
  • C#WinForm调用百度地图接口用法示例

    WinForm调用百度地图接口用法示例

    这篇文章主要介绍了WinForm调用百度地图接口用法,结合具体实例形式简单分析了WinForm WebBrower控件与前端百度接口交互的相关操作技巧,需要的朋友可以参考...

    廖先生4912022-01-10
  • C#一文看懂C#中List的扩容机制

    一文看懂C#中List的扩容机制

    这篇文章主要介绍了C#中的扩容机制,文中以实例代码辅助,帮助大家更好的工作和学习,感兴趣的小伙伴不妨了解下...

    一线码农上海7262022-09-08
  • C#C# salt+hash 加密

    C# salt+hash 加密

    本文主要介绍了C# salt+hash加密规则、C# salt产生伪随机数原理、hash原理、使用hash来加密的原因等等。具有一定的参考价值,下面跟着小编一起来看下吧...

    Alan_beijing12042021-12-18
  • C#C#中的委托使用

    C#中的委托使用

    委托是C#中新加入的一个类型,可以把它想作一个和Class类似的一种类型,和使用类相似,使用一个委托时,需要两个步骤,首先你要定义一个委托,就像是...

    10972021-11-29
  • C#C#常用正则验证函数示例

    C#常用正则验证函数示例

    这篇文章主要介绍了C#常用正则验证函数,举例分析了C#针对IP验证、价格验证及正整数验证的相关操作技巧,需要的朋友可以参考下...

    pan_junbiao7522021-12-20