首页 > 代码库 > 【C#】Socket中的ssl通信

【C#】Socket中的ssl通信

引言 
   有个项目中用到了Socket ssl通信,在此记录一下.

证书

   Socket ssl需要用到证书用来校验身份,而作为调试,我们只需用测试证书即可.

   有个工具可以很方便地制作测试证书,下载地址为http://supersocket.codeplex.com/releases/view/59311

   首先, 输入Common Name,密码和保存路径后,我们可以得到包含私钥的证书server.pfx.

   然后,安装证书到电脑中,在IE选项中导出一份证书作为client.cer.

客户端

   使用客户端的电脑需要安装client.cer到<受信任的根证书颁发机构>,且要把证书放在程序目录中,具体代码如下

技术分享
 class Program    {        private static SslStream _sslStream;        static void Main(string[] args)        {            try            {                TcpClient client = new TcpClient("127.0.0.1", 6000);                Console.WriteLine("Client connected.");                _sslStream = new SslStream(                   client.GetStream(),                   false,                   new RemoteCertificateValidationCallback(ValidateServerCertificate),                   null                   );                             X509CertificateCollection certs = new X509CertificateCollection();                X509Certificate cert = X509Certificate.CreateFromCertFile(System.Environment.CurrentDirectory + @"\" + "client.cer");                certs.Add(cert);                //验证证书                try                {                    _sslStream.AuthenticateAsClient("test", 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();                    Console.ReadLine();                    return;                }                //开始读取消息                Task.Factory.StartNew(() =>                {                    ReadMessage(_sslStream);                });                Console.WriteLine("按Q退出程序");                string message = "";                message = Console.ReadLine() + "<EOF>";                while (message != "Q")                {                    byte[] bytes = Encoding.UTF8.GetBytes(message);                    _sslStream.Write(bytes);                    _sslStream.Flush();                    Console.WriteLine("send:" + message);                    message = Console.ReadLine() + "<EOF>";                }                client.Close();            }            catch (Exception ex)            {                                Console.WriteLine(ex);                Console.ReadLine();            }        }        public static void 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("<EOF>", StringComparison.Ordinal) != -1)                {                    break;                }            } while (bytes != 0);            string message = messageData.ToString().Replace("<EOF>", "");            Console.WriteLine("recevied:" + message);            ReadMessage(sslStream);        }        private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)        {            if (sslpolicyerrors == SslPolicyErrors.None)                return true;            Console.WriteLine("Certificate error: {0}", sslpolicyerrors);            return false;        }    }
View Code

服务端

   服务端电脑要安装server.pfx证书,且要把证书放在程序目录中,具体代码如下

技术分享
  class Program    {        static void Main(string[] args)        {            TcpListener listener = new TcpListener(IPAddress.Any, 6000);            listener.Start();            Console.WriteLine("Waiting for a client to connect...");            TcpClient client = listener.AcceptTcpClient();            _sslStream = new SslStream(client.GetStream(), true);            try            {                serverCertificate = new X509Certificate(Environment.CurrentDirectory + @"\" + "server.pfx", "1");                _sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);            }            catch (Exception ex)            {                 Console.WriteLine(ex);                 Console.ReadLine();                 return;            }                   while (true)            {                string receivedMessage = ReadMessage(_sslStream);                Console.WriteLine("received:" + receivedMessage);                byte[] message = Encoding.UTF8.GetBytes("Success.<EOF>");                _sslStream.Write(message);                _sslStream.Flush();            }        }        static X509Certificate serverCertificate = null;        private static SslStream _sslStream;        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("<EOF>") != -1)                {                    break;                }            } while (bytes != 0);            return messageData.ToString();        }        static void ProcessClient(TcpClient client)        {            SslStream sslStream = new SslStream(                client.GetStream(), true);            try            {                sslStream.AuthenticateAsServer(serverCertificate, true, SslProtocols.Tls, true);                Console.WriteLine("Waiting for client message...");                string messageData =http://www.mamicode.com/ ReadMessage(sslStream);                Console.WriteLine("Received: {0}", messageData);                byte[] message = Encoding.UTF8.GetBytes("已收到信息.<EOF>");                sslStream.Write(message);                sslStream.Flush();            }            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();            }        }    }
View Code

注意事项

  1.服务端验证方法AuthenticateAsServer的参数clientCertificateRequired如果为true,那在客户端也要安装server.pfx.

  2.客户端验证方法AuthenticateAsClient的参数targetHost对应证书中Common Name,也就是受颁发者.

参考资料

   https://msdn.microsoft.com/zh-cn/library/system.net.security.sslstream(v=vs.110).aspx

【C#】Socket中的ssl通信