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.
SM2 Keys 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.
Code
First we create a folder named "bc_ec02", 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
We first need to use the "sm2p256v1" curve type:
X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
And then generate the key pair with
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();
Next some code:
namespace ECDSA { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Utilities; using System.Text; using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC; using System.ComponentModel.DataAnnotations; using Org.BouncyCastle.Asn1.GM; class Program { static void Main(string[] args) { try { var curvename="sm2p256v1"; if (args.Length >0) curvename=args[0]; 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; Console.WriteLine("Private key {0}",BobprivateKey.D); Console.WriteLine("Public key {0}, {1}",BobpublicKey.Q.AffineXCoord,BobpublicKey.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 secp2561 gives:
Private key 56172605536492177223661381434107759735851303136376608757534584160917602287750 Public key e0a4cc044cc675d1b9f214bb769ce299e81d34a70b7066ca3b1fb53f100d62df, 6948f25e86f20dee162a4c30f8cb75133acc97e9f4b0da1d870accd58676713a == ECC Parameters sm2p256v1 == ECC A=fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc, B=28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93, Order=115792089210356248756420345214020892766061623724957744567843809356293439045923 ECC N=115792089210356248756420345214020892766061623724957744567843809356293439045923, G=(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc), H=1
We can see that A is equal to fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc, B is 28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93 and the order of the curve is 115792089210356248756420345214020892766061623724957744567843809356293439045923.