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

 更新时间:2020年07月20日 08:39:42   作者:小y  
这篇文章主要给大家介绍了关于如何利用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步创建服务器端程序,代码如下:

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步,创建客户端代码

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();
    }
  }
}
}

运行效果如下图:

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

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步:创建客户端程序

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加密通讯内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于C#实现的端口扫描器实例代码

    基于C#实现的端口扫描器实例代码

    这篇文章主要介绍了基于C#实现的端口扫描器实例代码,需要的朋友可以参考下
    2014-07-07
  • 详解C#如何利用TcpListener和TcpClient实现Tcp通讯

    详解C#如何利用TcpListener和TcpClient实现Tcp通讯

    TcpListener 和 TcpClient 是在 System.Net.Sockets.Socket 类的基础上做的进一步封装,使用 GetStream 方法返回网络流,下面我们就来详细一下如何使用TcpListener和TcpClient实现Tcp通讯吧
    2023-12-12
  • C#实现获取MAC地址的方法

    C#实现获取MAC地址的方法

    这篇文章主要介绍了C#实现获取MAC地址的方法,很实用的功能,需要的朋友可以参考下
    2014-08-08
  • C#操作DataTable方法实现过滤、取前N条数据及获取指定列数据列表的方法

    C#操作DataTable方法实现过滤、取前N条数据及获取指定列数据列表的方法

    这篇文章主要介绍了C#操作DataTable方法实现过滤、取前N条数据及获取指定列数据列表的方法,实例分析了C#操作DataTable的各种常用技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • c#中LINQ的基本用法实例

    c#中LINQ的基本用法实例

    语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一项创新功能。下面这篇文章主要给大家介绍了关于c#中LINQ的基本用法,需要的朋友可以参考借鉴,下面来一起看看吧
    2019-01-01
  • .net中常用的正则表达式

    .net中常用的正则表达式

    这篇文章介绍了.net中常用的正则表达式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Unity3D实现列表分页效果

    Unity3D实现列表分页效果

    这篇文章主要为大家详细介绍了Unity3D实现列表分页效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C# .NET实现扫描识别图片中的文字

    C# .NET实现扫描识别图片中的文字

    本文以C#及VB.NET代码为例,介绍如何扫描并读取图片中的文字。文中的示例代码介绍详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下
    2021-12-12
  • C# 解析 Excel 并且生成 Csv 文件代码分析

    C# 解析 Excel 并且生成 Csv 文件代码分析

    这篇文章主要介绍了C# 解析 Excel 并且生成 Csv 文件的方法和代码分享,有需要的朋友可以参考下
    2014-10-10
  • C#基于jwt实现分布式登录

    C#基于jwt实现分布式登录

    这篇文章主要介绍了C#基于jwt实现分布式登录的步骤,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2021-02-02

最新评论