We have a number of possible types of elliptic curve types. These have a field (the prime number used), the order (the number of elliptic curve points), an \(a\) value, a \(b\) value, and a generator point (\(G\)). For a Weierstrass curve the standard form is \(y^2=x^3+ax+b\). In this case, we will generate a random private key (\(D\)) and then generate the public key: \(Q=D.G\). In this case we will use the SM2 elliptic curve, and use it to authenticate both Bob and Alice within a key exchange. For this Alice and Bob will have long-term static public keys, and for each session they will have emphemeral keys. Along with this, we can add-in their IDs into the key exchange.
SM2 Key Exchange with Mutual Authentication using Bouncy Castle and C# |
Coding
First we create a folder named "bc_sm02_keyex", and then go into that folder.We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
This produces a Csproject file of:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
We then add the latest Bouncy Castle library:
dotnet add package BouncyCastle.Cryptography --version 2.2.1
The following is the coding:
namespace SM2_Keyex { using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Utilities; class Program { static void Main(string[] args) { try { var curvename="sm2p256v1"; var bobID="[email protected]"; var aliceID="[email protected]"; var keysize=128; if (args.Length >0) keysize=Convert.ToInt32(args[0]); if (args.Length >1) bobID=args[1]; if (args.Length >2) aliceID=args[2]; X9ECParameters x9ECParameters = GMNamedCurves.GetByName(curvename); ECDomainParameters sm2Parameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N); Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters (sm2Parameters, 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; generator.Init(keygenParams); keyPair = generator.GenerateKeyPair(); var BobEprivateKey = (ECPrivateKeyParameters) keyPair.Private; var BobEpublicKey = (ECPublicKeyParameters) keyPair.Public; keyPair = generator.GenerateKeyPair(); var AliceprivateKey = (ECPrivateKeyParameters) keyPair.Private; var AlicepublicKey = (ECPublicKeyParameters) keyPair.Public; generator.Init(keygenParams); keyPair = generator.GenerateKeyPair(); var AliceEprivateKey = (ECPrivateKeyParameters) keyPair.Private; var AliceEpublicKey = (ECPublicKeyParameters) keyPair.Public; var exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange(); exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true ,AliceprivateKey,AliceEprivateKey),Strings.ToByteArray(bobID))); byte[] kAlice = exch.CalculateKey(keysize, new ParametersWithID(new SM2KeyExchangePublicParameters(BobpublicKey,BobEpublicKey), Strings.ToByteArray(aliceID))); exch = new Org.BouncyCastle.Crypto.Agreement.SM2KeyExchange(); exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, BobprivateKey,BobEprivateKey),Strings.ToByteArray(aliceID))); byte[] kBob = exch.CalculateKey(keysize, new ParametersWithID(new SM2KeyExchangePublicParameters(AlicepublicKey,AliceEpublicKey), Strings.ToByteArray(bobID))); Console.WriteLine("\n\nKey Alice:\t{0}",Convert.ToHexString(kAlice)); Console.WriteLine("Key Bob:\t{0}",Convert.ToHexString(kBob)); Console.WriteLine("=== Static keys ==="); Console.WriteLine("\n\nBob Static Private key {0}",BobprivateKey.D); Console.WriteLine("Bob Static Public key {0}, {1}",BobpublicKey.Q.AffineXCoord,BobpublicKey.Q.AffineYCoord); Console.WriteLine("\nAlice Static Private key {0}",AliceprivateKey.D); Console.WriteLine("Alice Static Public key {0}, {1}",AlicepublicKey.Q.AffineXCoord,AlicepublicKey.Q.AffineYCoord); Console.WriteLine("=== Ephemeral keys ==="); Console.WriteLine("\n\nBob Ephemeral Private key {0}",BobprivateKey.D); Console.WriteLine("Bob Ephemeral Public key {0}, {1}",BobpublicKey.Q.AffineXCoord,BobpublicKey.Q.AffineYCoord); Console.WriteLine("\nAlice Ephemeral Private key {0}",AliceprivateKey.D); Console.WriteLine("Alice Ephemeral Public key {0}, {1}",AlicepublicKey.Q.AffineXCoord,AlicepublicKey.Q.AffineYCoord); Console.WriteLine("\n\n== ECC Parameters {0} == ",curvename); Console.WriteLine("ECC A={0}, B={1}, Order={2}",sm2Parameters.Curve.A,sm2Parameters.Curve.B,sm2Parameters.Curve.Order); Console.WriteLine("\nECC N={0}, G={1}, H={2}",keygenParams.DomainParameters.N, keygenParams.DomainParameters.G,keygenParams.DomainParameters.H); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run for a 128-bit key is:
Key Alice: A9B4598194A4A7FA93B1488E03219D08 Key Bob: A9B4598194A4A7FA93B1488E03219D08 Bob ID: [email protected] Alice ID: [email protected] === Static keys === Bob Static Private key 22663629632319858499911831467800316779032123351317036294738147722932151044961 Bob Static Public key 2e024e12f1046808fdeb12535dc32ca910b1df719670c1309e5756c8363bd851, bbb76ab086084ecda8d866c1c1806e3bc15aaec73ef87df476f3e24ce14a7cad Alice Static Private key 25704379927464203383792470642436765260982773552233098385500408151033422766094 Alice Static Public key ef32e3f459a73473a34520a4b13c93315712ffc31b08421b061759144523dfde, 7ef8d0f4bc581a0ede0280d9c035c3138153204e6438534a83cccbaf48a786e2 === Ephemeral keys === Bob Ephemeral Private key 22663629632319858499911831467800316779032123351317036294738147722932151044961 Bob Ephemeral Public key 2e024e12f1046808fdeb12535dc32ca910b1df719670c1309e5756c8363bd851, bbb76ab086084ecda8d866c1c1806e3bc15aaec73ef87df476f3e24ce14a7cad Alice Ephemeral Private key 25704379927464203383792470642436765260982773552233098385500408151033422766094 Alice Ephemeral Public key ef32e3f459a73473a34520a4b13c93315712ffc31b08421b061759144523dfde, 7ef8d0f4bc581a0ede0280d9c035c3138153204e6438534a83cccbaf48a786e2
A sample run for a 256-bit key is:
Key Alice: 8AFDDCED1E280209319C1E30E2773AFA752C41A689595997E73E656E5D09AC58 Key Bob: 8AFDDCED1E280209319C1E30E2773AFA752C41A689595997E73E656E5D09AC58 Bob ID: [email protected] Alice ID: [email protected] === Static keys === Bob Static Private key 9961657569207165213288658243160183756591630536646422832095952833975417070225 Bob Static Public key af4f696154f671e5bd2c108b3477c05e719e61f70ce18cee509807c526913401, e031fd2defb4f3ae6e78c67ff6cbab9d1d5e6807ed26c27d4438c206f6ac3501 Alice Static Private key 29191140555732067136790628671982194060002195813426885016916187114911668495454 Alice Static Public key 1166c34f114deba4e7379727edd6183f140dad99dc002f2d38d27dc4435909a6, 93817c339baa7a2ad14d95618b97f4f32c39fc0752bf37ce2be5960e7c6f4fcf === Ephemeral keys === Bob Ephemeral Private key 9961657569207165213288658243160183756591630536646422832095952833975417070225 Bob Ephemeral Public key af4f696154f671e5bd2c108b3477c05e719e61f70ce18cee509807c526913401, e031fd2defb4f3ae6e78c67ff6cbab9d1d5e6807ed26c27d4438c206f6ac3501 Alice Ephemeral Private key 29191140555732067136790628671982194060002195813426885016916187114911668495454 Alice Ephemeral Public key 1166c34f114deba4e7379727edd6183f140dad99dc002f2d38d27dc4435909a6, 93817c339baa7a2ad14d95618b97f4f32c39fc0752bf37ce2be5960e7c6f4fcf == ECC Parameters sm2p256v1 == ECC A=fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc, B=28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93, Order=115792089210356248756420345214020892766061623724957744567843809356293439045923 ECC N=115792089210356248756420345214020892766061623724957744567843809356293439045923, G=(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc), H=1