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 with a range of hashing methods (such as MD5, SHA-1 and SHA-256).
ECDSA for Multiple Curves with Different Hashing Methods and C# |
Method
Overall, Microsoft has been a little sluggish in getting into elliptic curve cryptography (ECC), but now .NET and Powershell support it. In fact, Powershell is now supported on Linux, Mac OSX and Windows. .
So, let’s see if we can create a signature that is used by Bitcoin and Ethereum: ECDSA (Elliptic Curve Digital Signature Algorithm). With ECDSA 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 with a range of hashing methods (such as MD5, SHA-1 and SHA-256). Common curve types include Brainpool, secp, and NIST. To set up a NIST P-256 curve, we create with:
ECDsa ecc = System.Security.Cryptography.ECDsa.Create(System.Security.Cryptography.ECCurve.CreateFromFriendlyName("nistp256));
We can then export the keys with:
ECParameters s = ecc.ExportExplicitParameters(true);
To select an SHA-1 hashing method for a word of “hello”:
byte[] hash1 = System.Security.Cryptography.HashAlgorithm.Create(hashmethod).ComputeHash(System.Text.Encoding.UTF8.GetBytes("Hello"));
The signature is then created with:
byte[] hash1 = System.Security.Cryptography.HashAlgorithm.Create(hashmethod).ComputeHash(System.Text.Encoding.UTF8.GetBytes(word)); ECDsa ecdsa = System.Security.Cryptography.ECDsa.Create(e); byte[] ecdsa_sig = ecdsa.SignHash(hash1);
To verify, we need to provide the hash of the message and the signature:
bool rtn = ecdsa.VerifyHash(hash1, ecdsa_sig); if (rtn == true) str1 = str1 + "\n\nSignature verifies"; else str1 = str1 + "Signature not verified!";
Coding
The coding is:
namespace ECDSA { using System.Security.Cryptography; class Program { static void Main(string[] args) { var word="Test"; var curvename="secp256k1"; var hashmethod="SHA1"; if (args.Length >0) word=args[0]; if (args.Length >1) curvename=args[1]; if (args.Length >2) hashmethod=args[2]; try { ECDsa ecc = System.Security.Cryptography.ECDsa.Create(System.Security.Cryptography.ECCurve.CreateFromFriendlyName(curvename)); ECParameters s = ecc.ExportExplicitParameters(true); ECParameters e = ecc.ExportParameters(true); string str1 = "Message: " + word; str1 = str1+"\nHash: " + hashmethod; str1 = str1+"\nCurve: " + e.Curve.Oid.FriendlyName; str1 = str1 + "\nCurve: " + e.Curve.Oid.Value; str1 = str1 + "\nA=" + BitConverter.ToString(s.Curve.A).Replace("-", string.Empty); str1 = str1 + "\nB=" + BitConverter.ToString(s.Curve.B).Replace("-", string.Empty); str1 = str1 + "\nGx=" + BitConverter.ToString(s.Curve.G.X).Replace("-", string.Empty); str1 = str1 + "\nGy=" + BitConverter.ToString(s.Curve.G.Y).Replace("-", string.Empty); str1 = str1 + "\nP=" + BitConverter.ToString(s.Curve.Prime).Replace("-", string.Empty); str1 = str1 + "\nOrder=" + BitConverter.ToString(s.Curve.Order).Replace("-", string.Empty); str1 = str1 + "\n\nPrivate key:"; str1 = str1 + "\nD=" + BitConverter.ToString(e.D).Replace("-", string.Empty); str1 = str1 + "\n\nPublic key:"; str1 = str1 + "\nQx=" + BitConverter.ToString(e.Q.X).Replace("-", string.Empty); str1 = str1 + "\nQy=" + BitConverter.ToString(e.Q.Y).Replace("-", string.Empty); byte[] hash1 = System.Security.Cryptography.HashAlgorithm.Create(hashmethod).ComputeHash(System.Text.Encoding.UTF8.GetBytes(word)); ECDsa ecdsa = System.Security.Cryptography.ECDsa.Create(e); byte[] ecdsa_sig = ecdsa.SignHash(hash1); str1 = str1 + "\n\nECDSA (Hex)=" + BitConverter.ToString(ecdsa_sig).Replace("-", string.Empty); str1 = str1 + "\nECDSA (Base64)=" + System.Convert.ToBase64String(ecdsa_sig).Replace("-", string.Empty); bool rtn = ecdsa.VerifyHash(hash1, ecdsa_sig); if (rtn == true) str1 = str1 + "\n\nSignature verifies"; else str1 = str1 + "Signature not verified!"; Console.WriteLine("{0}",str1); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
and a sample test for secp256k1:
Curve: secp256k1 Curve: A=0000000000000000000000000000000000000000000000000000000000000000 B=0000000000000000000000000000000000000000000000000000000000000007 Gx=79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 Gy=483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 P=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F Order=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 Private key: D=7C28BF7A06AA97061E470280E3A0954074F2D6FC2D07ACCFB66FBAE8016B7BA2 Public key: Qx=FE88C5697960D2CB36B2B99BE963F4410FDAED39BC1FA81C45555A79C75F15C6 Qy=7730131BDE73BEDDA4D7E7D993B477D2172E014620AA5496DA67906AD8743443 ECDSA (Hex)=753E1D84AC1B39C5D273B2C12F5D1D95D1798EC47C0FBF48DB07904CFC74B0DD7EF534D5B3F9181CCB41D382F096DE2D328C632AE9C726C1B174F78169CE0B7E ECDSA (Base64)=dT4dhKwbOcXSc7LBL10dldF5jsR8D79I2weQTPx0sN1+9TTVs/kYHMtB04Lwlt4tMoxjKunHJsGxdPeBac4Lfg== Signature verifies