ECDSA and C#

Prof Bill Buchanan OBE FRSE
2 min readNov 6, 2023

With ECDSA (Elliptic Curve Digital Signature), we use an elliptic curve to produce a digital signature. Overall, we take a hash of a message and then create a signature using a private key. The public key can then be used to verify the signature. In this case, we will use a range of curves, such as 192-bit, 256-bit, 384-bit and 521-bit curves, and create a range of hashing methods (such as MD5, SHA-1 and SHA-256).

With Elliptic Curve Cryptography (ECC) we can use a Weierstrass curve form of the form of y²=x³+ax+b (mod p). Bitcoin and Ethereum use secp256k1 and which has the form of =x³+7 (mod p). In most cases, though, we use the NIST-defined curves. SECP256k1 has 256-bit (x,y) points, and where the private key is a 256-bit scalar value (a) and which gives a public key point of:

a.G

and where G is a base point on the curve. An outline of ECDSA is:

We can code with [here]:

namespace ECDSA
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;


class Program
{

static void Main(string[] args)
{

try {

var msg="Hello";
var method="SHA-1withECDSA";

if (args.Length >0) msg=args[0];
if (args.Length >1) method=args[1];


var gen = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator("ECDSA");


var secureRandom = new SecureRandom();


var keyGenParam = new KeyGenerationParameters(secureRandom, 256);


gen.Init(keyGenParam);


var keyPair = gen.GenerateKeyPair();


ECPrivateKeyParameters privateKeyParam = (ECPrivateKeyParameters)keyPair.Private;
ECPublicKeyParameters publicKeyParam = (ECPublicKeyParameters)keyPair.Public;


var signer = SignerUtilities.GetSigner(method);
signer.Init(true,keyPair.Private);
signer.BlockUpdate(System.Text.Encoding.UTF8.GetBytes(msg), 0,System.Text.Encoding.UTF8.GetBytes(msg).Length);
byte[] signature = signer.GenerateSignature();


signer = SignerUtilities.GetSigner(method);
signer.Init(false,keyPair.Public);
signer.BlockUpdate(System.Text.Encoding.UTF8.GetBytes(msg), 0,System.Text.Encoding.UTF8.GetBytes(msg).Length);
var rtn=signer.VerifySignature(signature);

Console.WriteLine("Message: {0}",msg);
Console.WriteLine("\n=== Private key ===");
Console.WriteLine("D={0}",privateKeyParam.D.ToString());
Console.WriteLine("Method={0}",method);

Console.WriteLine("\n=== Public key ===");
Console.WriteLine("Gy={0}",publicKeyParam.Parameters.G.YCoord.ToString());
Console.WriteLine("Gx={0}",publicKeyParam.Parameters.G.XCoord.ToString());
Console.WriteLine("Curve={0}",publicKeyParam.Parameters.Curve.ToString());
Console.WriteLine("Order={0}",publicKeyParam.Parameters.N.ToString());
Console.WriteLine("Qx={0}",publicKeyParam.Q.XCoord.ToString());
Console.WriteLine("Qy={0}",publicKeyParam.Q.YCoord.ToString());

Console.WriteLine("\n=== Signature ===");
Console.WriteLine("\nSignature: r={0}",Convert.ToHexString(signature)[0..64]);
Console.WriteLine("\nVerified={0}",rtn);



} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}

}
}
}

A sample run gives [here]:

Message: Post Quantum Crypto

=== Private key ===
D=121419095404849764515855012415047775391541554722394902556065690372269803511

Method=SHA-1withECDSA

=== Public key ===
Gy=4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
Gx=6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
Curve=Org.BouncyCastle.Math.EC.Custom.Sec.SecP256R1Curve
Order=115792089210356248762697446949407573529996955224135760342422259061068512044369
Qx=eb3472338fbfbb1510870bb820ad05f30b9d1330197cd8abf30e6de98abf9b64
Qy=4375cdefe245958f3a0358a723f7dbe2dc8847f7df180c1f2bc6ce691b2cbfb2

=== Signature ===
Signature=304502206DE460A0E46515B578A838CA71961E51FF3B6A76257E07744912EDC48F72AEF802210088753A7A3294DCD9808B87CDA1A7E668833FB57F79DBD696F6DABAB98771B18A

Verified=True

The signature is in a DER form, and we can then parse with [here] to get the r and s values:

DER: 304502206DE460A0E46515B578A838CA71961E51FF3B6A76257E07744912EDC48F72AEF802210088753A7A3294DCD9808B87CDA1A7E668833FB57F79DBD696F6DABAB98771B18A
[U] SEQUENCE (30)
[U] INTEGER (02): 49705608531639052973379532627260569791942375067203030641079606654887303229176
[U] INTEGER (02): 61721672109631760174112530506626131835392659902044938154054687780295991734666
-----BEGIN PUBLIC KEY-----
MEUCIG3kYKDkZRW1eKg4ynGWHlH/O2p2JX4HdEkS7cSPcq74AiEAiHU6ejKU3NmAi4fNoafmaIM/tX9529aW9tq6uYdxsYo=
-----END PUBLIC KEY-----

We thus have an (r,s) of 49705608531639052973379532627260569791942375067203030641079606654887303229176, 61721672109631760174112530506626131835392659902044938154054687780295991734666)

--

--

Prof Bill Buchanan OBE FRSE
Prof Bill Buchanan OBE FRSE

Written by Prof Bill Buchanan OBE FRSE

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.

No responses yet