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

 更新时间:2020年11月3日 15:20  点击:1869

前言

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

[!--infotagslink--]

相关文章

  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • vue接口请求加密实例

    这篇文章主要介绍了vue接口请求加密实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-12
  • AES加密解密的例子小结

    关于AES加密的算法我们就不说了,这里主要给各位演示了三个关于AES算法实现的加密例子,希望本文章能给你带来帮助。 话不多说,先放上代码,一共有两个文件:AES.php(aes算...2016-11-25
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块。加密模块需要底层系统提供OpenSSL的支持。它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher...2014-06-07
  • C#连接加密的Sqlite数据库的方法

    对数据加密分两种,一种是对数据库本身进行加密,另一种是对数据表中的数据进行加密,下面通过本文给大家介绍C#连接加密的Sqlite数据库的方法,感兴趣的朋友一起看看吧...2020-06-25
  • vue中利用mqtt服务端实现即时通讯的步骤记录

    前些日子了解到mqtt这样一个协议,可以在web上达到即时通讯的效果,所以下面这篇文章主要给大家介绍了关于vue中如何利用mqtt服务端实现即时通讯的相关资料,需要的朋友可以参考下...2021-07-01
  • C#实现对文件进行加密解密的方法

    这篇文章主要介绍了C#实现对文件进行加密解密的方法,涉及C#加密与解密的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • php使用异或实现的加解密的方法

    若a=b ^ c;则b=a ^ c (^是异或的意思),php在处理异或的字符时先把字符转化为二进制的ascii值,对这些值进行异或,获取结果后在将ascii值转化为字符...2013-09-26
  • go语言使用RC4加密的方法

    这篇文章主要介绍了go语言使用RC4加密的方法,实例分析了RC4加密的技巧与实现方法,具有一定参考借鉴价值,需要的朋友可以参考下...2020-05-07
  • C#为配置文件加密的实现方法

    这篇文章主要介绍了C#为配置文件加密的实现方法,可实现对配置文件中的敏感信息进行加密,非常具有实用价值,需要的朋友可以参考下...2020-06-25
  • c#实现md5加密示例

    这篇文章主要介绍了md5加密,加密结果可以为32位、48位、64位,只要修改一下参数就可以实现...2020-06-25
  • C#编写的Base64加密和解密类

    本文给大家汇总介绍了几种C#编写的Base64加密和解密类的代码,从简单到复杂,都能够实现功能,有需要的小伙伴根据自己的项目需求参考下吧。...2020-06-25
  • C#实现的MD5加密功能与用法示例

    这篇文章主要介绍了C#实现的MD5加密功能与用法,结合实例形式分析了C# MD5加密类的定义与使用方法,需要的朋友可以参考下...2020-06-25
  • C#实现对AES加密和解密的方法

    C#实现对AES加密和解密的方法,需要的朋友可以参考一下...2020-06-25
  • 微信小程序 MD5加密登录密码详解及实例代码

    这篇文章主要介绍了微信小程序 MD5加密登录密码详解及实例代码的相关资料,这里附有实例代码,需要的朋友可以参考下...2017-01-16
  • C# 实现对PPT文档加密、解密及重置密码的操作方法

    这篇文章主要介绍了C# 实现对PPT文档加密、解密及重置密码的操作方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • 分析网页的几种加密技术

      现在专业性的网站越来越多,许多网友们都在网上建立起了自己的小家。不过辛辛苦苦制作的网页被人拿去改头换面却是件非常痛心的事,所以大家都想保护自己独创的...2016-09-20
  • c#文本加密程序代码示例

    这是一个加密软件,但只限于文本加密,加了窗口控件的滑动效果,详细看下面的代码...2020-06-25
  • Android使用RSA加密实现接口调用时的校验功能

    这篇文章主要介绍了Android+Java使用RSA加密实现接口调用时的校验功能,帮助大家更好的利用Android进行开发,感兴趣的朋友可以了解下...2020-12-24