Network Protocol Design for Cryptography

CS 463 Lecture, Dr. Lawlor

Let's say we'd like to have a client and server securely exchange a key when they first connect.  We start with the algorithm; we'll pick Elliptic Curve Diffie-Hellman key exchange.  We'll use a plain-ASCII protocol, so we can test things manually at the keyboard.

Here's a typical network server (on the left) and client (on the right), built using my osl/socket and ecc_lib libraries  (download the latest versions as a Zip or Tar-gzip; these are "net_server_ascii_ecdh.cpp").  Lines IN RED match up between client and server.
Server
Client
#include "bigint.h"
#include "ecc_lib.h"
#include "osl/socket.h"

int main() {
srandom(3); // <sarcasm> nobody could ever guess... three! </sarcasm>

unsigned int port=12345;
SERVER_SOCKET serv=skt_server(&port);
std::cout<<"Server: Listening on port "<<port<<"\n";

SOCKET s; // socket for talking to the current client
while (s=skt_accept(serv,NULL,NULL))
{
std::cout<<"Server: client connected. Starting exchange.\n";

// Elliptic Curve Diffie-Hellman Key Exchange:
ECcurve_BitCoin curve; // pick a common curve
std::string protocol="ECDH-BitCoin";
skt_send_line(s,protocol); // send ours to client
if (skt_recv_line(s)!=protocol) { // check client's protocol
std::cout<<"Server: Protocol mismatch!\n";
skt_close(s);
continue;
}

// Make our half of the secret:
int bits=256; // length of secret key
BigInteger A=BigInteger::random(bits);
ECpoint GA=curve.start.multiply(A,curve);

// Send GA to the client.
skt_send_line(s,GA.x.hex());
skt_send_line(s,GA.y.hex());

// Receive GB from the client.
ECpoint GB;
GB.x.readHex(skt_recv_line(s));
GB.y.readHex(skt_recv_line(s));

// Compute GAB by advancing client's point by our secret.
ECpoint GAB=GB.multiply(A,curve);

// We now have a shared secret--stupidly print it out.
// (In reality, this could be the encryption key.)
std::cout<<"Server: shared secret is "<<GAB.x.hex()<<"\n";

skt_close(s);

}

return 0;
}
#include "bigint.h"
#include "ecc_lib.h"
#include "osl/socket.h"

int main() {
srandom(6); // <sarcasm> nobody could ever guess... six! </sarcasm>

unsigned int port=12345;



std::cout<<"Client: Connecting to server on port "<<port<<"\n";
SOCKET s=skt_connect(skt_lookup_ip("sandy.cs.uaf.edu"),port,10);
std::cout<<"Client: Connected to server. Starting exchange.\n";


// Elliptic Curve Diffie-Hellman Key Exchange:
ECcurve_BitCoin curve; // pick a common curve
std::string protocol="ECDH-BitCoin";
skt_send_line(s,protocol); // send ours to server
if (skt_recv_line(s)!=protocol) { // check server's protocol
std::cout<<"Client: Protocol mismatch!\n";
skt_close(s);
exit(1);
}

// Make our half of the secret:
int bits=256; // length of secret key
BigInteger B=BigInteger::random(bits);
ECpoint GB=curve.start.multiply(B,curve);

// Send GB to the server.
skt_send_line(s,GB.x.hex());
skt_send_line(s,GB.y.hex());

// Receive GA from the server.
ECpoint GA;
GA.x.readHex(skt_recv_line(s));
GA.y.readHex(skt_recv_line(s));

// Compute GAB by advancing server's point by our secret.
ECpoint GAB=GA.multiply(B,curve);

// We now have a shared secret--stupidly print it out.
// (In reality, this could be the encryption key.)
std::cout<<"Client: shared secret is "<<GAB.x.hex()<<"\n";

skt_close(s);

return 0;
}

This works fine, the algorithm is secure, and I think the code is fairly secure (other than dumping the secret to the screen!).  But what happens if:
The lesson here is that it's not at all easy to implement a bulletproof network communication protocol, even for something trivial.