Zum Inhalt springen
ecdsa.com
C · C++

BoringSSL

BoringSSL von Google, der OpenSSL-Fork in Chrome und Android: ECDSA mit DER-Signaturen nur auf den NIST-Kurven, Ed25519 sowie ML-KEM, ML-DSA und SLH-DSA mit eigenen APIs – ohne Releases und ohne Stabilitätsversprechen.
Lizenz
Apache-2.0
Geprüfte Version
2026-10-19-b50cad27ee80 ·
Quellcode
boringssl.googlesource.com/boringssl
Dokumentation
commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html

Kompatibilität auf einen Blick

ECDSAEdDSAPost-Quanten-Verfahren

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

BoringSSL ist Googles Fork von OpenSSL und wird in Chrome und Android verwendet; AWS-LC, die Bibliothek unter aws-lc-rs, ist wiederum ein Fork von BoringSSL, und ring übernimmt Assembler-Code aus BoringSSL. BoringSSL hat keine Releases und gibt kein Versprechen zur Stabilität der API – wer es einsetzt, pinnt einen Commit. Die Fakten auf dieser Seite wurden geprüft, indem Commit b50cad27ee80 (19. Oktober 2026) aus dem Quellcode gebaut wurde.

ECDSA folgt den OpenSSL-Konventionen: DER-Signaturen, zufällige Nonces, keine Low-S-Normalisierung und eine Prüfung, die High-S akzeptiert; ECDSA_sign signiert einen Digest, den du selbst berechnet hast. Anders als bei OpenSSL führt fehlerhafte Eingabe hier einfach zu einer fehlgeschlagenen Prüfung – EVP_DigestVerify gab für eine rohe r‖s-Signatur und für einen 3-Byte-Blob 0 zurück, sodass ein Formatproblem nur in der Fehlerwarteschlange auftaucht. Prüfe Kodierungen mit dem Konverter DER ⇄ Raw.

Die Kurven sind bewusst auf P-224, P-256, P-384 und P-521 beschränkt – EC_GROUP_new_by_curve_name(NID_secp256k1) gab NULL zurück –, und Ed25519 ist die einzige funktionierende EdDSA-Variante: EVP_PKEY_ED448 ist aus Kompatibilitätsgründen definiert, aber das Erzeugen eines Ed448-Schlüssels über EVP schlug fehl. Code, der von OpenSSL zu BoringSSL wechselt, verliert secp256k1, Brainpool und Ed448 ohne Kompilierfehler; das fällt erst auf, wenn der Algorithmus angefordert wird.

Die Post-Quanten-Unterstützung ist umfangreich und kommt in Form eigener, typisierter APIs statt über EVP: MLKEM768_* und MLKEM1024_*, MLDSA65_* samt zugehörigen Größen sowie SLHDSA_SHA2_128S_* – alle bestanden in der Prüfung den Roundtrip; ssl.h definiert außerdem die hybride TLS-Gruppe X25519MLKEM768 (0x11EC). Das Beispiel verwendet ML-KEM-768 und ML-DSA-65 direkt. Was dein Browser aushandelt, zeigt der Post-Quanten-Browser-Check.

Fakten und die Prüfungen dahinter

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

  • Kodierung von ECDSA-Signaturen

    der

    EVP_DigestSign erzeugt ASN.1-DER.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = der
  • ECDSA-Nonce

    random

    Zufällige Nonce: Zwei Signaturen derselben Nachricht unterscheiden sich.

    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 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

    EVP_DigestSign hasht; ECDSA_sign 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

    EVP_DigestVerify gab für eine rohe r‖s-Signatur und für einen 3-Byte-Blob 0 zurück.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: EVP_DigestVerify returned 0 for raw r||s and 0 for 3 bytes (1 = valid, 0 = invalid)
  • ECDSA-Kurven

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

    P-224, P-256, P-384 und P-521; eine Gruppe für secp256k1 gibt es nicht.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = P-224, P-256, P-384, P-521
    evidence ecdsa-curves: EC_GROUP_new_by_curve_name(NID_secp256k1): NULL
  • EdDSA

    Ed25519

    Ed25519 über ED25519_sign und ED25519_verify; EVP_PKEY_ED448 ist definiert, aber das Erzeugen eines Ed448-Schlüssels schlug fehl.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519
    evidence eddsa: EVP_PKEY_ED448 is defined; generating an Ed448 key through EVP: fails
  • 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-128s funktionierten, jeweils über die eigenen Header.

    Von der Prüfung aufgezeichnet
    fact pqc = ML-KEM, ML-DSA, SLH-DSA
    evidence pqc: ssl.h defines SSL_GROUP_X25519_MLKEM768 = 0x11ec
    evidence pqc: ML-DSA-65 signature 3309 bytes

Verwendung

Führe mit den eigenen Post-Quanten-APIs von BoringSSL eine ML-KEM-768-Kapselung durch und erstelle eine ML-DSA-65-Signatur.
#include <openssl/mldsa.h>
#include <openssl/mlkem.h>
#include <openssl/bytestring.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    /* ML-KEM-768: the receiver publishes the encoded public key. */
    uint8_t pub[MLKEM768_PUBLIC_KEY_BYTES], ct[MLKEM768_CIPHERTEXT_BYTES];
    uint8_t ss_sender[MLKEM_SHARED_SECRET_BYTES], ss_receiver[MLKEM_SHARED_SECRET_BYTES];
    struct MLKEM768_private_key priv;
    struct MLKEM768_public_key pk;
    MLKEM768_generate_key(pub, NULL, &priv);
    CBS cbs;
    CBS_init(&cbs, pub, sizeof pub);
    if (!MLKEM768_parse_public_key(&pk, &cbs)) return 1;
    MLKEM768_encap(ct, ss_sender, &pk);
    MLKEM768_decap(ss_receiver, ct, sizeof ct, &priv);
    printf("ML-KEM-768 secrets match: %d\n", memcmp(ss_sender, ss_receiver, sizeof ss_sender) == 0);

    /* ML-DSA-65 with an empty context string. */
    static const uint8_t msg[] = "release manifest";
    uint8_t dpub[MLDSA65_PUBLIC_KEY_BYTES], seed[MLDSA_SEED_BYTES];
    struct MLDSA65_private_key *dpriv = malloc(sizeof *dpriv);
    struct MLDSA65_public_key *dpk = malloc(sizeof *dpk);
    uint8_t *sig = malloc(MLDSA65_SIGNATURE_BYTES);
    MLDSA65_generate_key(dpub, seed, dpriv);
    MLDSA65_public_from_private(dpk, dpriv);
    MLDSA65_sign(sig, dpriv, msg, sizeof msg - 1, NULL, 0);
    printf("ML-DSA-65 verified: %d\n", MLDSA65_verify(dpk, sig, MLDSA65_SIGNATURE_BYTES, msg, sizeof msg - 1, NULL, 0));
    free(dpriv); free(dpk); free(sig);
    return 0;
}

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

Einrichtung
apt-get -qq update >/dev/null && apt-get -qq install -y --no-install-recommends build-essential cmake ninja-build git ca-certificates perl golang >/dev/null 2>&1 && git clone -q --filter=blob:none https://boringssl.googlesource.com/boringssl /bssl && git -C /bssl checkout -q b50cad27ee8013f241648ef6a7adf7f6f6b3d25b && cmake -S /bssl -B /bssl/build -G Ninja -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 && ninja -C /bssl/build crypto >/dev/null
Befehl
cc -I/bssl/include -o usage usage.c /bssl/build/libcrypto.a -lstdc++ -lpthread && ./usage
Ausgabe muss passen (regulärer Ausdruck)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1

Bibliotheken