本文へスキップ
ecdsa.com
.NET

Bouncy Castle for .NET (BouncyCastle.Cryptography)

Bouncy Castle for .NET は、基本クラスライブラリに欠けている機能を補うために .NET 開発者が追加するマネージドの暗号ライブラリです。Ed25519 と Ed448、すべてのプラットフォームで使える secp256k1、決定的 ECDSA、PGP、PEM、そして OS に依存しない ML-KEM、ML-DSA、SLH-DSA を提供します。
ライセンス
MIT
確認したバージョン
2.7.0 ·
ソースコード
github.com/bcgit/bc-csharp
ドキュメント
www.bouncycastle.org/documentation/documentation-c/

互換性の概要

ECDSAEdDSAポスト量子暗号

ECDSA の曲線
P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519Ed448
公開鍵の形式
spki-pemspki-der
秘密鍵の形式
pkcs8-dersec1-pem

BouncyCastle.Cryptography(Portable.BouncyCastle に代わるパッケージ)は純粋なマネージドコードです。結果が Windows CNG や Linux の OpenSSL のバージョンに左右されないことこそが、System.Security.Cryptography と併用する価値です。文字列ベースの SignerUtilities API と、ECDsaSigner などの低レベルのクラスを提供しています。

ECDSA のデフォルトは .NET ではなく OpenSSL の伝統に従っています。SHA-256withECDSA は DER を生成し、SHA-256withPLAIN-ECDSA は .NET 自身の ECDsa や JWS が使う 64 バイトの生の r‖s を返します。この 2 つを取り違えるのが、1 つのアプリケーション内で両ライブラリを使うときの典型的な相互運用の失敗です。また、不正な入力に対しては例外をスローせず、常に false を返します。nonce は SignerUtilities ではランダムで、HMacDsaKCalculator を指定した ECDsaSigner では RFC 6979 のテストベクトルを再現できました。s は正規化されず、検証は high-S も受け入れます。

対応範囲こそが、このライブラリが追加される理由です。P-224〜P-521、secp256k1、Brainpool の r1 曲線、サンプルにある Ed25519 と Ed448、そして MLKemEncapsulator、MLDsaSigner、SlhDsaSigner による ML-KEM、ML-DSA、SLH-DSA に対応しています。これらはすべて、基本クラスライブラリがポスト量子暗号に一切対応していないと報告した同じ Linux イメージ上で動作しました。ポスト量子署名ラボでアルゴリズムを試してください。

PemWriter は EC 秘密鍵を SEC1 の -----BEGIN EC PRIVATE KEY----- として書き出し、PemReader はそれを AsymmetricCipherKeyPair として返します。PKCS#8 は PrivateKeyInfoFactory を経由します。アセンブリ自体のバージョンはすべての 2.x リリースで厳密な名前の 2.0.0 なので、動作を比較するときはパッケージのバージョン(ここでは 2.7.0)を確認してください。

事実とその根拠となるチェック

以下の内容はドキュメントからの転記ではありません。2026年10月20日に、チェック content/libraries/verify/bouncy-castle-csharp/run.sh がコンテナイメージ mcr.microsoft.com/dotnet/sdk:10.0.402-noble 内で Bouncy Castle for .NET (BouncyCastle.Cryptography) 2.7.0 を実行しました。このページの内容はその出力と一致していなければならず、各事実には該当する出力行を示しています。

  • ECDSA 署名のエンコーディング

    der

    SHA-256withECDSA は DER を返し、SHA-256withPLAIN-ECDSA は 64 バイトの生の r‖s を返します。

    チェックによる記録
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: SHA-256withPLAIN-ECDSA output: 64 bytes
  • ECDSA の nonce

    rfc6979-opt-in

    SignerUtilities ではランダムです。HMacDsaKCalculator を指定した ECDsaSigner では RFC 6979 付録 A.2.5 を再現できました。

    チェックによる記録
    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

    either

    s は正規化されません。64 個の署名の中に high-S の値が現れました。

    チェックによる記録
    fact ecdsa-low-s-sign = either
  • 検証時の high-S

    accepts-high-s

    s を n − s に置き換えた DER 署名も検証を通りました。

    チェックによる記録
    fact ecdsa-low-s-verify = accepts-high-s
  • 署名呼び出しがハッシュする対象

    hashes-message-or-digest

    SHA-256withECDSA はハッシュを計算します。NONEwithECDSA はダイジェストに署名し、その署名はメッセージに対して検証できました。

    チェックによる記録
    fact ecdsa-prehash = hashes-message-or-digest
  • 不正な形式の ECDSA 署名

    returns-false

    SHA-256withECDSA に渡した生の r‖s 署名と 3 バイトのデータでは false が返ります。

    チェックによる記録
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: raw r||s to SHA-256withECDSA: false; 3 bytes: false
  • ECDSA の曲線

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

    P-224、P-256、P-384、P-521、secp256k1、brainpoolP256r1/P384r1/P512r1 で署名と検証ができました。

    チェックによる記録
    fact ecdsa-curves = P-224, P-256, P-384, P-521, secp256k1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
  • EdDSA

    Ed25519Ed448

    Ed25519 と Ed448 です。

    チェックによる記録
    fact eddsa = Ed25519, Ed448
  • ポスト量子アルゴリズム

    ML-KEMML-DSASLH-DSA

    マネージドコードで、ML-KEM-768 のカプセル化とデカプセル化、ML-DSA-65 と SLH-DSA-SHA2-128f の署名と検証ができました。

    チェックによる記録
    fact pqc = ML-KEM, ML-DSA, SLH-DSA
  • 公開鍵の形式

    spki-pemspki-der

    PemReader による SPKI PEM と、PublicKeyFactory による SPKI DER です。

    チェックによる記録
    fact public-key-formats = spki-pem, spki-der
    evidence public-key-formats: PublicKeyFactory.CreateKey(SPKI DER) verifies: True
  • 秘密鍵の形式

    pkcs8-dersec1-pem

    PemWriter が SEC1 PEM を書き出し、PemReader が読み込みます。PKCS#8 DER は PrivateKeyFactory で読み込めます。

    チェックによる記録
    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

使い方

System.Security.Cryptography にはない Ed25519 で署名と検証を行います。
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)}");

スニペットのテストハーネスは、すべてのサンプルをコンテナイメージ mcr.microsoft.com/dotnet/sdk:10.0.402-noble 内でそのまま実行し、出力が一致しなければ実行は失敗します。

セットアップ
dotnet new console --force -o . >/dev/null && dotnet add package BouncyCastle.Cryptography --version 2.7.0 >/dev/null
コマンド
rm -f Program.cs && DOTNET_NOLOGO=1 dotnet run 2>/dev/null
一致すべき出力(正規表現)
signature: 64 bytes, verified: True

ライブラリ