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 generate PEM format outputs for the keys, and which bounds keys with a header and footer. The header for a private key is '-----BEGIN EC PRIVATE KEY-----'.
EC Curve Keys with PEM format 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
Next some code:
namespace ECCurves { using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; 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 privateKey = (ECPrivateKeyParameters) keyPair.Private; var publicKey = (ECPublicKeyParameters) keyPair.Public; Console.WriteLine("== Curve: {0} ",curvename); Console.WriteLine("\n== Private key === "); Console.WriteLine("== D ==={0} ",privateKey.D.ToString()); Console.WriteLine("\n== Public key === "); Console.WriteLine("== Q_x ==={0} ",publicKey.Q.XCoord); Console.WriteLine("== Q_t ==={0} ",publicKey.Q.YCoord); 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); Console.WriteLine("\n== PEM Keys == "); StringWriter stringWriter = new StringWriter (); PemWriter pemWriter = new PemWriter (stringWriter); pemWriter.WriteObject(keyPair.Private); pemWriter.Writer.Flush(); pemWriter.Writer.Close(); Console.WriteLine("{0}",stringWriter.ToString()); StringWriter stringWriter2 = new StringWriter (); pemWriter = new PemWriter (stringWriter2); pemWriter.WriteObject(keyPair.Public); pemWriter.Writer.Flush(); pemWriter.Writer.Close(); Console.WriteLine("{0}",stringWriter2.ToString()); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run for secp2561 gives:
== Curve: secp256k1 == Private key === == D ===43250499650242596509689166032012670046190113460404858020166639295206771656023 == Public key === == Q_x ===7b95c5ca46483c9571f9e011f66bb1ddbbea0e79e862ff9be6a2dc7d6e55bf92 == Q_t ===9259573461fab4aa93bf7b4f6d4d5c05180d9b051d02f81d5b0fbf1d738da959 Curve details: G=(79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,1,0), N=115792089237316195423570985008687907852837564279074904382605163141518161494337, H=1 A=0 B=7 Field size=256 == PEM Keys == -----BEGIN EC PRIVATE KEY----- MIIBUQIBAQQgX57qUTrWzGTaeOK0eyGIv1SaMm+vXrpB+Pj9TyOUBVeggeMwgeAC AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv MEQEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAABwRBBHm+Zn753LusVaBilc6HCwcCm/zbLc4o 2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ1LgCIQD///// ///////////////+uq7c5q9IoDu/0l6M0DZBQQIBAaFEA0IABHuVxcpGSDyVcfng EfZrsd276g556GL/m+ai3H1uVb+SkllXNGH6tKqTv3tPbU1cBRgNmwUdAvgdWw+/ HXONqVk= -----END EC PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA//////////////// /////////////////////v///C8wRAQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBEEEeb5m fvncu6xVoGKVzocLBwKb/NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0 SKaFVBmcR9CP+xDUuAIhAP////////////////////66rtzmr0igO7/SXozQNkFB AgEBA0IABHuVxcpGSDyVcfngEfZrsd276g556GL/m+ai3H1uVb+SkllXNGH6tKqT v3tPbU1cBRgNmwUdAvgdWw+/HXONqVk= -----END PUBLIC KEY-----
And for NIST (FIPS) P-256:
== Curve: P-256 == Private key === == D ===86743583738379448146094505808110034179188128696718648342714252621347788199862 == Public key === == Q_x ===d0710c1f0d9bd54faea6e803b2aefa6e463a5fe410155ff98d6d0120dd134203 == Q_t ===ce6dc2f17010cbd776aa9143860161b9d311c6159bd8ff1bc77c976d22abdaf8 Curve details: G=(6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,1,ffffffff00000001000000000000000000000000fffffffffffffffffffffffc), N=115792089210356248762697446949407573529996955224135760342422259061068512044369, H=1 A=ffffffff00000001000000000000000000000000fffffffffffffffffffffffc B=5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b Field size=256 == PEM Keys == -----BEGIN EC PRIVATE KEY----- MIIBaAIBAQQgv8cg51nFI3tl6Lh4bMbH46nPv9sR5KNjTwVGn4BAl7aggfowgfcC AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 YyVRAgEBoUQDQgAE0HEMHw2b1U+upugDsq76bkY6X+QQFV/5jW0BIN0TQgPObcLx cBDL13aqkUOGAWG50xHGFZvY/xvHfJdtIqva+A== -----END EC PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA//// ///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5 RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA //////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABNBxDB8Nm9VPrqboA7Ku+m5G Ol/kEBVf+Y1tASDdE0IDzm3C8XAQy9d2qpFDhgFhudMRxhWb2P8bx3yXbSKr2vg= -----END PUBLIC KEY-----