HTTPS 經常使用的密鑰交換算法有兩種,分別是 RSA 和 ECDHE 算法。算法
其中,RSA 是比較傳統的密鑰交換算法,它不具有前向安全的性質,所以如今不多服務器使用的。而 ECDHE 算法具備前向安全,因此被普遍使用。編程
我在上一篇已經介紹了 RSA 握手的過程,今天這一篇就「從理論再到實戰抓包」介紹 ECDHE 算法。安全
ECDHE 密鑰協商算法是 DH 算法演進過來的,因此咱們先從 DH 算法提及。服務器
DH 算法是非對稱加密算法, 所以它能夠用於密鑰交換,該算法的核心數學思想是離散對數。app
是否是聽到這個數學概念就慫了?不怕,此次不會說離散對數推到的過程,只簡單提一下它的數學公式。dom
離散對數是「離散 + 對數」的兩個數學概念的組合,因此咱們先來複習一遍對數。編程語言
要提及對數,必然要說指數,由於它們是互爲反函數,指數就是冪運算,對數是指數的逆運算。函數
舉個栗子,若是以 2 做爲底數,那麼指數和對數運算公式,以下圖所示:工具
那麼對於底數爲 2 的時候, 32 的對數是 5,64 的對數是 6,計算過程以下:性能
對數運算的取值是能夠連續的,而離散對數的取值是不能連續的,所以也以「離散」得名,
離散對數是在對數運算的基礎上加了「模運算」,也就說取餘數,對應編程語言的操做符是「%」,也能夠用 mod 表示。離散對數的概念以下圖:
上圖的,底數 a 和模數 p 是離散對數的公共參數,也就說是公開的,b 是真數,i 是對數。知道了對數,就能夠用上面的公式計算出真數。但反過來,知道真數卻很難推算出對數。
特別是當模數 p 是一個很大的質數,即便知道底數 a 和真數 b ,在現有的計算機的計算水平是幾乎沒法算出離散對數的,這就是 DH 算法的數學基礎。
認識了離散對數,咱們來看看 DH 算法是如何密鑰交換的。
現假設小紅和小明約定使用 DH 算法來交換密鑰,那麼基於離散對數,小紅和小明須要先肯定模數和底數做爲算法的參數,這兩個參數是公開的,用 P 和 G 來代稱。
而後小紅和小明各自生成一個隨機整數做爲私鑰,雙方的私鑰要各自嚴格保管,不能泄漏,小紅的私鑰用 a 代稱,小明的私鑰用 b 代稱。
如今小紅和小明雙方都有了 P 和 G 以及各自的私鑰,因而就能夠計算出公鑰:
A 和 B 也是公開的,由於根據離散對數的原理,從真數(A 和 B)反向計算對數 a 和 b 是很是困難的,至少在現有計算機的計算能力是沒法破解的,若是量子計算機出來了,那就有可能被破解,固然若是量子計算機真的出來了,那麼密鑰協商算法就要作大的升級了。
雙方交換各自 DH 公鑰後,小紅手上共有 5 個數:P、G、a、A、B,小明手上也一樣共有 5 個數:P、G、b、B、A。
而後小紅執行運算: B ^ a ( mod P ),其結果爲 K,由於離散對數的冪運算有交換律,因此小明執行運算: A ^ b ( mod P ),獲得的結果也是 K。
這個 K 就是小紅和小明之間用的對稱加密密鑰,能夠做爲會話密鑰使用。
能夠看到,整個密鑰協商過程當中,小紅和小明公開了 4 個信息:P、G、A、B,其中 P、G 是算法的參數,A 和 B 是公鑰,而 a、b 是雙方各自保管的私鑰,黑客沒法獲取這 2 個私鑰,所以黑客只能從公開的 P、G、A、B 入手,計算出離散對數(私鑰)。
前面也屢次強調, 根據離散對數的原理,若是 P 是一個大數,在現有的計算機的計算能力是很難破解出 私鑰 a、b 的,破解不出私鑰,也就沒法計算出會話密鑰,所以 DH 密鑰交換是安全的。
根據私鑰生成的方式,DH 算法分爲兩種實現:
static DH 算法裏有一方的私鑰是靜態的,也就說每次密鑰協商的時候有一方的私鑰都是同樣的,通常是服務器方固定,即 a 不變,客戶端的私鑰則是隨機生成的。
因而,DH 交換密鑰時就只有客戶端的公鑰是變化,而服務端公鑰是不變的,那麼隨着時間延長,黑客就會截獲海量的密鑰協商過程的數據,由於密鑰協商的過程有些數據是公開的,黑客就能夠依據這些數據暴力破解出服務器的私鑰,而後就能夠計算出會話密鑰了,因而以前截獲的加密數據會被破解,因此 static DH 算法不具有前向安全性。
既然固定一方的私鑰有被破解的風險,那麼幹脆就讓雙方的私鑰在每次密鑰交換通訊時,都是隨機生成的、臨時的,這個方式也就是 DHE 算法,E 全稱是 ephemeral(臨時性的)。
因此,即便有個牛逼的黑客破解了某一次通訊過程的私鑰,其餘通訊過程的私鑰仍然是安全的,由於每一個通訊過程的私鑰都是沒有任何關係的,都是獨立的,這樣就保證了「前向安全」。
DHE 算法因爲計算性能不佳,由於須要作大量的乘法,爲了提高 DHE 算法的性能,因此就出現瞭如今普遍用於密鑰交換算法 —— ECDHE 算法。
ECDHE 算法是在 DHE 算法的基礎上利用了 ECC 橢圓曲線特性,能夠用更少的計算量計算出公鑰,以及最終的會話密鑰。
小紅和小明使用 ECDHE 密鑰交換算法的過程:
這個過程當中,雙方的私鑰都是隨機、臨時生成的,都是不公開的,即便根據公開的信息(橢圓曲線、公鑰、基點 G)也是很難計算出橢圓曲線上的離散對數(私鑰)。
知道了 ECDHE 算法基本原理後,咱們就結合實際的狀況來看看。
我用 Wireshark 工具抓了用 ECDHE 密鑰協商算法的 TSL 握手過程,能夠看到是四次握手:
細心的小夥伴應該發現了,使用了 ECDHE,在 TLS 第四次握手前,客戶端就已經發送了加密的 HTTP 數據,而對於 RSA 握手過程,必需要完成 TLS 四次握手,才能傳輸應用數據。
因此,ECDHE 相比 RSA 握手過程省去了一個消息往返的時間,這個有點「搶跑」的意思,它被稱爲是「TLS False Start」,跟「TCP Fast Open」有點像,都是在還沒鏈接徹底創建前,就發送了應用數據,這樣便提升了傳輸的效率。
接下來,分析每個 ECDHE 握手過程。
客戶端首先會發一個「Client Hello」消息,消息裏面有客戶端使用的 TLS 版本號、支持的密碼套件列表,以及生成的隨機數(Client Random)。
服務端收到客戶端的「打招呼」,一樣也要回禮,會返回「Server Hello」消息,消息面有服務器確認的 TLS 版本號,也給出了一個隨機數(Server Random),而後從客戶端的密碼套件列表選擇了一個合適的密碼套件。
不過,此次選擇的密碼套件就和 RSA 不同了,咱們來分析一下此次的密碼套件的意思。
「 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384」
接着,服務端爲了證實本身的身份,發送「Certificate」消息,會把證書也發給客戶端。
這一步就和 RSA 握手過程有很大到區別了,由於服務端選擇了 ECDHE 密鑰協商算法,因此會在發送完證書後,發送「Server Key Exchange」消息。
這個過程服務器作了三件事:
爲了保證這個橢圓曲線的公鑰不被第三方篡改,服務端會用 RSA 簽名算法給服務端的橢圓曲線公鑰作個簽名。
隨後,就是「Server Hello Done」消息,服務端跟客戶端代表:「這些就是我提供的信息,打招呼完畢」。
至此,TLS 兩次握手就已經完成了,目前客戶端和服務端經過明文共享了這幾個信息:Client Random、Server Random 、使用的橢圓曲線、橢圓曲線基點 G、服務端橢圓曲線的公鑰,這幾個信息很重要,是後續生成會話密鑰的材料。
客戶端收到了服務端的證書後,天然要校驗證書是否合法,若是證書合法,那麼服務端到身份就是沒問題的。校驗證書到過程,會走證書鏈逐級驗證,確認證書的真實性,再用證書的公鑰驗證簽名,這樣就能確認服務端的身份了,確認無誤後,就能夠繼續往下走。
客戶端會生成一個隨機數做爲客戶端橢圓曲線的私鑰,而後再根據服務端前面給的信息,生成客戶端的橢圓曲線公鑰,而後用「Client Key Exchange」消息發給服務端。
至此,雙方都有對方的橢圓曲線公鑰、本身的橢圓曲線私鑰、橢圓曲線基點 G。因而,雙方都就計算出點(x,y),其中 x 座標值雙方都是同樣的,前面說 ECDHE 算法時候,說 x 是會話密鑰,但實際應用中,x 還不是最終的會話密鑰。
還記得 TLS 握手階段,客戶端和服務端都會生成了一個隨機數傳遞給對方嗎?
最終的會話密鑰,就是用「客戶端隨機數 + 服務端隨機數 + x(ECDHE 算法算出的共享密鑰) 」三個材料生成的。
之因此這麼麻煩,是由於 TLS 設計者不信任客戶端或服務器「僞隨機數」的可靠性,爲了保證真正的徹底隨機,把三個不可靠的隨機數混合起來,那麼「隨機」的程度就很是高了,足夠讓黑客計算出最終的會話密鑰,安全性更高。
算好會話密鑰後,客戶端會發一個「Change Cipher Spec」消息,告訴服務端後續改用對稱算法加密通訊。
接着,客戶端會發「Encrypted Handshake Message」消息,把以前發送的數據作一個摘要,再用對稱密鑰加密一下,讓服務端作個驗證,驗證下本次生成的對稱密鑰是否能夠正常使用。
最後,服務端也會有一個一樣的操做,發「Change Cipher Spec」和「Encrypted Handshake Message」消息,若是雙方都驗證加密和解密沒問題,那麼握手正式完成。因而,就能夠正常收發加密的 HTTP 請求和響應了。
RSA 和 ECDHE 握手過程的區別: