Start Debugging

.NET 11 Preview 5 で X25519 鍵共有が標準搭載されました

.NET 11 Preview 5 は System.Security.Cryptography に第一級の X25519DiffieHellman 型を追加し、BouncyCastle や NSec なしで Curve25519 の鍵交換ができます。

.NET 11 Preview 5 の発表は LINQ と Blazor が中心ですが、安全なトランスポートを構築する人にとって最も重要な一行は、暗号化の項目にある箇条書きです。System.Security.Cryptography が X25519 鍵共有を標準で搭載するようになりました。このリリースまで、.NET で Curve25519 上の Diffie-Hellman 交換を行うには BouncyCastle または NSec を取り込む必要がありました。組み込みの ECDiffieHellman が Curve25519 を移植可能でクロスプラットフォームな形で公開していなかったためです。

なぜ Curve25519 は厄介な空白だったのか

X25519 は Curve25519 上の Diffie-Hellman 関数であり、現代の暗号が動くあらゆる場所に存在します。TLS 1.3、SSH、Signal、WireGuard、Noise はいずれも一時鍵の交換にこれを頼っています。高速で、パラメーター検証の厄介な落とし穴がなく、NIST P 曲線の特許やサイドチャネルの負担を回避します。

問題は、.NET の ECDiffieHellman が名前付き曲線と SEC の点形式を中心に構築されているのに対し、Curve25519 は異なるエンコーディングを使うことでした。ECCurve.NamedCurves.nistP256 の親戚を渡して X25519 を得る、ということはできません。そのため、それを必要とする .NET プロジェクトはすべてサードパーティのライブラリに頼り、それに伴うサプライチェーンや AOT トリミングの問題を抱えていました。

新しい API サーフェス

Preview 5 は X25519DiffieHellmanAPI 提案 dotnet/runtime#126206)を導入します。これはポスト量子の MLKem クラスや MLDsa クラスと同じファクトリーパターンに従う抽象型です。鍵と共有シークレットはすべて固定の 32 バイトです。

using System.Security.Cryptography;

// Each party generates an ephemeral key pair.
using X25519DiffieHellman alice = X25519DiffieHellman.GenerateKey();
using X25519DiffieHellman bob = X25519DiffieHellman.GenerateKey();

// Wire format for the public keys (SubjectPublicKeyInfo).
byte[] alicePub = alice.ExportSubjectPublicKeyInfo();
byte[] bobPub = bob.ExportSubjectPublicKeyInfo();

// Reconstruct the peer's public key and derive the raw shared secret.
using X25519DiffieHellman bobPeer = X25519DiffieHellman.ImportSubjectPublicKeyInfo(bobPub);
byte[] secretA = alice.DeriveRawSecretAgreement(bobPeer);

using X25519DiffieHellman alicePeer = X25519DiffieHellman.ImportSubjectPublicKeyInfo(alicePub);
byte[] secretB = bob.DeriveRawSecretAgreement(alicePeer);

// Both sides computed the same 32 bytes.
Console.WriteLine(CryptographicOperations.FixedTimeEquals(secretA, secretB)); // True

メソッド名は意図的です。DeriveRawSecretAgreement は生の X25519 出力を返します。この 32 バイトを暗号化鍵として直接使わないでください。TLS がまさにそうしているように、まず KDF に通してください。

byte[] key = HKDF.DeriveKey(
    HashAlgorithmName.SHA256,
    ikm: secretA,
    outputLength: 32,
    info: "my-app handshake v1"u8.ToArray());

これが次にどう位置づけられるか

インポートとエクスポートのヘルパーは、期待される一式を網羅します。ExportPkcs8PrivateKeyImportFromPemImportEncryptedPkcs8PrivateKey、そしてホットパス向けの span ベースのオーバーロードです。Windows では実装は CNG が支え、Linux では OpenSSL が支えます。[SupportedOSPlatform] の注釈が付いているため、アナライザーが非対応のターゲットについて警告します。

興味深いのは、.NET 10 のポスト量子プリミティブとの組み合わせです。X25519 を ML-KEM と組み合わせるハイブリッドハンドシェイクは TLS が向かう方向であり、両方の半分が標準搭載された今、サードパーティの暗号依存を一切使わずに、純粋な .NET でその交換を構築できます。それが Preview 5 の本当の見どころです。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る