In the past, I’ve talked about how to create Elliptic Curve (EC) keys using OpenSSL and how to use them to sign JWTs and sign XML in .NET and .NET Core. This time, I’m going to talk about different ways of parsing and loading EC keys in .NET.

In this article, you’re going to learn what EC keys look like and then see how to use that knowledge in four different ways to load or create an `ECDsa`

object in .NET.
By the end of this article, you should be able to load in an EC key, no matter the format.

## The parameters of an Elliptic Curve (EC) key

When loading an EC key, you’re going to want to know three things:

- The private key (optional)
- The public key
- The curve you need to use

The private key, *d*, is a random integer, the length of which depends on what curve you are using.
If you have the private key, you’ll be able to sign data.

The public key is a point on the elliptic curve, using coordinates *x* & *y*.
As a result, the public key is specific to that curve and is generated using the private key multiplied by a generator point, *G*, on your curve.
With the public key, you’ll be able to verify signatures.

This shows that you need to know the elliptic curve in use (e.g., NIST’s P-256 or secp256k1) in order to use Elliptic Curve Cryptography (ECC). Without knowing the curve, you won’t know how long the private key should be, the level of security provided, or if the public key is valid (if they are points on the curve).

If you want to learn more about how Elliptic Curve Cryptography works, I found Practical Cryptography for Developers to be a useful read.

## .NET’s ECDsa object

.NET’s abstraction for ECDSA is the class `ECDsa`

found in `System.Security.Cryptography`

.
This inherits from `AsymmetricAlgorithm`

and follows a similar pattern to the `RSA`

class you may have used before.
`ECDsa`

is an abstract class with various platforms using different implementations (e.g., CNG on Windows and OpenSSL on Linux).

Your primary usage of this class will be to call the `SignData`

and `VerifyData`

methods.
Otherwise, you might be passing it into a SecurityKey implementation or SignedXml.

The rest of this article will be focused on how to create an `ECDsa`

implementation.

## Generating an EC key using ECDsa and named curves

The simplest way to create a new EC key is to have .NET do it for you by using the `Create`

method on `ECDsa`

.
This will create a private key on the curve of your choice.
You’re typically going to use a known, named curve such as NIST’s P-256, aka secp256r1.
You can find the curves supported out-of-the-box by .NET in the `ECCurve.NamedCurve`

class.

`ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP256);`

This approach is great for generating keys on the fly during testing, but you’ll lose the key once the object gets disposed.
Luckily, you can use various export methods on `ECDsa`

; otherwise, you can access the EC parameters directly using the `ExportParameters`

method.
These export methods give you access to the `ECParameters`

object, containing the key’s curve, D, and Q (*x & y*) points, which you’ll see in action next.

## Creating ECDsa using ECParameters

Let’s say you’ve received the raw points for the curve, and you need to load the key in that way. This is common when using JSON Web Keys (JWK) and OpenID Connect.

Here’s an example JWK from RFC 7517:

```
{
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"kid": "my EC key"
}
```

To load the key, you’ll need to know what curve the key uses and the public key parameters (the *x* and *y* coordinates).
The private key can also be included in the JWK using the *d* parameter; however, this is rare.

You can again use `ECDsa`

’s `Create`

method to load in these coordinates, but this time you’re passing in some `ECParameters`

.

```
// parse curve from JOSE format
// https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
var curve = crv switch
{
"P-256" => ECCurve.NamedCurves.nistP256,
"P-384" => ECCurve.NamedCurves.nistP384,
"P-521" => ECCurve.NamedCurves.nistP521,
_ => throw new NotSupportedException()
};
ECDsa key = ECDsa.Create(new ECParameters
{
Curve = curve,
D = Base64UrlEncoder.DecodeBytes(d), // optional
Q = new ECPoint
{
X = Base64UrlEncoder.DecodeBytes(x),
Y = Base64UrlEncoder.DecodeBytes(y)
}
});
```

Here you are parsing the curve from the JOSE designation and base64url decoding the other parameters using the encoder found in `Microsoft.IdentityModel.Tokens`

.

This parsing is specific to the formatting used by JWKs, but it demonstrates how you can load in an EC key if you know its parameters.

There is a `Validate`

method on `ECParameters`

, which will check key and coordinate sizes and check that the curve is valid.
However, the `Create`

method on `ECDsa`

will call this for you.

## Loading ECDsa from X509Certificate2

Loading an EC key from an `X509Certificate2`

is a case of simply using the `GetECDsaPrivateKey`

and `GetECDsaPublicKey`

methods.

`ECDsa key = cert.HasPrivateKey ? cert.GetECDsaPrivateKey() : cert.GetECDsaPublicKey();`

For loading the `X509Certificate2`

in the first place, you could load it from a PEM file.

### X509Certificate2.PrivateKey vs GetRSAPrivateKey and GetECDsaPrivateKey

In the past, you might have used the `PrivateKey`

and `PublicKey`

properties on `X509Certificate2`

.
However, if you try to use these properties on a certificate containing an EC key, you will get null for `PrivateKey`

and the following exception for `PublicKey`

:

System.NotSupportedException: The certificate key algorithm is not supported. at System.Security.Cryptography.X509Certificates.PublicKey.get_Key()

To use an EC key from an X.509, you’ll need to use the `GetECDsaPrivateKey`

and `GetECDsaPublicKey`

methods.

As of .NET 6, the `PrivateKey`

and `PublicKey`

properties are marked as obsolete.
As a result, you’ll have to use the `RSA`

and `ECDsa`

specific methods to load in keys across the board.

## Loading ECDsa from a hex string

Sometimes, you’ll see EC keys shared as a hexadecimal string. This is common in the crypto communities, and by that, I mean both cryptography and cryptocurrency. I couldn’t say if it has much use in cryptozoology. These keys look something like this:

```
Private: c711e5080f2b58260fe19741a7913e8301c1128ec8e80b8009406e5047e6e1ef
Public: 04e33993f0210a4973a94c26667007d1b56fe886e8b3c2afdd66aa9e4937478ad20acfbdc666e3cec3510ce85d40365fc2045e5adb7e675198cf57c6638efa1bdb
```

These keys might look a bit odd at first, but they actually map back to the parameters you’ve been using already.
The private key is just the hexadecimal representation of the *d* parameter, and the public key is the *x* & *y* coordinates concatenated together (with the first byte being a tag).

As a result, you can again use `ECParameters`

to create your `ECDsa`

object:

```
public static ECDsa LoadFromHex()
{
var privateKeyBytes = FromHexString("c711e5080f2b58260fe19741a7913e8301c1128ec8e80b8009406e5047e6e1ef");
var publicKeyBytes = FromHexString("04e33993f0210a4973a94c26667007d1b56fe886e8b3c2afdd66aa9e4937478ad20acfbdc666e3cec3510ce85d40365fc2045e5adb7e675198cf57c6638efa1bdb");
return ECDsa.Create(new ECParameters
{
Curve = ECCurve.NamedCurves.nistP256, // you'd need to know the curve before hand
D = privateKeyBytes,
Q = new ECPoint
{
X = publicKeyBytes.Skip(1).Take(32).ToArray(),
Y = publicKeyBytes.Skip(33).ToArray()
}
});
}
private static byte[] FromHexString(string hex) {
var numberChars = hex.Length;
var hexAsBytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
hexAsBytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return hexAsBytes;
}
```

## Source Code

You can find executable code demonstrating the above approaches on my GitHub samples repository. This code is multitargeting .NET Core 3.1 onwards and runs on both Windows and Linux.

To learn more about elliptic curve cryptography in .NET, check out some of my other articles: