Open11

Hybrid Public Key Encryption

抄録

この文書では、ハイブリッド公開鍵暗号化(HPKE)のためのスキームについて述べる。このスキームは、受信者公開鍵に対して任意のサイズの平文の認証済み公開鍵暗号化を提供する。HPKEは、非対称鍵カプセル化機構(KEM)、鍵導出関数(KDF)、および追加データ付き認証済み暗号化(AEAD)関数の任意の組み合わせで動作する。楕円曲線ディフィー・エルマン鍵一致、HKDF、SHA2など、広く利用されている効率的なプリミティブを用いたスキームのインスタンスを提供する。

本文書は、IRTFのCrypto Forum Research Group (CFRG)の製品です。

1. 序章

非対称アルゴリズムと対称アルゴリズムを組み合わせた暗号化方式は、公開鍵暗号の初期の頃から指定され、実践されてきました (例: [RFC1421]など)。この2つを組み合わせることで、非対称暗号の鍵管理上の利点と対称暗号の性能上の利点が得られる。従来の組み合わせは、「公開鍵で対称鍵を暗号化する」というものであった。ここで指定されている "ハイブリッド "公開鍵暗号化方式(HPKE)は、異なるアプローチをとっています。"対称鍵とそのカプセル化を公開鍵で生成する "というものです。具体的には、暗号化されたメッセージは、公開鍵暗号化方式でカプセル化された暗号化鍵と、その鍵を使用して暗号化された1つ以上の任意のサイズの暗号文を伝えます。このタイプの公開鍵暗号化は、Messaging Layer Security [I-D.ietf-mls-protocol]やTLS Encrypted ClientHello [I-D.ietf-tls-esni]など、実際には多くのアプリケーションがあります。

現在、ハイブリッド暗号化のために、ANSI X9.63 (ECIES) [ANSI]、IEEE 1363a [IEEE1363]、ISO/IEC 18033-2 [ISO]、およびSECG SEC 1 [SECG]を含むECIESに基づいた、多数の競合する非相互運用の規格および変種が存在する。徹底した比較については、[MAEA10]を参照のこと。これらの既存のスキームはすべて、古いプリミティブに依存していたり、 IND-CCA2セキュリティの証明を欠いていたり、テストベクタを提供していなかったりするなどの問題がある。

本文書は、上記のスキームのコレクションによって提供される機能のサブセットを提供するHPKEスキームを定義するが、それらが相互運用可能に実装されることができるように十分に明確に指定されている。本文書で定義されているHPKE構造は、基礎となるプリミティブについての古典的な仮定の下で、(適応的な)選択された暗号文攻撃(IND-CCA2安全)に対して安全である[HPKEAnalysis], [ABHKLR20]。これらの分析の要約はセクション8.1にある。

本文書は、Crypto Forum Research Group (CFRG)のコンセンサスを表している。

3. 表記法

以下の用語は、HPKE の操作、役割、および動作を説明するために、このドキュメント全体で使用される。

  • (skX、pkX)。skXは秘密鍵であり、pkXは公開鍵である。
  • pk(skX): ロールXで使用されるKEM鍵ペア。KEM秘密鍵skXに対応するKEM公開鍵。
  • 送信者(S): 暗号化されたメッセージを送信するエンティティの役割。
  • 受信者(R): 暗号化されたメッセージを受信するエンティティの役割。暗号化されたメッセージを受信するエンティティの役割。
  • エフェメラル(E): 一回限りの使用を意味する新鮮なランダム値の役割。
  • I2OSP(n) および OS2IP(x)。RFC8017]で述べられているように、バイト文字列を非負整数に変換する。これらの関数は、バイト文字列をビッグエンディアンのバイト順で操作することに注意してください。
  • concat(x0, ..., xN). バイト文字列の連結。 concat(0x01, 0x0203, 0x040506) = 0x010203040506.
  • random(n)。長さnバイトの疑似ランダムバイト文字列
  • xor(a,b). バイト文字列のXOR; xor(0xF0F0, 0x1234) = 0xE2C4。長さが不等長の2つの引数を指定してこの関数を呼び出すのはエラーです。

4. 暗号の依存関係

HPKE バリアントは、以下のプリミティブに依存する。

  • キーカプセル化メカニズム(KEM):

    • GenerateKeyPair()。鍵ペア (skX, pkX) を生成するためのランダム化アルゴリズム
    • DeriveKeyPair(ikm). ここで、ikm は少なくとも Nsk バイトのエントロピーを持つべきである (SHOULD) (議論は項7.1.3を参照)
    • SerializePublicKey(pkX)。公開鍵 pkX をエンコードした長さ Npk のバイト文字列を生成します。
    • DeserializePublicKey(pkXm): 公開鍵を復元するために、長さ Npk のバイト列をパースします。公開鍵を回復するために、長さ Npk のバイト文字列を解析します。この関数は、pkXmのデシリアライズ失敗時にDeserializeErrorエラーを発生させることがあります。
    • Encap(pkR)。エフェメラルな固定長の対称鍵(KEM共有秘密)と、 pkRに対応する秘密鍵の保持者がデカプセル化できる鍵の固定長のカプセル化を生成するためのランダム化アルゴリズム。
    • Decap(enc, skR)。秘密鍵 skR を用いた決定論的アルゴリズムで、カプセル化された表現 enc からエフェメラル対称鍵 (KEM 共有秘密) を復元します。この関数は、カプセル化に失敗した場合に DecapError を発生させることができます。
    • AuthEncap(pkR, skS) (オプション)。出力は、KEM 共有秘密が秘密鍵 skS の保持者によって生成されたことを保証するエンコードを行います。
    • AuthDecap(enc, skR, pkS) (オプション)。受信者は、KEM 共有秘密が秘密鍵 skS の保持者によって生成されたことを保証する。
    • Nsecret: このKEMによって生成されたKEM共有秘密のバイト数。
    • Nenc。この KEM によって生成されたカプセル化された鍵のバイト数
    • Npk. この KEM のエンコードされた公開鍵のバイト数。
    • Nsk。この KEM のエンコードされた秘密鍵のバイト数。
  • キー導出関数(KDF):

    • Extract(salt, ikm). 入力キーイング材料 ikm とオプションのバイト文字列 salt から、固定長 Nh バイトの疑似ランダムキーを抽出します。
    • Expand(prk, info, L)。疑似ランダムキー prk を、オプションの文字列 info を用いて L バイトの出力キーイング素材に展開します。
    • Nh. Extract() 関数の出力サイズをバイト単位で指定します。
  • AEAD 暗号化アルゴリズム [RFC5116]:

    • Seal(key, nonce, aad, pt). 平文ptと関連データaadを対称鍵とnonce nonceを用いて暗号化・認証し、暗号文とタグctを生成します。この関数は、失敗した場合に NonceOverflowError を発生させることができます。
    • Open(key, nonce, aad, ct)。暗号文とタグ ct を復号化し、平文メッセージ pt を返します。この関数は、失敗すると OpenError または NonceOverflowError を発生させることができます。
    • Nk。このアルゴリズムの鍵のバイト数。
    • Nn. このアルゴリズムのノンスのバイト数.

上記に加えて、KEMは次の関数も公開する場合があります。その動作についてはセクション7.1.2で詳しく説明します。:

  • SerializePrivateKey(skX). SerializePrivateKey(skX): 秘密鍵skXをエンコードした長さNskのバイト文字列を生成する。
  • DeserializePrivateKey(skXm): 秘密鍵 skX をエンコードした長さ Nsk のバイト列を生成する。秘密鍵を復元するために、長さNskのバイト列を解析する。この関数は、skXm のデシリアライズ失敗時に DeserializeError エラーを発生させることがあります。

暗号スイートは、各プリミティブのアルゴリズムの選択を含むトリプル(KEM, KDF, AEAD)である。

これらのプリミティブの具体的なインスタンスのアルゴリズム識別子のセットがセクション7で提供される。アルゴリズム識別子の値は2バイト長である。

GenerateKeyPairはDeriveKeyPair(random(Nsk))として実装できることに注意してください。

表記法pk(skX)は、その使用法とKEMとその実装に応じて、秘密鍵を使用した公開鍵の計算か、あるいは秘密鍵オブジェクトと一緒に格納されていると仮定した公開鍵の取得を表現する構文のいずれかである。

以下の2つの関数は、コンテキストバインディングと同様に、KDF呼び出しのドメイン分離を容易にするために定義されています。

def LabeledExtract(salt, label, ikm):
  labeled_ikm = concat("HPKE-v1", suite_id, label, ikm)
  return Extract(salt, labeled_ikm)

def LabeledExpand(prk, label, info, L):
  labeled_info = concat(I2OSP(L, 2), "HPKE-v1", suite_id,
                        label, info)
  return Expand(prk, labeled_info, L)

suite_id の値は、KDF がどこで使用されるかに依存する。KEMアルゴリズムの中で使用される場合、suite_idは「KEM」で始まり、このKEMアルゴリズムを識別しな ければならない[MUST]。HPKEの残りの部分で使用される場合、「HPKE」で始まり、使用中の暗号スイート全体を識別しな ければならない[MUST]。詳細はセクション4.1とセクション5.1を参照のこと。

4.1. DHベースのKEM

KDF と Diffie-Hellman 群が与えられ,以下の操作を提供するとします.

  • GenerateKeyPair(). 使用される DH グループの鍵ペア (skX, pkX) を生成するランダム化アルゴリズム
  • DeriveKeyPair(ikm). ここで、ikm は少なくとも Nsk バイトのエントロピーを持つべきである (SHOULD) (議論は項7.1.3を参照)
  • DH(skX, pkY). 秘密鍵 skX と公開鍵 pkY を使用して非対話的な DH 交換を行い、長さ Ndh の Diffie-Hellman 共有秘密を生成する。この関数は、セクション7.1.4に記述されているように ValidationError を発生させる可能性がある。
  • Serialize(pk)。公開鍵 pk をエンコードした長さ Npk のバイト文字列を生成します。
  • Deserialize(enc)。公開鍵を復元するために、長さNpkのバイト文字列を解析します。この関数は enc のデシリアライズに失敗したときに DeserializeError エラーを発生させることができます。
  • Ndh。DH() によって生成される Diffie-Hellman 共有秘密のバイト長。
  • Nsk. Diffie-Hellman 秘密鍵のバイト数

この KEM アルゴリズムでは、カプセル化された鍵は Diffie-Hellman 公開鍵であるため、Serialize() を使用して暗号化し、Npk は Nenc と等しくなる。Deserialize()も同様である。

そして、以下のようにしてDHKEM(Group, KDF)と呼ばれるKEMを構築することができ、ここでGroupはDiffie-Hellmanグループ、KDFはKDFを表す。関数パラメータpkR,pkSはデシリアライズ公開鍵であり、encはシリアライズ公開鍵である。7.1.3 節には、本文書で定義されている DHKEM のための DeriveKeyPair 関数の仕様が記載されている。

def ExtractAndExpand(dh, kem_context):
  eae_prk = LabeledExtract("", "eae_prk", dh)
  shared_secret = LabeledExpand(eae_prk, "shared_secret",
                                kem_context, Nsecret)
  return shared_secret

def Encap(pkR):
  skE, pkE = GenerateKeyPair()
  dh = DH(skE, pkR)
  enc = SerializePublicKey(pkE)

  pkRm = SerializePublicKey(pkR)
  kem_context = concat(enc, pkRm)

  shared_secret = ExtractAndExpand(dh, kem_context)
  return shared_secret, enc

def Decap(enc, skR):
  pkE = DeserializePublicKey(enc)
  dh = DH(skR, pkE)

  pkRm = SerializePublicKey(pk(skR))
  kem_context = concat(enc, pkRm)

  shared_secret = ExtractAndExpand(dh, kem_context)
  return shared_secret

def AuthEncap(pkR, skS):
  skE, pkE = GenerateKeyPair()
  dh = concat(DH(skE, pkR), DH(skS, pkR))
  enc = SerializePublicKey(pkE)

  pkRm = SerializePublicKey(pkR)
  pkSm = SerializePublicKey(pk(skS))
  kem_context = concat(enc, pkRm, pkSm)

  shared_secret = ExtractAndExpand(dh, kem_context)
  return shared_secret, enc

def AuthDecap(enc, skR, pkS):
  pkE = DeserializePublicKey(enc)
  dh = concat(DH(skR, pkE), DH(skR, pkS))

  pkRm = SerializePublicKey(pk(skR))
  pkSm = SerializePublicKey(pkS)
  kem_context = concat(enc, pkRm, pkSm)

  shared_secret = ExtractAndExpand(dh, kem_context)
  return shared_secret

LabeledExtractとLabeledExpandの中で使用される暗黙のsuite_id値は以下のように定義されており、kem_idは7.1節で定義されている。

suite_id = concat("KEM", I2OSP(kem_id, 2))

DHKEM で使用される KDF は、選択されたバリアントに応じて、HPKE の残りの部分で使用される KDF と同じか、異なることがある。実装は,DHKEM を実装するとき,適切な KDF の定数 (Nh) と関数呼び出し (LabeledExtract, LabeledExpand) を確実に使用しなければならない[MUST]。HPKE の残りの部分のための KDF の選択に関するコメントについてはセクション 8.3 を、ラベルの根拠についてはセクション 8.5 を参照のこと。

本文書で定義されているDHKEMの亜種については、KEM共有秘密のサイズNsecretは、 KDFの基礎となるハッシュ関数の出力長に等しい。P-256、P-384、およびP-521では、Diffie-Hellman共有秘密のサイズNdhは、それぞれ32、48、および66に等しく、結果として得られる楕円曲線点のx座標に対応する[IEEE1363]。X25519およびX448については、Ndhのサイズはそれぞれ32および56に等しい([RFC7748]、セクション5を参照のこと)。

このドキュメントで定義されているDHKEMの亜種のAuthEncap()およびAuthDecap()関数は、鍵-妥協のなりすまし(KCI)に対して脆弱であることに注意することが重要である。これは、受信者の秘密鍵 skR が漏洩した場合、KEM 共有秘密が秘密鍵 skS の保持者によって生成されたという保証が 保持されないことを意味する。詳細はセクション8.1を参照のこと。

送信者と受信者は、セクション7.1に記載されているように、KEMの入出力を検証しなければならない[MUST]。

5. ハイブリッド公開鍵暗号化

このセクションでは、いくつかの HPKE バリアントを定義する。すべてのバリエーションは、受信者の公開鍵と平文のシーケンスptを受け取り、カプセル化された鍵 enc と暗号文のシーケンスctを生成する。これらの出力は、skR の保持者のみが enc から鍵を復号化し、暗号文を復号化できるように構成されている。すべてのアルゴリズムはまた、鍵の生成に影響を与えるために使用できる(例えば、同一性情報を畳み込むために使用できる)infoパラメータと、使用中のAEADアルゴリズムに付加的な認証データを提供するaadパラメータを取る。

公開鍵で暗号化する基本ケースに加えて、事前共有鍵の所持を認証するもの、KEM 秘密鍵の所持を認証するもの、および事前共有鍵と KEM 秘密鍵の両方の所持を認証するものの 3 つの認証済みバリアントを含める。すべての認証された variant は、暗号化操作に追加の鍵生成材料を提供する。モード間の区別には、以下の半角値が使用される。

これらのケースはすべて、同じ基本的な2段階のパターンに従います。

  1. 送信者と受信者の間で共有される暗号化コンテキストをセットアップします。
  2. そのコンテキストを使用してコンテンツを暗号化または復号化する。

コンテキストは、使用中の AEAD アルゴリズムと鍵をエンコードし、同じ nonce が複数の平文で使用されないように、使用される nonce を管理します。また、セクショ ン 5.3 で説明したように、秘密値をエクスポートするためのインターフェイスも持ちます。この構造とそのインターフェイスについては、セクション5.2を参照のこと。HPKE 復号化は、基礎となる AEAD 復号化が失敗した場合に失敗する。

ここで説明する構造は、関連する非プライベートパラメータ(enc、psk_id など)が、HPKE を利用するアプリケーションによって送信者と受信者の間で転送されることを前提としている。さらに、複数の公開鍵を持つ受信者は、どの公開鍵がカプセル化処理に使用されたかを 判断する何らかの方法を必要とする。例として、アプリケーションはこの情報を送信者から受信者へ暗号文と一緒に送るかもしれない。このようなメカニズムの仕様はアプリケーションに任されている。詳細についてはセクション9を参照のこと。

一部のKEMはAuthEncap()やAuthDecap()をサポートしていないかもしれないことに注意してください。そのようなKEMでは、mode_baseまたはmode_pskのみがサポートされています。新しいKEMを定義する将来の仕様では、これらのモードがサポートされているかどうかを示さなければなりません[MUST]。詳細はセクション7.1.5を参照してください。

このセッションで説明されている手順は、Pythonライクな擬似コードで記述されている。使用されているアルゴリズムは暗黙のままである。

5.1. 暗号化コンテキストの作成

このドキュメントで定義されている HPKE のバリアントは、プロトコル入力を暗号化コンテキストに変換する共通のキースケジュールを共有している。キースケジュールの入力は以下の通りである。

  • mode - 表1で定義されているHPKEモードを示す1バイト値。
  • shared_secret - このトランザクションのために生成されたKEM共有秘密。
  • info - アプリケーションが提供する情報(オプション。デフォルト値は「""」)。
  • psk - 送信者と受信者の両方が保持する事前共有鍵(PSK) (オプション。デフォルト値 "")。
  • psk_id - PSKの識別子(オプション。デフォルト値は「」)。

送信者と受信者は、セクション7.1で述べられているようにKEMの入出力を検証しなければならない[MUST]。

psk と psk_id フィールドは一緒に出現しなければならない[MUST]、または全く出現しない[MUST]。つまり、一方のフィールドに非デフォルト値が与えられた場合、他方のフィールドには非デフォルト値が設定されなければ ならない[MUST]。この要件は、以下の VerifyPSKInputs() でエンコードされています。

psk, psk_id, infoフィールドは、KDF自体、LabeledExtract()の定義、およびそれらと共に使用される定数ラベルに依存する最大の長さを持っています。これらの長さの正確な制限については項7.2.1を参照してください。

鍵スケジュールによって計算される鍵、base_nonce、exporter_secretは、受信者秘密鍵の保持者と、shared_secretと encを生成するためにKEMを使用したエンティティのみが知っているという性質を持っています。

AuthおよびAuthPSKモードでは、受信者は、送信者が秘密鍵skSを保持していたことを保証される。この保証は、セクション4.1およびセクション8.1で述べられているように、鍵の 妥協によるなりすましのため、本文書で定義されているDHKEMの変種では制限される。PSKおよびAuthPSKモードで、必要に応じてpskおよびpsk_id引数が提供された場合、受信者は、送信者が対応する事前共有鍵を保持していたことを保証される。詳細はセクション8.1を参照のこと。

HPKE アルゴリズム識別子、すなわち、表 2、表 3、および表 5 で定義されている KEM kem_id、KDF kdf_id、および AEAD aead_id 2 バイトコードポイントは、実装から暗黙のうちに想定され、パラメータとしては渡されない。LabeledExtract および LabeledExpand で使用する暗黙の suite_id 値は、それらを基に以下のように定義される。

suite_id = concat(
  "HPKE",
  I2OSP(kem_id, 2),
  I2OSP(kdf_id, 2),
  I2OSP(aead_id, 2)
)
default_psk = ""
default_psk_id = ""

def VerifyPSKInputs(mode, psk, psk_id):
  got_psk = (psk != default_psk)
  got_psk_id = (psk_id != default_psk_id)
  if got_psk != got_psk_id:
    raise Exception("Inconsistent PSK inputs")

  if got_psk and (mode in [mode_base, mode_auth]):
    raise Exception("PSK input provided when not needed")
  if (not got_psk) and (mode in [mode_psk, mode_auth_psk]):
    raise Exception("Missing required PSK input")

def KeySchedule<ROLE>(mode, shared_secret, info, psk, psk_id):
  VerifyPSKInputs(mode, psk, psk_id)

  psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id)
  info_hash = LabeledExtract("", "info_hash", info)
  key_schedule_context = concat(mode, psk_id_hash, info_hash)

  secret = LabeledExtract(shared_secret, "secret", psk)

  key = LabeledExpand(secret, "key", key_schedule_context, Nk)
  base_nonce = LabeledExpand(secret, "base_nonce",
                             key_schedule_context, Nn)
  exporter_secret = LabeledExpand(secret, "exp",
                                  key_schedule_context, Nh)

  return Context<ROLE>(key, base_nonce, 0, exporter_secret)

ROLEテンプレートパラメータは、それぞれ送信者または受信者の役割に応じてSまたはRのいずれかである。ロール固有のContext構造とそのAPIを含むキースケジュール出力については、セクション5.2を参照してください。

KeySchedule() の key_schedule_context 構造体は、TLS 提示構文で以下の形式の構造体をシリアライズすることと同等であることに注意してください。

struct {
    uint8 mode;
    opaque psk_id_hash[Nh];
    opaque info_hash[Nh];
} KeyScheduleContext;

5.1.1. 公開鍵への暗号化

HPKE スキームの最も基本的な機能は、与えられた KEM 秘密鍵の保持者に対して暗号化を可能にすることである。SetupBaseS() および SetupBaseR() プロシージャは、与えられた秘密鍵に対して、それぞれ暗号化と復号化に使用できるコンテクストを確立する。

KEM 共有秘密は、KDF を介して、呼び出し元によって提供される明示的な info パラメータと同様に、鍵交換を記述する情報と結合される。

パラメータpkRは公開鍵であり、encはカプセル化されたKEM共有秘密である。

def SetupBaseS(pkR, info):
  shared_secret, enc = Encap(pkR)
  return enc, KeyScheduleS(mode_base, shared_secret, info,
                           default_psk, default_psk_id)

def SetupBaseR(enc, skR, info):
  shared_secret = Decap(enc, skR)
  return KeyScheduleR(mode_base, shared_secret, info,
                      default_psk, default_psk_id)

5.1.2. 事前共有鍵を用いた認証

このバリアントは、受信者が送信者が与えられたPSKを持っていることを認証できるようにすることで、 基本的なメカニズムを拡張したものである。PSKはまた、セクション8.1でより詳細に説明されているように、特定の敵対者モデルでの機密性保証を向上させる。ここでは、両当事者にPSK値pskと、どのPSKを使用すべきかを識別するために使用される別のバイト文字列psk_idの両方が提供されていると仮定する。

ベースケースとの主な違いは、(空の文字列を使用する代わりに) pskとpsk_id値がKDFへのikm入力として使用されることである。

PSKは少なくとも32バイトのエントロピーを持たなければならず[MUST]、長さはNhバイト以上であるべきである[SHOULD]。より詳細な議論についてはセクション8.4を参照のこと。

def SetupPSKS(pkR, info, psk, psk_id):
  shared_secret, enc = Encap(pkR)
  return enc, KeyScheduleS(mode_psk, shared_secret, info, psk, psk_id)

def SetupPSKR(enc, skR, info, psk, psk_id):
  shared_secret = Decap(enc, skR)
  return KeyScheduleR(mode_psk, shared_secret, info, psk, psk_id)

5.1.3. 非対称鍵を用いた認証

このバリアントは、受信者が送信者が与えられたKEM秘密鍵を持っていることを 認証できるようにすることで、基本的な仕組みを拡張しています。この保証は、カプセル化された値encがAuthEncap(pkR, skS)によって生成された場合にのみ、 AuthDecap(enc, skR, pkS)が正しいKEM共有秘密を生成するという仮定に基づいています。言い換えれば、最大でも2つのエンティティ(正確には2つ、DHKEMの場合)がこの秘密を生成した可能性があるので、受信者が最大でも1つであれば、圧倒的な確率で送信者がもう1つであることになる。

基本ケースとの主な違いは、Encap() と Decap() の呼び出しが AuthEncap() と AuthDecap() の呼び出しに置き換えられ、送信者の公開鍵が内部コンテキスト文字列に追加されることです。関数のパラメータ pkR と pkS は公開鍵で、enc はカプセル化された KEM 共有秘密です。

明らかに、このバリアントは、AuthEncap() および AuthDecap() 手続きを提供する KEM でのみ使用できます。

このメカニズムは、送信者のキーペアのみを認証し、他の識別子は認証しません。アプリケーションが、HPKE 暗号文またはエクスポートされた秘密を送信者の別の ID (電子メール アドレスやドメイン名など)にバインドすることを望む場合、この識別子は、ID の誤バインドの問題 [IMB]を回避するために info パラメータに含めるべきである。

def SetupAuthS(pkR, info, skS):
  shared_secret, enc = AuthEncap(pkR, skS)
  return enc, KeyScheduleS(mode_auth, shared_secret, info,
                           default_psk, default_psk_id)

def SetupAuthR(enc, skR, info, pkS):
  shared_secret = AuthDecap(enc, skR, pkS)
  return KeyScheduleR(mode_auth, shared_secret, info,
                      default_psk, default_psk_id)

5.1.4. PSKと非対称鍵の両方を用いた認証

このモードは、PSKと認証済みモードをストレートに組み合わせたものである。前者と同様にPSKを鍵スケジュールに通し、後者と同様に認証されたKEMバリアントを使用する。

def SetupAuthPSKS(pkR, info, psk, psk_id, skS):
  shared_secret, enc = AuthEncap(pkR, skS)
  return enc, KeyScheduleS(mode_auth_psk, shared_secret, info,
                           psk, psk_id)

def SetupAuthPSKR(enc, skR, info, psk, psk_id, pkS):
  shared_secret = AuthDecap(enc, skR, pkS)
  return KeyScheduleR(mode_auth_psk, shared_secret, info,
                      psk, psk_id)

PSKは少なくとも32バイトのエントロピーを持たなければならず[MUST]、長さはNhバイト以上であるべきである[SHOULD]。より詳細な議論はセクション8.4を参照のこと。

5.2. 暗号化と復号化

HPKE は、与えられたセットアップトランザクションに基づいて複数の暗号化操作を行うことを可能にします。セットアップに関与する公開鍵操作は、一般的に対称暗号化や復号化よりも高価であるため、これによりアプリケーションは公開鍵操作のコストを償却し、全体的なオーバーヘッドを削減することができます。

しかし、非暗号化の再利用を避けるためには、この暗号化はステートフルでなければならない。上記の各セットアップ手順は、AEADパラメータとシークレットエクスポートパラメータを格納するロール固有のコンテキストオブジェクトを生成します。AEAD パラメータは以下の内容で構成されます。

  • 使用中の AEAD アルゴリズム
  • 秘密の鍵
  • ベースの nonce base_nonce
  • シーケンス番号(最初は0

シークレットエクスポートのパラメータは次のように構成されています。

  • 使用中の HPKE 暗号スイート
  • シークレットエクスポートインターフェースに使用される exporter_secret。5.3節

AEAD シーケンス番号以外のこれらのパラメータはすべて一定です。シーケンス番号は、nonce の一意性を提供します。各暗号化または復号化操作に使用される nonce は、base_nonce を現在のシーケンス番号で XOR した結果であり、base_nonce と同じ長さのビッグエンディアン整数としてエンコードされています。実装では、nonce の長さよりも短いシーケンス番号を使用してもよい[MAY]が、 シーケンス番号がオーバーフローした場合はエラーを発生させなければならない[MUST]。

暗号化は、送信者から受信者への一方向性である。送信者のコンテキストは、以下のように平文ptと関連データaadを暗号化することができる。

def ContextS.Seal(aad, pt):
  ct = Seal(self.key, self.ComputeNonce(self.seq), aad, pt)
  self.IncrementSeq()
  return ct

受信者のコンテキストは、以下のように、関連付けられたデータaadを持つ暗号文ctを復号化することができる。

def ContextR.Open(aad, ct):
  pt = Open(self.key, self.ComputeNonce(self.seq), aad, ct)
  if pt == OpenError:
    raise OpenError
  self.IncrementSeq()
  return pt

暗号化または復号化の各操作は、使用中のコンテキストのシーケンス番号をインクリメントします。メッセージごとのnonceとシーケンス番号のインクリメントの詳細は以下の通りです。

def Context<ROLE>.ComputeNonce(seq):
  seq_bytes = I2OSP(seq, Nn)
  return xor(self.base_nonce, seq_bytes)

def Context<ROLE>.IncrementSeq():
  if self.seq >= (1 << (8*Nn)) - 1:
    raise NonceOverflowError
  self.seq += 1

送信者のコンテキストは復号化に使用してはならない[MUST NOT]。同様に、受信者のコンテキストは暗号化に使用してはならない[MUST NOT]。より一般的な目的のためにHPKE鍵交換を再利用する高レベルプロトコルは、Secret Exportインターフェイスを使用して、必要に応じて別個の鍵材料を導出することができる。

暗号化と復号が適切な順序で行われ、暗号化と復号の非暗号化が一致するようにするのはアプリケーション次第である。ContextS.Seal() や ContextR.Open() が seq フィールドをオーバーフローさせる場合は、実装はエラーで失敗しなければならない[MUST]。(以下の擬似コードでは、Context<ROLE>.IncrementSeq() は seq がオーバーフローするとエラーで失敗します。内部の Seal() と Open() の呼び出しがコンテキストの AEAD アルゴリズムに対応していることに注意してください。

5.3. 秘密の輸出

HPKEは、TLS 1.3エクスポートインターフェース(参考文献[RFC8446]、セクション7.5)と同様に、可変長PRFを使用して 暗号化コンテキストから秘密をエクスポートするためのインターフェースを提供する。このインターフェイスは、入力としてコンテキスト文字列exporter_contextと希望する長さLをバイト単位で受け取り、対応するKDF Expand関数を使用して内部のexporter秘密から派生した秘密を生成する。本仕様で定義されているKDFでは、Lの最大値は255*Nhである。新しいKDFを定義する将来の仕様では、Lの制限値を指定しなければならない[MUST]。

exporter_contextフィールドは,KDF自体,LabeledExpand()の定義,及びそれらと共に使用される定数ラベルに依存する最大の長さを持つ。この長さの正確な制限については,セクション7.2.1を参照のこと。

def Context.Export(exporter_context, L):
  return LabeledExpand(self.exporter_secret, "sec",
                       exporter_context, L)

5.2 節の暗号化 API を使用しないアプリケーションは、鍵スケジュールを計算する際にエクスポート専用の AEAD ID 0xFFFF を使用することができます。このようなアプリケーションでは、鍵スケジュールの key と base_nonce の値は、上述の Export インタフェースでは使用されないため、計算を回避することができます。

6. 単発API

6.1. 暗号化と復号化

多くの場合、アプリケーションは、受信者の公開鍵に対して単一のメッセージのみを暗号化する。このセクションでは、セクション5.1.1およびセクション5.2で指定されたAPIを使用してステートレスな「シングルショット」暗号化および復号化を実装するHPKE APIのテンプレートを提供する。

def Seal<MODE>(pkR, info, aad, pt, ...):
  enc, ctx = Setup<MODE>S(pkR, info, ...)
  ct = ctx.Seal(aad, pt)
  return enc, ct

def Open<MODE>(enc, skR, info, aad, ct, ...):
  ctx = Setup<MODE>R(enc, skR, info, ...)
  return ctx.Open(aad, ct)

MODE テンプレートパラメータは Base,PSK,Auth,AuthPSK のいずれかです。で示されるオプションのパラメータは、MODE に依存しており、空であっても構いません。例えば、SetupBase()には追加のパラメータはありません。SealAuthPSK()とOpenAuthPSK()は以下のように実装されます。

def SealAuthPSK(pkR, info, aad, pt, psk, psk_id, skS):
  enc, ctx = SetupAuthPSKS(pkR, info, psk, psk_id, skS)
  ct = ctx.Seal(aad, pt)
  return enc, ct

def OpenAuthPSK(enc, skR, info, aad, ct, psk, psk_id, pkS):
  ctx = SetupAuthPSKR(enc, skR, info, psk, psk_id, pkS)
  return ctx.Open(aad, ct)

6.2. 秘密の輸出

アプリケーションは、指定された受信者のみが知っている秘密を導出したい場合もある。このセクションでは、セクション5.3で指定されたAPIを使用してステートレスな「シングルショット」 秘密のエクスポートを実装するHPKE APIのテンプレートを提供する。

def SendExport<MODE>(pkR, info, exporter_context, L, ...):
  enc, ctx = Setup<MODE>S(pkR, info, ...)
  exported = ctx.Export(exporter_context, L)
  return enc, exported

def ReceiveExport<MODE>(enc, skR, info, exporter_context, L, ...):
  ctx = Setup<MODE>R(enc, skR, info, ...)
  return ctx.Export(exporter_context, L)

6.1 節と同様に、MODE テンプレートパラメータは Base、PSK、Auth、AuthPSK のいずれかとなります。で示されるオプションパラメータは MODE に依存し、空であっても構いません。

7. アルゴリズム識別子

7.1. 鍵のカプセル化機構(KEM)について

Auth列は、KEMアルゴリズムがAuthEncap()/AuthDecap()インタフェースを提供するかどうかを示します。他のすべての列の意味は、セクション10.1で説明されています。

7.1.1. SerializePublicKey と DeserializePublicKey

P-256、P-384、およびP-521の場合、KEMのSerializePublicKey()関数は、[SECG]に従って、非圧縮の楕円曲線ポイントからオクテット文字列への変換を行います。DeserializePublicKey()は、非圧縮のOctet-StringからElliptic-Curve-Pointへの変換を実行します。

X25519およびX448では、SerializePublicKey()およびDeserializePublicKey()関数は、これらの曲線では既に公開鍵に固定長のバイト文字列を使用しているため、同一性関数となります。

いくつかのデシリアライズされた公開鍵は、使用する前に検証しなければならない[MUST]。詳細はセクション7.1.4を参照のこと。

7.1.2. SerializePrivateKeyとDeserializePrivateKey

SECG]によると、P-256、P-384、およびP-521の秘密鍵は、使用するカーブのスカラーフィールドの フィールド要素である。このセクションおよびセクション7.1.3では、これらの曲線上のECDHの実装者が、OS2IP()関数と互換性のある 秘密鍵の整数表現を使用することを前提としている。

P-256、P-384、およびP-521については、KEMのSerializePrivateKey()関数は、[SECG]に従ってField-Element-to-Octet-String変換を実行する。秘密鍵が [0, order-1] の範囲外の整数(orderは使用される曲線の順序)の場合、秘密鍵はシリアライズされる前に [0, order-1] の代表値まで削減されなければなりません(MUST)。DeserializePrivateKey()は、[SECG]に従って、Octet-String-to-Field-Element変換を実行します。

X25519およびX448では、秘密鍵はバイト文字列表現と同じであるため、ほとんど処理を行う必要がありません。SerializePrivateKey()関数はその出力をクランプしなければならず[MUST]、DeserializePrivateKey()はその入力をクランプしな ければならない[MUST]。ここで、クランプとは、[RFC7748]のセクション5で定義されている decodeScalar25519()およびdecodeScalar448()関数でkに対して実行されるビット単位の操作を指す。

無効な鍵を早期にキャッチするために、DHKEMの実装者は、デシリアライズされた 秘密鍵が0(mod order)と等価でないことをチェックするべきである[SHOULD]。クランプされた値が0(mod order)になることはないので、このプロパティは X25519およびX448グループに対しては自明に真であることに注意すること。

7.1.3. DeriveKeyPair

DeriveKeyPair()が生成する鍵は、与えられた入力キーイング材料と同程度のエントロピーしか持たない。与えられたKEMに対して、DeriveKeyPair()に与えられるikmパラメータは、少なくともNskの長さを持つべきであり[SHOULD]、少なくともNskバイトのエントロピーを持つべきである[SHOULD]。

任意の DHKEM の DeriveKeyPair() 関数における KDF 関数 (LabeledExtract や LabeledExpand など) のすべての呼び出しは、 (暗号スイートの KDF とは対照的に) DHKEM の関連する KDF を使用する。

P-256、P-384、および P-521 では、KEM の DeriveKeyPair() 関数は、フィールド要素に対して拒絶サンプリングを行います。

def DeriveKeyPair(ikm):
  dkp_prk = LabeledExtract("", "dkp_prk", ikm)
  sk = 0
  counter = 0
  while sk == 0 or sk >= order:
    if counter > 255:
      raise DeriveKeyPairError
    bytes = LabeledExpand(dkp_prk, "candidate",
                          I2OSP(counter, 1), Nsk)
    bytes[0] = bytes[0] & bitmask
    sk = OS2IP(bytes)
    counter = counter + 1
  return (sk, pk(sk))

orderは使用される曲線の順序([NISTCurves]のD.1.2節参照)であり、完全性のために以下に列挙する。

P-256:
0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551

P-384:
0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf
  581a0db248b0a77aecec196accc52973

P-521:
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
  fa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409

ビットマスクは、P-256 および P-384 では 0xFF、P-521 では 0x01 と定義されています。DeriveKeyPairError で DeriveKeyPair() が失敗する可能性は、使用するグループに依存しますが、すべての場合で無視できるほど小さくなります。

X25519 および X448 では、DeriveKeyPair() 関数は入力に KDF を適用します。

def DeriveKeyPair(ikm):
  dkp_prk = LabeledExtract("", "dkp_prk", ikm)
  sk = LabeledExpand(dkp_prk, "sk", "", Nsk)
  return (sk, pk(sk))

7.1.4. 入力と出力の検証

グループが公開鍵の検証を必要とする場合、以下の公開鍵は検証の対象となる。送信者は受信者の公開鍵 pkRを検証しなければならない[MUST]。受信者はエフェメラル公開鍵 pkEを検証しなければならない[MUST]。

P-256、P-384、およびP-521の場合、送信者と受信者は、[keyagreement]の5.6.2.3.4節で定義されているように、 すべての公開鍵入力に対して部分的な公開鍵検証を実行しなければならない[MUST]。これには、座標が正しい範囲にあること、点が曲線上にあること、および点が無限大の点ではない ことの確認が含まれる。さらに、送信者と受信者は、Diffie-Hellman 共有秘密が無限大の点でないことを確認しなければならない[MUST]。

X25519とX448の場合、公開鍵とDiffie-Hellmanの出力は[RFC7748]に記載されているように検証されなければ ならない[MUST]。特に、受信者は、Diffie-Hellman 共有秘密が全ゼロ値であるかどうかをチェックし、そうであればアボートしな ければならない[MUST]。

7.1.5. 将来のKEM

セクション8.2は、HPKE内で使用されるKEMのセキュリティ要件をリストアップしています。

AuthEncap()およびAuthDecap()関数はオプションです。KEMアルゴリズムがそれらを提供しない場合、HPKEのBaseとPSKモードのみがサポートされる。新しいKEMを定義する将来の仕様では、AuthとAuthPSKモードがサポートされているかどうかを示さなければなりません[MUST]。

KEMアルゴリズムは、KEM公開鍵に対して、異なる出力長を持つ異なるエンコーディング アルゴリズムをサポートしてもよい。そのようなKEMアルゴリズムは、出力長がNpkである1つのエンコーディング アルゴリズムのみを指定しなければならない[MUST]。

7.2. 鍵導出関数(KDF)

7.2.1. 入力長の制限

この文書は、上記の KDF に基づいて LabeledExtract() と LabeledExpand() を定義します。これらの関数は、KDF の Extract() および Expand() 関数を呼び出す前に、それぞれの入力 ikm および info に接頭辞を付加します。これにより、入力 psk、psk_id、info、exporter_context、すなわち HPKE アプリケーションによって提供される可変長パラメータで利用可能な最大入力長が減少します。以下の表は、このドキュメントで定義されているKDFについて、これらのフィールドの最大許容長をバイト単位で示しています。

これは、制限値が基礎となるハッシュ関数の最大入力長よりもわずかに小さいことを示しているが、これらの制限値は大きく、実用的なアプリケーションでは到達する可能性は低い。新しいKDFを定義する将来の仕様では、これらの可変長パラメータの境界を指定しなければならない[MUST]。

LabeledExtract() の入力である psk, psk_id, info の値は、以下の式で計算されました。

max_size_hash_input - Nb - size_version_label -
    size_suite_id - size_input_label

LabeledExpand() の入力である exporter_context の値は、以下の式で計算されました。

max_size_hash_input - Nb - Nh - size_version_label -
    size_suite_id - size_input_label - 2 - 1

これらの式において、max_size_hash_inputはハッシュ関数の最大入力長をバイト単位で表し、Nbはハッシュ関数のブロックサイズをバイト単位で表し、size_version_labelは "HPKE-v1 "のサイズをバイト単位で表し、7に相当します。

7.3. 関連づけられたデータを用いた認証済み暗号化 (AEAD) 関数

0xFFFF AEAD ID は、Export インターフェースのみを使用するアプリケーション用に予約されています。

8. セキュリティに関する考察

8.1. セキュリティのプロパティ

HPKE は、送信者と受信者の部分的な秘密を侵害することができる能動的な攻撃者と適応的な攻撃者に対して、動作モードに応じていくつかのセキュリ ティ目標を持っています。望ましいセキュリティ目標を以下に詳述します。

  • メッセージの秘密性。メッセージの秘密性: 選択された暗号文攻撃に対する送信者のメッセージの秘密性
  • エクスポートキーの秘密性。つまり、Context.Export は可変長の PRF である。
  • 送信者認証。PSK、Auth、AuthPSK モードでの送信元の証明

これらのセキュリティ目標は、正直な送信者と正直な受信者の鍵、および正直な送信者と正直な 受信者の鍵が同じである場合と同様に、どのような正直な送信者と正直な受信者の鍵にも適用されると 予想される。

セクション8.6.2で述べたように、HPKEは前方秘匿を提供しない。BaseおよびAuthモードでは、受信者秘密鍵skRがいかなる時点でも危殆化されていない場合にのみ、 秘密性の特性が保持されることが期待される。PSKおよびAuthPSKモードでは、受信者の秘密鍵skRと事前共有鍵がいずれの時点でも漏洩していない場合にのみ、機密性の特性が保持されることが期待されます。

Authモードでは、メッセージ受信時に送信者秘密鍵skSが漏洩していなければ、一般的に送信者認証は保持されると予想されます。AuthPSK モードでは、メッセージ受信時に送信者秘密鍵 skS と事前共有鍵の両方が危殆化していない場合、送信者認証は一般的に保持されると予想されます。

HPKEは、すべての公開鍵をコンテキスト鍵スケジュールに含めることで、ECIESに基づく以前の公開鍵暗号化標準の可鍛性問題( benign malleability [SECG]と呼ばれる)を緩和する。

8.1.1. 鍵の妥協の偽装

この文書で定義されているDHKEMの亜種は、受信者秘密鍵skRが漏洩した場合はAuthモードで、事前共有鍵と受信者秘密鍵skRの両方が漏洩した場合はAuthPSKモードで送信者認証を保持することが期待できないことを意味する[BJM97]に脆弱である。NaClのボックスインターフェース[NaCl]も同様の問題を抱えています。同時に、これにより、否認が可能になります。

ABHKLR20]で示されているように、KEM暗号文はHPKEメッセージにバインドされていないため、鍵侵害のなりすまし攻撃は一般的にHPKE上で可能である。受信者の秘密鍵を知っている敵対者は、観測されたKEM暗号文をデキャップし、 鍵スケジュールを計算し、受信者が元の送信者から来たものとして受け入れる任意のメッセージを暗号化することが できる。重要なことに、これは、鍵侵害のなりすまし攻撃に耐性のある KEM であっても可能である。その結果、この問題を緩和するには、本仕様の範囲外の根本的な変更が必要となる。

鍵と妥協のなりすまし攻撃に対する耐性を必要とするアプリケーションは、この攻撃を 防ぐために余分な手順を取るべきである[SHOULD]。1つの可能性としては、送信者の秘密鍵を使用して(enc, ct)タプル上のデジタル署名を生成することがある - ctはシングルショットまたはマルチショットAPIによって生成されたAEAD暗号文であり、 encは対応するKEMカプセル化された鍵である。

これらの特性を考慮すると、事前共有鍵は、特定の敵対者モデルにおいて認証と秘密性の両方の特性を強化する。HPKEで使用される非量子耐性KEMが量子コンピュータによって破られた場合、事前共有鍵を使用することでセキュリ ティ特性が保持されます。これは、[WireGuard]に記載されているように、事前共有鍵が危殆化していないことを前提としている。

8.1.2. 計算解析

CS01]では、ここで述べたベースモードと本質的に同じ形式のハイブリッド公開鍵暗号化方式は、基礎となるKEMとAEADがIND-CCA2安全である限り、IND-CCA2安全であることが示されている。また、[HHK06]では、ハイブリッド公開鍵暗号化におけるIND-CCA2セキュリティを実現するためには、KEMのIND-CCA2セキュリティとデータカプセル化機構が必要な条件であることが示されている。CS01]で提案された方式と本文書で提案されたベースモード(両方ともHPKEと命名)の主な違いは、KEMとAEADの間にKDFコールを介在させていることである。したがって、このドキュメントの HPKE ベースモードのインスタンス化を分析するには、追加の KDF 呼 び出しが IND-CCA2 プロパティを失敗させないことを検証する必要がある。

本文書で定義されているPSK、Auth、およびAuthPSKモードの解析には、送信者認証プロパティの検証も必要である。PSK モードが鍵スケジュールに補足的な鍵作成材料を追加するだけであるのに対し、Auth および AuthPSK モードは、非標準の認証済み KEM 構成を使用しています。一般的に、HPKEの認証済みモードは、 シグンクリプション[SigncryptionDZ10]のフレーバーとして見て分析することができる。

すべてのHPKEモードの予備的な計算解析が[HPKEAnalysis]で行われ、KEMがDHKEM、AEADが任意のIND-CPAおよびINT-CTXT-secureスキーム、DHグループおよびKDFが以下の条件を満たす場合の漸近的安全性が示されている。

  • DHグループである。ギャップDiffie-Hellman(GDH)問題は、適切なサブグループ[GAP]では困難である。
  • Extract()とExpand() (DHKEMでは)。Extract() はランダムオラクルとしてモデル化できる。Expand()は、第1引数がキーである疑似ランダム関数としてモデル化することができる。
  • Extract() と Expand() (他の場所)。Extract() はランダムオラクルとしてモデル化することができます。Expand()は、第1引数がキーである疑似ランダム関数としてモデル化することができる。

特に、本明細書で定義されているKDFとDHグループ(セクション7.2とセクション7.1参照)は、指定された通りに使用された場合、これらの特性を満たす。HPKEAnalysis]の分析は、これらの制約の下で、HPKEがIND-CCA2セキュリティを提供し続け、上述の追加の特性を提供することを示している。また、この分析では、上述のさまざまな鍵の危殆化のケースの下で、期待されたプロパ ティが保持されることを確認している。解析では、暗号化コンテキストを使用して1つのメッセージを送信し、さらに秘密エクスポートインターフェースを使用して2つの独立した秘密をエクスポートする送信者を考慮しています。

以下の表は、[HPKEAnalysis]の主な結果をまとめたものです。N/Aは、あるプロパティが指定されたモードに適用されないことを意味し、yは、指定されたモードがそのプロパティを満たしていることを意味します。

非DHベースのKEMがHPKEで使用される場合、その安全性を証明するためにさらなる解析が必要である。CS01]からの結果は、ここではどのようなIND-CCA2でも安全なKEMで十分であることを示 しているが、スキームの違いを考えると決定的なものではない。

HPKEのAuthモードシングルショット暗号化APIの詳細な計算解析は、 [ABHKLR20]で行われている。この論文では、signcryption[SigncryptionDZ10]で知られるアウトサイダーおよびインサイダーのセキュリティ用語を使用して、認証されたKEMおよび認証された公開鍵暗号化のセキュリティ概念を定義している。解析の結果、DHKEMのAuthEncap()/AuthDecap()インタフェースが、この文書で指定されているすべてのDiffie-Hellmanグループについて、これらの概念を満たすことが証明され、適切なサブグループ[GAP]においてギャップDiffie-Hellman(GDH)問題が困難であり、HKDFがランダムオラクルとしてモデル化できるという仮定の下で、正確なセキュリティ境界を示した。

さらに、[ABHKLR20]は、HPKEのAuthモードが、本文書で規定されているすべてのKDFとAEADスキームのための認証済み公開鍵暗号化のセキュリティ概念を満たすことを示し、構成定理を証明する。KDF の前提条件は、Extract()とExpand()が、それぞれ第 1 引数が鍵である擬似乱数関数としてモデル化できることである。また、AEADはIND-CPAとIND-CTXTのセキュリティを前提としている。

ABHKLR20]の解析により、HPKEのAuthモードのシングルショット暗号化APIは、本節の冒頭に記載されている所望のメッセージの機密性と送信者認証の特性を満たすことが証明された。

8.1.3. ポスト量子セキュリティ

CS01]、[HPKEAnalysis]、[ABHKLR20]はすべて古典的なセキュリティモデルと仮定を前提としており、量子計算が可能な敵対者を考慮していない。ポスト量子セキュリティの完全な証明には、単にポスト量子KEMを用いるだけでなく、適切なセキュリティモデルと仮定を考慮する必要があります。しかし、HPKEのAuthモードのための[ABHKLR20]の構成定理は、標準的な仮定(すなわち、ランダムオラクル仮定を用いない)をしているだけであり、それは量子的な敵対者に対して保持されると予想されています(わずかに悪い境界ではありますが)。このように、これらの構成定理は、量子的に安全な認証済みKEMと組み合わせて、HPKEのAuthモードの量子的な安全性を保証する。将来的には、[ABHKLR20]の解析をHPKEの他のモードと望ましいセキュリティ特性をカバーするように拡張することができる。PSKまたはAuthPSKモードを使用することで達成される上記のハイブリッド量子耐性特性は、[HPKEAnalysis]では証明されていませんが、この解析ではランダムオラクルモデルを必要とするためです。

8.2. HPKEで使用されるKEMのセキュリティ要件

HPKE内で使用されるKEMは、HPKEがセクション8.1で述べられている所望のセキュリ ティ特性を満たさなければならない[MUST]。特に、KEM共有秘密は、長さNsecretの一様にランダムなバイト文字列でなければならない[MUST]。これは、例えば、KEM 共有秘密がバイト文字列としてエンコードされる前のいくつかの集合の要素として一様にランダムであるだけでは十分ではないことを意味する。

8.2.1. エンキャップ/デキャップインタフェース

セクション8で述べたように、[CS01]は、KEMのEncap()/Decap()インタフェース(BaseおよびPSKモードで使用される)が IND-CCA2-secureであれば、HPKEは所望のセキュリティ特性を満たすことができることを示すいくつかの示唆を提供している。KEMs のための IND-CCA2-security の適切な定義は、[CS01]および[BHK09]にある。

8.2.2. AuthEncap/AuthDecap インターフェース

ABHKLR20]のHPKEのAuthモードシングルショット暗号化APIの解析は、KEMのAuthEncap()/AuthDecap()インタフェースが、同じ論文で定義されているように、マルチユーザのOutsider-CCA、Outsider-Auth、およびInsider-CCAセキュリティを満たす場合、HPKEのAuthモードが所望のセキュリティ特性を達成することを保証する構成定理を提供する。

直感的には、Outsider-CCAセキュリティは機密性を形式化し、Outsider-Authセキュリティは、送信者と受信者の秘密鍵のいずれも漏洩しなかった場合のKEM共有秘密の認証を形式化します。Insider-CCA セキュリティは、送信者の秘密鍵が知られていたり、敵対者によって選択されていた場合に、 KEM 共有秘密の機密性を形式的に保証する。(受信者の秘密鍵が攻撃者によって知られていたり、選択されていたりした場合、機密性は些細なことで破られます。)

インサイダー認証(Insider-Auth)セキュリティの概念は、受信者の秘密鍵が知られていたり、敵対者によって選択されていた場合に、 KEMの共有秘密の認証を形式化するものである。(送信者の秘密鍵が知られていたり、敵対者によって選択されている場合、送信者の名前でKEM暗号文を作成することができる)。セクション8.1で述べたHPKEの類似したInsider-Authセキュリティの概念に対する一般的な攻撃のため、 HPKE内で使用されるKEMのためのInsider-Authセキュリティの定義は有用ではない。

8.3. KDF 上のセキュリティ要件

HPKE の残りの部分のための KDF の選択は、KEM が提供するセキュリティレベルに基づいて行われる べきであり、また、該当する場合には PSK が提供するセキュリティレベルに基づいて行われるべきである。KDF は、少なくとも KEM のセキュリティレベルを持つべきであり、少なくとも PSK が提供するセキュリティレベルを持つべきである[SHOULD]。

8.4. 事前共有鍵の推奨事項

PSKおよびAuthPSKモードでは、PSKは少なくとも32バイトのエントロピーを持たなければならず[MUST]、長さはNhバイト以上でなければならない[SHOULD]。32 バイトより長いが、Nh バイトより短い PSK を使用して許可される。

HPKE はキーの派生機能として HKDF を使用するように指定されます。HKDF は、辞書攻撃を減速させるように設計されていない、[RFC5869]を参照してください。したがって、HPKEのPSKメカニズムは、低エントロピーなパスワードをPSKとして使用するのには適していない:敵対者がKEM共有秘密shared_secretを知っていて、良いPSKと間違ったPSKを区別することを可能にするオラクルへのアクセスを持っているシナリオでは、PSK回復攻撃を実行することができる。このオラクルは、捕捉されたHPKE暗号文に対する復号操作、または誤ったPSKを使用したときに観察可能なほど異なる他の受信者の動作であり得る。敵対者は、1人の参加者のすべてのKEM秘密鍵を知っている場合、KEM共有秘密shared_secretを知っている。PSKモードでは、敵対者が送信者として振る舞う場合、これは些細なことである。

エントロピーの低いPSKを回復するために、このシナリオの攻撃者は辞書攻撃を簡単に行うことができる。可能な PSK 値の集合 S が与えられると、攻撃者は S の各値に対して HPKE 暗号文を生成し、その結果得られた暗号文をオラクルに送信して、受信者がどの PSK を使用しているかを知る。さらに、HPKE は鍵をコミットしない AEAD スキームを使用するため、攻撃者は、ブロック単位の最大メッセージ長である k に比例する長さの暗号文を使用して、約 m + log k のクエリで、|S| = m*k の S 個の可能な PSK 値のセットから PSK を回復することができるパーティショニングオラクル攻撃 [LGR20] を実行することができる。したがって、PSK は、攻撃者にとって m + log k が禁止値となるように十分なエントロピーを持って選択されなければならない (例えば、2^128)。

8.5. 領域分離

HPKE は、両方の KDF が同じ KDF によってインスタンス化されるような DHKEM バリアント DHKEM(Group, KDF') と KDF を組み合わせることを可能にします。設計上、DHKEM 内の Extract() と Expand() への呼び出しと HPKE の残りの部分は、2 番目のパラメータに対して異なる接頭辞なしのエンコーディングを持つ。これは、LabeledExtract() および LabeledExpand() への呼び出しにおける異なるプレフィックスフリーのラベルパラメータによって達成される。これは、すべての Extract() と Expand() の呼び出しの入力ドメインを分離するのに役立ちます。また、同じKDFによってインスタンス化された場合でも、それらを独立した関数としてモデル化することを正当化します。

将来の KEM インスタンスは、すべての内部の Extract() と Expand() の呼び出しが、HPKE の残りの部分の Extract() と Expand() の呼び出しから独立した関数としてモデル化できるようにしなければなりません (MUST)。これを確実にする一つの方法は、「HPKE-v1」とは異なる識別子を持つ、同等または類似の接頭辞スキームを使用することである。KEM が、HKDF の場合の Hash() や HMAC() のような HPKE の Extract() や Expand() で内部的に使用される関数を直接呼び出す場合には、特に注意を払う必要がある。これらの呼び出しへの入力が、Extract または Expand 内のこれらの関数の内部呼び出しへの入力と衝突しないようにしなければならない[MUST]。HPKE の KeySchedule() では、これは、任意の長さの info と psk_id の入力に対して Hash() の代わりに Extract() を使用することで回避される。

LabeledExtract() および LabeledExpand() で使用される文字列リテラル「HPKE-v1」は、HPKE で導出された秘密が、たとえ他のスキームと同じ Diffie-Hellman または KEM 共有秘密から導出される可能性があっても、スキームの名前にバインドされることを確実にする。

8.6. アプリケーションの埋め込み

HPKE は、かなり低レベルのメカニズムであるように設計されている。その結果、HPKE が埋め込まれているアプリケーションによって特定のプロパティが提供されることを前提とし、他のメカニズムによって提供される特定のセキュリ ティプロパティを残す。

8.6.1. 外部要件

HPKE がアプリケーションに課す主な要件は、暗号文が ContextS.Seal() によって生成された順序と同じ順序で ContextR.Open() に提示されなければならない[MUST]という要件である。シングルショット API を使用している場合 (セクション 6 を参照)、これは単純に真である (暗号文は 1 つしか存在しないので)。同一コンテキスト上で Open() / Seal() の複数回の呼び出しを可能にするアプリケーションは、上述の順序付けプロパティを強制しなければならない[MUST]。

この文字の順序付けの要件は、通常、暗号化されたメッセージのフレーミングでシーケンス番号を提供することで満たされます。HPKE 暗号化されたメッセージの順序を決定するために使用される情報は何であれ、 ContextS.Seal() と ContextR.Open() に渡される AAD に含まれるべきである[SHOULD]。このスキームの詳細はアプリケーション次第である。

HPKE は失われたメッセージを許容しない。アプリケーションは、メッセージが失われたことを検出できなければならない[MUST]。回復不可能な損失が検出されたとき、アプリケーションは、関連するHPKEコンテキストをすべて破棄しな ければならない[MUST]。

8.6.2. 非目標

HPKEは、より高レベルのプロトコルが提供するかもしれないいくつかの機能を提供しない。

  • ダウングレード防止 - HPKEは、送信者と受信者が使用するアルゴリズムに同意することを前提としている。これらのアルゴリズムがどのようにネゴシエートされるかによっては、仲介者が 2 つの当事者に最適でないアルゴリズムを使用するように強制することが可能であるかもしれない。
  • リプレイ保護 - ContextS.Seal() で生成されたのと同じ順序で ContextR.Open() 関数に暗号文が提示されるという要件は、与えられたコンテキストから得られる暗号文のストリーム内でのリプレイ保護の程度を提供します。HPKE は他のリプレイ保護を提供しません。
  • 前方秘匿 - HPKE 暗号文は前方秘匿ではありません。Base および Auth モードでは、受信者の公開暗号化キーが漏洩した場合、与えられた暗号文を復号化することができます。PSK および AuthPSK モードでは、受信者の秘密鍵と PSK が漏洩した場合、与えられた暗号文を復号化できます。
  • 平文長の隠蔽 - HPKE が生成する AEAD 暗号文は平文長を隠蔽しません。このレベルのプライバシーを必要とするアプリケーションは、適切なパディング機構を使用すべきである。プロトコル固有のパディングポリシーの例については、[I-D.ietf-tls-esni]および[RFC8467]を参照のこと。

8.7. 双方向暗号化

セクション5.2で説明したように、HPKE暗号化は送信者から受信者への一方向性である。双方向の暗号化を必要とするアプリケーションは、セクション5.3節のシークレットエクスポートインタフェースを使用して必要なキーイング材料を導出することができる。そのようなキーイング材料のタイプと長さは、アプリケーションのユースケースに依存する。

例として、アプリケーションが受信者から送信者への AEAD 暗号化を必要とする場合、以下のように、対応する HPKE コンテキストから鍵と nonce を導出することができます。

key = context.Export("response key", Nk)
nonce = context.Export("response nonce", Nn)

この例では、各シークレットの長さは、対応する HPKE コンテキストで使用される AEAD アルゴリズムに基づいている。

送信者認証に関するHPKEの制限が、このコンテキストでは受信者認証の制限になることに注意してください。特に、Baseモードでは、リモートパーティの認証はまったくない。リモートパーティが特定の秘密鍵を保持していることが証明されているAuthモードでも、この認証は、セクショ ン8.1.1で議論されているように、鍵侵害のなりすましの対象となる。

8.8. メタデータの保護

HPKEの認証モード(PSK、Auth、AuthPSK)は、受信者が送信者に使用する鍵材料を知っていることを必要とする。これは、PSK ID(上記のpsk_id)および/または送信者の公開鍵(pkS)を送信することで、アプリケーショ ンで信号化することができる。しかし、これらの値自体は、あるアプリケーションのコンテキストでは、送信者を特定する可能性があるため、機密性が高いと考えられるかもしれません。

鍵のさらなるプロビジョニングを必要とせずにこれらのメタデータ値を保護したいアプリケーションは、 認証されていないベースモードを使用してHPKEの追加インスタンスを使用することができる。アプリケーションは以前に(psk_id, pkS, enc, ciphertext)を送信していたかもしれないが、今回は(enc2, ciphertext2, enc, ciphertext)を送信し、(enc2, ciphertext2)は psk_id と pkS の暗号化を表す。

このアプローチのコストは、送信者と受信者それぞれに追加のKEM処理が必要となる。BNT19]の非暗号化保護スキームを他のメタデータをカバーするように拡張できれば、より低コストのアプロー チ(対称演算のみを含む)が可能になる可能性がある。しかし、この構築にはさらなる分析が必要である。

9. メッセージの符号化

この文書は、HPKE メッセージのためのワイヤフォーマットのエンコーディングを指定しない。したがって、HPKE を採用するアプリケーションは、最低限、カプセル化された値 enc、暗号文の値 (複数ある場合はその順序)、および暗黙ではない情報値を含む、あいまいさのないエンコーディングメカニズムを 指定しなければならない。非暗黙的な値の一例として、カプセル化に使用される受信者公開鍵があるが、これは受信者が複数の公開鍵を持っている場合に必要となる。

10. IANAの考慮事項

この文書は、3つの新しいIANAレジストリの作成を要求します。

  • HPKE KEM識別子
  • HPKE KDF識別子
  • HPKE AEAD識別子

これらのレジストリはすべて「ハイブリッド公開鍵暗号化」の見出しの下に置かれ、仕様要求ポリシー[RFC8126]の下で管理されるべきである。

10.1. KEM 識別子

HPKE KEM 識別子」レジストリは、HPKE で使用するために定義された鍵カプセル化アルゴリズムの識別子をリストアップする。これらは 2 バイトの値なので、最大値は 0xFFFF = 65535 です。

テンプレート。

  • 値。アルゴリズムの 2 バイト識別子
  • KEM: アルゴリズムの名前
  • Nsecret: アルゴリズムによって生成される KEM 共有秘密のバイト数
  • Nenc. アルゴリズムによって生成されたエンコードされたカプセル化された鍵のバイト数
  • Npk. アルゴリズム用にエンコードされた公開鍵のバイト数
  • Nsk. アルゴリズムのエンコードされた秘密鍵のバイト数
  • Auth。このアルゴリズムが AuthEncap()/AuthDecap() インターフェースを提供するかどうかを示すブール値。
  • 参照。このアルゴリズムが定義されている場所
    初期内容。表2に記載

10.2. KDF識別子

HPKE KDF Identifiers」レジストリは、HPKE で使用するために定義された鍵派生関数の識別子をリストアップする。これらは 2 バイトの値なので、最大値は 0xFFFF = 65535 です。

テンプレート。

  • 値。アルゴリズムの 2 バイト識別子
  • KDFです。アルゴリズムの名前
  • Nh. Extract関数の出力サイズをバイト単位で指定します。
  • 参照。このアルゴリズムが定義されている場所

初期内容。表3に記載

10.3. AEAD 識別子

HPKE AEAD Identifiers」レジストリには、HPKE で使用するために定義された、関連付けられたデータを使用した認証済み暗号化 (AEAD) アルゴリズム用の識別子がリストアップされています。これらは 2 バイトの値なので、最大値は 0xFFFF = 65535 です。

テンプレート。

  • 値。アルゴリズムの 2 バイト識別子
  • AEAD:アルゴリズムの名前
  • Nk. このアルゴリズムの鍵のバイト数
  • Nn. このアルゴリズムのノンスのバイト数.
  • 参照。このアルゴリズムが定義されている場所

初期内容。表5に記載

作成者以外のコメントは許可されていません