AES-CTR HMAC ストリーミング AEAD

このドキュメントでは、AES-CTR HMAC ストリーミングキー(type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey として proto 形式でエンコード)によって表される数学関数を正式に定義します。

この暗号化は [HRRV15]1 に大まかに基づいています。セキュリティの分析については、[HS20]2 をご覧ください。また、Tink の多言語テストには test_manually_created_test_vector を含むテスト aes_ctr_hmac_streaming_key_test.py があり、暗号テキストの取得方法の詳細なチュートリアルが含まれています。

キーとパラメータ

鍵は次の部分で記述します(このドキュメントのサイズはすべてバイト単位です)。

  • \(\mathrm{InitialKeyMaterial}\): バイト文字列: 初期鍵マテリアル。
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
  • \(\mathrm{HmacHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
  • \(\mathrm{HmacTagSize} \in \mathbb{N}\).

有効なキーは、さらに次のプロパティも満たします。

  • \(\mathrm{len}(\mathrm{InitialKeyMaterial}) \geq \mathrm{DerivedKeySize}\).
  • もし \(\mathrm{HmacHashType} = \mathrm{SHA1}\) それなら \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\)。
  • もし \(\mathrm{HmacHashType} = \mathrm{SHA256}\) それなら \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\)。
  • もし \(\mathrm{HmacHashType} = \mathrm{SHA512}\) それなら \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\)。
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (後述の\(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) と同じです)。

これらのプロパティのいずれも満たさない鍵は、Tink によって拒否されます(鍵の解析時または対応するプリミティブの作成時)。

暗号化関数

関連データ\(\mathrm{AssociatedData}\)を使用してメッセージを \(\mathrm{Msg}\) 暗号化するには、ヘッダーを作成し、メッセージをセグメントに分割し、各セグメントを暗号化して、セグメントを連結します。以下では、この手順について説明します。

ヘッダーの作成

ヘッダーを作成するには、まず、 \(\mathrm{Salt}\)長さ \(\mathrm{DerivedKeySize}\)の均一なランダム文字列を選択します。次に、長さ 7 の均一なランダムな文字列\(\mathrm{NoncePrefix}\) を選択します。

次に、\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)を設定します。ここで、ヘッダーの長さが 1 バイトにエンコードされます。\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)と記録されます。

次に、HKDF3 とハッシュ関数を使用して、 \(\mathrm{HkdfHashType}\) \(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\)というメッセージの長さ\(\mathrm{DerivedKeySize} + 32\) の鍵マテリアルを計算します。 入力は、対応する\(\mathrm{HKDF}\)の入力に使用されます。 \(\mathrm{InitialKeyMaterial}\) is \(\mathrm{ikm}\)、\(\mathrm{Salt}\) はソルト、\(\mathrm{AssociatedData}\) は \(\mathrm{info}\)として使用されます。

その後、文字列 \(k\) は、\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) と \(\mathrm{len}(k_2) = 32\)のように、 \(k_1 \| k_2 := k\)の 2 つの部分に分割されます。

メッセージの分割

次に、 \(M\) メッセージは \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\)に分割されます。

その長さは、次の条件を満たすように選択されます。

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{HmacTagSize}\}\).
  • \(n > 1\)の場合は、 \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{HmacTagSize}\}\)。
  • \(n > 1\)の場合、 \(M_{0}, \ldots, M_{n-2}\) は上記の制約に従って最大長にする必要があります。

この分割では、 \(n\) 最大 \(2^{32}\)になる可能性があります。それ以外の場合、暗号化は失敗します。

ブロックの暗号化

セグメント \(M_i\)を暗号化するには、まず\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\)を計算します。ここで、ビッグ エンディアン エンコードを使用して \(\mathrm{i}\) 4 バイトでエンコードします。$i < n-1$ の場合は $b$ を 0x00、そうでない場合は 0x01 を設定します。

次に、 \(M_i\) AES CTR 鍵 \(k_1\)と初期化ベクトル\(\mathrm{IV}_i\)を使用して暗号化します。つまり、AES の呼び出しへの入力は\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\)です。ここで、 \(\mathrm{IV}_i\) はビッグ エンディアン整数として解釈されます。これにより、 \(C'_i\)が生成されます。

HMAC を使用して、 \(\mathrm{HmacHashType}\) で指定されたハッシュ関数と、連結\(\mathrm{IV}_i \| C'_i\)に対するキー \(k_2\) を使用してタグを計算します。

次に、暗号テキストの後にタグを連結して、 \(C_i\)を取得します。

セグメントを連結する

最後に、すべてのセグメントが最終的な暗号テキストである\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)として連結されます。

復号関数

復号とは、単に暗号化を反転させるだけです。ヘッダーを使用してノンスを取得し、暗号テキストの各セグメントを個別に復号します。

API は、ランダム アクセス、つまりファイルの末尾を検査せずにファイルの先頭にアクセスすることを許可します(通常は許可します)。 \(C_i\)から \(M_i\) を復号でき、前と残りのすべての暗号テキスト ブロックを復号できるため、これは意図的なものです。

ただし、API では、ユーザーがファイル終了エラーと復号エラーを混同しないように注意する必要があります。どちらの場合も API はおそらくエラーを返す必要があり、その差分を無視すると、攻撃者がファイルを効果的に切り捨てる可能性があります。

キーのシリアル化と解析

キーを「Tink Proto」形式でシリアル化するには、まず aes_ctr_hmac_streaming.proto にある proto にパラメータをわかりやすい方法でマッピングします。フィールド version は 0 に設定する必要があります。次に、通常の proto シリアル化を使用してこれをシリアル化し、結果の文字列を KeyData プロトコルのフィールド値に埋め込みます。type_url フィールドを type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey に設定します。次に、key_material_typeSYMMETRIC に設定し、これをキーセットに埋め込みます。通常、output_prefix_typeRAW に設定します。例外として、output_prefix_type に異なる値を設定してキーが解析された場合、Tink は RAW または以前の値のいずれかを書き込むことがあります。

キーを解析するには、上記のプロセスを(proto を解析するときの通常の方法)を逆にします。フィールド key_material_type は無視されます。output_prefix_type の値は無視することも、output_prefix_typeRAW と異なるキーは拒否することもできます。version が 0 以外のキーは拒否されます。

参照


  1. [HRRV15] Hoang、Reyhanitabar、Rogaway、Vizarオンライン認証暗号化とノンス再利用の不正使用耐性。CRYPTO 2015 https://eprint.iacr.org/2015/189 

  2. [HS20] Google の Tink ライブラリのストリーミング暗号化のセキュリティ。Hoang, Shen、2020 年。 https://eprint.iacr.org/2020/1019 

  3. [HKDF] HMAC ベースの Extract-and-Expand Key Derivation Function(HKDF)、RFC 5869。https://www.rfc-editor.org/rfc/rfc5869