.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 インスペクターで解析してください。