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

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

この暗号化は、[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{Msg}\) 関連データを含む\(\mathrm{AssociatedData}\)メッセージを暗号化するには、ヘッダーを作成し、メッセージをセグメントに分割し、各セグメントを暗号化して、セグメントを連結します。これらの手順について以下で説明します。

ヘッダーの作成

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

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

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

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

メッセージの分割

次に、メッセージ \(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 バイトにエンコードし、バイト $b$ を $i < n-1$ の場合は 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\)が生成されます。

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

次に、暗号文にタグを連結して \(C_i\)を取得します。

セグメントを連結する

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

復号関数

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

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

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

キーのシリアル化と解析

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

キーを解析するには、上記のプロセスを逆にします(プロトコルを解析する場合の通常の方法で)。フィールド 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 ベースの抽出拡張鍵導出関数(HKDF)、RFC 5869。https://www.rfc-editor.org/rfc/rfc5869