A Diffie-Hellman key exchange library for multiple parties built on top of the asynchronous, event-driven Vert.x framework.
Diffie-Hellman has been the de-facto standard for key exchange for many years. Two parties who want to communicate on an insecure channel, can use it to generate symmetric keys, and encrypt the messages between them. Diffie-Hellman (or derivatives of it, e.g. Elliptic Curve Diffie-Hellman) is commonly used in many authentication protocols and confidential tunneling schemes such as SSL/TLS, SSHv2, SNMPv3, and many more. The most common and general scenario for the use of Diffie-Hellman is two parties that want to exchange messages over an insecure network. Common use-cases are client to web-server or peer-to-peer file-sharing communication. However, the case where multiple parties need to share a secret key is rarely addressed. Such cases may arise in complex distributed systems where participants are located on different machines, and need to communicate with each other directly, rather than through one central entity. Instead of generating a secret key for each pair of participants, it is possible to generate a single secret key shared by all participants, in a manner which is resistable to eavesdropping attacks. This is where Generalized Diffie-Hellman comes in.
The following sequence diagram illustrates how the key exchange is performed. At first, two large numbers are distributed among the participants in plaintext. These numbers are the cyclic group generator (g) and a large prime(N). Then the participants come up with their secret numbers (a,b,c) which they do not reveal to anyone. They then begin a series of transactions at the end of which, they can each calculate the same secret key, without it ever being transmitted on the wire. In old-style Diffie-Hellman we would have 3 different keys produced, one per each couple of participants. This scheme can be performed for any number of participants. The number of messages needed for N participants to complete a key exchange is N(N-1).
Due to the discrete logarithm problem, it is impossible for any third party listening in on the communication to compute the final key.
It has been known for a few years now that the NSA has the ability to break Diffie-Hellman encrypted traffic which uses 1024 bit primes. Because these primes need to be carefully picked out, only a handful of such primes are used in practice. That's why it's beneficial for the NSA to invest in breaking those primes - it allows them to decrypt a big percentage of the world's traffic. This is why GDH uses 2048 bit primes and generates 256 bit symmetric keys, which are considered safe for now.
Written in Java 8.
Built with Gradle.
Get the code and build:
git clone https://github.com/maxamel/GDH.git
cd GDH
gradle clean build
Get the generated Jar from the build directory of the project. Add it to the build path of your project and that's it.
The basic usage of the library is spinning up verticles and initiating a key exchange between them. Once you have the key you can start encrypting/decrypting messages safely between the verticles. Note this library only provides a key exchange platform and utility methods for encryption/decryption. The network layer (e.g messaging protocol) must be implemented by the user.
The basic object used for deploying and undeploying verticles is the PrimaryVertex.
PrimaryVertex pv = new PrimaryVertex();
The verticle object participating in the key exchange is the GDHVertex. Let's define our first GDHVertex and call it activeVertex as it will be the one who initiates key exchanges. All other verticles will be passive. The following example will be run between two verticles on localhost, but can be run with multiple participants in a distributed environment.
GDHVertex activeVertex = new GDHVertex();
Define a Configuration for the verticle:
Configuration config = new Configuration();
// add parameters to the Configuration
config.setIP("localhost").setPort("5000").setRetries(5).setLogLevel(Level.OFF);
// assign the configuration to the verticle
activeVertex.setConfiguration(config);
Now let's define another verticle to participate in the key exchange.
GDHVertex passiveVertex = new GDHVertex();
Configuration config2 = new Configuration();
config2.setIP("localhost").setPort("5001").setExchangeTimeout(5000).setLogLevel(Level.OFF);
passiveVertex.setConfiguration(config2);
Once we have all participants defined, we can go ahead and form a group with the Configuration of one of the verticles. The id of the group is determined by its nodes, so if you construct 2 groups with the same nodes it will essentially be the same group.
Group g = new Group(config,
new Node("localhost","5000"),
new Node("localhost","5001"));
Now it's all set up and you can run the verticles and initiate a key exchange. The most important rule when developing with Vert.x (or any asynchronous platform) is DO NOT BLOCK THE EVENT LOOP! So remember not to perform blocking operations inside the asynchronous calls.
pv.run(passiveVertex,deployment1 -> {
if (deployment1.succeeded()) {
pv.run(activeVertex,deployment2 -> {
if (deployment2.succeeded()) {
activeVertex.exchange(g.getGroupId(), exchange -> {
if (exchange.succeeded()) {
// the key is available in this context and also later as a Future object
System.out.println("Got new key: " + exchange.result());
}
else {
System.out.println("Error exchanging!");
}
}
}
else {
System.out.println("Error deploying!");
}
}
}
else {
System.out.println("Error deploying!");
}
}
You can also use blocking code for key exchange: