I have an algorithm that I believe to be secure. So the server creates a public and private key combination for every new connection. In this example I am just dealing with one thread but in reality I will have to construct several threads so that the server can be listening for multiple connections.
The client is Alice and it also creates a public and private key combination. here is how the client Alice creates a random symmetric key to give to the server bob securely.
server code (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;
}
}
}
}
Client code (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;
}
}
}
perhaps I should use the ssl connection. I think we learn a lot when creating this kind of programs. I want to know if this technique will be a secure way of Alice giving a symmetric key to Bob in a secure way.
Your code is subject to man-in-the-middle attacks. SSL addresses this problem by relying on trusted third-party and validating the public key by checking the certificate chain up to the trusted root. So your best option is to (a) take SSL and use it, and (b) learn by reading security books (first) rather than by implementing your own algorithms.