TLS 1.2 密鑰派生過程需要澄清
關於密鑰生成,請參閱 TLS 1.2 標准文件第 6.3 節:
要生成密鑰材料,請計算
key_block = PRF(SecurityParameters.master_secret, "key expansion", SecurityParameters.server_random + SecurityParameters.client_random);
直到產生足夠的輸出。然後,key_block 被
分區如下:
client_write_MAC_key[SecurityParameters.mac_key_length] server_write_MAC_key[SecurityParameters.mac_key_length] client_write_key[SecurityParameters.enc_key_length] server_write_key[SecurityParameters.enc_key_length] client_write_IV[SecurityParameters.fixed_iv_length] server_write_IV[SecurityParameters.fixed_iv_length]
我為他們分配了以下變數:
- $ kc_{mac} $ =
client_write_MAC_key[SecurityParameters.mac_key_length]
- $ ks_{mac} $ =
server_write_MAC_key[SecurityParameters.mac_key_length]
- $ kc_{data} $ =
client_write_key[SecurityParameters.enc_key_length]
- $ ks_{data} $ =
server_write_key[SecurityParameters.enc_key_length]
在 DHE 密鑰交換中,客戶端和伺服器交換密鑰並且兩者都有 $ \mathit{premaster} = g^{xy} $ .
客戶端和伺服器計算主密鑰:
$$ ms = \operatorname{hkdf}(\mathit{premaster},\mathit{nonce}\mathrm{client}+\mathit{nonce}\mathrm{server}) $$
然後兩者都計算會話密鑰:
$$ \mathit{kc}\mathrm{mac}, \mathit{ks}\mathrm{mac}, \mathit{kc}\mathrm{data}, \mathit{ks}\mathrm{data} = \operatorname{hkdf}(\mathit{ms}, \mathit{nonce}\mathrm{client} + \mathit{nonce}\mathrm{server}) $$
這 $ ms $ 在 Finished
MAC
計算中使用如下: $ \operatorname{MAC}(\mathit{ms}, \operatorname{hash}(\mathit{handshake})) $消息被
Finished
加密 $ \mathit{kc}_\mathrm{mac} $ ,例如客戶端完成的MAC:$$ \operatorname{enc}{\mathit{kc}\mathrm{mac}}(\operatorname{Finished}(\operatorname{MAC}(\mathit{ms}, \operatorname{hash}(\mathit{handshake}))) $$
從客戶端到伺服器的數據被加密如下:
$$ \operatorname{enc}{\mathit{kc}\mathrm{data}}(\mathit{data}) $$
我的問題是:
- 我對 TLS 1.2 密鑰生成和使用的解釋是否正確?
- 是萬能鑰匙 $ \mathit{ms} $ 和四個會話密鑰: $ \mathit{kc}\mathrm{mac} $ , $ \mathit{ks}\mathrm{mac} $ , $ \mathit{kc}\mathrm{data} $ , $ \mathit{ks}\mathrm{mac} $ 在兩個連續的步驟中計算,即:在客戶端*和消息之後
Client Key Exchange
和之前?Change Cipher Spec``Finished
*或者他們之間是否有任何其他消息發送/接收?
你的描述有幾處不對勁。
首先,您使用術語“hkdf”。有HKDF這樣的東西,它是一個密鑰推導函式,內部使用 HMAC;但是,在 TLS 中不使用 HKDF。TLS 定義了自己的密鑰派生函式,它始終將其稱為“PRF”。它在標準的第 5 節中進行了描述。該函式也基於 HMAC,但具有不同的結構。PRF 有三個輸入參數:
- “秘密”;
- 種子”;
- 標籤”。
每個參數的具體內容取決於上下文。通常,“標籤”是限定使用點的常量字元串(例如
"client finished"
,在計算客戶端Finished
消息時)。“種子”由握手中的元素組成,這些元素通常是可觀察的,即非秘密的。“秘密”輸入是任何實際秘密數據的去向。PRF 會將所有這些值與相當數量的 HMAC 呼叫混合在一起,形成任意長度的字節序列。在 TLS 中,使用了一種密鑰交換機制,這會產生“預主密鑰”。使用 RSA 密鑰交換時,“pre-master”由客戶端隨機生成,並使用伺服器的 RSA 公鑰加密。當使用 Diffie-Hellman 密鑰交換時,“pre-master”是由 DH 產生的整數的編碼( $ g^{ab} \pmod p $ )。當使用 ECDH(橢圓曲線上的 Diffie-Hellman)時,預主密鑰是 $ X $ 計算的 DH 點的座標( $ abG $ )。請注意,此時不存在散列問題:pre-master secret 是一個字節序列,其長度和內容取決於使用的密鑰交換方法。
主密鑰是使用 PRF 從預主密鑰計算出來的。這在第 8 節中進行了描述。標籤是
"master secret"
,種子是客戶端隨機數和伺服器隨機數的串聯(這兩個值各為 32 字節,為每次握手隨機生成,並在ClientHello
和ServerHello
消息中交換)。主密鑰的長度正好是 48 個字節。從主密鑰派生出對稱加密所需的密鑰和 IV。這是您展示的“關鍵塊”。請注意,密鑰塊中各種密鑰的大小取決於協商的密碼套件。例如,如果密碼套件使用 AES/GCM(例如
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
),則沒有 MAC 密鑰(或者,等效地,MAC 密鑰長度為 0),因為 GCM 模式確保使用相同的密鑰進行加密和完整性檢查。密鑰塊計算使用 PRF,此時主密鑰作為“秘密”輸入;“種子”是伺服器和客戶端隨機數的串聯。注意順序!這一次,伺服器隨機首先出現。
Finished
消息具有再次使用 PRF 計算的內容。消息的內容是Finished
通過呼叫 PRF 獲得的 12 個字節,作為“秘密”輸入,主秘密;“種子”是所有先前握手消息的雜湊值。“標籤”因客戶端和伺服器之間的誰發送該特定Finished
消息而異。由於Finished
消息是在 之後發送的ChangeCipherSpec
,因此使用剛剛協商的算法和密鑰對它們進行加密和 MAC 化。從這個意義上說,密鑰和隨機數(客戶端和伺服器隨機數)涉及多次。因此,在您的描述中,“hkdf”術語的使用以及 MAC 的使用都是虛假的,特別是在
Finished
消息方面。下圖是 SSL 握手的一個很好的總結,它是TLS 1.2 標準的一部分:
Client Server ClientHello --------> ServerHello Certificate* ServerKeyExchange* CertificateRequest* <-------- ServerHelloDone Certificate* ClientKeyExchange CertificateVerify* [ChangeCipherSpec] Finished --------> [ChangeCipherSpec] <-------- Finished Application Data <-------> Application Data Figure 1. Message flow for a full handshake
注意,在
ClientKeyExchange
來自客戶端的消息之後,在.之前ChangeCipherSpec
,可能有一個CertificateVerify
消息(這是在伺服器請求客戶端證書時由客戶端發送,客戶端發送一個,這不是全靜態DH或ECDH) .The “hash of all previous handshake messages” that is used as an input to the PRF for the computation of the
Finished
messages really includes all previous messages for this handshake, starting with theClientHello
. Notably, when the server responds with its ownFinished
message, the hash used in that secondFinished
message will include the contents of the firstFinished
message. Also note that theChangeCipherSpec
message is not formally a handshake message (though it may occur only at very specific times within the handshake) so its contents are not used for these hashes.The complete TLS handshake is quite complicated, mostly for historical reasons. If you want to formalize its use of cryptographic algorithms, you have little choice but to invest a few hours of reading time to get through all the details. I suggest starting with this answer.