With ECDH (Elliptic Curve Diffie Hellman), Bob generates a scalar value of \(b\) and Alice generates a scalar value of \(a\). Bob computes \(b.G\) and Alice computes \(a.G\), and where \(G\) is the base point on the curve. Bob passes \(b.G\) to Alice, and Alice passes \(a.G\) to Bob. They then both compute \(a.b.G\) as a shared secret. In this case we will use a number of standard curves to produce the shared secret.
ECDH Curve Key Exchange using Bouncy Castle and C# |
Method
With elliptic curve cryptography, we start with a definition for the curve, such as:
\(y^2 = x^3 + ax + b \pmod p\)
This defines values for \(a\), \(b\) and \(p\). Next we select a base point on the curve (\(G\), and generate a random scalar value (\(D\)). This is the private key, and where the public key is generated from a point multiplcation of:
\(Q=D.G\)
This results in an \((x,y)\) point on the curve.
With ECDH, Bob generates a scalar value of \(b\) and Alice generates a scalar value of \(a\). Bob computes \(b.G\) and Alice computes \(a.G\), and where \(G\) is the base point on the curve. Bob passes \(b.G\) to Alice, and Alice passes \(a.G\) to Bob. They then both compute \(a.b.G\) as a shared secret:
Code
First we create a folder named "bc_ec03", 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 we can install the Bouncy Castle library with:
dotnet add package BouncyCastle.Crypto.dll --version 1.8.1
Next some code:
namespace ECCurves { using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; class Program { static void Main(string[] args) { var curvename="secp256k1"; if (args.Length >0) curvename=args[0]; try { X9ECParameters ecParams = ECNamedCurveTable.GetByName(curvename); var curveparam = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed()); Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters (curveparam, new SecureRandom()); Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator generator = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator(); generator.Init(keygenParams); var keyPair = generator.GenerateKeyPair(); var BobprivateKey = (ECPrivateKeyParameters) keyPair.Private; var BobpublicKey = (ECPublicKeyParameters) keyPair.Public; // var BobpublicKey = ecParams.G.Multiply(BobprivateKey.D); var keyPair2 = generator.GenerateKeyPair(); var AliceprivateKey = (ECPrivateKeyParameters) keyPair2.Private; var AlicepublicKey = (ECPublicKeyParameters) keyPair2.Public; // var AlicepublicKey = ecParams.G.Multiply(AliceprivateKey.D); var ShareKeyAlice = BobpublicKey.Q.Multiply(AliceprivateKey.D); var ShareKeyBob = AlicepublicKey.Q.Multiply(BobprivateKey.D); Console.WriteLine("== Curve: {0} ",curvename); Console.WriteLine("\n Bob Private key === "); Console.WriteLine("== D_b={0} ",BobprivateKey.D.ToString()); Console.WriteLine("\n Bob Public key === "); Console.WriteLine("== Q_x={0} ",BobpublicKey.Q.AffineXCoord); Console.WriteLine("== Q_y={0} ",BobpublicKey.Q.AffineYCoord); Console.WriteLine("\n== Alice Private key === "); Console.WriteLine(" D_a={0} ",AliceprivateKey.D.ToString()); Console.WriteLine("\n== Alice Public key === "); Console.WriteLine(" Q_x={0} ",AlicepublicKey.Q.AffineXCoord); Console.WriteLine(" Q_y={0} ",AlicepublicKey.Q.AffineYCoord); Console.WriteLine("\n\n== Shared key === "); Console.WriteLine(" Shared key (Bob) ==={0} ",ShareKeyBob.Normalize().AffineXCoord); Console.WriteLine(" Shared key (Alice) ==={0} ",ShareKeyAlice.Normalize().AffineXCoord); Console.WriteLine("\n\nCurve details: G={0}, N={1}, H={2}", ecParams.G, ecParams.N, ecParams.H); Console.WriteLine("A={0}\nB={1}\nField size={2}",ecParams.Curve.A,ecParams.Curve.B,ecParams.Curve.FieldSize); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } } }
A sample run for secp2561 gives:
== Curve: secp256k1 Bob Private key === == D_b=104440660231868095396729365161125744441732891662618747308192395954925556452661 Bob Public key === == Q_x=f2b12dd1bee1262ac0104d75a927918469c801f7714bd2777d3f37e061a7da7a == Q_y=2580bd44df0618df9ea4897384b55020e671cdd9a029f5501d7c94fafe7b3324 == Alice Private key === D_a=37691210022027421675390073679228940555709453553957591812838571855334943714279 == Alice Public key === Q_x=73f6bc668a95ef0c835cffae2cf3c32a80bdde40f17c2ce2c83eed0f662f58de Q_y=557e983f400c47002fedf9f515607cb4c072739448a170aa71ec4655612ad9c3 == Shared key === Shared key (Bob) ===5ddb4213ee3b2fd663ce681c6bc8010aab42f3229e2479e59b6af8babf846615 Shared key (Alice) ===5ddb4213ee3b2fd663ce681c6bc8010aab42f3229e2479e59b6af8babf846615 Curve details: G=(79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,1,0), N=115792089237316195423570985008687907852837564279074904382605163141518161494337, H=1 A=0 B=7 Field size=256
We see we have a shared secret of "5ddb4213ee3b2fd663ce681c6bc8010aab42f3229e2479e59b6af8babf846615", and which is the x-coordinate point of the shared point (\(abG\)). And for NIST (FIPS) P-256:
== Curve: P-256 Bob Private key === == D_b=14396998444177855214832276087174687118195290575531943149305766547256278170161 Bob Public key === == Q_b=(a1fe64a9e7e4ffee4c25d3b6dd4f86bdb7a808d30cd227e0076a169ca6b39a23,f87f8a2f2f5318f4538464cdd8f1583d43c5f585f0f495a43ada8939f9935cf0,1,ffffffff00000001000000000000000000000000fffffffffffffffffffffffc) == Alice Private key === D_a=43409290524029651895132107402409201272456245443545075570599407853849715049771 == Alice Public key === Q_a=(1b774bffcc89e26d0e0b764f6c1cc3b0e2186337b17ac63dfe6f7406e9a61966,888a9cba5f3a2cd5e4ef908c4015bff2bdb2288510a034f8e68beea31fa003c3,1,ffffffff00000001000000000000000000000000fffffffffffffffffffffffc) == Shared key === Shared key (Bob) ===3a8decbe96075773b59cf55adb85062cc08e2b11158e2b43ed74f2db0011b927 Shared key (Alice) ===3a8decbe96075773b59cf55adb85062cc08e2b11158e2b43ed74f2db0011b927 Curve details: G=(6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,1,ffffffff00000001000000000000000000000000fffffffffffffffffffffffc), N=115792089210356248762697446949407573529996955224135760342422259061068512044369, H=1 A=ffffffff00000001000000000000000000000000fffffffffffffffffffffffc B=5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b Field size=256