Zum Inhalt springen
ecdsa.com
Rust

ring

ring von Brian Smith, die Rust-Kryptobibliothek unter rustls und vielen Webservern: eine bewusst kleine API, in der die Algorithmuskonstante die Kodierung der Signatur festlegt, private Schlüssel nur als PKCS#8 akzeptiert werden und nur die Kurven P-256, P-384 und Ed25519 zur Verfügung stehen.
Lizenz
Apache-2.0 AND ISC
Geprüfte Version
0.17.14 ·
Quellcode
github.com/briansmith/ring
Dokumentation
docs.rs/ring/0.17.14/ring/

Kompatibilität auf einen Blick

ECDSAEdDSA

ECDSA-Kurven
P-256P-384
EdDSA
Ed25519

ring bietet eine kurze Liste von Algorithmen mit aus BoringSSL abgeleitetem Assembler-Code und eine missbrauchsresistente API: Es gibt keine Möglichkeit, eine Nonce zu wählen, einen vorab berechneten Digest zu signieren oder einen Schlüssel in einem ungewöhnlichen Format zu laden. Das macht die Bibliothek schnell und schwer falsch zu benutzen – und deshalb steckt die eigentliche Arbeit im Konvertieren von Schlüsseln und Signaturen aus anderen Stacks.

Die Kodierung ist Teil des Algorithmus: ECDSA_P256_SHA256_FIXED_SIGNING erzeugt rohes r‖s mit 64 Byte und ECDSA_P256_SHA256_ASN1_SIGNING DER, dazu gibt es passende Prüfkonstanten _FIXED und _ASN1. Eine Signatur, die unter der jeweils anderen Konstante geprüft wird, scheitert schlicht mit Unspecified; eine JWS-Signatur, die mit der ASN1-Konstante geprüft wird – oder eine OpenSSL-Signatur mit FIXED –, sieht also genau wie eine Fälschung aus. Das Beispiel zeigt beide Ergebnisse. Signaturen verwenden eine zufällige Nonce, s wird nicht normalisiert, und die Prüfung akzeptiert beide Hälften.

Private Schlüssel werden nur als PKCS#8-DER gelesen, und Ed25519-Schlüssel müssen PKCS#8 v2 mit eingeschlossenem öffentlichem Schlüssel sein: Die 48 Byte lange v1-Form, die OpenSSL und die meisten Tools schreiben, wurde von Ed25519KeyPair::from_pkcs8 mit VersionNotSupported abgelehnt, während from_pkcs8_maybe_unchecked und from_seed_unchecked sie akzeptierten. Private Schlüssel in PEM, SEC1 und JWK müssen zuerst konvertiert werden, zum Beispiel mit dem JWK-Konverter. Öffentliche Schlüssel sind bloße SEC1-Punkte: public_key() liefert die 65 Byte lange unkomprimierte Form, und komprimierte Punkte werden nicht akzeptiert.

Die Kurvenliste endet bei P-256 und P-384 plus Ed25519; es gibt kein P-521, kein secp256k1 und keinen Post-Quanten-Algorithmus. Projekte, die diese oder eine FIPS-Validierung brauchen, wechseln zu aws-lc-rs, das eine zu ring kompatible API bietet.

Um zu prüfen, in welcher Kodierung eine Signatur aus ring vorliegt, füge sie in den Konverter DER ⇄ Raw ein.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/ring/run.sh hat ring 0.17.14 am 20. Oktober 2026 im Container-Image rust:1.99.1-trixie ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Kodierung von ECDSA-Signaturen

    der-or-raw

    Die Algorithmuskonstante bestimmt die Kodierung: *_FIXED signiert und prüft rohes r‖s mit 64 Byte, *_ASN1 DER; unter der jeweils anderen Konstante besteht eine Signatur die Prüfung nicht.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = der-or-raw
    evidence ecdsa-signature-encoding: FIXED signs 64 bytes; ASN1 output starts with 0x30 (a DER SEQUENCE)
    evidence ecdsa-signature-encoding: a signature verifies under the other encoding's constant: false
  • ECDSA-Nonce

    random

    Zufällige Nonce: Zwei Signaturen derselben Nachricht unterscheiden sich, und es gibt keine deterministische Option.

    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

    Der FIXED-Verifizierer akzeptierte die Signatur, in der s durch n − s ersetzt war.

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

    hashes-message

    Die Nachricht wird so gehasht, wie es der Algorithmus vorgibt; eine API zum Signieren eines vorab berechneten Digests gibt es nicht.

    Von der Prüfung aufgezeichnet
    fact ecdsa-prehash = hashes-message
    evidence ecdsa-prehash: the API has no entry point for signing a precomputed digest
  • Fehlerhafte ECDSA-Signatur

    returns-error

    verify() gibt für eine fehlerhaft formatierte oder falsche Signatur Err(Unspecified) zurück, ohne Details.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = returns-error
    evidence ecdsa-malformed-signature: verify() of 3 bytes: Err(Unspecified)
  • ECDSA-Kurven

    P-256P-384

    Nur P-256 und P-384.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = P-256, P-384
    evidence ecdsa-curves: ring defines ECDSA_P256_* and ECDSA_P384_* algorithms only
  • EdDSA

    Ed25519

    Ed25519.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519
  • Ed25519-Schlüssel in PKCS #8 v1

    rejected-by-from-pkcs8

    Ein Ed25519-Schlüssel im Format PKCS#8 v1 mit 48 Byte wurde von from_pkcs8 mit VersionNotSupported abgelehnt; from_pkcs8_maybe_unchecked und from_seed_unchecked akzeptierten ihn. generate_pkcs8 schreibt v2-Schlüssel mit 83 Byte.

    Von der Prüfung aufgezeichnet
    fact ed25519-pkcs8-v1 = rejected-by-from-pkcs8
    evidence ed25519-pkcs8-v1: generate_pkcs8 writes 83 bytes (PKCS#8 v2 with the public key); a 48-byte v1 key: from_pkcs8 Err(KeyRejected("VersionNotSupported")), from_pkcs8_maybe_unchecked ok true, from_seed_unchecked ok true
  • Post-Quanten-Algorithmen

    none

    Keine Post-Quanten-Algorithmen.

    Von der Prüfung aufgezeichnet
    fact pqc = none
  • Formate öffentlicher Schlüssel

    sec1-uncompressed

    Öffentliche Schlüssel sind unkomprimierte Punkte im SEC1-Format (65 Byte bei P-256); komprimierte Punkte scheiterten, und SPKI, PEM oder JWK werden nicht geparst.

    Von der Prüfung aufgezeichnet
    fact public-key-formats = sec1-uncompressed
    evidence public-key-formats: public_key() returns 65 bytes (uncompressed SEC1); no SPKI, PEM or JWK parsing
  • Formate privater Schlüssel

    pkcs8-der

    Private Schlüssel werden nur aus PKCS#8-DER geladen.

    Von der Prüfung aufgezeichnet
    fact private-key-formats = pkcs8-der

Verwendung

Signiere mit der Konstante FIXED (roh) und zeige, dass nur die passende Prüfkonstante die Signatur akzeptiert.
use ring::rand::SystemRandom;
use ring::signature::{self, EcdsaKeyPair, KeyPair, UnparsedPublicKey};

fn main() {
    let rng = SystemRandom::new();
    // ring only reads PKCS#8 DER private keys.
    let pkcs8 = EcdsaKeyPair::generate_pkcs8(&signature::ECDSA_P256_SHA256_FIXED_SIGNING, &rng).unwrap();
    let message = b"order #1042 approved";

    // The algorithm constant fixes the encoding: FIXED = raw r||s (JWS, WebCrypto),
    // ASN1 = DER (OpenSSL, Java). Verify with the matching constant.
    let fixed = EcdsaKeyPair::from_pkcs8(&signature::ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8.as_ref(), &rng).unwrap();
    let raw = fixed.sign(&rng, message).unwrap();
    let public = fixed.public_key().as_ref(); // 65-byte uncompressed SEC1 point

    let ok = UnparsedPublicKey::new(&signature::ECDSA_P256_SHA256_FIXED, public).verify(message, raw.as_ref()).is_ok();
    let wrong = UnparsedPublicKey::new(&signature::ECDSA_P256_SHA256_ASN1, public).verify(message, raw.as_ref()).is_ok();
    println!("raw bytes: {}, verified: {ok}, verified as DER: {wrong}", raw.as_ref().len());
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image rust:1.99.1-trixie aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Befehl
cargo run --quiet --release
Ausgabe muss passen (regulärer Ausdruck)
raw bytes: 64, verified: true, verified as DER: false

Bibliotheken