Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Shared Key Generation using Diffie-Hellman

4.89/5 (11 votes)
25 Mar 2008CPOL2 min read 1   6.5K  
Generate an encryption key between two parties and foil the eavesdropper

Introduction

Sometimes you cannot rely on technologies such as TLS or SSL to protect your passwords on-the-wire: one example is programming against a device with limited capabilities. Furthermore, passwords may need to be stored locally on the machine (e.g. 'remember me' checkbox): this is hard or impossible using salt/salt+hash algorithms.

One solution would be to include the encryption key on both the client at compile time. This opens up a security hole because the source code can simply be decompiled to obtain the secret key.

Another solution would be to send the key over-the-wire when encryption is needed. However, a eavesdropper may be able to sniff out the encryption key.

This solution allows a key to be generated as encryption is required.

A simple explanation that I came across is that you should image a trunk with two padlocks on it. These padlocks have different keys that each party carries with them: the trunk may only be opened once both keys have been obtained.

Background

This article presents a C# implementation of the Diffie-Hellman algorithm. I recommend reading the Wikipedia article to get a grounding in the algorithm: but it is surprisingly easy. Note that the prime and base are transmitted, but if they are compromised it has no effect on the security of the transaction.

Using the Code

The demonstration program should give you everything you need.

The only class you should need to interact with is the DiffieHellman class.

This class contains three methods.

Generate Request

This generates a request packet. This packet contains the p (shared prime) and g (shared base) fields, as well as the originator's portion of the key. Each field is delimited using a pipe (|).

C#
protected virtual void OnClientConnected(string packet)
{
    currentClient.Dh = new DiffieHellman(256).GenerateRequest();
    networkSocket.Send(currentClient.Dh.ToString());
}

Generate Response

This generates a response packet. This packet contains only the receiver's portion of the key.

C#
protected virtual void OnDiffieHellmanReceived(string packet)
{
    this.Dh = new DiffieHellman(256).GenerateResponse(packet);
    this.Key = Dh.Key;
    networkSocket.Send(Dh.ToString());
    networkSocket.Send(Encrpyt(this.Password));
}

Receive Response

This allows the originator to finalize her/his key.

C#
protected virtual void OnPacketReceived(string packet)
{
    if(currentClient.MustDh)
    {
        currentClient.Dh.HandleResponse(packet);
        currentClient.Key = currentClient.Dh.Key;
        currentClient.MustDh = false;
    }
    else
    {
        currentClient.Password = currentClient.Decrypt(packet);
        this.Authenticate(currentClient);
        if(!currentClient.Authenticated)
            currentClient.ForceDisconnect("Invalid Credentials.");
    }
}

Points of Interest

Note that I deliberately chose to call the entities originator and receiver. The originator need not be a server and the receiver need not be a client.

Portions of this code are based on the code provided by Chew Keong TAN.

History

  • 25th March, 2008: Initial post
    Fixed a small error in the receive response section (MustDh was set to true instead of false)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)