Zum Inhalt springen
ecdsa.com
.NET

.NET System.Security.Cryptography

System.Security.Cryptography von .NET: ECDSA, das standardmäßig rohe r‖s-Signaturen (IEEE P1363) erzeugt – anders als jeder Stack auf OpenSSL-Basis –, kein mitgeliefertes Ed25519 und Post-Quanten-Klassen, deren Verfügbarkeit vom Betriebssystem abhängt.
Lizenz
MIT
Geprüfte Version
10.0.13 ·
Quellcode
github.com/dotnet/runtime
Dokumentation
learn.microsoft.com/dotnet/api/system.security.cryptography.ecdsa

Kompatibilität auf einen Blick

ECDSA

ECDSA-Kurven
P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
none
Formate öffentlicher Schlüssel
spki-pemspki-derraw-xy
Formate privater Schlüssel
pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-derraw-scalar

.NET kapselt die Kryptografie der Plattform – CNG unter Windows, OpenSSL unter Linux, Apples Bibliotheken unter macOS – hinter einer einzigen API: ECDsa, RSA, MLDsa, MLKem und Co. Die Prüfung lief mit .NET 10.0.13 unter Ubuntu 24.04, wo das darunterliegende OpenSSL die Version 3.0.13 hat, und diese Version prägt mehrere Ergebnisse.

Die Standardkodierung von Signaturen ist genau umgekehrt wie bei den meisten serverseitigen Bibliotheken. ECDsa.SignData liefert das 64 Byte lange r‖s nach IEEE P1363, und VerifyData erwartet es; für DER braucht es bei beiden Aufrufen DSASignatureFormat.Rfc3279DerSequence. Damit passt .NET ohne weiteres Zutun zu JWS und WebCrypto, aber weder zu OpenSSL noch zu SHA256withECDSA in Java oder SignASN1 in Go. Bei jeder fehlerhaften oder unpassenden Signatur gibt VerifyData false zurück, sodass eine DER-Signatur, die mit dem Standardformat geprüft wird, genau wie eine Fälschung aussieht – das Beispiel zeigt beide Ergebnisse, und der Konverter DER ⇄ Raw zeigt, welche Form du hast.

Unter Linux deckte ECDSA P-256 bis P-521, secp256k1 und die Brainpool-r1-Kurven ab, alle über OpenSSL. SignHash signiert einen Digest, den du selbst berechnet hast, die Nonces sind zufällig, s wird nicht normalisiert, und die Prüfung akzeptiert High-S. In der Basisklassenbibliothek gibt es keine Klasse für Ed25519 oder Ed448; für EdDSA brauchst du Bouncy Castle für .NET oder ein anderes Paket.

MLKem, MLDsa, SlhDsa und CompositeMLDsa gibt es in .NET 10, aber jede dieser Klassen meldet IsSupported je nach Plattform. Mit OpenSSL 3.0.13 war der Wert bei allen false; OpenSSL hat ML-KEM und ML-DSA in 3.5 hinzugefügt, unter Linux brauchen die Klassen also eine Distribution, die diese Version mitliefert, und unter Windows die entsprechende CNG-Unterstützung. Code muss IsSupported prüfen, statt die Unterstützung vorauszusetzen, und diese Seite hat keine Plattform geprüft, auf der die Antwort true lautet.

Schlüssel lassen sich aus SPKI und PKCS#8 (PEM oder DER, verschlüsselt oder nicht), aus SEC1 EC PRIVATE KEY und aus rohen Koordinaten in ECParameters importieren; einen Import von SEC1-Punkten oder JWK gibt es nicht. Untersuche PFX-Bundles mit dem PFX-Inspektor.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/dotnet-crypto/run.sh hat .NET System.Security.Cryptography 10.0.13 unter .NET 10.0.13 on Ubuntu 24.04.5 LTS am 20. Oktober 2026 im Container-Image mcr.microsoft.com/dotnet/sdk:10.0.402-noble ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Kodierung von ECDSA-Signaturen

    raw

    SignData liefert standardmäßig 64 Byte r‖s nach IEEE P1363; DSASignatureFormat.Rfc3279DerSequence erzeugt DER.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = raw
    evidence ecdsa-signature-encoding: SignData default: 64 bytes; with Rfc3279DerSequence: parses as DER True
  • ECDSA-Nonce

    random

    Zufällige Nonce: Der Schlüssel aus RFC 6979 signierte dieselbe Nachricht zweimal mit unterschiedlichem Ergebnis.

    Von der Prüfung aufgezeichnet
    fact ecdsa-nonce = random
  • Low-S beim Signieren

    either

    s wird nicht normalisiert: Unter 64 Signaturen traten High-S-Werte auf.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-sign = either
  • High-S bei der Prüfung

    accepts-high-s

    Eine Signatur, in der s durch n − s ersetzt war, bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-verify = accepts-high-s
  • Was der Signaturaufruf hasht

    hashes-message-or-digest

    SignData hasht; SignHash signiert einen Digest, den du selbst berechnet hast, und diese Signatur bestand die Prüfung gegen die Nachricht.

    Von der Prüfung aufgezeichnet
    fact ecdsa-prehash = hashes-message-or-digest
  • Fehlerhafte ECDSA-Signatur

    returns-false

    Eine als P1363 geprüfte DER-Signatur, eine als DER geprüfte rohe Signatur und ein 3-Byte-Blob ergeben alle false.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: DER to the default verifier: false; raw to the DER verifier: false; 3 bytes: false
  • ECDSA-Kurven

    P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1

    Unter Linux funktionierten Signieren und Prüfen mit P-256, P-384, P-521, secp256k1 und brainpoolP256r1/P384r1/P512r1.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = P-256, P-384, P-521, secp256k1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
  • EdDSA

    none

    In System.Security.Cryptography gibt es keine Klasse Ed25519.

    Von der Prüfung aufgezeichnet
    fact eddsa = none
    evidence eddsa: System.Security.Cryptography.Ed25519 type present: False
  • Post-Quanten-Algorithmen

    none

    MLKem.IsSupported, MLDsa.IsSupported, SlhDsa.IsSupported und die Unterstützung für Composite-ML-DSA waren auf dieser Plattform alle false.

    Von der Prüfung aufgezeichnet
    fact pqc = none
    evidence pqc: MLKem.IsSupported False, MLDsa.IsSupported False, SlhDsa.IsSupported False, CompositeMLDsa.IsSupported(MLDsa65WithECDsaP256) False
  • OpenSSL der Plattform

    3.0.13

    Unter Linux verwenden die Klassen das OpenSSL des Systems, hier 3.0.13 aus Ubuntu 24.04, eine Version aus der Zeit vor ML-KEM und ML-DSA.

    Von der Prüfung aufgezeichnet
    fact platform-openssl = 3.0.13
    evidence platform-openssl: OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
  • Formate öffentlicher Schlüssel

    spki-pemspki-derraw-xy

    Öffentliche Schlüssel lassen sich aus SPKI als PEM (ImportFromPem), SPKI als DER und den rohen X- und Y-Koordinaten in ECParameters importieren.

    Von der Prüfung aufgezeichnet
    fact public-key-formats = spki-pem, spki-der, raw-xy
    evidence public-key-formats: ImportParameters takes Q.X and Q.Y separately; there is no SEC1 point or JWK import in the BCL
  • Formate privater Schlüssel

    pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-derraw-scalar

    Private Schlüssel lassen sich aus PKCS#8 als PEM und DER, verschlüsseltem PKCS#8, SEC1 als PEM und DER sowie aus dem rohen Skalar in ECParameters importieren.

    Von der Prüfung aufgezeichnet
    fact private-key-formats = pkcs8-pem, pkcs8-der, encrypted-pkcs8, sec1-pem, sec1-der, raw-scalar

Verwendung

Signiere im Standardformat P1363 und in DER und zeige, dass die Prüfung von DER das passende Formatargument braucht.
using System.Security.Cryptography;
using System.Text;

using var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var message = Encoding.UTF8.GetBytes("order #1042 approved");

// .NET signs raw r||s (IEEE P1363) by default; OpenSSL, Java and Go expect DER.
var raw = key.SignData(message, HashAlgorithmName.SHA256);
var der = key.SignData(message, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);

// Verifying a DER signature needs the same format argument, or VerifyData returns false.
var ok = key.VerifyData(message, der, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);
var wrongFormat = key.VerifyData(message, der, HashAlgorithmName.SHA256);
Console.WriteLine($"raw: {raw.Length} bytes, DER verified: {ok}, DER as raw: {wrongFormat}");
Console.WriteLine(key.ExportSubjectPublicKeyInfoPem().Split('\n')[0]);

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image mcr.microsoft.com/dotnet/sdk:10.0.402-noble aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
dotnet new console --force -o . >/dev/null
Befehl
rm -f Program.cs && DOTNET_NOLOGO=1 dotnet run 2>/dev/null
Ausgabe muss passen (regulärer Ausdruck)
raw: 64 bytes, DER verified: True, DER as raw: False\n-----BEGIN PUBLIC KEY-----

Bibliotheken