Zum Inhalt springen
ecdsa.com
.NET

Bouncy Castle for .NET (BouncyCastle.Cryptography)

Bouncy Castle für .NET, die Kryptobibliothek in verwaltetem Code, mit der .NET-Projekte nachrüsten, was der Basisklassenbibliothek fehlt: Ed25519 und Ed448, secp256k1 auf jeder Plattform, deterministisches ECDSA, PGP, PEM sowie ML-KEM, ML-DSA und SLH-DSA unabhängig vom Betriebssystem.
Lizenz
MIT
Geprüfte Version
2.7.0 ·
Quellcode
github.com/bcgit/bc-csharp
Dokumentation
www.bouncycastle.org/documentation/documentation-c/

Kompatibilität auf einen Blick

ECDSAEdDSAPost-Quanten-Verfahren

ECDSA-Kurven
P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519Ed448
Post-Quanten-Algorithmen
ML-KEMML-DSASLH-DSA

BouncyCastle.Cryptography (das Paket, das Portable.BouncyCastle abgelöst hat) ist reiner verwalteter Code: Seine Ergebnisse hängen weder von Windows CNG noch von der OpenSSL-Version unter Linux ab – genau das macht es neben System.Security.Cryptography nützlich. Das Paket bietet die stringbasierte API SignerUtilities und tiefer liegende Klassen wie ECDsaSigner.

Die ECDSA-Standardeinstellungen folgen der OpenSSL-Tradition, nicht der von .NET: SHA-256withECDSA erzeugt DER, während SHA-256withPLAIN-ECDSA das 64 Byte lange rohe r‖s liefert, das ECDsa aus .NET selbst und JWS verwenden. Diese beiden zu verwechseln ist der typische Interoperabilitätsfehler zwischen den zwei Bibliotheken in einer Anwendung, und jede fehlerhafte Eingabe gibt false zurück, statt eine Ausnahme zu werfen. Über SignerUtilities sind die Nonces zufällig; ECDsaSigner mit einem HMacDsaKCalculator reproduzierte den Testvektor aus RFC 6979. s wird nicht normalisiert, und die Prüfung akzeptiert High-S.

Der Funktionsumfang ist der Grund, Bouncy Castle einzubinden: P-224 bis P-521, secp256k1 und die Brainpool-r1-Kurven; Ed25519 und Ed448 wie im Beispiel; außerdem ML-KEM, ML-DSA und SLH-DSA über MLKemEncapsulator, MLDsaSigner und SlhDsaSigner – alle funktionierten auf demselben Linux-Image, auf dem die Basisklassenbibliothek überhaupt keine Post-Quanten-Unterstützung meldete. Probiere die Algorithmen im Playground für Post-Quanten-Signaturen aus.

PemWriter schreibt private Schlüssel vom Typ EC als SEC1 -----BEGIN EC PRIVATE KEY-----, und PemReader gibt sie als AsymmetricCipherKeyPair zurück; PKCS#8 läuft über PrivateKeyInfoFactory. Die Version der Assembly selbst ist für jedes 2.x-Release die Strong-Name-Version 2.0.0; achte beim Vergleich des Verhaltens daher auf die Paketversion (hier 2.7.0).

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/bouncy-castle-csharp/run.sh hat Bouncy Castle for .NET (BouncyCastle.Cryptography) 2.7.0 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

    der

    SHA-256withECDSA liefert DER; SHA-256withPLAIN-ECDSA liefert 64 Byte rohes r‖s.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: SHA-256withPLAIN-ECDSA output: 64 bytes
  • ECDSA-Nonce

    rfc6979-opt-in

    Zufällig über SignerUtilities; ECDsaSigner mit HMacDsaKCalculator reproduzierte RFC 6979, Anhang A.2.5.

    Von der Prüfung aufgezeichnet
    fact ecdsa-nonce = rfc6979-opt-in
    evidence ecdsa-nonce: SHA-256withECDSA repeats: False; ECDsaSigner with HMacDsaKCalculator reproduces RFC 6979 A.2.5: True
  • 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 DER-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

    SHA-256withECDSA hasht; NONEwithECDSA signiert einen Digest, 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 an SHA-256withECDSA übergebene rohe r‖s-Signatur und ein 3-Byte-Blob ergeben false.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: raw r||s to SHA-256withECDSA: false; 3 bytes: false
  • ECDSA-Kurven

    P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1

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

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

    Ed25519Ed448

    Ed25519 und Ed448.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519, Ed448
  • Post-Quanten-Algorithmen

    ML-KEMML-DSASLH-DSA

    Kapselung und Entkapselung mit ML-KEM-768 sowie Signieren und Prüfen mit ML-DSA-65 und SLH-DSA-SHA2-128f funktionierten, in verwaltetem Code.

    Von der Prüfung aufgezeichnet
    fact pqc = ML-KEM, ML-DSA, SLH-DSA
  • Formate öffentlicher Schlüssel

    spki-pemspki-der

    SPKI als PEM über PemReader und SPKI als DER über PublicKeyFactory.

    Von der Prüfung aufgezeichnet
    fact public-key-formats = spki-pem, spki-der
    evidence public-key-formats: PublicKeyFactory.CreateKey(SPKI DER) verifies: True
  • Formate privater Schlüssel

    pkcs8-dersec1-pem

    PemWriter schreibt und PemReader liest SEC1 als PEM; PKCS#8 als DER wird über PrivateKeyFactory geladen.

    Von der Prüfung aufgezeichnet
    fact private-key-formats = pkcs8-der, sec1-pem
    evidence private-key-formats: PemWriter writes -----BEGIN EC PRIVATE KEY-----; PemReader returns AsymmetricCipherKeyPair; PKCS#8 DER round trip signs: True

Verwendung

Signiere und prüfe mit Ed25519, das System.Security.Cryptography nicht bietet.
using System.Text;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

var message = Encoding.UTF8.GetBytes("order #1042 approved");

// Ed25519, which the .NET base class library does not offer.
var generator = new Ed25519KeyPairGenerator();
generator.Init(new Ed25519KeyGenerationParameters(new SecureRandom()));
var pair = generator.GenerateKeyPair();

var signer = SignerUtilities.GetSigner("Ed25519");
signer.Init(true, pair.Private);
signer.BlockUpdate(message, 0, message.Length);
var signature = signer.GenerateSignature();

var verifier = SignerUtilities.GetSigner("Ed25519");
verifier.Init(false, pair.Public);
verifier.BlockUpdate(message, 0, message.Length);
Console.WriteLine($"signature: {signature.Length} bytes, verified: {verifier.VerifySignature(signature)}");

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 && dotnet add package BouncyCastle.Cryptography --version 2.7.0 >/dev/null
Befehl
rm -f Program.cs && DOTNET_NOLOGO=1 dotnet run 2>/dev/null
Ausgabe muss passen (regulärer Ausdruck)
signature: 64 bytes, verified: True

Bibliotheken