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

.NET System.Security.Cryptography

.NET の System.Security.Cryptography です。ECDSA は OpenSSL ベースのどのスタックとも異なり、デフォルトで生の r‖s(IEEE P1363)で署名します。Ed25519 は標準では含まれず、ポスト量子暗号のクラスが使えるかどうかは OS によって異なります。
ライセンス
MIT
確認したバージョン
10.0.13 ·
ソースコード
github.com/dotnet/runtime
ドキュメント
learn.microsoft.com/dotnet/api/system.security.cryptography.ecdsa

互換性の概要

ECDSA

ECDSA の曲線
P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
none
公開鍵の形式
spki-pemspki-derraw-xy
秘密鍵の形式
pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-derraw-scalar

.NET は、プラットフォームの暗号機能(Windows では CNG、Linux では OpenSSL、macOS では Apple のライブラリ)を、ECDsa、RSA、MLDsa、MLKem などからなる 1 つの API にまとめています。チェックでは Ubuntu 24.04 上で .NET 10.0.13 を実行しました。その下で動く OpenSSL は 3.0.13 で、このバージョンがいくつかの結果を左右しています。

デフォルトの署名エンコーディングは、多くのサーバーサイドのライブラリとは逆です。ECDsa.SignData は 64 バイトの IEEE P1363 形式の r‖s を返し、VerifyData もこの形式を前提とします。DER を使うには、両方の呼び出しで DSASignatureFormat.Rfc3279DerSequence を指定する必要があります。そのため .NET は、そのままで JWS や WebCrypto と一致し、OpenSSL、Java の SHA256withECDSA、Go の SignASN1 とは一致しません。不正な形式の署名や形式が合わない署名では、VerifyData は常に false を返します。そのため、DER 署名をデフォルトの形式で検証すると、偽造された署名とまったく区別がつきません。サンプルでは両方の結果を示しています。手元の署名がどちらの形式かは、DER ⇄ 生形式の変換ツールで確認できます。

Linux では、ECDSA は P-256〜P-521、secp256k1、Brainpool の r1 曲線に対応しており、いずれも OpenSSL を経由します。SignHash は自分で計算したダイジェストに署名します。nonce はランダムで、s は正規化されず、検証は high-S も受け入れます。基本クラスライブラリには Ed25519 や Ed448 のクラスがありません。EdDSA には Bouncy Castle for .NET などのパッケージが必要です。

.NET 10 には MLKem、MLDsa、SlhDsa、CompositeMLDsa がありますが、いずれもプラットフォームに応じて IsSupported の値が変わります。OpenSSL 3.0.13 では、すべて false でした。OpenSSL が ML-KEM と ML-DSA を追加したのは 3.5 なので、Linux ではそのバージョンを同梱したディストリビューションが、Windows では対応する CNG のサポートが必要です。コードでは対応していると決めつけず、必ず IsSupported を確認しなければなりません。なお、このページでは結果が true になるプラットフォームは検証していません。

鍵は SPKI と PKCS#8(PEM または DER、暗号化の有無を問わず)、SEC1 の EC PRIVATE KEY、ECParameters の生の座標からインポートできます。SEC1 の点や JWK からのインポートはできません。PFX バンドルは PFX インスペクターで解析してください。

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

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

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

    raw

    SignData はデフォルトで IEEE P1363 形式の 64 バイトの r‖s を返します。DSASignatureFormat.Rfc3279DerSequence を指定すると DER になります。

    チェックによる記録
    fact ecdsa-signature-encoding = raw
    evidence ecdsa-signature-encoding: SignData default: 64 bytes; with Rfc3279DerSequence: parses as DER True
  • ECDSA の nonce

    random

    nonce はランダムです。RFC 6979 のテスト用の鍵で同じメッセージに 2 回署名すると、異なる結果になりました。

    チェックによる記録
    fact ecdsa-nonce = random
  • 署名時の low-S

    either

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

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

    accepts-high-s

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

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

    hashes-message-or-digest

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

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

    returns-false

    P1363 として検証した DER 署名、DER として検証した生の署名、3 バイトのデータのいずれでも false が返ります。

    チェックによる記録
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: DER to the default verifier: false; raw to the DER verifier: false; 3 bytes: false
  • ECDSA の曲線

    P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1

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

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

    none

    System.Security.Cryptography には Ed25519 クラスがありません。

    チェックによる記録
    fact eddsa = none
    evidence eddsa: System.Security.Cryptography.Ed25519 type present: False
  • ポスト量子アルゴリズム

    none

    このプラットフォームでは、MLKem.IsSupported、MLDsa.IsSupported、SlhDsa.IsSupported、複合 ML-DSA のサポートがすべて false でした。

    チェックによる記録
    fact pqc = none
    evidence pqc: MLKem.IsSupported False, MLDsa.IsSupported False, SlhDsa.IsSupported False, CompositeMLDsa.IsSupported(MLDsa65WithECDsaP256) False
  • プラットフォームの OpenSSL

    3.0.13

    Linux では、各クラスはシステムの OpenSSL を使います。ここでは Ubuntu 24.04 の 3.0.13 で、ML-KEM と ML-DSA が追加される前のバージョンです。

    チェックによる記録
    fact platform-openssl = 3.0.13
    evidence platform-openssl: OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
  • 公開鍵の形式

    spki-pemspki-derraw-xy

    公開鍵は SPKI PEM(ImportFromPem)、SPKI DER、ECParameters の生の X 座標と Y 座標からインポートできます。

    チェックによる記録
    fact public-key-formats = spki-pem, spki-der, raw-xy
    evidence public-key-formats: ImportParameters takes Q.X and Q.Y separately; there is no SEC1 point or JWK import in the BCL
  • 秘密鍵の形式

    pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-derraw-scalar

    秘密鍵は PKCS#8 の PEM と DER、暗号化された PKCS#8、SEC1 の PEM と DER、ECParameters の生のスカラーからインポートできます。

    チェックによる記録
    fact private-key-formats = pkcs8-pem, pkcs8-der, encrypted-pkcs8, sec1-pem, sec1-der, raw-scalar

使い方

デフォルトの P1363 形式と DER で署名し、DER の検証には対応する形式の引数が必要であることを示します。
using System.Security.Cryptography;
using System.Text;

using var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var message = Encoding.UTF8.GetBytes("order #1042 approved");

// .NET signs raw r||s (IEEE P1363) by default; OpenSSL, Java and Go expect DER.
var raw = key.SignData(message, HashAlgorithmName.SHA256);
var der = key.SignData(message, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);

// Verifying a DER signature needs the same format argument, or VerifyData returns false.
var ok = key.VerifyData(message, der, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);
var wrongFormat = key.VerifyData(message, der, HashAlgorithmName.SHA256);
Console.WriteLine($"raw: {raw.Length} bytes, DER verified: {ok}, DER as raw: {wrongFormat}");
Console.WriteLine(key.ExportSubjectPublicKeyInfoPem().Split('\n')[0]);

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

セットアップ
dotnet new console --force -o . >/dev/null
コマンド
rm -f Program.cs && DOTNET_NOLOGO=1 dotnet run 2>/dev/null
一致すべき出力(正規表現)
raw: 64 bytes, DER verified: True, DER as raw: False\n-----BEGIN PUBLIC KEY-----

ライブラリ