Перейти к содержимому
ecdsa.com
C · C++

BoringSSL

BoringSSL от Google — форк OpenSSL, используемый в Chrome и Android: ECDSA в DER только на кривых NIST, Ed25519, а также ML-KEM, ML-DSA и SLH-DSA с отдельными API; без релизов и без гарантий стабильности.
Лицензия
Apache-2.0
Проверенная версия
2026-10-19-b50cad27ee80 ·
Исходный код
boringssl.googlesource.com/boringssl
Документация
commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html

Совместимость вкратце

ECDSAEdDSAПостквантовая криптография

Кривые ECDSA
P-224P-256P-384P-521
EdDSA
Ed25519

BoringSSL — форк OpenSSL от Google, используемый в Chrome и Android. От него, в свою очередь, ответвилась AWS-LC — библиотека, на которой построен aws-lc-rs, а ring заимствует его ассемблерный код. У BoringSSL нет релизов и нет гарантий стабильности API: пользователи фиксируют конкретный коммит. Факты на этой странице проверены на сборке коммита b50cad27ee80 (19 октября 2026 года) из исходного кода.

ECDSA следует соглашениям OpenSSL: подписи в DER, случайные nonce, никакой нормализации low-S, а проверка принимает high-S; ECDSA_sign подписывает вычисленный вами дайджест. В отличие от OpenSSL, некорректные входные данные дают просто неудачную проверку: EVP_DigestVerify вернула 0 и для подписи raw r‖s, и для 3-байтового фрагмента данных, поэтому проблема с форматом видна только в очереди ошибок. Проверяйте кодировки конвертером DER ⇄ raw.

Набор кривых намеренно ограничен P-224, P-256, P-384 и P-521 (EC_GROUP_new_by_curve_name(NID_secp256k1) вернула NULL), а Ed25519 — единственный работающий вариант EdDSA: EVP_PKEY_ED448 определён для совместимости, но генерация ключа Ed448 через EVP завершилась ошибкой. Код, который переходит с OpenSSL на BoringSSL, теряет secp256k1, Brainpool и Ed448, и компилятор об этом не сообщает: ошибка появится, только когда код запросит такой алгоритм.

Поддержка постквантовых алгоритмов обширна и реализована отдельными типизированными API, а не через EVP: MLKEM768_* и MLKEM1024_*, MLDSA65_* вместе со связанными константами размеров, а также SLHDSA_SHA2_128S_*; в ходе проверки все они прошли полный цикл. В ssl.h также определена гибридная группа TLS X25519MLKEM768 (0x11EC). Пример использует ML-KEM-768 и ML-DSA-65 напрямую. Что согласовывает ваш браузер, покажет проверка постквантового TLS в браузере.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/boringssl/run.sh запустила BoringSSL 2026-10-19-b50cad27ee80 в образе контейнера debian:trixie-20261005-slim; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Кодировка подписи ECDSA

    der

    EVP_DigestSign выдаёт ASN.1 DER.

    Что записала проверка
    fact ecdsa-signature-encoding = der
  • Nonce в ECDSA

    random

    Случайный nonce: две подписи одного сообщения различаются.

    Что записала проверка
    fact ecdsa-nonce = random
  • Low-S при подписи

    either

    s не нормализуется: среди 64 подписей встретились значения high-S.

    Что записала проверка
    fact ecdsa-low-s-sign = either
  • High-S при проверке

    accepts-high-s

    Подпись в DER, в которой s заменили на n − s, прошла проверку.

    Что записала проверка
    fact ecdsa-low-s-verify = accepts-high-s
  • Что хеширует вызов подписи

    hashes-message-or-digest

    EVP_DigestSign хеширует данные; ECDSA_sign подписывает дайджест, и такая подпись прошла проверку по сообщению.

    Что записала проверка
    fact ecdsa-prehash = hashes-message-or-digest
  • Некорректная подпись ECDSA

    returns-false

    EVP_DigestVerify вернула 0 для подписи raw r‖s и для 3-байтового фрагмента данных.

    Что записала проверка
    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

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

    P-224, P-256, P-384 и P-521; группы secp256k1 нет.

    Что записала проверка
    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 через ED25519_sign и ED25519_verify; EVP_PKEY_ED448 определён, но генерация ключа Ed448 завершилась ошибкой.

    Что записала проверка
    fact eddsa = Ed25519
    evidence eddsa: EVP_PKEY_ED448 is defined; generating an Ed448 key through EVP: fails
  • Постквантовые алгоритмы

    ML-KEMML-DSASLH-DSA

    ML-KEM-768 прошёл инкапсуляцию и декапсуляцию, а ML-DSA-65 и SLH-DSA-SHA2-128s — подпись и проверку; все через собственные заголовочные файлы.

    Что записала проверка
    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

Использование

Выполните инкапсуляцию ML-KEM-768 и подпись ML-DSA-65 через отдельные постквантовые API BoringSSL.
#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;
}

Тестовый стенд для фрагментов кода запускает каждый пример без изменений в образе контейнера debian:trixie-20261005-slim, и запуск завершается ошибкой, если вывод не совпадает.

Подготовка
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
Команда
cc -I/bssl/include -o usage usage.c /bssl/build/libcrypto.a -lstdc++ -lpthread && ./usage
Вывод должен совпадать (регулярное выражение)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1

Библиотеки