今日あなたのアプリケーションが扱うデータについて、問うべき問いがあります。それはどれくらいの期間、機密性を保つ必要があるかということです。医療記録、契約書、給与データ、認証情報の集まりなど。答えが数年以上であるなら、注目すべき脅威は今すぐ暗号を破ろうとする攻撃者ではありません。今のうちに通信を記録して保存しておき、ツールが追いついた将来に復号する攻撃者です。この手口にはharvest now, decrypt laterという呼び名があり、今日この時点で誰かが実際に量子コンピュータを構築する必要はありません。誰かがいずれ構築すると信じさせるだけで十分なのです。
だからこそ標準規格が先に動きました。NISTは2024年にアルゴリズムを発表し、2025年にはブラウザやCDNがハイブリッド鍵交換を有効にし、RSAと楕円曲線鍵合意を廃止する期限も公開のガイドラインに明記されるようになりました。sgcWebSockets 2026.10はこの一式をすべてDelphiにもたらします。sgcCryptoパック内にObject Pascalで実装されており、インストールやデプロイが必要な外部ライブラリはありません。
3つのアルゴリズム、1つのパック
この3つのNIST標準はそれぞれ異なる役割を担っており、通常使用するのは最初の2つです。
- ML-KEM(FIPS 203)は共有秘密を合意します。現在Diffie-Hellmanが担っている役割を置き換えるものです。
- ML-DSA(FIPS 204)は署名を行います。RSAおよびECDSA署名を置き換えるものです。
- SLH-DSA(FIPS 205)も署名を行い、ハッシュ関数のみを基盤としています。利用可能な中で最も保守的な前提を求め、署名サイズのコストを許容できる場合に向いています。
ML-KEMによる鍵合意
鍵カプセル化メカニズムは、Diffie-Hellmanよりも使い方がシンプルです。送信者は受信者の公開鍵を使って、新しい共有秘密と、それを伝える暗号文という2つのものを生成します。受信者はその暗号文から同じ秘密を復元します。
uses
sgcCrypto_MLKEM;
var
oPublicKey, oPrivateKey, oCiphertext, oSecret, oSame: TBytes;
begin
sgcMLKEM_GenerateKeyPair(mlkem768, oPublicKey, oPrivateKey);
// the sender, who only ever sees the public key
sgcMLKEM_Encapsulate(mlkem768, oPublicKey, oCiphertext, oSecret);
// the recipient, who holds the private key, gets the same 32 bytes
oSame := sgcMLKEM_Decapsulate(mlkem768, oPrivateKey, oCiphertext);
end;
パラメータセットはmlkem512、mlkem768、mlkem1024です。FIPS 203が要求する入力チェックは他の処理より先に実行されるため、不正な形式の公開鍵は黙って秘密を生成する代わりに例外を発生させます。また、復号できない暗号文はエラーではなく疑似乱数の秘密を返しますが、これは標準が求める暗黙的拒否です。
X-Wing、選びたくないときに
新しいアルゴリズムを採用するということは、それを信頼するということです。ハイブリッド構成はその判断を不要にします。古典的なアルゴリズムと耐量子アルゴリズムを組み合わせることで、どちらか一方さえ安全であれば結果全体が安全になるからです。X-WingはX25519とML-KEM-768を組み合わせ、単一の鍵ペアとして公開します。
uses
sgcCrypto_MLKEM_Hybrid;
var
oPublicKey, oPrivateKey, oCiphertext, oSecret: TBytes;
begin
sgcXWing_GenerateKeyPair(oPublicKey, oPrivateKey);
sgcXWing_Encapsulate(oPublicKey, oCiphertext, oSecret);
oSecret := sgcXWing_Decapsulate(oPrivateKey, oCiphertext);
end;
ML-DSAによる署名
署名にはパラメータセット、秘密鍵、メッセージ、そして通常は空であるコンテキスト文字列を使用します。
uses
sgcCrypto_MLDSA;
var
oSeed, oPublicKey, oPrivateKey, oSignature: TBytes;
begin
sgcMLDSA_GenerateKeyPairAndSeed(mldsa65, oSeed, oPublicKey, oPrivateKey);
oSignature := sgcMLDSA_Sign(mldsa65, oPrivateKey, aMessage, nil);
if sgcMLDSA_Verify(mldsa65, oPublicKey, aMessage, oSignature, nil) then
ShowMessage('signature is valid');
end;
シードに注目してください。ML-DSAの秘密鍵は、生成元となった32バイトのシードとして保存することも、展開された鍵として保存することも、あるいはその両方として保存することもでき、このライブラリはこの3つすべての読み書きに対応しています。設定ファイルに保存するのに適した形式はシードです。サイズが小さく、展開された鍵はシードから決定論的に導出されるためです。
持ち運べる鍵
誰とも鍵を交換できないアルゴリズムにはあまり価値がありません。そこでエンコーディングは公開されたプロファイルに従います。SubjectPublicKeyInfoとPKCS#8を、DERまたはPEM形式で、ML-KEMはRFC 9935、ML-DSAはRFC 9881、SLH-DSAはRFC 9909に準拠します。
var
vPublicPEM, vPrivatePEM: string;
begin
vPublicPEM := sgcMLDSA_ExportPublicKeyPEM(mldsa65, oPublicKey);
vPrivatePEM := sgcMLDSA_ExportPrivateKeyPEM(mldsa65, oSeed, nil);
end;
これらは他の実装でも読み込める、ごく普通のBEGIN PUBLIC KEYおよびBEGIN PRIVATE KEYブロックです。秘密鍵はインポート時に検証されます。公開鍵側が再度導出されて比較されるため、証明書と一致しない鍵は、誰も検証できない署名を生み出す前に、その場で拒否されます。
証明書と耐量子CA
証明書と証明書要求は耐量子鍵を保持でき、認証局も同様に保持できるため、チェーン全体を耐量子にすることができます。
var
vKey: TsgcX509SignKey;
vOptions: TsgcX509Options;
oCertDER: TBytes;
begin
vKey := sgcX509_MLDSAKey(mldsa65, oPrivateKey, oPublicKey);
vOptions.Subject.CommonName := 'My Post-Quantum CA';
vOptions.KeyUsage := [kuKeyCertSign, kuCRLSign];
oCertDER := sgcX509_CreateSelfSignedEx(vKey, vOptions);
end;
プロファイルの鍵用途規則は署名を行う前に検証されるため、鍵の暗号化を求められた耐量子鍵は、自身のプロファイルに違反する証明書を生成する代わりに例外を発生させます。チェーン検証は現在、発行元証明書が宣言するパス長と名前制約も検証します。
すでに組み込まれている場所
ライブラリ内の2箇所ではこれらすべてがすでに利用されており、暗号処理を自分で書く必要はありません。
- TLS。ネイティブTLS 1.3エンジンは、RFC 10024のハイブリッド鍵交換グループである
X25519MLKEM768、SecP256r1MLKEM768、SecP384r1MLKEM1024をネゴシエートし、デフォルトのリストはすでにハイブリッドのものから始まっています。詳しくはOpenSSL DLLを使わないDelphi TLS 1.3を参照してください。 - JWT。トークンはRFC 9964に基づきML-DSAで署名・検証できます。詳しくはDelphiでML-DSAを使ってJWTに署名するを参照してください。
正しいことをどう確認しているか
標準の実装は、何かによって検証されるまでは単なる主張にすぎません。3つのアルゴリズムはすべてNISTの既知解ベクタに対して検証されており、それらのベクタはデータシートの一文としてではなく、実行可能なテストセットとしてライブラリに同梱されています。ML-DSAの署名器は決定論的な方式であるため、同じ鍵と同じメッセージからは常に同じ署名が得られ、これによりRFCに掲載された例をバイト単位で再現できます。
どれを使うべきか
鍵合意には、ハイブリッドを使用してください。単体で使うならX-Wing、トラフィックがTLSであればハイブリッドTLSグループです。失うものはほとんどなく、どちらの前提が誤りであっても対応できます。署名についてはML-DSA-65が妥当な既定値であり、サイズが重要な場合はML-DSA-44、そうでない場合はML-DSA-87を選びます。ファームウェアのように更新できないものによって何年も先に署名が検証される場合で、署名サイズを許容できるのであれば、SLH-DSAを選んでください。
アップグレード
これらはすべてsgcCryptoパック内にあり、依存関係を一切追加しません。OpenSSLもDLLも不要で、アプリケーションを実行するマシンに何もインストールする必要はありません。既存のコードは、呼び出すまで変更されません。
次に読む
動画で見る
eSeGeCe チャンネルにこの内容の短い動画があります。
質問、フィードバック、移行に関するサポートが必要ですか?お問い合わせください—コードを書いた本人から返信が届きます。
