Zum Inhalt springen
ecdsa.com

ES256 vs. EdDSA (Ed25519) für JWTs

Beide erzeugen 64-Byte-Signaturen und nahezu identische Tokens. Entscheidend ist, welche Bibliotheken, Schlüsselspeicher und Empfänger welches Verfahren unterstützen – und der neue Wert Ed25519 für alg.

ES256 vs. EdDSA für JWTs ist eine engere Frage als ECDSA vs. EdDSA im Allgemeinen. Die Tokens sind gleich groß, beide Verfahren sind schnell, und beide werden neuen Ausstellern statt RS256 empfohlen. Unterschiedlich ist die Unterstützung: Viele Plattformen und Schlüsselspeicher verlangen oder erwarten ES256, während sich Ed25519 einfacher korrekt implementieren lässt und in JOSE jetzt Ed25519 statt EdDSA heißt.

Die Anleitung zu ES256 vs. RS256 behandelt die RSA-Seite derselben Entscheidung; diese Seite vergleicht die beiden Optionen auf Basis elliptischer Kurven.

Auf einen Blick

ES256EdDSA / Ed25519
alg in JOSEES256 (RFC 7518 §3.4)Ed25519 (RFC 9864); älter: EdDSA (RFC 8037), inzwischen veraltet
Kurve und HashP-256 mit SHA-256Edwards25519 mit SHA-512
JWKkty: EC, crv: P-256, x, ykty: OKP, crv: Ed25519, x
Öffentlicher JWK (gemessen, kompaktes JSON)126 Zeichen79 Zeichen
Signatur im Token64 Byte r‖s im Raw-Format, 86 Zeichen64 Byte, 86 Zeichen
Beispiel-Token (unten gemessen)232 Zeichen234 Zeichen (längerer Wert für alg)
DeterministischNein (zufällige Nonce in den meisten Bibliotheken)Ja
Anforderungsstufe in JWARecommended+Optional
COSE-Kennung−7 (oder −9 ESP256 nach RFC 9864)−19 (älter: −8)
Cloud-KMSAWS, Google, Azure: jaAWS (seit November 2025) und Google: ja; Azure: nein
WebCrypto im BrowserAlle BrowserAb Firefox 129, Safari 17, Chrome 137

Größe und Geschwindigkeit

Beide Signaturen sind 64 Byte groß, die Tokens sind also bis auf den Header gleich lang. Das folgende Skript, ausgeführt mit Node.js 26.10, signiert dieselben Claims auf beide Arten und nutzt dabei nur node:crypto (echter Code sollte eine JOSE-Bibliothek verwenden).

Node.js: JWTs mit ES256 und Ed25519 über dieselbe Payload
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");
Ausgabe
ES256   token 232 chars, public JWK 126 chars
Ed25519 token 234 chars, public JWK 79 chars

Die Geschwindigkeit gibt nicht den Ausschlag: Auf einem Kern eines Apple M4 Max erzeugt OpenSSL 3.6.5 etwa 87.000 P-256- und 60.000 Ed25519-Signaturen pro Sekunde. Ein JWKS mit Ed25519-Schlüsseln ist kleiner, weil OKP-Schlüssel nur eine Koordinate haben.

Kodierung und Korrektheit

ES256-Signaturen in JWS müssen im 64-Byte-Raw-Format r‖s vorliegen (RFC 7518 §3.4). Viele ECDSA-APIs liefern standardmäßig DER: OpenSSL, SHA256withECDSA in Java, ecdsa.SignASN1 in Go, crypto.sign() in Node ohne dsaEncoding sowie die Signatur-APIs von AWS KMS und Google Cloud KMS. Selbst geschriebener ES256-Code, der die Umwandlung vergisst, erzeugt Signaturen mit 70–72 Byte, die standardkonforme Verifizierer ablehnen; der umgekehrte Fehler lässt die Prüfung korrekter Tokens scheitern. ECDSA-Verifizierer müssen außerdem r oder s gleich null ablehnen; Java 15 bis 18 tat das nicht (CVE-2022-21449), sodass bis zum Patch jeder ES256-Tokens fälschen konnte.

Ed25519 hat nur eine 64-Byte-Kodierung, signiert deterministisch und hat keine Nonce, bei der etwas schiefgehen kann. Seine Fallen liegen anderswo: Manche Bibliotheken behandeln den privaten Schlüssel als 32-Byte-Seed, andere als 64 Byte, und ältere JOSE-Bibliotheken erkennen nur "alg": "EdDSA".

Die Kennung in alg hat sich geändert

RFC 8037 (2017) registrierte EdDSA als polymorphen JOSE-Algorithmus, dessen Kurve der Schlüssel bestimmt (crv: Ed25519 oder Ed448). RFC 9864 (Oktober 2025) erklärt polymorphe Kennungen für veraltet und registriert Ed25519 und Ed448, sodass alg allein die Operation festlegt, wie es bei ES256 schon immer der Fall war. Die Unterstützung ist 2026 uneinheitlich: jose 6 akzeptiert sowohl EdDSA als auch Ed25519, joserfc und Nimbus JOSE+JWT unterstützen die neuen Namen, während PyJWT 2.15 und golang-jwt v5 weiterhin nur EdDSA akzeptieren. Bei Tokens, die viele Parteien verarbeiten, prüfe jeden Empfänger, bevor du den Wert im Header umstellst; Verifizierer können während einer Übergangszeit beide Namen für denselben Schlüssel akzeptieren.

Unterstützung in Plattformen und Schlüsselspeichern

ES256 ist der kleinste gemeinsame Nenner. Für DPoP-Proofs (RFC 9449) ist es die übliche Wahl, und es ist einer von drei Algorithmen, die FAPI 2.0 zulässt (PS256, ES256 oder EdDSA mit Ed25519). Die App Store Server API von Apple und Provider-Tokens für APNs verlangen es, jeder Anbieter für OpenID Connect unterstützt es, und in WebAuthn ist es der standardmäßige COSE-Algorithmus. Jedes HSM, jedes TPM, jede Secure Enclave und jedes Cloud-KMS bietet P-256-Schlüssel an.

In Software hat Ed25519 aufgeholt: Node.js, Go, Java ab Version 15, .NET über Bibliotheken, cryptography für Python, WebCrypto im Browser und die wichtigsten JOSE-Bibliotheken. In Schlüsselspeichern ist es neuer: AWS KMS hat im November 2025 Signaturschlüssel für Ed25519 eingeführt, Google Cloud KMS bietet EC_SIGN_ED25519 an, manche HSM-Modelle und Azure Key Vault dagegen nicht. Wenn Tokens in einem verwalteten Schlüsselspeicher signiert werden müssen, prüfe zuerst dessen Liste der Algorithmen.

Wann welches Verfahren passt

  • Öffentlicher Identity Provider, viele Relying Parties: ES256 (bei Bedarf zusätzlich RS256 für alte Empfänger).
  • Schlüssel in HSM oder KMS über mehrere Clouds hinweg: ES256 für einheitliche Unterstützung.
  • Interne Services, beide Seiten in deiner Hand, moderne Bibliotheken: Ed25519 mit alg: Ed25519, wenn alle Verifizierer es unterstützen, sonst EdDSA.
  • Sendergebundene Tokens (DPoP) aus Browsern und mobilen Apps: ES256, das jeder Schlüsselspeicher einer Plattform als nicht exportierbaren Schlüssel erzeugen kann.
  • Profile, die Algorithmen vorgeben (FAPI, Behörden, Finanzwesen): das, was das Profil auflistet.

Hinweise zur Migration

  1. Füge den neuen Schlüssel dem JWKS hinzu, mit eigenem kid und explizitem alg, und gib den Empfängern Zeit, ihre Caches zu aktualisieren.
  2. Konfiguriere die Verifizierer pro Schlüssel: Jeder Schlüssel akzeptiert genau einen Algorithmus (und bei Ed25519 beide Header-Werte, EdDSA und Ed25519, falls sich deine Empfänger unterscheiden). Akzeptiere nie den alg aus dem Token ohne diese Bindung.
  3. Stelle den Aussteller auf den neuen Schlüssel um; vorhandene Tokens lassen sich weiter mit dem alten prüfen, bis sie ablaufen.
  4. Entferne den alten Schlüssel, sobald die längste Token-Laufzeit verstrichen ist.
  5. Teste die Kodierungen durchgängig: Eine ES256-Signatur aus einem KMS muss von DER ins Raw-Format umgewandelt werden, bevor sie in ein Token kommt; der Konverter DER ⇄ Raw und der JWT-Debugger zeigen, was ein Token enthält.

Quellen

Alle Vergleiche