次の方法で共有


ASP.NET Core でのコンテキスト ヘッダー

背景と理論

データ保護システムにおける "キー" は、認証された暗号化サービスを提供できるオブジェクトを意味します。 各キーは一意の ID (GUID) によって識別され、それと共にアルゴリズムの情報とエントロピ マテリアルが伝達されます。 各キーは一意のエントロピを伝達することを目的としていますが、システムでそれを強制することはできません。また、キー リング内の既存のキーのアルゴリズム情報を変更することによってキー リングを手動で変更する可能性がある開発者を考慮に入れる必要もあります。 これらの場合にセキュリティ要件を達成するため、データ保護システムには暗号化方式の指定という概念があります。これにより、複数の暗号化アルゴリズムにわたって 1 つのエントロピ値を安全に使用することができます。

暗号化方式の指定をサポートするほとんどのシステムでは、アルゴリズムに関する特定の識別情報をペイロード内に含めることで、それを行っています。 アルゴリズムの OID は、通常、この場合に適した候補となります。 ただし Microsoft では、1 つの問題に遭遇しました。同じアルゴリズムを指定する方法が複数あるという問題です。 "AES" (CNG) と managed Aes や、AesManaged、AesCryptoServiceProvider、AesCng、RijndaelManaged (特定のパラメーターの場合) といったクラスはすべて、実際には同じものであり、これらすべての、正しい OID へのマッピングを維持する必要がありました。 開発者がカスタム アルゴリズム (または AES の別の実装) を提供したければ、その OID を Microsoft に通知する必要があったのです。 この追加の登録手順によって、システム構成が特に困難になります。

Microsoft は、一歩離れて見ることで、間違った方向から問題に取り組んでいると判断しました。 OID を見るとアルゴリズムがどのようなものかわかりますが、Microsoft は実際には、これは重要であると考えていません。 2 つの異なるアルゴリズムで 1 つのエントロピ値を安全に使用する必要がある場合、アルゴリズムが実際にどのようなものかを知る必要はありません。 Microsoft が実際に重要であると考えているのは、それらがどのように動作するかです。 適正な対称ブロック暗号アルゴリズムはすべて、強力な擬似乱数順列 (PRP) でもあります。入力 (キー、チェーン モード、IV、プレーンテキスト) を修正すると、暗号文の出力は、極めて高い確率で、同じ入力が指定された他の対称ブロック暗号アルゴリズムとはまるで異なるものとなります。 同様に、適正なキー付きハッシュ関数も強力な擬似乱数関数 (PRF) であり、固定された入力セットを指定した場合の出力は、他のどのキー付きハッシュ関数ともまったく異なるものになります。

Microsoft では、この強力な PRP と PRF の概念を利用してコンテキスト ヘッダーを構築しています。 このコンテキスト ヘッダーは、基本的に、特定の操作で使用されるアルゴリズムに対する安定した拇印として機能します。そして、これによって、データ保護システムで必要とされる暗号化方式の指定が実現されています。 このヘッダーは再現可能で、後でサブキー派生プロセスの一部として使用されます。 コンテキスト ヘッダーを作成する方法は、基になるアルゴリズムの動作モードに応じて異なるものが 2 つあります。

CBC モード暗号化 + HMAC 認証

コンテキスト ヘッダーは、以下の構成要素からなります。

  • [16 ビット] 値 00 00。これは "CBC 暗号化 + HMAC 認証" を意味するマーカーです。

  • [32 ビット] 対称ブロック暗号アルゴリズムのキーの長さ (バイト単位、ビッグ エンディアン)。

  • [32 ビット] 対称ブロック暗号アルゴリズムのブロック サイズ (バイト単位、ビッグ エンディアン)。

  • [32 ビット] HMAC アルゴリズムのキーの長さ (バイト単位、ビッグ エンディアン)。 (現在のところ、キー サイズは常にダイジェスト サイズと一致します。)

  • [32 ビット] HMAC アルゴリズムのダイジェスト サイズ (バイト単位、ビッグ エンディアン)。

  • EncCBC(K_E, IV, "")。これは、空の文字列入力を指定した場合の、対称ブロック暗号アルゴリズムの出力であり、ここで IV は、すべてゼロのベクターです。 K_E の構造については後述します。

  • MAC(K_H, "")。これは、空の文字列入力を指定した場合の、HMAC アルゴリズムの出力です。 K_H の構造については後述します。

理想的なのは、K_EK_H にすべてゼロのベクターを渡すことができるという状態です。 ただし Microsoft では、基になるアルゴリズムが、何らかの操作 (特に DES と 3DES) を実行する前に弱いキーが存在するかどうか調べるという状況を回避したいと考えています。そうすることで、すべてゼロのベクターのように、簡単であったり繰り返し可能であったりするパターンが使用されないようにするのです。

代わりに、長さ 0 のキー、ラベル、コンテキストを指定し、基になる PRF としては HMACSHA512 を使用して、カウンター モードで NIST SP800-108 KDF を使用します (セクション 5.1 の「NIST SP800-108」を参照)。 | K_E | + | K_H | バイトの出力を派生させてから、結果を K_E および K_H 自体に分解します。 これは数学的には次のように表されます。

( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

例: AES-192-CBC + HMACSHA256

例として、対称ブロック暗号アルゴリズムが AES-192-CBC で、検証アルゴリズムが HMACSHA256 である場合を考えます。 システムでは、以下の手順を使用してコンテキスト ヘッダーが生成されます。

まず、( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "") の実行を許可します。ここで | K_E | = 192 bits| K_H | = 256 bits は、指定されたアルゴリズムに従っています。 これは下の例では K_E = 5BB6..21DDK_H = A04A..00A9 になっています。

5B B6 C9 83 13 78 22 1D 8E 10 73 CA CF 65 8E B0
61 62 42 71 CB 83 21 DD A0 4A 05 00 5B AB C0 A2
49 6F A5 61 E3 E2 49 87 AA 63 55 CD 74 0A DA C4
B7 92 3D BF 59 90 00 A9

次に、上記のように、IV = 0*K_E が指定されて AES-192-CBC の Enc_CBC (K_E, IV, "") が計算されます。

result := F474B1872B3B53E4721DE19C0841DB6F

次に、上記のように、K_H が指定されて HMACSHA256 の MAC(K_H, "") が計算されます。

result := D4791184B996092EE1202F36E8608FA8FBD98ABDFF5402F264B1D7211536220C

これで、下の完全なコンテキスト ヘッダーが生成されます。

00 00 00 00 00 18 00 00 00 10 00 00 00 20 00 00
00 20 F4 74 B1 87 2B 3B 53 E4 72 1D E1 9C 08 41
DB 6F D4 79 11 84 B9 96 09 2E E1 20 2F 36 E8 60
8F A8 FB D9 8A BD FF 54 02 F2 64 B1 D7 21 15 36
22 0C

このコンテキスト ヘッダーが、認証された暗号化アルゴリズム ペア (AES-192-CBC 暗号化 + HMACSHA256 検証) の拇印です。 上で説明した構成要素は以下のとおりです。

  • マーカー (00 00)

  • ブロック暗号キーの長さ (00 00 00 18)

  • ブロック暗号ブロック サイズ (00 00 00 10)

  • HMAC キーの長さ (00 00 00 20)

  • HMAC ダイジェスト サイズ (00 00 00 20)

  • ブロック暗号 PRP 出力 (F4 74 - DB 6F)

  • HMAC PRF 出力 (D4 79 - end)

Note

CBC モードの暗号化と HMAC 認証のコンテキスト ヘッダーは、アルゴリズムの実装が Windows CNG によって提供されるか、マネージド型の SymmetricAlgorithm および KeyedHashAlgorithm によって管理されるかを問わず、同様に構築されます。 これにより、異なるオペレーティング システムで実行されているアプリケーションでは、OS 間でアルゴリズムの実装が異なっている場合であっても、同じコンテキスト ヘッダーを確実に生成できます。 (実際には、KeyedHashAlgorithm は、適切な HMAC である必要はありません。任意のキー付きハッシュ アルゴリズム タイプにすることができます。)

例: 3DES-192-CBC + HMACSHA1

まず、( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "") の実行を許可します。ここで | K_E | = 192 bits| K_H | = 160 bits は、指定されたアルゴリズムに従っています。 これは下の例では K_E = A219..E2BBK_H = DC4A..B464 になっています。

A2 19 60 2F 83 A9 13 EA B0 61 3A 39 B8 A6 7E 22
61 D9 F8 6C 10 51 E2 BB DC 4A 00 D7 03 A2 48 3E
D1 F7 5A 34 EB 28 3E D7 D4 67 B4 64

次に、上記のように、IV = 0*K_E が指定されて 3DES-192-CBC の Enc_CBC (K_E, IV, "") が計算されます。

result := ABB100F81E53E10E

次に、上記のように、K_H が指定されて HMACSHA1 の MAC(K_H, "") が計算されます。

result := 76EB189B35CF03461DDF877CD9F4B1B4D63A7555

これにより、次に示すように、認証された暗号化アルゴリズム ペア (3DES-192-CBC 暗号化 + HMACSHA1 検証) の拇印である完全なコンテキスト ヘッダーが生成されます。

00 00 00 00 00 18 00 00 00 08 00 00 00 14 00 00
00 14 AB B1 00 F8 1E 53 E1 0E 76 EB 18 9B 35 CF
03 46 1D DF 87 7C D9 F4 B1 B4 D6 3A 75 55

コンポーネントは以下のように細分化されます。

  • マーカー (00 00)

  • ブロック暗号キーの長さ (00 00 00 18)

  • ブロック暗号ブロック サイズ (00 00 00 08)

  • HMAC キーの長さ (00 00 00 14)

  • HMAC ダイジェスト サイズ (00 00 00 14)

  • ブロック暗号 PRP 出力 (AB B1 - E1 0E)

  • HMAC PRF 出力 (76 EB - end)

Galois/Counter Mode 暗号化 + 認証

コンテキスト ヘッダーは、以下の構成要素からなります。

  • [16 ビット] 値 00 01。これは "CGM 暗号化 + 認証" を意味するマーカーです。

  • [32 ビット] 対称ブロック暗号アルゴリズムのキーの長さ (バイト単位、ビッグ エンディアン)。

  • [32 ビット] 認証される暗号化操作時に使用される nonce サイズ (バイト単位、ビッグ エンディアン)。 (Microsoft システムの場合、nonce サイズは 96 ビットに固定されています。)

  • [32 ビット] 対称ブロック暗号アルゴリズムのブロック サイズ (バイト単位、ビッグ エンディアン)。 (GCM の場合、ブロック サイズは 128 ビットに固定されています。)

  • [32 ビット] 認証される暗号化関数によって生成される認証タグのサイズ (バイト単位、ビッグ エンディアン)。 (Microsoft システムの場合、タグ サイズは 128 ビットに固定されています。)

  • [128 ビット] Enc_GCM (K_E, nonce, "") のタグ。これは、空の文字列入力を指定した場合の、対称ブロック暗号アルゴリズムの出力であり、ここで nonce は 96 ビットの、すべてゼロのベクターです。

K_E は、CBC 暗号化 + HMAC 認証シナリオと同じメカニズムを使用して派生されます。 ただし、ここには影響を及ぼす K_H がないため、本質的に | K_H | = 0 があることになり、このアルゴリズムは次の形式に折りたたまれます。

K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

例: AES-256-GCM

まず、K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "") の実行を許可します。ここで、| K_E | = 256 bits です。

K_E := 22BC6F1B171C08C4AE2F27444AF8FC8B3087A90006CAEA91FDCFB47C1B8733B8

次に、上記のように、nonce = 096K_E が指定されて AES-256-GCM の認証タグ Enc_GCM (K_E, nonce, "") が計算されます。

result := E7DCCE66DF855A323A6BB7BD7A59BE45

これで、下の完全なコンテキスト ヘッダーが生成されます。

00 01 00 00 00 20 00 00 00 0C 00 00 00 10 00 00
00 10 E7 DC CE 66 DF 85 5A 32 3A 6B B7 BD 7A 59
BE 45

コンポーネントは以下のように細分化されます。

  • マーカー (00 01)

  • ブロック暗号キーの長さ (00 00 00 20)

  • nonce のサイズ (00 00 00 0C)

  • ブロック暗号ブロック サイズ (00 00 00 10)

  • 認証タグのサイズ (00 00 00 10)

  • ブロック暗号の実行から得られた認証タグ (E7 DC - end)