本文へスキップ
ecdsa.com
Java · Kotlin

Bouncy Castle (Java)

The Legion of the Bouncy Castle による Java プロバイダー兼 PKIX ツールキットです。JDK が削除したすべての曲線、指定すれば使える決定的 ECDSA、PEM の解析、そして JVM で最も多くの種類のポスト量子署名を提供します。
ライセンス
MIT
確認したバージョン
1.86 ·
ソースコード
github.com/bcgit/bc-java
ドキュメント
www.bouncycastle.org/documentation/documentation-java/

互換性の概要

ECDSAEdDSAポスト量子暗号

ECDSA の曲線
P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519Ed448
ポスト量子アルゴリズム
ML-KEMML-DSASLH-DSAFalconLMSXMSS
公開鍵の形式
spki-pemspki-der
秘密鍵の形式
pkcs8-dersec1-pem

Bouncy Castle は 2 つの役割を兼ねています。Signature、KeyPairGenerator、KEM に組み込まれる JCA プロバイダー(BC)と、JCA なしで動作する ECDSASigner などの軽量 API です。bcpkix は証明書、CMS、OCSP、そして JDK にいまだにない PEMParser を追加します。secp256k1、Brainpool、PGP、証明書を扱う JVM のコードの大半は、このライブラリに依存しています。

ECDSA のデフォルトは JDK と同じです。SHA256withECDSA はランダムな nonce で DER を生成し、s を正規化しないまま残します。検証は low-S と high-S のどちらも受け入れます。JDK と異なる動作は、アルゴリズム名で明示的に選んだときだけ有効になります。SHA256withPLAIN-ECDSA は JWS が求める 64 バイトの生の r‖s を生成し、SHA256withECDDSA は決定的に署名します。また、軽量 API の ECDSASigner に HMacDSAKCalculator を指定すると、RFC 6979 のテストベクトルを正確に再現できました。SunEC と同様に、生の署名を DER 用のアルゴリズムに渡すと、false を返さずに SignatureException がスローされます。

多くの開発者がこのライブラリを選ぶ理由は、対応する曲線の幅広さです。P-224〜P-521、secp256k1、Brainpool の r1 曲線のすべてで署名と検証ができ、Ed25519 と Ed448 にも対応しています。プロバイダーを登録したうえで、KeyPairGenerator.getInstance("EC", "BC") のように名前で指定してください。指定しないと JDK の SunEC が先に参照され、secp256k1 を拒否します。サンプルではこれを回避しています。

1.86 のポスト量子暗号への対応は、チェックしたライブラリの中で最も幅広いものです。BC プロバイダーでは javax.crypto.KEM 経由の ML-KEM、ML-DSA、SLH-DSA、LMS が、BCPQC では Falcon と XMSS が使えます。ポスト量子署名ラボでアルゴリズムを試し、PQ 証明書インスペクターでハイブリッド証明書を解析してください。

JcaPEMWriter は EC 秘密鍵を SEC1 の -----BEGIN EC PRIVATE KEY----- として書き出し、PEMParser はそれを PEMKeyPair として読み戻します。PKCS#8 を前提とするツールでは、先に鍵を変換する必要があります。PLAIN 署名と DER 署名を取り違えたときは、DER ⇄ 生形式の変換ツールが役立ちます。

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

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

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

    der

    SHA256withECDSA は DER を返し、SHA256withPLAIN-ECDSA は 64 バイトの生の r‖s を返します。

    チェックによる記録
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: SHA256withPLAIN-ECDSA output is 64 bytes, parses as DER: false
  • ECDSA の nonce

    rfc6979-opt-in

    デフォルトではランダムです。SHA256withECDDSA は同じ入力に対して同一の署名を生成し、HMacDSAKCalculator を指定した ECDSASigner は RFC 6979 の付録 A.2.5 を再現しました。

    チェックによる記録
    fact ecdsa-nonce = rfc6979-opt-in
    evidence ecdsa-nonce: SHA256withECDSA repeats: false; ECDSASigner with HMacDSAKCalculator reproduces RFC 6979 A.2.5: true; SHA256withECDDSA repeats: 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

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

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

    throws

    SHA256withECDSA に生の r‖s 署名や 3 バイトのデータを渡すと、SignatureException がスローされます。

    チェックによる記録
    fact ecdsa-malformed-signature = throws
    evidence ecdsa-malformed-signature: raw r||s to SHA256withECDSA: throws SignatureException; 3 bytes: throws SignatureException
  • 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-DSAFalconLMSXMSS

    BC プロバイダーの ML-KEM(javax.crypto.KEM 経由)、ML-DSA、SLH-DSA、LMS と、BCPQC の Falcon と XMSS です。チェックでは、いずれも署名と検証(ML-KEM はカプセル化とデカプセル化)を往復で確認できました。

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

    spki-pemspki-der

    公開鍵は PEMParser による SPKI PEM と、SPKI DER から読み込めました。

    チェックによる記録
    fact public-key-formats = spki-pem, spki-der
  • 秘密鍵の形式

    pkcs8-dersec1-pem

    JcaPEMWriter は EC 秘密鍵を SEC1 PEM(EC PRIVATE KEY)として書き出し、PEMParser はそれを PEMKeyPair として読み込みます。PKCS#8 DER は JCA 経由で読み込めます。

    チェックによる記録
    fact private-key-formats = pkcs8-der, sec1-pem
    evidence private-key-formats: JcaPEMWriter writes an EC private key as -----BEGIN EC PRIVATE KEY-----; PEMParser returns PEMKeyPair

使い方

BC プロバイダーで secp256k1 の鍵を生成し、SHA256withECDDSA で決定的に署名して検証します。
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Usage {
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        // secp256k1 is not in the JDK's SunEC; it is in BC.
        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC");
        generator.initialize(new ECGenParameterSpec("secp256k1"));
        KeyPair pair = generator.generateKeyPair();
        byte[] message = "order #1042 approved".getBytes(StandardCharsets.UTF_8);

        // ECDDSA = deterministic ECDSA (RFC 6979); PLAIN-ECDSA = raw r||s instead of DER.
        Signature signer = Signature.getInstance("SHA256withECDDSA", "BC");
        signer.initSign(pair.getPrivate());
        signer.update(message);
        byte[] der = signer.sign();

        Signature verifier = Signature.getInstance("SHA256withECDSA", "BC");
        verifier.initVerify(pair.getPublic());
        verifier.update(message);
        System.out.println("verified: " + verifier.verify(der) + ", DER starts with 0x" + Integer.toHexString(der[0] & 0xff));
    }
}

スニペットのテストハーネスは、すべてのサンプルをコンテナイメージ maven:3.9.16-eclipse-temurin-25 内でそのまま実行し、出力が一致しなければ実行は失敗します。

セットアップ
mvn -q -B dependency:copy -Dartifact=org.bouncycastle:bcprov-jdk18on:1.86 -DoutputDirectory=lib >/dev/null
コマンド
java -cp lib/bcprov-jdk18on-1.86.jar Usage.java
一致すべき出力(正規表現)
verified: true, DER starts with 0x30

ライブラリ