Aller au contenu
ecdsa.com

ES256 vs EdDSA (Ed25519) pour les JWT

Tous deux produisent des signatures de 64 octets et des jetons presque identiques. Le choix dépend des bibliothèques, des magasins de clés et des consommateurs qui prennent en charge chacun d’eux, ainsi que du nouveau nom alg Ed25519.

ES256 vs EdDSA pour les JWT est une question plus étroite qu’ECDSA vs EdDSA en général. Les jetons ont la même taille, les deux sont rapides, et les deux sont recommandés plutôt que RS256 pour les nouveaux émetteurs. Ce qui diffère, c’est la prise en charge : ES256 est exigé ou attendu par de nombreuses plateformes et de nombreux magasins de clés, tandis qu’Ed25519 est plus simple à implémenter correctement et s’appelle désormais Ed25519 plutôt qu’EdDSA dans JOSE.

Le guide ES256 vs RS256 traite le versant RSA de la même décision ; cette page compare les deux options sur courbes elliptiques.

Vue d’ensemble

ES256EdDSA / Ed25519
alg JOSEES256 (RFC 7518 §3.4)Ed25519 (RFC 9864) ; l’ancien EdDSA (RFC 8037), désormais déprécié
Courbe et fonction de hachageP-256 avec SHA-256Edwards25519 avec SHA-512
JWKkty: EC, crv: P-256, x, ykty: OKP, crv: Ed25519, x
JWK publique (mesurée, JSON compact)126 caractères79 caractères
Signature dans le jeton64 octets bruts r‖s, 86 caractères64 octets, 86 caractères
Jeton d’exemple (mesuré ci-dessous)232 caractères234 caractères (valeur alg plus longue)
DéterministeNon (nonce aléatoire dans la plupart des bibliothèques)Oui
Niveau d’exigence JWARecommandé+Facultatif
Identifiant COSE−7 (ou −9 ESP256 dans la RFC 9864)−19 (anciennement −8)
KMS cloudAWS, Google, Azure : ouiAWS (depuis novembre 2025) et Google : oui ; Azure : non
WebCrypto des navigateursTous les navigateursFirefox 129, Safari 17, Chrome 137 et versions ultérieures

Taille et vitesse

Les deux signatures font 64 octets : les jetons ont donc la même longueur, à l’en-tête près. Le script ci-dessous, exécuté avec Node.js 26.10, signe les mêmes claims des deux façons avec node:crypto seul (du vrai code devrait utiliser une bibliothèque JOSE).

Node.js : JWT ES256 et Ed25519 sur la même charge utile
import { generateKeyPairSync, sign } from "node:crypto";

const b64url = (value) => Buffer.from(value).toString("base64url");
const payload = b64url(JSON.stringify({ iss: "https://auth.example.com", sub: "user-42", aud: "api", exp: 1792500000 }));

const es = generateKeyPairSync("ec", { namedCurve: "P-256" });
const esInput = `${b64url(JSON.stringify({ alg: "ES256", kid: "es-1" }))}.${payload}`;
const es256 = `${esInput}.${b64url(sign("sha256", Buffer.from(esInput), { key: es.privateKey, dsaEncoding: "ieee-p1363" }))}`;

const ed = generateKeyPairSync("ed25519");
const edInput = `${b64url(JSON.stringify({ alg: "Ed25519", kid: "ed-1" }))}.${payload}`;
const ed25519 = `${edInput}.${b64url(sign(null, Buffer.from(edInput), ed.privateKey))}`;

console.log("ES256   token", es256.length, "chars, public JWK", JSON.stringify(es.publicKey.export({ format: "jwk" })).length, "chars");
console.log("Ed25519 token", ed25519.length, "chars, public JWK", JSON.stringify(ed.publicKey.export({ format: "jwk" })).length, "chars");
Sortie
ES256   token 232 chars, public JWK 126 chars
Ed25519 token 234 chars, public JWK 79 chars

La vitesse n’est pas un critère décisif : sur un cœur d’Apple M4 Max, OpenSSL 3.6.5 produit environ 87 000 signatures P-256 et 60 000 signatures Ed25519 par seconde. Un JWKS contenant des clés Ed25519 est plus petit, car les clés OKP n’ont qu’une coordonnée.

Encodage et exactitude

Dans un JWS, les signatures ES256 doivent avoir la forme brute r‖s de 64 octets (RFC 7518 §3.4). De nombreuses API ECDSA produisent du DER par défaut : OpenSSL, SHA256withECDSA en Java, ecdsa.SignASN1 en Go, crypto.sign() de Node sans dsaEncoding, ainsi que les API de signature d’AWS KMS et de Google Cloud KMS. Du code ES256 écrit à la main qui oublie la conversion produit des signatures de 70 à 72 octets que les vérificateurs conformes rejettent, et l’erreur inverse fait échouer la vérification de jetons corrects. Les vérificateurs ECDSA doivent aussi rejeter un r ou un s égal à zéro ; Java 15 à 18 ne le faisait pas (CVE-2022-21449), ce qui permettait à n’importe qui de forger des jetons ES256 tant que le correctif n’était pas appliqué.

Ed25519 a un seul encodage de 64 octets, une signature déterministe et aucun nonce à mal gérer. Ses pièges sont ailleurs : certaines bibliothèques traitent la clé privée comme une graine de 32 octets, d’autres comme 64 octets, et les anciennes bibliothèques JOSE ne reconnaissent que "alg": "EdDSA".

Le nom alg a changé

La RFC 8037 (2017) a enregistré EdDSA comme algorithme JOSE polymorphe, dont la courbe est déterminée par la clé (crv: Ed25519 ou Ed448). La RFC 9864 (octobre 2025) déprécie les identifiants polymorphes et enregistre Ed25519 et Ed448 : l’alg seul détermine ainsi l’opération, comme l’a toujours fait ES256. La prise en charge reste inégale en 2026 : jose 6 accepte à la fois EdDSA et Ed25519, joserfc et Nimbus JOSE+JWT prennent en charge les nouveaux noms, tandis que PyJWT 2.15 et golang-jwt v5 n’acceptent toujours qu’EdDSA. Pour des jetons consommés par de nombreuses parties, vérifiez chaque consommateur avant de changer la valeur de l’en-tête ; pendant une transition, les vérificateurs peuvent accepter les deux noms pour la même clé.

Prise en charge par les plateformes et les magasins de clés

ES256 est le plus petit dénominateur commun. C’est le choix habituel pour les preuves DPoP (RFC 9449) et l’un des trois algorithmes qu’autorise FAPI 2.0 (PS256, ES256, ou EdDSA avec Ed25519) ; il est exigé pour l’App Store Server API d’Apple et les jetons de fournisseur APNs, pris en charge par tous les fournisseurs OpenID Connect, et c’est l’algorithme COSE par défaut de WebAuthn. Tous les HSM, TPM, Secure Enclave et KMS cloud proposent des clés P-256.

Côté logiciel, Ed25519 a rattrapé son retard : Node.js, Go, Java 15 et versions ultérieures, .NET via des bibliothèques, cryptography en Python, WebCrypto dans les navigateurs et les principales bibliothèques JOSE. Dans les magasins de clés, sa prise en charge est plus récente : AWS KMS a ajouté des clés de signature Ed25519 en novembre 2025, Google Cloud KMS propose EC_SIGN_ED25519, tandis que certains modèles de HSM et Azure Key Vault ne le proposent pas. Si les jetons doivent être signés dans un magasin de clés géré, consultez d’abord sa liste d’algorithmes.

Quand choisir l’un ou l’autre

  • Fournisseur d’identité public, nombreuses parties de confiance (relying parties) : ES256 (en conservant RS256 pour les anciens consommateurs si nécessaire).
  • Clés dans des HSM ou des KMS répartis sur plusieurs clouds : ES256, pour une prise en charge uniforme.
  • Services internes, deux extrémités sous votre contrôle, bibliothèques modernes : Ed25519 avec alg: Ed25519 si tous les vérificateurs le prennent en charge, sinon EdDSA.
  • Jetons liés à l’expéditeur (DPoP) émis depuis des navigateurs et des applications mobiles : ES256, que tout magasin de clés de plateforme peut générer de façon non exportable.
  • Profils qui imposent des algorithmes (FAPI, secteur public, finance) : ce que le profil indique.

Notes de migration

  1. Ajoutez la nouvelle clé au JWKS avec son propre kid et un alg explicite, et laissez aux consommateurs le temps de rafraîchir leurs caches.
  2. Configurez les vérificateurs clé par clé : chaque clé accepte exactement un algorithme (et, pour Ed25519, les deux valeurs d’en-tête EdDSA et Ed25519 si vos consommateurs diffèrent). N’acceptez jamais l’alg du jeton sans cette association.
  3. Basculez l’émetteur sur la nouvelle clé ; les jetons existants continuent de se vérifier avec l’ancienne jusqu’à leur expiration.
  4. Retirez l’ancienne clé une fois écoulée la plus longue durée de vie des jetons.
  5. Testez les encodages de bout en bout : une signature ES256 produite par un KMS doit être convertie du DER au format brut avant d’entrer dans un jeton ; le convertisseur DER ⇄ brut et le débogueur JWT montrent ce que contient un jeton.

Références

Tous les comparatifs