web-dev-qa-db-ja.com

PSK TLSでは、暗号化に使用される鍵はどのように導出されますか?

TLS_PSK_WITH_3DES_EDE_CBC_SHAを使用して、安全な通信チャネルを介して送信されたメッセージを復号化しようとしています。これで、クライアントの乱数、サーバーの乱数、PSK ID、およびPSK値がわかりました。私の問題は、暗号化と復号化に使用されたキーをどのようにして導出するかです。

私は、RFC 2246 TLS 1.0、およびTLS標準のRFC 4279事前共有鍵暗号スイートを読みました。私の理解では、クライアントとサーバー間のPSK TLSハンドシェイク中に、クライアントとサーバーは使用するPSK(事前共有キー)について合意します。このPSKは、セッションキーの導出に使用されます。このセッションキーは、メッセージの暗号化と復号化に使用されます。しかし、標準を読んでいる間に、これを導き出すための公式や手順を見つけることができませんでした。プレマスターシークレットを計算する式を見つけましたが、これが暗号化または復号化に使用されるものかどうかはわかりません。

  1. PSK TLSでは、プリマスターシークレットは暗号化および復号化に使用されるキーと同じですか?
  2. 事前共有秘密が暗号化および復号化に使用されるキーと同じでない場合、このキーはどのようにして導出されますか?
6
bookhuntress

プリマスターシークレットは暗号化され、TLSハンドシェイクで交換されます。この値は、マスターキーを取得するために使用されます。マスターキーは、それを疑似ランダム関数(PRF)に渡し、ハンドシェイクから他のデータを組み合わせることにより、他のすべてのキー生成情報を導出するために使用されます。


PSKのプリマスターシークレットの導出

から RFC427:セクション2

プリマスターシークレットは次のように形成されます。PSKがNオクテット長の場合、uint16を値N、Nゼロオクテット、2番目のuint16を値Nで連結し、PSK自体を連結します。

PSKでDiffie Hellmanを使用する場合、 セクション

プリマスターシークレットは次のように形成されます。最初に、[TLS]の他のDiffie-Hellmanベースの暗号スイートと同じ方法でDiffie-Hellman計算を実行します。この計算によって生成された値をZとします(他のDiffie-Hellmanベースの暗号スイートと同様に、先頭のゼロバイトが削除されます)。 Z(オクテット単位)の長さを含むuint16、Z自体、PSK(オクテット単位)の長さを含むuint16、およびPSK自体を連結します。

PSKでRSAを使用する場合、 セクション4

クライアントからサーバーに送信されるEncryptedPreMasterSecretフィールドには、[TLS]のセクション7.4.7.1で説明されているように、サーバーのRSA公開鍵を使用して暗号化された2バイトのバージョン番号と46バイトのランダム値が含まれます。実際のプリマスターシークレットは、次のように両方の当事者によって形成されます。uint16を値48、2バイトのバージョン番号と46バイトのランダム値、PSKの長さ(オクテット)を含むuint16、およびPSKと連結します。自体。 (したがって、プリマスターシークレットは、PSKより52オクテット長くなります。)


マスターキーの導出

以下はすべてjustがTLS PSKに適用されません。すべての鍵交換タイプに適用されます。 RFC 2246から: セクション8.1

すべての鍵交換方式で、同じアルゴリズムを使用してpre_master_secretをmaster_secretに変換します。 master_secretが計算されたら、pre_master_secretをメモリから削除する必要があります。マスターシークレットの長さは常に正確に48バイトです。プリマスターシークレットの長さは、鍵の交換方法によって異なります。

   master_secret = PRF(pre_master_secret, "master secret",
                       ClientHello.random + ServerHello.random)
   [0..47];

PRFは、2つの異なるハッシュ関数を組み合わせたものとして定義されています。 セクション5 RFC 2246の:

最初に、単一のハッシュ関数を使用してシークレットを拡張し、任意の量の出力にシードするデータ拡張関数P_hash(secret、data)を定義します。

   P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                          HMAC_hash(secret, A(2) + seed) +
                          HMAC_hash(secret, A(3) + seed) + ...

   Where + indicates concatenation.

   A() is defined as:
       A(0) = seed
       A(i) = HMAC_hash(secret, A(i-1))

上記の関数は、実際にはP_MD5またはP_SHA1です。 TLS PRFは次のように説明されます。

TLSのPRFは、シークレットを2つに分割し、半分を使用してP_MD5でデータを生成し、残りの半分をP_SHA-1でデータを生成して、これら2つの拡張関数の出力を排他的論理和(XOR)することによって作成されます。

だから、次のように主張しましょう:

L_S = length in bytes of secret;
L_S1 = L_S2 = ceil(L_S / 2);

PRFは次のようになります。

PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
                              P_SHA-1(S2, label + seed);

暗号化キーを取得する

キーの派生はRFC 2246で説明されています: セクション6.

キーブロック全体は次のように導出されます。

key_block = PRF(SecurityParameters.master_secret,
                "key expansion",
                SecurityParameters.server_random +
                SecurityParameters.client_random);

十分な素材が生成されてkey_blockに保存されると、key_blockは暗号化/復号化キーに分割されます。暗号化または復号化は方向によって異なります。それらはすべてwriteキーとして参照されるため。 key_blockは順番に配列に分割されます:

client_write_MAC_secret[SecurityParameters.hash_size]
server_write_MAC_secret[SecurityParameters.hash_size]
client_write_key[SecurityParameters.key_material_length]
server_write_key[SecurityParameters.key_material_length]
client_write_IV[SecurityParameters.IV_size]
server_write_IV[SecurityParameters.IV_size]  

エクスポート可能なブロック暗号に対して実行されるいくつかの追加の計算があります。これらの詳細は、RFC2246のセクション6.3でも読むことができます。 セクション6.3.1 は、追加の説明なしでこれらの計算の例を示します。

5
RoraΖ