以安全的方式在服务器和客户端之间交换系统密钥

本文关键字:客户端 之间 交换 系统密钥 服务器 安全 方式 | 更新日期: 2023-09-27 18:09:47

我有一个我认为是安全的算法。因此,服务器为每个新连接创建一个公钥和私钥组合。在这个例子中,我只是处理一个线程,但在现实中,我将不得不构造几个线程,以便服务器可以监听多个连接。

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

服务器代码(Bob):

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

客户端代码(Alice):

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

也许我应该使用ssl连接。我认为我们在创建这类项目的过程中学到了很多东西。我想知道这个技术是否会是一种安全的方式让Alice以一种安全的方式给Bob一个对称密钥。

以安全的方式在服务器和客户端之间交换系统密钥

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