{"id":13647166,"url":"https://github.com/maxamel/GDH","last_synced_at":"2025-04-21T21:33:15.093Z","repository":{"id":85171623,"uuid":"100943978","full_name":"maxamel/GDH","owner":"maxamel","description":"Generalized Diffie-Hellman key exchange Java library built on top of the Vert.x framework","archived":false,"fork":false,"pushed_at":"2019-10-25T08:51:27.000Z","size":290,"stargazers_count":31,"open_issues_count":5,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-08-02T01:27:01.369Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxamel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-08-21T11:07:23.000Z","updated_at":"2024-04-11T22:23:55.000Z","dependencies_parsed_at":"2023-03-04T21:00:18.972Z","dependency_job_id":null,"html_url":"https://github.com/maxamel/GDH","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxamel%2FGDH","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxamel%2FGDH/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxamel%2FGDH/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxamel%2FGDH/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxamel","download_url":"https://codeload.github.com/maxamel/GDH/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223880520,"owners_count":17219131,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T01:03:22.456Z","updated_at":"2024-11-09T20:31:16.553Z","avatar_url":"https://github.com/maxamel.png","language":"Java","funding_links":[],"categories":["Frameworks and Libs","Java","Miscellaneous"],"sub_categories":["Java"],"readme":"[![Build Status](https://travis-ci.org/maxamel/GDH.svg)](https://travis-ci.org/maxamel/GDH)\n[![Coverage Status](https://sonarcloud.io/api/project_badges/measure?project=GDH\u0026metric=coverage)](https://sonarcloud.io/api/project_badges/measure?project=GDH\u0026metric=coverage)\n[![Mentioned in Awesome Vert.x](https://awesome.re/mentioned-badge.svg)](https://github.com/vert-x3/vertx-awesome)\n[![Known Vulnerabilities](https://snyk.io/test/github/maxamel/GDH/badge.svg)](https://snyk.io/test/github/maxamel/GDH)\n\n[![Quality Gate](https://sonarcloud.io/api/project_badges/quality_gate?project=GDH)](https://sonarcloud.io/api/project_badges/quality_gate?project=GDH)\u003cbr/\u003e\n\n\u003cimg src=\"https://github.com/maxamel/GDH/blob/master/resources/logo.png\" align=\"right\" /\u003e\n\n\n# GDH : Generalized Diffie-Hellman Key Exchange Platform\n\nA Diffie-Hellman key exchange library for multiple parties built on top of the asynchronous, event-driven [Vert.x](http://vertx.io/) framework.\n\n# Overview\n\n[Diffie-Hellman](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) 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. \nDiffie-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. \nThe most common and general scenario for the use of Diffie-Hellman is two parties that want to exchange messages over an insecure network. \nCommon use-cases are client to web-server or peer-to-peer file-sharing communication. \nHowever, the case where multiple parties need to share a secret key is rarely addressed. Such cases may arise in complex distributed \nsystems where participants are located on different machines, and need to communicate with each other directly, rather than through one \ncentral 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.\n\nThe 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. \nThis 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).  \n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/maxamel/GDH/blob/master/resources/GDH.png\" /\u003e\n\u003c/p\u003e\n\nDue to the [discrete logarithm](https://en.wikipedia.org/wiki/Discrete_logarithm) problem, it is impossible for any third party listening in on the communication to compute the final key.\n\n# Security\n\nIt has been known for a few years now that the NSA has the ability to [break](https://arstechnica.com/information-technology/2015/10/how-the-nsa-can-break-trillions-of-encrypted-web-and-vpn-connections/) 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. \n\n# Prerequisites\n\nWritten in Java 8. \n\nBuilt with Gradle.\n\n# Installation\n\nGet the code and build:\n\n```\ngit clone https://github.com/maxamel/GDH.git\ncd GDH\ngradle clean build    \n```\n\nGet the generated Jar from the build directory of the project. Add it to the build path of your project and that's it.\n\n# Usage\n\nThe basic usage of the library is spinning up verticles and initiating a key exchange between them.\nOnce you have the key you can start encrypting/decrypting messages safely between the verticles. Note this library only\nprovides a key exchange platform and utility methods for encryption/decryption. The network layer (e.g messaging protocol)\nmust be implemented by the user.\n\nThe basic object used for deploying and undeploying verticles is the PrimaryVertex. \n\n```java\nPrimaryVertex pv = new PrimaryVertex();\n```\n\nThe verticle object participating in the key exchange is the GDHVertex. \nLet's define our first GDHVertex and call it activeVertex as it will be the one who initiates key exchanges. \nAll other verticles will be passive. The following example will be run between two verticles on localhost, \nbut can be run with multiple participants in a distributed environment.\n```java \nGDHVertex activeVertex = new GDHVertex();\n```\nDefine a Configuration for the verticle:\n```java\nConfiguration config = new Configuration();\n// add parameters to the Configuration\nconfig.setIP(\"localhost\").setPort(\"5000\").setRetries(5).setLogLevel(Level.OFF);\n// assign the configuration to the verticle\nactiveVertex.setConfiguration(config);\n```\n\nNow let's define another verticle to participate in the key exchange. \n```java\nGDHVertex passiveVertex = new GDHVertex();\nConfiguration config2 = new Configuration();\nconfig2.setIP(\"localhost\").setPort(\"5001\").setExchangeTimeout(5000).setLogLevel(Level.OFF);\npassiveVertex.setConfiguration(config2);\n```\n\nOnce we have all participants defined, we can go ahead and form a group with the Configuration of one of the verticles.\nThe id of the group is determined by its nodes, so if you construct 2 groups with the same nodes it will essentially be the\nsame group.\n```java\nGroup g = new Group(config,\n                    new Node(\"localhost\",\"5000\"),\n                    new Node(\"localhost\",\"5001\"));\n```\n\nNow it's all set up and you can run the verticles and initiate a key exchange. \nThe most important rule when developing with Vert.x (or any asynchronous platform) is DO NOT BLOCK THE EVENT LOOP!\nSo remember not to perform blocking operations inside the asynchronous calls. \n```java\npv.run(passiveVertex,deployment1 -\u003e {\n    if (deployment1.succeeded()) {\n        pv.run(activeVertex,deployment2 -\u003e {\n        \tif (deployment2.succeeded()) {\n        \t\tactiveVertex.exchange(g.getGroupId(), exchange -\u003e {\n        \t\t\tif (exchange.succeeded()) {\n        \t\t\t    // the key is available in this context and also later as a Future object\n        \t\t\t\tSystem.out.println(\"Got new key: \" + exchange.result());\n        \t\t\t}\n        \t\t\telse {\n        \t\t\t\tSystem.out.println(\"Error exchanging!\");\n        \t\t\t}\n        \t\t}\n        \t}\n        \telse {\n        \t\tSystem.out.println(\"Error deploying!\");\n        \t}\n        }\n    }\n    else {\n        System.out.println(\"Error deploying!\");\n    }\n}        \t\n```\n\nYou can also use blocking code for key exchange: \n```java\npv.run(passiveVertex,deployment1 -\u003e {\n    if (deployment1.succeeded()) {\n        pv.run(activeVertex,deployment2 -\u003e {\n            if (deployment2.succeeded()) {\n                // get the key as a Future. Do not block inside the asynchronous call\n                CompletableFuture\u003cBigInteger\u003e futureKey = activeVertex.exchange(g.getGroupId());\n            }\n            else {\n                System.out.println(\"Error deploying!\");\n            }\n        }\n    }\n    else {\n        System.out.println(\"Error deploying!\");\n    }\n}           \n```\nYou can even use blocking code for the deployments. The verticle which initiates key exchanges should still be deployed\nusing an asynchronous call (Otherwise you have to busy wait on it with a while loop!). All other nodes will participate in \nthe exchange once they are up and running. \n```java\npv.run(activeVertex,deployment1 -\u003e {\n    if (deployment1.succeeded()) {\n        pv.run(passiveVertex);\n        // get the key as a Future. Do not block inside the asynchronous call\n        CompletableFuture\u003cBigInteger\u003e futureKey = activeVertex.exchange(g.getGroupId());\n    }\n    else {\n        System.out.println(\"Error deploying!\");\n    }\n} \n```\n\nAt any point you can access the exchanged key as a CompletableFuture object from any verticle.\nThis object is a representation of the key. The actual key might not be available at this moment in time,\nbut will be made available as soon as the exchange finishes. Here are just a handful of options you have \nwith the CompletableFuture:\n```java\nCompletableFuture\u003cBigInteger\u003e key = passiveVertex.getKey(g.getGroupId());\n\n// Wait for the key exchange to complete and get the final key\nBigInteger fin = key.get();\n\n// Wait for the key for a bounded time and throw Exception if this time is exceeded\nBigInteger fin = key.get(1000, TimeUnit.MILLISECONDS);\n\n// Get the key immediately. If it's not available return the default value given as a parameter (null)\nBigInteger fin = key.getNow(null);\n```\n\nDon't forget to kill the verticles when you're finished with them. As in the deployment, you can use either\nasynchronous calls or blocking code:\n```java\npv.kill(activeVertex,undeployment1 -\u003e {\n\tif (undeployment1.succeeded()) {\n\t\tSystem.out.println(\"First undeployment successful!\");\n\t\tpv.kill(passiveVertex,undeployment2 -\u003e {\n                if (undeployment2.succeeded()) {\n                    System.out.println(\"Second undeployment successful!\");\n                }\n                else {\n                    System.out.println(\"Error undeploying!\");\n                }\n        }      \n\t}\n\telse {\n\t\tSystem.out.println(\"Error undeploying!\");\n\t}\n}      \n```\n\nLet's say you have a distributed system, where each machine is running GDH, and you have no way of choosing or enforcing the GDHVertex which initiates the key exchange, i.e. every machine runs the same code.\nHese's a sample code which can run in such an environment and enforce only one key exchange initiator.\n\n```java\nGDHVertex vertex = new GDHVertex();\n        \nConfiguration config = new Configuration();\nconfig.setIP(\"localhost\").setPort(\"5000\").setRetries(8).setLogLevel(Level.DEBUG);\nvertex.setConfiguration(config);\n        \nGroup g = new Group(config,\n          new Node(\"172.52.44.120\",\"5000\"),\n          new Node(\"172.52.44.121\",\"5000\"),\n          new Node(\"172.52.44.122\",\"5000\"));\n        \nvertex.addGroup(g);\n        \nPrimaryVertex pv = new PrimaryVertex();\npv.run(vertex);\n        \nif (vertex.getNode().equals(g.getActiveNode())) vertex.exchange(g.getGroupId());\nCompletableFuture\u003cBigInteger\u003e key = vertex.getKey(g.getGroupId());      // \u003c---- key here\n```\n\n# Code Quality\n\nThis project is analyzed on [Sonarcloud](https://sonarcloud.io/dashboard?id=GDH) and on [Snyk](https://snyk.io/org/maxamel/project/fe48906b-d65e-4e19-97af-b1fe986d536f). \nEvery build the code runs through a couple of static code analyzers (PMD and findbugs) to ensure code quality is maintained.\nEach push to the repository triggers a cloud build via TravisCI, which in turn pushes the code into Sonarcloud to find coding bugs and into Snyk to find security vulnerabilities in the dependencies. If anything goes wrong during any of these steps the build fails.\n\n# Testing\n\nThe code is tested by both unit tests and integration tests. The integration testing involves actual spinning up of verticles, performing exchanges and checking the correctness and security of the transactions. Testing must cover at least 80% of the code, otherwise the quality gate of Sonarcloud fails. \n\n# Logging \n\nGDH logs messages at different points during the exchange. This allows easy debugging and also lets users follow the exchange and helps understand the protocol. Logs are also used in tests. For example, verifying the final key after the exchange is NOT transmitted over the wire, or counting the number of messages required to complete a key exchange. So if you change the logging messages, make sure this hasn't affected any tests.\n\n# License\n\nPublished under the MIT License. This basically means the software is free and anyone can use it however they wish.\nNo liability or warranty.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxamel%2FGDH","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxamel%2FGDH","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxamel%2FGDH/lists"}