本記事はAIを利用して作成した技術解説・実装例です。掲載するコードや手順は一次情報を基に構成していますが、筆者による実機での動作確認は行っていません。環境やバージョンによって動作が異なる場合があります。
Secure Shell(SSH)プロトコルは、従来の楕円曲線暗号(ECDH)などの鍵共有方式を長年利用してきました。しかし、将来的に十分な性能を持つ量子コンピュータが実現した場合、これまでの方式は安全性が脅かされる可能性があります。こうした懸念に対して、攻撃者が暗号化された通信を保存しておき、後から量子コンピュータで復号を試みる「今記録し、後で復号する(Harvest now, decrypt later)」攻撃への対策が急務となっています。
RFC 10042 は、こうした課題に対応するため、耐量子計算機暗号であるModule-Lattice-Based Key-Encapsulation Mechanism(ML-KEM)と、従来の楕円曲線ディフィー・ヘルマン(ECDH)鍵共有を組み合わせた「Post-Quantum/Traditional(PQ/T)Hybrid key exchange」の仕組みをSSHのトランスポート層プロトコルへ導入するための仕様を定義しています。 、一次情報に基づき、このハイブリッド鍵交換の抽象構造、メッセージのやり取り、具体的な方式のバリエーション、および共有秘密の生成方法について整理します。
1. 背景とハイブリッド鍵交換の基本概念
従来のSSH鍵交換では、離散対数問題の困難性に基づいたECDH方式(RFC 5656やRFC 8731など)が利用されてきました。これに対し、一次情報ではNISTで標準化されたML-KEMと古典的アルゴリズムを組み合わせたPQ/Tハイブリッド鍵交換を定義しています。
ハイブリッド方式における個別の鍵交換スキームのセキュリティは互いに独立しています。つまり、PQ/Tハイブリッド鍵交換方式は、構成要素の中で最も安全な鍵交換スキームと同等以上に安全性が確保される仕組みになっています。
NISTの枠組みにおけるKEM(Key-Encapsulation Mechanism)は、主に以下の3つのアルゴリズムで構成されます。
KeyGen() -> (pk, sk): 公開鍵
pkと秘密鍵skを生成する確率的アルゴリズム。Encaps(pk) -> (ct, ss): 公開鍵
pkを入力として、暗号文ctと共有秘密ssを出力する確率的アルゴリズム。Decaps(sk, ct) -> ss: 秘密鍵
skと暗号文ctを入力として、共有秘密ss(またはエラー値)を出力するアルゴリズム。
KEMの主なセキュリティ要件には、適応的選択暗号文攻撃に対する非識別性(IND-CCA2)や、選択平文攻撃に対する非識別性(IND-CPA)が含まれます。RFC 10042で採用されているML-KEMは、2024年にFIPS 203として標準化されたものであり、パラメータとして ML-KEM-512、ML-KEM-768、ML-KEM-1024 の3つのバリエーションが存在します。
2. 通信シーケンスとメッセージ構造の仕様
PQ/Tハイブリッド鍵交換では、従来の SSH_MSG_KEXDH_INIT や SSH_MSG_KEX_ECDH_INIT の代わりに、新しいメッセージが定義されています。
以下は、クライアントとサーバ間で行われるPQ/Tハイブリッド鍵交換のメッセージフローの全体像です。
sequenceDiagram
participant Client as SSH Client
participant Server as SSH Server
Client->>Server: SSH_MSG_KEX_HYBRID_INIT (C_INIT = C_PK2 || C_PK1)
Server->>Client: SSH_MSG_KEX_HYBRID_REPLY (K_S, S_REPLY = S_CT2 || S_PK1, Signature)
クライアントからの送信メッセージ: SSH_MSG_KEX_HYBRID_INIT
メッセージ番号として 30 が割り当てられた SSH_MSG_KEX_HYBRID_INIT を用いて、クライアントは以下の文字列データを送信します。
byte:
SSH_MSG_KEX_HYBRID_INIT(30)string:
C_INIT
ここで、C_INIT は2つのエフェメラル公開鍵の結合値であり、C_INIT = C_PK2 || C_PK1(|| は結合を表す)として構成されます。
C_PK1: 従来の古典的鍵交換(ECDHなど)のエフェメラル公開鍵。C_PK2: 対応するポスト量子KEMのKeyGenから出力された公開鍵pk。
サーバからの返信メッセージ: SSH_MSG_KEX_HYBRID_REPLY
メッセージ番号として 31 が割り当てられた SSH_MSG_KEX_HYBRID_REPLY を用いて、サーバは以下のデータを返します。
byte:
SSH_MSG_KEX_HYBRID_REPLY(31)string:
K_S(サーバの公開ホスト鍵)string:
S_REPLYstring: 交換ハッシュに対する署名
ここで、S_REPLY は S_REPLY = S_CT2 || S_PK1 として構成されます。
S_PK1: 従来のエフェメラルECDHサーバ公開鍵。S_CT2: サーバ側のEncapsアルゴリズムが生成したKEMの暗号文ct(クライアントの公開鍵C_PK2に対して秘密をカプセル化したもの)。
3. 検証処理と安全性の確保
メッセージの送受信においては、長さを狙った攻撃(レングス・エクステンション攻撃など)を防ぐための厳格なチェックが義務付けられています。
サーバ側のチェック: サーバは
S_CT2を生成する前に、受信したC_INITの長さが、ネゴシエートされた方式における各公開鍵(C_PK1およびC_PK2)の期待される長さの総和と一致していることを必ず(MUST)確認しなければなりません。また、FIPS 203で定義されているカプセル化鍵のチェックも実行する必要があります。失敗した場合は、SSH_MSG_DISCONNECT(理由:SSH_DISCONNECT_KEY_EXCHANGE_FAILED)を用いて接続を中断します。クライアント側のチェック: クライアントは復号(デカプセル化)を行う前に、
S_REPLYの長さが伝統的公開鍵S_PK1とML-KEM暗号文S_CT2の期待される長さの総和と一致していることを確認しなければなりません。長さの不一致や復号エラーが発生した場合は、同様に切断メッセージで接続をアボートします。
4. 定義されている具体的なハイブリッド方式
RFC 10042では、具体的な組み合わせとして以下の3つの方式名がIANAに登録されています。これらは SSH_MSG_KEXINIT で使用されます。
mlkem768nistp256-sha256伝統的鍵交換: NIST P-256曲線(
ecdh-sha2-nistp256)ポスト量子KEM: ML-KEM-768
ハッシュ関数: SHA-256
mlkem1024nistp384-sha384伝統的鍵交換: NIST P-384曲線(
ecdh-sha2-nistp384)ポスト量子KEM: ML-KEM-1024
ハッシュ関数: SHA-384
mlkem768x25519-sha256伝統的鍵交換: Curve25519(
curve25519-sha256)ポスト量子KEM: ML-KEM-768
ハッシュ関数: SHA-256
5. 共有秘密(Shared Secret K)の導出方法
ハイブリッド鍵交換では、古典的ECDHから得られる共有秘密 K_CL と、ML-KEMから得られるポスト量子共有秘密 K_PQ の2つが確立されます。
最終的な共有秘密 K は、これら2つの共有秘密を結合したもののハッシュ値として算出されます。
$$K = \text{HASH}(K_{\text{PQ}} \parallel K_{\text{CL}})$$
TLS 1.3(RFC 9954)などでは結合した秘密をそのままキースケジュールに入力しますが、本仕様ではSSHの鍵導出方法に合わせて、結合した後に一度ハッシュ関数を通すアプローチをとっています。
また、従来方式ではECDHの共有秘密が整数(mpint)としてエンコードされていましたが、本仕様では固定長のビッグエンディアンバイト配列(Curve25519およびsecp256r1は32バイト、secp384r1は48バイト)として扱われます。
6. 鍵導出とハッシュ計算(H)の入力要素
鍵交換メソッドのハッシュ関数 $H$ は、以下の要素を連結したデータに対してハッシュを計算することで得られます。
クライアント識別文字列
V_Cサーバ識別文字列
V_Sクライアントの
SSH_MSG_KEXINITペイロードI_Cサーバの
SSH_MSG_KEXINITペイロードI_Sサーバの公開ホスト鍵
K_Sクライアントメッセージ文字列
C_INITサーバメッセージ文字列
S_REPLYSSH共有秘密
K
このハッシュ結果 H と共有秘密 K を基に、暗号化キーが導出されます。なお、メッセージサイズに関しては、従来のSSH仕様(RFC 4253)で規定される最小サポートペイロード長(32768バイト以下)の範囲内で運用されることが前提となっています。

コメント