Pular para o conteúdo
ecdsa.com
.NET

Bouncy Castle for .NET (BouncyCastle.Cryptography)

O Bouncy Castle para .NET, a biblioteca de criptografia gerenciada que desenvolvedores .NET adicionam para suprir o que falta na biblioteca de classes base: Ed25519 e Ed448, secp256k1 em todas as plataformas, ECDSA determinístico, PGP, PEM e ML-KEM, ML-DSA e SLH-DSA sem depender do sistema operacional.
Licença
MIT
Versão verificada
2.7.0 ·
Código-fonte
github.com/bcgit/bc-csharp
Documentação
www.bouncycastle.org/documentation/documentation-c/

Visão geral da compatibilidade

ECDSAEdDSAPós-quântica

Curvas ECDSA
P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519Ed448
Algoritmos pós-quânticos
ML-KEMML-DSASLH-DSA
Formatos de chave privada
pkcs8-dersec1-pem

O BouncyCastle.Cryptography (o pacote que substituiu o Portable.BouncyCastle) é código gerenciado puro: seus resultados não dependem do CNG do Windows nem da versão do OpenSSL no Linux, e é exatamente isso que o torna útil ao lado do System.Security.Cryptography. Ele oferece uma API SignerUtilities baseada em strings e classes de nível mais baixo, como ECDsaSigner.

Os padrões de ECDSA seguem a tradição do OpenSSL, e não a do .NET: SHA-256withECDSA produz DER, enquanto SHA-256withPLAIN-ECDSA gera o r‖s bruto de 64 bytes que o próprio ECDsa do .NET e o JWS usam. Confundir os dois é a falha de interoperabilidade mais comum entre as duas bibliotecas em uma mesma aplicação, e toda entrada malformada retorna false em vez de lançar uma exceção. Os nonces são aleatórios pelo SignerUtilities; ECDsaSigner com um HMacDsaKCalculator reproduziu o vetor de teste da RFC 6979. O s não é normalizado e a verificação aceita high-S.

A cobertura é o motivo pelo qual as pessoas o adicionam: da P-224 à P-521, secp256k1 e as curvas Brainpool r1; Ed25519 e Ed448, como no exemplo; e ML-KEM, ML-DSA e SLH-DSA por meio de MLKemEncapsulator, MLDsaSigner e SlhDsaSigner — tudo isso funcionou na mesma imagem Linux em que a biblioteca de classes base não indicou nenhum suporte pós-quântico. Experimente os algoritmos no playground de assinaturas pós-quânticas.

PemWriter grava chaves privadas EC como SEC1 -----BEGIN EC PRIVATE KEY-----, e PemReader as retorna como um AsymmetricCipherKeyPair; o PKCS#8 passa por PrivateKeyInfoFactory. A versão do próprio assembly é a de nome forte 2.0.0 em todas as versões 2.x, então confira a versão do pacote (aqui, 2.7.0) ao comparar comportamentos.

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

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/bouncy-castle-csharp/run.sh executou Bouncy Castle for .NET (BouncyCastle.Cryptography) 2.7.0 na imagem de contêiner mcr.microsoft.com/dotnet/sdk:10.0.402-noble 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

    SHA-256withECDSA retorna DER; SHA-256withPLAIN-ECDSA retorna 64 bytes de r‖s bruto.

    Registrado pela verificação
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: SHA-256withPLAIN-ECDSA output: 64 bytes
  • Nonce do ECDSA

    rfc6979-opt-in

    Aleatório pelo SignerUtilities; ECDsaSigner com HMacDsaKCalculator reproduziu o apêndice A.2.5 da RFC 6979.

    Registrado pela verificação
    fact ecdsa-nonce = rfc6979-opt-in
    evidence ecdsa-nonce: SHA-256withECDSA repeats: False; ECDsaSigner with HMacDsaKCalculator reproduces RFC 6979 A.2.5: True
  • 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

    SHA-256withECDSA calcula o hash; NONEwithECDSA 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

    Uma assinatura r‖s bruta passada a SHA-256withECDSA e um blob de 3 bytes retornam false.

    Registrado pela verificação
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: raw r||s to SHA-256withECDSA: false; 3 bytes: false
  • Curvas ECDSA

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

    Assinatura e verificação funcionaram com P-224, P-256, P-384, P-521, secp256k1 e brainpoolP256r1/P384r1/P512r1.

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

    Ed25519Ed448

    Ed25519 e Ed448.

    Registrado pela verificação
    fact eddsa = Ed25519, Ed448
  • 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-128f funcionaram em código gerenciado.

    Registrado pela verificação
    fact pqc = ML-KEM, ML-DSA, SLH-DSA
  • Formatos de chave pública

    spki-pemspki-der

    SPKI PEM por meio de PemReader e SPKI DER por meio de PublicKeyFactory.

    Registrado pela verificação
    fact public-key-formats = spki-pem, spki-der
    evidence public-key-formats: PublicKeyFactory.CreateKey(SPKI DER) verifies: True
  • Formatos de chave privada

    pkcs8-dersec1-pem

    PemWriter grava e PemReader lê SEC1 PEM; o PKCS#8 DER é carregado por meio de PrivateKeyFactory.

    Registrado pela verificação
    fact private-key-formats = pkcs8-der, sec1-pem
    evidence private-key-formats: PemWriter writes -----BEGIN EC PRIVATE KEY-----; PemReader returns AsymmetricCipherKeyPair; PKCS#8 DER round trip signs: True

Uso

Assine e verifique com Ed25519, que o System.Security.Cryptography não oferece.
using System.Text;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

var message = Encoding.UTF8.GetBytes("order #1042 approved");

// Ed25519, which the .NET base class library does not offer.
var generator = new Ed25519KeyPairGenerator();
generator.Init(new Ed25519KeyGenerationParameters(new SecureRandom()));
var pair = generator.GenerateKeyPair();

var signer = SignerUtilities.GetSigner("Ed25519");
signer.Init(true, pair.Private);
signer.BlockUpdate(message, 0, message.Length);
var signature = signer.GenerateSignature();

var verifier = SignerUtilities.GetSigner("Ed25519");
verifier.Init(false, pair.Public);
verifier.BlockUpdate(message, 0, message.Length);
Console.WriteLine($"signature: {signature.Length} bytes, verified: {verifier.VerifySignature(signature)}");

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner mcr.microsoft.com/dotnet/sdk:10.0.402-noble, e a execução falha se a saída não corresponder.

Configuração
dotnet new console --force -o . >/dev/null && dotnet add package BouncyCastle.Cryptography --version 2.7.0 >/dev/null
Comando
rm -f Program.cs && DOTNET_NOLOGO=1 dotnet run 2>/dev/null
A saída deve corresponder a (expressão regular)
signature: 64 bytes, verified: True

Bibliotecas