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.
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
This class contains three methods.
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 (|).
protected virtual void OnClientConnected(string packet)
currentClient.Dh = new DiffieHellman(256).GenerateRequest();
This generates a response packet. This packet contains only the receiver's portion of the key.
protected virtual void OnDiffieHellmanReceived(string packet)
this.Dh = new DiffieHellman(256).GenerateResponse(packet);
this.Key = Dh.Key;
This allows the originator to finalize her/his key.
protected virtual void OnPacketReceived(string packet)
currentClient.Key = currentClient.Dh.Key;
currentClient.MustDh = false;
currentClient.Password = currentClient.Decrypt(packet);
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.
- 25th March, 2008: Initial post
Fixed a small error in the receive response section (
MustDh was set to
true instead of