C# 以安全的方式在服务器和客户端之间交换对称密钥

C# 以安全的方式在服务器和客户端之间交换对称密钥,c#,cryptography,encryption-asymmetric,C#,Cryptography,Encryption Asymmetric,我有一个我相信是安全的算法。因此,服务器为每个新连接创建公钥和私钥组合。在本例中,我只处理一个线程,但实际上我必须构造几个线程,以便服务器可以侦听多个连接 客户端是Alice,它还创建公钥和私钥的组合。下面是客户机Alice如何创建随机对称密钥以安全地提供给服务器bob 服务器代码(Bob): 也许我应该使用ssl连接。我认为我们在制作这种节目时学到了很多东西。我想知道这种技术是否是Alice以安全的方式向Bob提供对称密钥的安全方法 您的代码受限制。SSL通过依赖受信任的第三方并通过检查到受信

我有一个我相信是安全的算法。因此,服务器为每个新连接创建公钥和私钥组合。在本例中,我只处理一个线程,但实际上我必须构造几个线程,以便服务器可以侦听多个连接

客户端是Alice,它还创建公钥和私钥的组合。下面是客户机Alice如何创建随机对称密钥以安全地提供给服务器bob

服务器代码(Bob):


也许我应该使用ssl连接。我认为我们在制作这种节目时学到了很多东西。我想知道这种技术是否是Alice以安全的方式向Bob提供对称密钥的安全方法

您的代码受限制。SSL通过依赖受信任的第三方并通过检查到受信任根的证书链来验证公钥来解决此问题。因此,您最好的选择是(a)采用SSL并使用它,(b)通过阅读安全书籍(首先)而不是通过实现您自己的算法来学习

您的代码受限制。SSL通过依赖受信任的第三方并通过检查到受信任根的证书链来验证公钥来解决此问题。因此,您最好的选择是(a)采用SSL并使用它,(b)通过阅读安全书籍(首先)而不是通过实现您自己的算法来学习

解释Alice和Bob是如何知道彼此的公钥的。正如我在最后一个问题上指出的,整个系统的安全性依赖于Alice和Bob准确地知道对方的密钥。你建议他们怎么做?bob将是一个具有静态wan ip(“myWebsite.com”)的服务器,当建立新连接时,bob将知道alice ip。也许我应该解释一下,对不起。每次服务器bob遇到新连接时,我计划运行一个单独的线程,服务器将在同一端口上侦听新连接,但使用不同的公钥和私钥组合。如果攻击者控制bob和Alice之间的连接,静态IP无助于抵御MitM攻击。Paulo是正确的。请记住,您使用加密通道的原因首先是因为作恶者控制通道。您不知道是否有攻击者切断了服务器的连接,将其替换为他们自己的相同但邪恶的服务器,从而使服务器脱机。请解释Alice和Bob如何知道彼此的公钥。正如我在最后一个问题上指出的,整个系统的安全性依赖于Alice和Bob准确地知道对方的密钥。你建议他们怎么做?bob将是一个具有静态wan ip(“myWebsite.com”)的服务器,当建立新连接时,bob将知道alice ip。也许我应该解释一下,对不起。每次服务器bob遇到新连接时,我计划运行一个单独的线程,服务器将在同一端口上侦听新连接,但使用不同的公钥和私钥组合。如果攻击者控制bob和Alice之间的连接,静态IP无助于抵御MitM攻击。Paulo是正确的。请记住,您使用加密通道的原因首先是因为作恶者控制通道。你不知道一些攻击者是否通过将线切断到服务器并用自己的相同但邪恶的服务器来替换服务器,使服务器离线。如果有中间人,他将能够建立与服务器的连接,我同意。服务器为每个新的连接创建公钥和私钥组合,因此如果中间的人试图获取服务器的公钥,他将能够得到它,但他将得到不同的。理解为什么人们告诉我使用ssl会很好。也许我应该也同意,但我只是想了解这一切。我知道我可以阅读我的书中的ssl章节并使用它,但是理解它会很好this@TonoMITM不需要将服务器密钥传递给客户端。相反,MITM创建自己的密钥并发送给客户端。也就是说,MITM看起来是服务器的客户机,也可以是客户端的服务器。如果中间有一个人,他将能够与服务器建立连接,我同意。服务器为每个新的连接创建公钥和私钥组合,因此如果中间的人试图获取服务器的公钥,他将能够得到它,但他将得到不同的。理解为什么人们告诉我使用ssl会很好。也许我应该也同意,但我只是想了解这一切。我知道我可以阅读我的书中的ssl章节并使用它,但是理解它会很好this@TonoMITM不需要将服务器密钥传递给客户端。相反,MITM创建自己的密钥并发送给客户端。也就是说,MITM对于服务器来说是一个客户端,对于客户端来说是一个服务器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.IO;


namespace ServerListener
{
    class Program
    {
        static TcpListener server;

        static CngKey bobKey;          // server private key
        static byte[] alicePubKeyBlob; // client public key
        static byte[] bobPubKeyBlob;   // server public key

        static byte[] symetricKey;     // the symetric key that will later be used to transfer data more efficeintly

        static void Main(string[] args)
        {

            // create server private and public keys
            CreateKeys(); 

            // start listening for new connections
            IPAddress ipAddress = IPAddress.Parse("192.168.0.120");
            server = new TcpListener(ipAddress, 54540);
            server.Start();
            var client = server.AcceptTcpClient();

            // once a connection is established open the stream
            var stream = client.GetStream();

            // we need the client public key so we need to instantiate it.
            alicePubKeyBlob = new byte[bobPubKeyBlob.Length];

            // waint until the client send us his public key
            stream.Read(alicePubKeyBlob, 0, alicePubKeyBlob.Length);

            // alicePubKeyBlob should now be the client's public key

            // now let's send this servers public key to the client
            stream.Write(bobPubKeyBlob, 0, bobPubKeyBlob.Length);

            // encrytpedData will be the data that server will recive encrypted from the client with the server's public key
            byte[] encrytpedData = new byte[1024];
            // wait until client sends that data
            stream.Read(encrytpedData, 0, encrytpedData.Length);

            // decrypt the symetric key with the private key of the server
            symetricKey = BobReceivesData(encrytpedData);

            // server and client should know have the same symetric key in order to send data more efficently and securely
            Console.Read();

        }

        private static void CreateKeys()
        {
            //aliceKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
            bobKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
            //alicePubKeyBlob = aliceKey.Export(CngKeyBlobFormat.EccPublicBlob);
            bobPubKeyBlob = bobKey.Export(CngKeyBlobFormat.EccPublicBlob);
        }

        private static byte[] BobReceivesData(byte[] encryptedData)
        {
            Console.WriteLine("Bob receives encrypted data");
            byte[] rawData = null;

            var aes = new AesCryptoServiceProvider();

            int nBytes = aes.BlockSize >> 3;
            byte[] iv = new byte[nBytes];
            for (int i = 0; i < iv.Length; i++)
                iv[i] = encryptedData[i];

            using (var bobAlgorithm = new ECDiffieHellmanCng(bobKey))
            using (CngKey alicePubKey = CngKey.Import(alicePubKeyBlob,
                  CngKeyBlobFormat.EccPublicBlob))
            {
                byte[] symmKey = bobAlgorithm.DeriveKeyMaterial(alicePubKey);
                Console.WriteLine("Bob creates this symmetric key with " +
                      "Alices public key information: {0}",
                      Convert.ToBase64String(symmKey));

                aes.Key = symmKey;
                aes.IV = iv;

                using (ICryptoTransform decryptor = aes.CreateDecryptor())
                using (MemoryStream ms = new MemoryStream())
                {
                    var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write);
                    cs.Write(encryptedData, nBytes, encryptedData.Length - nBytes);
                    cs.Close();

                    rawData = ms.ToArray();

                    Console.WriteLine("Bob decrypts message to: {0}",
                          Encoding.UTF8.GetString(rawData));
                }
                aes.Clear();

                return rawData;
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.IO;

namespace ClientAlice
{
    class Program
    {
        static CngKey aliceKey;  // client private key

        static byte[] alicePubKeyBlob; // client public key
        static byte[] bobPubKeyBlob;   // server public key
        static byte[] symetricKey;     // the symetric key that we want to give to the server securely

        static void Main(string[] args)
        {
            //create the client private and public keys
            CreateKeys();

            // initialice the server's public key we will need it later
            bobPubKeyBlob = new byte[alicePubKeyBlob.Length];

            // connect to the server and open a stream in order to comunicate with it
            TcpClient alice = new TcpClient("192.168.0.120", 54540);
            var stream = alice.GetStream();

            // send to the server the public key (client's public key)
            stream.Write(alicePubKeyBlob, 0, alicePubKeyBlob.Length);

            // now wait to receive the server's public key
            stream.Read(bobPubKeyBlob, 0, bobPubKeyBlob.Length);

            // create a random symetric key
            symetricKey = new byte[1000];
            Random r = new Random();
            r.NextBytes(symetricKey);

            // Encrypt the symetric key with the server's public key
            byte[] encrytpedData = AliceSendsData(symetricKey);

            // once encrypted send that encrypted data to the server. The only one that is going to be able to unecrypt that will be the server
            stream.Write(encrytpedData, 0, encrytpedData.Length);

            // not the server and client should have the same symetric key
        }


        private static void CreateKeys()
        {
            aliceKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
            alicePubKeyBlob = aliceKey.Export(CngKeyBlobFormat.EccPublicBlob);
        }

        private static byte[] AliceSendsData(byte[] rawData)
        {

            byte[] encryptedData = null;

            using (var aliceAlgorithm = new ECDiffieHellmanCng(aliceKey))
            using (CngKey bobPubKey = CngKey.Import(bobPubKeyBlob,
                  CngKeyBlobFormat.EccPublicBlob))
            {
                byte[] symmKey = aliceAlgorithm.DeriveKeyMaterial(bobPubKey);
                Console.WriteLine("Alice creates this symmetric key with " +
                      "Bobs public key information: {0}",
                      Convert.ToBase64String(symmKey));

                using (var aes = new AesCryptoServiceProvider())
                {
                    aes.Key = symmKey;
                    aes.GenerateIV();
                    using (ICryptoTransform encryptor = aes.CreateEncryptor())
                    using (MemoryStream ms = new MemoryStream())
                    {
                        // create CryptoStream and encrypt data to send
                        var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);

                        // write initialization vector not encrypted
                        ms.Write(aes.IV, 0, aes.IV.Length);
                        cs.Write(rawData, 0, rawData.Length);
                        cs.Close();
                        encryptedData = ms.ToArray();
                    }
                    aes.Clear();
                }
            }
            Console.WriteLine("Alice: message is encrypted: {0}",
                  Convert.ToBase64String(encryptedData)); ;
            Console.WriteLine();
            return encryptedData;
        }
    }
}