Pular para o conteúdo
ecdsa.com
C

wolfSSL (wolfCrypt)

O wolfSSL, biblioteca TLS embarcada, e o wolfCrypt: ECDSA em DER sobre um digest que você fornece, com uma chamada de verificação que separa código de retorno e veredito — e um conjunto de recursos que depende inteiramente de como a biblioteca foi compilada.
Licença
GPL-3.0-only
Versão verificada
5.9.4 ·
Código-fonte
github.com/wolfSSL/wolfssl
Documentação
www.wolfssl.com/documentation/manuals/wolfssl/

Visão geral da compatibilidade

ECDSAEdDSAPós-quântica

Curvas ECDSA
P-224P-256P-384P-521
EdDSA
Ed25519

O wolfSSL é voltado a sistemas embarcados e implantações FIPS, e quase tudo é uma opção de compilação: curvas, variantes de EdDSA, nonces determinísticos, algoritmos pós-quânticos e suporte a PEM entram e saem com flags do ./configure. Os fatos desta página descrevem o pacote do Alpine 3.24.2 do wolfSSL 5.9.4, compilado com HAVE_ECC, HAVE_ED25519, HAVE_CURVE25519 e WOLFSSL_HAVE_MLKEM, mas sem HAVE_ED448, HAVE_DILITHIUM, curvas Koblitz ou Brainpool, nem WOLFSSL_ECDSA_DETERMINISTIC_K. Um build personalizado pode ser diferente em cada um desses pontos.

wc_ecc_sign_hash assina um digest calculado por você e retorna DER; wc_ecc_verify_hash_ex recebe r e s como inteiros, para assinaturas brutas. A verificação tem duas saídas: o código de retorno da função diz se ela conseguiu ser executada, e o argumento int *res guarda o veredito. Uma assinatura bruta de 64 bytes passada a wc_ecc_verify_hash retornou -171 (ECC ASN1 bad key data, invalid input) com o veredito 0; quem confere só o código de retorno, ou só o veredito, trata errado um dos dois casos. O exemplo imprime os dois.

Neste build, os nonces são aleatórios (a assinatura determinística da RFC 6979 exige WOLFSSL_ECDSA_DETERMINISTIC_K), o s não é normalizado e assinaturas high-S passam na verificação. As curvas disponíveis iam da P-224 à P-521; secp256k1 e Brainpool ficam de fora, a menos que sejam habilitadas. O Ed25519 funciona, e o encapsulamento e o desencapsulamento com ML-KEM-768 funcionaram por meio de wc_MlKemKey_*; o ML-DSA (Dilithium) não está neste build.

As chaves circulam em DER: wc_EccPublicKeyToDer grava SPKI e wc_EccKeyToDer grava uma ECPrivateKey SEC1; a conversão para PEM (wc_DerToPem) está disponível porque o pacote define WOLFSSL_DER_TO_PEM. O pacote do Alpine declara a licença como GPL-3.0-only; licenças comerciais são vendidas à parte pela wolfSSL Inc. Compare as codificações com as de outras implementações usando o conversor DER ⇄ bruto.

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

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/wolfssl/run.sh executou wolfSSL (wolfCrypt) 5.9.4 na imagem de contêiner alpine:3.24.2 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

    wc_ecc_sign_hash retorna DER; wc_ecc_verify_hash_ex verifica r e s passados como inteiros.

    Registrado pela verificação
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: wc_ecc_verify_hash_ex with r and s as integers verifies: 1
  • Nonce do ECDSA

    random

    Nonce aleatório neste build, que não tem WOLFSSL_ECDSA_DETERMINISTIC_K.

    Registrado pela verificação
    fact ecdsa-nonce = random
    evidence ecdsa-nonce: this build lacks WOLFSSL_ECDSA_DETERMINISTIC_K, so RFC 6979 signing is not available
  • 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

    takes-digest

    wc_ecc_sign_hash e wc_ecc_verify_hash operam sobre um digest calculado por quem as chama.

    Registrado pela verificação
    fact ecdsa-prehash = takes-digest
    evidence ecdsa-prehash: wc_ecc_sign_hash and wc_ecc_verify_hash take a digest the caller computed
  • Assinatura ECDSA malformada

    returns-error

    Uma assinatura r‖s bruta fez wc_ecc_verify_hash retornar -171 (ECC ASN1 bad key data, invalid input) com o veredito 0.

    Registrado pela verificação
    fact ecdsa-malformed-signature = returns-error
    evidence ecdsa-malformed-signature: wc_ecc_verify_hash on raw r||s: return code -171 (ECC ASN1 bad key data, invalid input), result 0
  • Curvas ECDSA

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

    P-224, P-256, P-384 e P-521 neste build; a geração de chaves secp256k1 e brainpoolP256r1 falhou.

    Registrado pela verificação
    fact ecdsa-curves = P-224, P-256, P-384, P-521
  • EdDSA

    Ed25519

    Ed25519; HAVE_ED448 não está definido neste build.

    Registrado pela verificação
    fact eddsa = Ed25519
    evidence eddsa: HAVE_ED448 is not set in this build
  • Algoritmos pós-quânticos

    ML-KEM

    O ciclo completo de ida e volta do ML-KEM-768 funcionou com wc_MlKemKey_*; HAVE_DILITHIUM (ML-DSA) não está definido neste build.

    Registrado pela verificação
    fact pqc = ML-KEM
    evidence pqc: HAVE_DILITHIUM (ML-DSA) is not set in this build
  • Formatos de chave pública

    spki-der

    wc_EccPublicKeyToDer e wc_EccPublicKeyDecode trabalham com SPKI DER, e a chave decodificada verificou uma assinatura.

    Registrado pela verificação
    fact public-key-formats = spki-der
  • Formatos de chave privada

    sec1-der

    wc_EccKeyToDer grava uma ECPrivateKey SEC1 (121 bytes para P-256) que wc_EccPrivateKeyDecode lê de volta.

    Registrado pela verificação
    fact private-key-formats = sec1-der
    evidence private-key-formats: wc_EccKeyToDer writes a SEC1 ECPrivateKey of 121 bytes
    evidence private-key-formats: WOLFSSL_DER_TO_PEM is set in this build

Uso

Calcule o hash, assine com P-256 e verifique, imprimindo tanto o código de retorno quanto o veredito da verificação.
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <stdio.h>

int main(void) {
    WC_RNG rng;
    ecc_key key;
    unsigned char digest[32], sig[ECC_MAX_SIG_SIZE];
    word32 sig_len = sizeof sig;
    int verified = 0;
    const unsigned char msg[] = "order #1042 approved";

    wc_InitRng(&rng);
    wc_ecc_init(&key);
    wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);

    /* wolfCrypt signs a digest you computed and returns DER. */
    wc_Sha256Hash(msg, sizeof msg - 1, digest);
    wc_ecc_sign_hash(digest, sizeof digest, sig, &sig_len, &rng, &key);
    /* The return code says whether verification ran; "verified" holds the verdict. */
    int rc = wc_ecc_verify_hash(sig, sig_len, digest, sizeof digest, &verified, &key);
    printf("rc: %d, verified: %d, DER starts with 0x%02x\n", rc, verified, sig[0]);

    wc_ecc_free(&key);
    wc_FreeRng(&rng);
    return 0;
}

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

Configuração
apk add --no-cache -q build-base wolfssl-dev=5.9.4-r0 >/dev/null
Comando
cc -o usage usage.c -lwolfssl && ./usage
A saída deve corresponder a (expressão regular)
rc: 0, verified: 1, DER starts with 0x30

Bibliotecas