C#使用Socket TCP实现SSL/TLS

16

我是C#开发的新手。我正在尝试在tcp上使用ssl/tls,但是在我的代码中,使用的是system.net.sockets.socket(裸套接字),而不是tcpclient或tcplistner。我已经在网上搜索了至少200个链接,但我没有找到任何相关的信息。我想要使用较少的编码完成ssl或tsll over tcp套接字连接。我有客户端、服务器、ca证书和以.key格式的密钥。请提供示例或链接来帮助我。如果需要更多细节,您可以询问问题。

3个回答

28

为什么不想使用TcpClient?使用TcpClientSslStream创建SSL连接非常简单。除非你需要成千上万个同时连接,否则我建议仍使用TcpClientSSLStream

以下是一个基本的TcpClientSslStream示例:

static void Main(string[] args)
{
    string server = "127.0.0.1";
    TcpClient client = new TcpClient(server, 443);

    using (SslStream sslStream = new SslStream(client.GetStream(), false,
        new RemoteCertificateValidationCallback(ValidateServerCertificate), null))
    {
        sslStream.AuthenticateAsClient(server);
        // This is where you read and send data
    }
    client.Close();
}

public static bool ValidateServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true;
}
高性能的套接字代码在.NET中编写可能很困难,但是有很好的示例。你有多个选择。我不确定一个解决方案适用于所有情况,因此在这里列出几个。
  1. 使用[异步客户端套接字]可能是一个很好的起点
  2. 有一些现有的库可以利用。我使用过Nito/Async,但我认为它自2009年以来没有更新。有关版本2的讨论,但我不认为它得到了实现。
  3. 我对此不熟悉,但CodeProject有C# SocketAsyncEventArgs高性能套接字代码
  4. 查看Microsoft的指导:使用异步Winsock的高性能.NET套接字服务器
  5. 阅读Stephen Toub的所有内容,包括等待套接字操作

我没有特别地讨论SSL,但要研究SslStream类。

你还需要研究缓冲池。如果你为数以千计的客户提供服务,垃圾回收将成为一个问题。关于此的优秀介绍是Sunny Ahuwanya的博客


https://github.com/StephenCleary/AsyncEx

之前。


6
付出了很多努力来回答,但可悲的是,这根本没有回答问题。 - Pradeep Puranik
Github仓库AsyncEx与何种关系? - Sahin

7

这个答案看起来足够简单。只有一个疑问:这是否意味着在我们像这样封装套接字之后,不应该使用socket.send(),而应该始终使用sslStream?我之所以问是因为我已经有一个使用Begin/End进行send/receive的异步套接字工程,并且它运行良好。使用SSL仅计划作为应用程序中的选项,因此我正在尝试弄清需要执行多少更改才能实现它。任何帮助将不胜感激。提前致谢。 - Pradeep Puranik
一定要使用 SSL 流,否则对方将无法正确读取数据。 - jjxtra
你可以使用这个来约定一把秘钥,并在连接上使用AES加密。创建并加密你的字节,然后像通常一样发送它们。 - BDevGW

-1

这是给你的

public class SSL
    {
        private bool CertificateValidationCallback(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
        public class Certificate
        {
            public System.Security.Cryptography.X509Certificates.X509Certificate2 GetCertificate()
            {
                string certificatePath = @"D:\Rayan Ab Niro\Projecr\VPN\WindowsVPN\SSL.pfx"; //ConfigurationManager.AppSettings["certificatePath"].ToString();
                var stream = File.OpenRead(certificatePath);
                return new System.Security.Cryptography.X509Certificates.X509Certificate2(ReadStream(stream), "mypassword", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
            }

            private byte[] ReadStream(Stream input)
            {
                byte[] buffer = new byte[16 * 1024];
                using (MemoryStream ms = new MemoryStream())
                {
                    int read;
                    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        ms.Write(buffer, 0, read);
                    }
                    return ms.ToArray();
                }
            }
        }
        
        
        public System.Net.Security.SslStream GetStream(NetworkStream _NetworkStream)
        {
            try
            {
                System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream(_NetworkStream, false,);
                sslStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired: false,
                enabledSslProtocols:
                    System.Security.Authentication.SslProtocols.Default |
                    System.Security.Authentication.SslProtocols.None |
                    System.Security.Authentication.SslProtocols.Tls |
                    System.Security.Authentication.SslProtocols.Tls11 |
                    System.Security.Authentication.SslProtocols.Tls12 |
                    System.Security.Authentication.SslProtocols.Ssl2 |
                    System.Security.Authentication.SslProtocols.Ssl3
                , checkCertificateRevocation: true);
                new SSL().DisplaySecurityLevel(sslStream);
                new SSL().DisplaySecurityServices(sslStream);
                new SSL().DisplayCertificateInformation(sslStream);
                new SSL().DisplayStreamProperties(sslStream);
                sslStream.ReadTimeout = 5000;
                sslStream.WriteTimeout = 5000;
                return sslStream;
            }
            catch (Exception ex)
            {
                
                throw ex;
            }
            
        }
        public string ReadMessage(System.Net.Security.SslStream sslStream)
        {
            // Read the  message sent by the client.
            // The client signals the end of the message using the
            // "<EOF>" marker.
            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            //do
            //{
            // Read the client's test message.
            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 or an empty message.
            if (messageData.ToString().IndexOf("<EOF>") != -1)
            {
                //break;
            }
            //} while (bytes != 0);

            return messageData.ToString();
        }
        public void DisplaySecurityLevel(System.Net.Security.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);
        }
        public void DisplaySecurityServices(System.Net.Security.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);
        }
        public void DisplayStreamProperties(System.Net.Security.SslStream stream)
        {
            Console.WriteLine("Can read: {0}, write {1}", stream.CanRead, stream.CanWrite);
            Console.WriteLine("Can timeout: {0}", stream.CanTimeout);
        }
        public void DisplayCertificateInformation(System.Net.Security.SslStream stream)
        {
            Console.WriteLine("Certificate revocation list checked: {0}", stream.CheckCertRevocationStatus);

            System.Security.Cryptography.X509Certificates.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.");
            }
            // Display the properties of the client's certificate.
            System.Security.Cryptography.X509Certificates.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.");
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接