Pular para o conteúdo
ecdsa.com
C · C++

BoringSSL

O BoringSSL do Google, o fork do OpenSSL usado no Chrome e no Android: ECDSA em DER apenas nas curvas do NIST, Ed25519 e ML-KEM, ML-DSA e SLH-DSA com APIs dedicadas — sem versões publicadas e sem promessa de estabilidade.
Licença
Apache-2.0
Versão verificada
2026-10-19-b50cad27ee80 ·
Código-fonte
boringssl.googlesource.com/boringssl
Documentação
commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html

Visão geral da compatibilidade

ECDSAEdDSAPós-quântica

Curvas ECDSA
P-224P-256P-384P-521
EdDSA
Ed25519
Algoritmos pós-quânticos
ML-KEMML-DSASLH-DSA

O BoringSSL é o fork do OpenSSL mantido pelo Google e usado no Chrome e no Android; o AWS-LC, a biblioteca por baixo do aws-lc-rs, é por sua vez um fork dele, e o ring reaproveita seu código assembly. Ele não tem versões publicadas e não promete estabilidade da API — quem o usa fixa um commit. Os fatos desta página foram verificados compilando a partir do código-fonte o commit b50cad27ee80 (19 de outubro de 2026).

O ECDSA mantém as convenções do OpenSSL: assinaturas DER, nonces aleatórios, nenhuma normalização low-S e uma verificação que aceita high-S; ECDSA_sign assina um digest calculado por você. Ao contrário do OpenSSL, uma entrada malformada é apenas uma verificação que falhou — EVP_DigestVerify retornou 0 para uma assinatura r‖s bruta e para um blob de 3 bytes, então a fila de erros é o único lugar em que um problema de formato aparece. Confira as codificações com o conversor DER ⇄ bruto.

As curvas são limitadas de propósito a P-224, P-256, P-384 e P-521 — EC_GROUP_new_by_curve_name(NID_secp256k1) retornou NULL —, e o Ed25519 é a única variante de EdDSA que funciona: EVP_PKEY_ED448 está definido por compatibilidade, mas a geração de uma chave Ed448 pela EVP falhou. Código que migra do OpenSSL para o BoringSSL perde secp256k1, Brainpool e Ed448 sem nenhum erro de compilação, até que o algoritmo seja solicitado.

O suporte pós-quântico é amplo e vem em APIs separadas e tipadas, e não pela EVP: MLKEM768_* e MLKEM1024_*, MLDSA65_* e os tamanhos relacionados, e SLHDSA_SHA2_128S_*, todas com o ciclo completo de ida e volta funcionando no teste; o ssl.h também define o grupo TLS híbrido X25519MLKEM768 (0x11EC). O exemplo usa ML-KEM-768 e ML-DSA-65 diretamente. Veja o que seu navegador negocia com a verificação pós-quântica do navegador.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/boringssl/run.sh executou BoringSSL 2026-10-19-b50cad27ee80 na imagem de contêiner debian:trixie-20261005-slim em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Codificação da assinatura ECDSA

    der

    EVP_DigestSign produz ASN.1 DER.

    Registrado pela verificação
    fact ecdsa-signature-encoding = der
  • Nonce do ECDSA

    random

    Nonce aleatório: duas assinaturas da mesma mensagem são diferentes.

    Registrado pela verificação
    fact ecdsa-nonce = random
  • Low-S ao assinar

    either

    O s não é normalizado: valores high-S apareceram entre 64 assinaturas.

    Registrado pela verificação
    fact ecdsa-low-s-sign = either
  • High-S ao verificar

    accepts-high-s

    Uma assinatura DER com s substituído por n − s foi verificada.

    Registrado pela verificação
    fact ecdsa-low-s-verify = accepts-high-s
  • Entrada do hash na chamada de assinatura

    hashes-message-or-digest

    EVP_DigestSign calcula o hash; ECDSA_sign assina um digest, e essa assinatura foi verificada contra a mensagem.

    Registrado pela verificação
    fact ecdsa-prehash = hashes-message-or-digest
  • Assinatura ECDSA malformada

    returns-false

    EVP_DigestVerify retornou 0 para uma assinatura r‖s bruta e para um blob de 3 bytes.

    Registrado pela verificação
    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)
  • Curvas ECDSA

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

    P-224, P-256, P-384 e P-521; não há grupo secp256k1.

    Registrado pela verificação
    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 por meio de ED25519_sign e ED25519_verify; EVP_PKEY_ED448 está definido, mas a geração de uma chave Ed448 falhou.

    Registrado pela verificação
    fact eddsa = Ed25519
    evidence eddsa: EVP_PKEY_ED448 is defined; generating an Ed448 key through EVP: fails
  • Algoritmos pós-quânticos

    ML-KEMML-DSASLH-DSA

    O encapsulamento e o desencapsulamento com ML-KEM-768 e a assinatura e a verificação com ML-DSA-65 e SLH-DSA-SHA2-128s funcionaram por meio dos respectivos arquivos de cabeçalho dedicados.

    Registrado pela verificação
    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

Uso

Execute um encapsulamento ML-KEM-768 e uma assinatura ML-DSA-65 com as APIs pós-quânticas dedicadas do 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;
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner debian:trixie-20261005-slim, e a execução falha se a saída não corresponder.

Configuração
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
Comando
cc -I/bssl/include -o usage usage.c /bssl/build/libcrypto.a -lstdc++ -lpthread && ./usage
A saída deve corresponder a (expressão regular)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1

Bibliotecas