Key exchange is a way for Bob and Alice to communicate and for them to agree on a shared secret. The original method defined uses discrete logarithms (Diffie-Hellman). With the Diffie-Hellman method, Alice generates \(a\) and shares \(A=g^a \pmod p\) with Bob. Bob generates \(b\) and shares \(B=g^b \pmod p\). Alice raises \(B\) to the power of \(a\), and Bob raises \(A\) to the power of \(b\). They should both end up with the same secret: \(K=g^{ab} \pmod p\).
Diffie Hellman (DH) using Bouncy Castle and C# |
Outline
The Diffie-Hellman (DH) method is perhaps one of the greatest inventions in Cybersecurity, and was created by Whitfield Diffie and Marty Hellman. With the DH method, Bob creates a random value (\(b\)) and Alice also creates a random value (\(a\)). Next Bob computes:
\(B=g^b \pmod p\)
and sends it to Alice. Alice computes:
\(A=g^a \pmod p\)
and sends this to Bob. Bob raises the value of \(A\) to the power of \(b\) and takes \(\pmod p\), and Alice raises \(B\) to the power of \(a\) and takes \(\pmod p\). In the end, they will have the same shared value:
\(g^{ab} \pmod p\)
This can then be used to derive an encryption key that they can use for a secure tunnel (Figure 1). Overall, \(p\) is the large prime number, and also known as the shared modulus between Bob and Alice.
Code
First we create a folder named "bc_dh", and then go into that folder.We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
Next some code:
namespace ECDH { using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Digests; using System.Text; using System.Security.Cryptography; class Program { static void Main(string[] args) { try { var size=256; if (args.Length >0) size=Convert.ToInt32(args[0]); var aliceKey = GeneratorUtilities.GetKeyPairGenerator ("DH"); DHParametersGenerator aliceGenerator = new DHParametersGenerator (); aliceGenerator.Init(size, 100, new SecureRandom ()); DHParameters aliceParameters = aliceGenerator.GenerateParameters (); var aliceKGP = new DHKeyGenerationParameters (new SecureRandom (), aliceParameters); aliceKey.Init (aliceKGP); var aliceKeyPair = aliceKey.GenerateKeyPair (); var aliceKeyAgree = AgreementUtilities.GetBasicAgreement ("DH"); aliceKeyAgree.Init (aliceKeyPair.Private); var bobKey = GeneratorUtilities.GetKeyPairGenerator ("DH"); DHParametersGenerator bobGenerator = new DHParametersGenerator (); bobGenerator.Init(size, 100, new SecureRandom ()); DHParameters bobParameters = aliceGenerator.GenerateParameters (); var bobKGP = new DHKeyGenerationParameters (new SecureRandom (), aliceParameters); aliceKey.Init (bobKGP); var bobKeyPair = aliceKey.GenerateKeyPair (); var bobKeyAgree = AgreementUtilities.GetBasicAgreement ("DH"); bobKeyAgree.Init (bobKeyPair.Private); var aliceAgree = aliceKeyAgree.CalculateAgreement (bobKeyPair.Public); var bobAgree = bobKeyAgree.CalculateAgreement (aliceKeyPair.Public); Console.WriteLine("Key size: {0}",size); Console.WriteLine("g:\t\t{0}\nP:\t\t{1}",bobParameters.G,bobParameters.P); var a= (DHPrivateKeyParameters) aliceKeyPair.Private; Console.WriteLine("\nAlice Private Key:\t{0}", a.X); var A= (DHPublicKeyParameters) aliceKeyPair.Public; Console.WriteLine("Alice Public Key:\t{0}",A.Y); var b= (DHPrivateKeyParameters) bobKeyPair.Private; Console.WriteLine("Bob Private Key:\t{0}",b.X); var B= (DHPublicKeyParameters) bobKeyPair.Public; Console.WriteLine("Bob Public Key:\t{0}",B.Y); Console.WriteLine("\nAlice Key:\t{0}",aliceAgree); Console.WriteLine("Bob Key:\t{0}",bobAgree); if (aliceAgree.Equals (bobAgree)) Console.WriteLine("Keys match"); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
Key size: 256 g: 32259974487183794416499361372713990702644486074496240708135562418518132654939 P: 69234343638616341294341802070224047203994183137085651021419312836532414307987 Alice Private Key: 16547342261270997888576284742384751809929302191652453904568191074081009056381 Alice Public Key: 68871015261301621898691329237236329560993238933340856839493134997803993018121 Bob Private Key: 1924183266892706636821740708766318587774348404629964294853747941353163203900 Bob Public Key: 26889109636431132458440992472548015781681995210325136654900321789840740213139 Alice Key: 67276705861661430366025633569922408078630863545838188854396733719920518569346 Bob Key: 67276705861661430366025633569922408078630863545838188854396733719920518569346 Keys match
Now, let's try these values with Python:
>>> g=32259974487183794416499361372713990702644486074496240708135562418518132654939 >>> p=69234343638616341294341802070224047203994183137085651021419312836532414307987 >>> a=16547342261270997888576284742384751809929302191652453904568191074081009056381 >>> A=pow(g,a,p) >>> print (A) 68871015261301621898691329237236329560993238933340856839493134997803993018121
and which agrees with Alice's public key. Now for Bob:
>>> b=1924183266892706636821740708766318587774348404629964294853747941353163203900 >>> B=pow(g,b,p) >>> print (B) 26889109636431132458440992472548015781681995210325136654900321789840740213139
and which agrees with Bob's public key. Now let's compute the shared secret:
>>> KeyA=pow(B,a,p) >>> KeyB=pow(A,b,p) >>> print (KeyA) 67276705861661430366025633569922408078630863545838188854396733719920518569346 >>> print (KeyB) 67276705861661430366025633569922408078630863545838188854396733719920518569346