Skip to content

EdDSA for JWS & jAdES

Aleksandar Gyonov edited this page Feb 16, 2024 · 9 revisions

EdDSA signatures for JWS and jAdES

The goal is to extend the functionality in the CryptoEx library to support EdDSA signatures.

The usage of these new extended classes is basically the same as the usage of the classes in the base CryptoEx library, except that you need to instantiate the new classes.

NB. The new classes support BOTH RSA, ECDSA, HMACS(from the base class) AND EdDSA!

For JWK - EdDSA

There are 3 (three) new extension methods:

/// <summary>
/// Gets the EdDsa public key from the jwk or null if the jwk does not have an EdDsa public key.
/// </summary>
public static EdDsa.EdDsa? GetEdDsaPublicKey(this Jwk jwk);

/// <summary>
/// Gets the EdDsa private key from the jwk or null if the jwk does not have an EdDsa private key.
/// </summary>
public static EdDsa.EdDsa? GetEdDsaPrivateKey(this Jwk jwk);

/// <summary>
/// Get Jwk from EdDsa key
/// </summary>
/// <param name="key">The EdDsa key</param>
/// <param name="includePrivateKey">True / Flase to include or not to include private key. Default is 'false'.</param>
/// <returns>The JWK that holds the EdKey</returns>
public static JwkEd GetJwk(this EdDsa.EdDsa key, bool includePrivateKey = false);

that bring the functionality to get the EdDsa key from the JWK and get JWK from EdDsa keys. These may be found in the CryptoEx.Ed.JWK namespace and are used in the same way as methods for RSA and EcDsa - JSON Web Signature JWS.

Some class diagrams

The main new classes that upgrade the base functionality to support EdDsa are:

---
title: Classes for EdDsa Algorithm for JWS and jAdES
---
classDiagram
    direction TD
    class JWSSigner { 
        This is main JWS signer class from the base project [CryptoEx]
    }
    class JWSSignerEd {
        This is the class to handle JWS with support for EdDSA [new]
    }
    
    class ETSISigner {
        This is main jAdES signer class from the base project [CryptoEx]
    }
    class ETSISignerEd {
        This is the class to handle jAdES with support for EdDSA [new]
    }
    JWSSigner <|-- JWSSignerEd
    ETSISigner <|-- ETSISignerEd
    JWSSigner <|-- ETSISigner

You can use them in the exact same way as the base classes. The only difference is that you need to instantiate the new classes. For example you may look at some tests that are using the new classes, from the CryptoEx.Tests project, in the CryptoEx.Tests.TestETSIEdDSA.cs file.

Basically:

// Get EdDSA key - from JWK, from PFX or from PEM
AsymmetricAlgorithm? privateKey = ...;

// Create signer 
JWSSigner signer = new JWSSignerEd((EdDsa)privateKey);

// Set some certificate and sign (Or add it as JWK)
signer.AttachSignersCertificate(cert);
signer.Sign(Encoding.UTF8.GetBytes(message), "text/json");

// Encode - produce JWS
var jSign = signer.Encode();

// Decode
var headers = signer.Decode<JWSHeader>(jSign, out byte[] _);
// Get some cetificate from the header (or from JWK)
var pubCertEnc = headers[0].X5c?.FirstOrDefault();
var pubCert = new X509Certificate2(Convert.FromBase64String(pubCertEnc));

// Get public key as EdDsa
AsymmetricAlgorithm? pubKey = pubCert.GetEdDsaPublicKey());

// Verify
signer.Verify<JWSHeader>(new AsymmetricAlgorithm[] { pubKey! }, null);

As you can see (if you compare it with the usage of the base classes JSON Web Signature JWS) the main difference is just when instantiating the new class - JWSSignerEd.

The same is true and for the JAdES signatures. Basically:

// Get EdDSA key - from PFX
AsymmetricAlgorithm? privateKey = ...;

// Create signer 
ETSISigner signer = new ETSISignerEd((EdDsa)privateKey);

// Get payload 
signer.AttachSignersCertificate(cert);
signer.Sign(Encoding.UTF8.GetBytes(message), "text/json", JWSConstants.JOSE);

// Encode - produce JWS
var jSign = signer.Encode(JWSEncodeTypeEnum.Compact);

// Decode & verify
signer.Verify(jSign, out byte[] _, out ETSIContextInfo _);

Again (if you compare it with the usage of the base classes ETSI JSON Signatures) the main difference is just when instantiating the new class - ETSISignerEd.

Some comment on the approach taken

The approach taken in bringing the support for EdDSA (see Ed Algorithms in .NET similar way) as a facade to Bouncy Castle library pays very well in extending base JWS and JAdES functionality to support EdDSA.

It is:

  1. The extension logic is in the new classes - JWSSignerEd and ETSISignerEd and is very simple and easy to understand (around 20-30 lines probably).
  2. Utilizes well known and maintained library - Bouncy Castle, for cryptographic operations, for new EdDSA.
  3. Eventually when support for Ed25519 and Ed448, comes to standard .NET, the dependency on Bouncy Castle can be removed without affecting seriously the client logic that uses the new API.