Noiseプロトコルに対するKEMベースの Hybrid Forward Secrecy
Noiseプロトコルで使用される"hfs"修飾子について説明します。この修飾子はNoiseプロトコルのハンドシェイクにKEMベースのHybrid forward secrecyの機能を追加するためのものです。"hfs"修飾子は提案段階のもので、Noiseプロトコルの正式な仕様ではありませんが、noise-cではここで提案されている"hfs"修飾子が実装されています。
概要
Noiseプロトコルのハンドシェイクは何らかの Diffie-Hellman関数(通常はX25519のような楕円曲線 Diffie-Hellman関数)に依存しています。これらの関数が将来破られた時、以前に暗号化されたトラフィックが復号化される可能性があります。
これを軽減するために、ハイブリッドな前方秘匿性を得るための異なる公開鍵アルゴリズムを使うことができます。それにより、古いトラフィックを復号化するためには、この新しいアルゴリズムとDHアルゴリズムの両方を破らなければいけなくなります。現在、DHを破る可能性がある量子コンピュータに対して安全性があるとされている耐量子暗号アルゴリズムの使用に関心が集まっています。
これらの耐量子アルゴリズムは多くの場合KEMすなわちKey Encapsulation Mechanismという形式で提供されます。両方の当事者が任意の順序で公開鍵を交換するDHアルゴリズムとは異なり、KEMアルゴリズムでは一方の当事者はもう一方の当事者の公開鍵を基にした暗号文を送る必要があります。
KEM関数
KEM 関数はDH関数と似ていますが、公開鍵の交換ではなく、公開鍵とそれに続く暗号文の交換が必要です。
これらの関数のシグネチャは以下の通り定義されています。
GENERATE_KEM_KEYPAIR()
新しい KEMキーペアを生成します。KEMキーペアはpublic_keyとprivate_keyで構成されています。public_keyは長さKEMPUBLICKEYLENのバイト列にエンコーディングされたKEM公開鍵を表します。
GENERATE_KEM_CIPHERTEXT(public_key)
受信者の公開鍵に基づくKEM暗号文(ciphertext)とKEM出力(kem_output)を生成します。ciphertextは長さKEMCIPHERTEXTLENのバイト列にエンコーディングされたKEM暗号文を表します。kem_outputは長さKEMOUTPUTLENのバイト列にエンコーディングされたKEM出力を表します。ciphertextとkem_outputのエンコーディングの詳細はそれぞれのKEM関数のセットに仕様化されています。
KEM(key_pair, ciphertext)
key_pair内の秘密鍵とciphertextの間でKEMの計算を行い、長さKEMOUTPUTLENのバイト列を返します。kem_outputはGENERATE_KEM_CIPHERTEXT()で生成された値と一致します。
KEMPUBLICKEYLEN
KEMで使用する公開鍵のバイトサイズを表す定数です。
KEMCIPHERTEXTLEN
KEMの暗号文のバイトサイズを表す定数です。
KEMOUTPUTLEN
KEMの出力のバイトサイズを表す定数です。
KEM トークン
2つの新しいトークンを定義します。
"e1"
このトークンはGENERATE_KEM_KEYPAIR()を呼ぶように送信者に指示します。結果となるKEM公開鍵はそれがあたかもstaticなDH公開鍵であるかのように受信者に送付されます。(すなわち、キーが利用可能な場合はEncryptAndHash()を使用します。)
"ekem1"
このトークンは前に受信したKEM公開鍵を使ってGENERATE_KEM_CIPHERTEXT()を呼ぶように送信者に指示します。
結果となるKEM暗号文はそれがあたかもstaticなDH公開鍵であるかのように受信者に送付されます。(すなわちキーが利用可能な場合はEncryptAndHash()を使用します。)このトークンを受信した時、受信者はKEM(key_pair, ciphertext)を呼び出し、送信者が所持しているのと同じkem_outputを導出します。このトークンを送受信した際、当事者たちはMixKey(kem_output)を呼びます。
hfs修飾子
"hfs"修飾子は、同じメッセージ内にDH操作はない場合は、最初の"e"のすぐ後ろに"e1"トークンを追加します。このケースでは"hfs"トークンはこのDH操作のすぐ後ろに置かれます。(そのため、公開鍵は暗号化されます)
"hfs"修飾子はまた、"ekem1"トークンを最初の"ee"トークンの直後に追加します。
"hfs"修飾子が使用されるとき、DH名のセクションにはDHアルゴリズム名の直後に、"+"記号区切りでKEMアルゴリズム名が含まれていなければ行けません。
以下の表では、左側に基となるパターン、右側にその HFSパターンを記述しています。
NN: NNhfs:
-> e -> e, e1
<- e, ee <- e, ee, ekem1
NK: NKhfs:
<- s <- s
... ...
-> e, es -> e, es, e1
<- e, ee <- e, ee, ekem1
NX: NXhfs:
-> e -> e, e1
<- e, ee, s, es <- e, ee, ekem1, s, es
XN: XNhfs:
-> e -> e, e1
<- e, ee <- e, ee, ekem1
-> s, se -> s, se
XK: XKhfs:
<- s <- s
... ...
-> e, es -> e, es, e1
<- e, ee <- e, ee, ekem1
-> s, se -> s, se
XX: XXhfs:
-> e -> e, e1
<- e, ee, s, es <- e, ee, ekem1, s, es
-> s, se -> s, se
KN: KNhfs:
-> s -> s
... ...
-> e -> e, e1
<- e, ee, se <- e, ee, ekem1, se
KK: KKhfs:
-> s -> s
<- s <- s
... ...
-> e, es, ss -> e, e1, es, ss
<- e, ee, se <- e, ee, ekem1, se
KX: KXhfs:
-> s -> s
... ...
-> e -> e, e1
<- e, ee, se, s, es <- e, ee, ekem1, se, s, es
IN: INhfs:
-> e, s -> e, e1, s
<- e, ee, se <- e, ee, ekem1, se
IK: IKhfs:
<- s <- s
... ...
-> e, es, s, ss -> e, es, e1, s, ss
<- e, ee, se <- e, ee, ekem1, se
IX: IXhfs:
-> e, s -> e, e1, s |
<- e, ee, se, s, es <- e, ee, ekem1, se, s, es
耐量子KEMの選択
耐量子暗号アルゴリズムは調査の活発な分野です。将来、どのアルゴリズムが安全なものとして残るのかははっきりしていないため、ここではそれらのアルゴリズムについては触れないことにします。
また、これらのアルゴリズムの安全性の強度とパフォーマンスのバランスを保つ方法についてもはっきりしていないし、どのアルゴリズムが広くサポートされるようになるかについてもはっきりしていません。
セキュリティに関する考慮事項
Noiseの鍵導出のため、弱いKEMアルゴリズムを使用していたとしてもプロトコルの安全性を損なうことはありません。しかし、現在の耐量子暗号アルゴリズムが提供する安全性を評価することは難しいです。
KEM公開鍵が時として、平文で送信されることに注意してください。ハンドシェイクをランダムなバイト列と区別できないようにすることがゴールである場合、これらの値(およびDHの一時公開キー)を隠すために、いくつかの追加の方法を使用する必要があります。
Rationale
KEM公開鍵と暗号文は可能な場合は暗号化されます。なぜなら:
これは、一時的なDH公開鍵を除くすべてのものを暗号化するという、現在のNoiseの振る舞いとの一貫性を維持します。
トークンのこの振る舞いのおかげで、より多くのハンドシェイクが暗号化されるため、実行されるプロトコルのタイプがよりわかりにくくなります。
この振る舞いは他の小さなセキュリティ上の利点を追加するかもしれません。(例えば、攻撃者が一部のKEM公開鍵を破ることができるが、すべてを破ることはできない場合、KEM公開鍵を暗号化することによって、KEM公開鍵が脆弱かどうかを判断するためにDHに対する高価な攻撃を実行しなければいけなくなるかもしれない)