Cybersecurity Can Be Beautiful and Simple: Meet EdDSA

So what’s the one method that holds up the security and trust of the Internet? Well, in terms of things created, the award would go to…

Cybersecurity Can Be Beautiful and Simple: Meet EdDSA

So what’s the one method that holds up the security and trust of the Internet? Well, in terms of things created, the award would go to Elliptic Curve Cryptography (ECC). In almost every single interaction with the Web, we initiate a key exchange using ECDH (Elliptic Curve Diffie Hellman). When it comes to determining whether we are connecting to a trusted Web site or not, we are increasingly using ECDSA to verify the Web site. The magic ECC method has basically secured the Web.

And ECDSA is used with Ethereum and Bitcoin and in digital wallets:

But ECDSA is a little cumbersome and does not scale well in distributed applications. Luckily, NIST has now defined EdDSA (Ed25519 — Edwards-curve Digital Signature Algorithm) as a FIPS 140 standard, which can be used in a production environment. With EdDSA, we have a much simpler approach to digital signatures:

Key generationAlice generates a random 32-byte secret key (SK) and then creates a public key of:

pk=skG

and where G is the base point of the curve.

Signing

Alice creates a SHA-512 hash of her private key:

h=HASH(sk)

Create r from the upper 32 bytes of hash and the message:

r=HASH(h[32:]||m))

And where “||” represents a concatenation of the byte array values. Next she matches r onto curve with:

R=rG

Next Alice computes s with:

s=r+(HASH(R||pk||m))⋅sk

The signature is (R,s). The values of R and s are 32 bytes long, and thus the signature is 64 bytes long.

Verifying

Bob creates S using R, pk and m:

S=HASH(R||pk||m)

And next creates two verification values:

v1=sG

v2=R+pkS

If v1==v2, the signature checks. This is because:

v1=s.G=(r+(HASH(R||pk||m))⋅sk)⋅G=rG+skG⋅(HASH(R||pk||m))=R+pkS=v2

Coding

The coding is [here]:

namespace CngEdDCSA
{
using System.Security.Cryptography;
using System.Text;
class Program
{

static void Main(string[] args)

{

var message="Hello";
var hash="SHA256";
try {
if (args.Length >0) message=args[0];
if (args.Length >1) hash=args[1];

var msg=Encoding.ASCII.GetBytes(message);
var keyCreationParameters = new CngKeyCreationParameters();
keyCreationParameters.ExportPolicy = CngExportPolicies.AllowExport;
keyCreationParameters.KeyUsage = CngKeyUsages.Signing;
keyCreationParameters.ExportPolicy = CngExportPolicies.AllowPlaintextExport;
/// Note if we change "null" to "AliceKeyPair" it would provide us with a named key and which is persistent.
var CngPrivateKey = CngKey.Create(CngAlgorithm.ECDsaP256,null, keyCreationParameters);
var alice = new ECDsaCng(CngPrivateKey);
var alicePrivate = alice.Key.Export(CngKeyBlobFormat.EccPrivateBlob);

var h = SHA256.HashData(msg); alice.HashAlgorithm = CngAlgorithm.Sha256;
if (hash=="MD5") { h = MD5.HashData(msg); alice.HashAlgorithm = CngAlgorithm.MD5;}
if (hash=="SHA1") { h = SHA1.HashData(msg); alice.HashAlgorithm = CngAlgorithm.Sha1;}
if (hash=="SHA384") { h = SHA384.HashData(msg); alice.HashAlgorithm = CngAlgorithm.Sha384;}
if (hash=="SHA512"){ h = SHA512.HashData(msg); alice.HashAlgorithm = CngAlgorithm.Sha512;}
var signature = alice.SignHash(h);
var alicePublic = alice.Key.Export(CngKeyBlobFormat.EccPublicBlob);

var bob = new ECDsaCng(CngKey.Import(alicePublic,CngKeyBlobFormat.EccPublicBlob));

var rtn=bob.VerifyHash(h,signature);
Console.WriteLine("Message:\t\t{0}",message);
Console.WriteLine("Hash method:\t\t{0}",hash);
Console.WriteLine("Hash:\t\t{0}",Convert.ToHexString(h));
Console.WriteLine("\nSignature:\t{0}",Convert.ToHexString(signature));

Console.WriteLine("\nVerified:\t{0}",rtn);
Console.WriteLine("\nPrivate key: {0}",Convert.ToHexString(alicePrivate));
Console.WriteLine("\nPrivate key (PEM):\n{0}",alice.ExportECPrivateKeyPem());
Console.WriteLine("\nPrivate key (DER):\n{0}",Convert.ToHexString(alice.ExportPkcs8PrivateKey()));
Console.WriteLine("\nPublic key: {0}",Convert.ToHexString(alicePublic));
Console.WriteLine("\nPublic key (DER):\n{0}",Convert.ToHexString(alice.ExportPkcs8PrivateKey()));
Console.WriteLine("Public key (PEM):\n{0}",alice.ExportSubjectPublicKeyInfoPem());

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

}
}
}
}

A sample test run is [here]:

Message:		Hello 123
Hash method: SHA256
Hash: 859E38D581E214DC7C8C871C425642913363A829065CF4ACDDD120ED5391B04B
Signature: E21B354399FA0B8304D79445963DF6458D4BD54FBFE5E04408056FD3D8C450E9F08CCD978353F76E05D090B6FDA92BA395FC7B390E81E5835D5146F9678F4A19
Verified: True

Private key: 454353322000000082B2AE069549C12A5CAF7A83BA3E25C79EB03E92D6BBE0CBE41B2069D3DB0D16ABCC386EA00F1D9186640FCADE8BA769E22AE0B7D0DC664FFEE13417859F32E8A38F6F4DD60103DEE49A76745220536764736C4D870C5D97B5E72B0E9B9B713E
Private key (PEM):
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIKOPb03WAQPe5Jp2dFIgU2dkc2xNhwxdl7XnKw6bm3E+oAoGCCqGSM49
AwEHoUQDQgAEgrKuBpVJwSpcr3qDuj4lx56wPpLWu+DL5BsgadPbDRarzDhuoA8d
kYZkD8rei6dp4irgt9DcZk/+4TQXhZ8y6A==
-----END EC PRIVATE KEY-----
Private key (DER):
3081A2020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420A38F6F4DD60103DEE49A76745220536764736C4D870C5D97B5E72B0E9B9B713EA00A06082A8648CE3D030107A1440342000482B2AE069549C12A5CAF7A83BA3E25C79EB03E92D6BBE0CBE41B2069D3DB0D16ABCC386EA00F1D9186640FCADE8BA769E22AE0B7D0DC664FFEE13417859F32E8A00D300B0603551D0F310403020080

Public key: 454353312000000082B2AE069549C12A5CAF7A83BA3E25C79EB03E92D6BBE0CBE41B2069D3DB0D16ABCC386EA00F1D9186640FCADE8BA769E22AE0B7D0DC664FFEE13417859F32E8
Public key (DER):
3081A2020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420A38F6F4DD60103DEE49A76745220536764736C4D870C5D97B5E72B0E9B9B713EA00A06082A8648CE3D030107A1440342000482B2AE069549C12A5CAF7A83BA3E25C79EB03E92D6BBE0CBE41B2069D3DB0D16ABCC386EA00F1D9186640FCADE8BA769E22AE0B7D0DC664FFEE13417859F32E8A00D300B0603551D0F310403020080
Public key (PEM):
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgrKuBpVJwSpcr3qDuj4lx56wPpLW
u+DL5BsgadPbDRarzDhuoA8dkYZkD8rei6dp4irgt9DcZk/+4TQXhZ8y6A==
-----END PUBLIC KEY-----

We can see that the signature has 64 bytes, and where the blob format encapsulates the keys.