天天看點

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

本文由融雲技術團隊分享,原題“網際網路通信安全之端到端加密技術”,内容有較多修訂和改動。

1、引言

在上篇《​​IM聊天系統安全手段之通信連接配接層加密技術​​》中,分享了關于通信連接配接層加密的相關技術和實踐,包括在傳輸即時通信消息時啟用 TLS 鍊路加密(保證消息在到達伺服器前無法被竊聽和篡改)、使用 CA 認證機制(杜絕中間人攻ji)等。

本篇将圍繞IM傳輸内容的安全問題,以實踐為基礎,為你分享即時通訊應用中的“端到端”加密技術。

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

學習交流:

- 移動端IM開發入門文章:《​​新手入門一篇就夠:從零開發移動端IM​​》

- 開源IM架構源碼:​​https://github.com/JackJiang2011/MobileIMSDK​​(​​備用位址點此​​)

(本文已同步釋出于:​​http://www.52im.net/thread-4026-1-1.html​​)

2、系列文章

本文是IM通訊安全知識系列文章中的第11篇,此系列總目錄如下:

  • 《​​即時通訊安全篇(一):正确地了解和使用Android端加密算法​​》
  • 《​​即時通訊安全篇(二):探讨組合加密算法在IM中的應用​​》
  • 《​​即時通訊安全篇(三):常用加解密算法與通訊安全講解​​》
  • 《​​即時通訊安全篇(四):執行個體分析Android中密鑰寫死的風險​​》
  • 《​​即時通訊安全篇(五):對稱加密技術在Android平台上的應用實踐​​》
  • 《​​即時通訊安全篇(六):非對稱加密技術的原理與應用實踐​​》
  • 《​​即時通訊安全篇(七):如果這樣來了解HTTPS原理,一篇就夠了​​》
  • 《​​即時通訊安全篇(八):你知道,HTTPS用的是對稱加密還是非對稱加密?​​》
  • 《​​即時通訊安全篇(九):為什麼要用HTTPS?深入淺出,探密短連接配接的安全性​​》
  • 《​​即時通訊安全篇(十):IM聊天系統安全手段之通信連接配接層加密技術​​》
  • 《​​即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術​​》(* 本文)

3、為什麼需要端到端加密?

上篇中提到的連接配接層加密技術,這是提升IM用戶端到伺服器之間資料傳輸的安全性手段,但是這并不能解決使用者間的通信隐私性以及安全性風險。

因為在将資料傳輸到伺服器之後,所有有權通路此伺服器的人,包括員工、供應商及其他有關人員(甚至黑客),都有可能讀取到使用者的資料。

有鑒于此,端到端加密技術在即時通訊IM領域被廣泛應用,包括WhatsApp、Signal、Telegram 等國外即時通信軟體中都有使用。

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

PS:有關端到端加密的基礎知識,可以從這兩篇裡得到,建議詳讀:

  • 《​​移動端安全通信的利器——端到端加密(E2EE)技術詳解​​》
  • 《​​簡述實時音視訊聊天中端到端加密(E2EE)的工作原理​​》

4、端到端加密的技術設計思路

4.1 簡化版思路

說到端到端加密,我們首先想到的解決方案是:在發送端發送消息前對整個消息進行加密,接收端接收到消息後進行解密。

如上這樣:消息中轉伺服器就無法擷取我們的消息内容了。

事實上:這确實是端到端加密中消息收發的簡化版解決方案,隻是我們在實際應用中要更加複雜,效果也更加安全。

4.2 如何安全地傳遞用于消息加解密的密鑰

對于端到端加密,我們需要先解決的前置安全問題是:如何安全地傳遞用于消息加解密的密鑰。

答案是:用非對稱加密的方式傳輸密鑰(與 SSL / TLS 中安全交換密鑰的方式類似)。

非對稱加密傳輸對稱加密密鑰的算法,一般歸結兩種方式:

  • 1)一種是以 RSA、ECC 等為主(公鑰加密私鑰解密的方式,本質是加解密的算法);
  • 2)另一種是以 DH、ECDH 為主的生成共享密鑰的方式(本質是通過計算協商一個共同的密鑰而不是加解密算法)。

實際上:大部分即時通信軟體中的端到端加密都采用生成共享密鑰的方式來傳輸會話密鑰。這是為什麼呢?

這就涉及到 DH 算法(即 Diffie-Hellman 密鑰交換算法),關于DH算法的資料,有興趣可以詳讀《​​Diffie-Hellman密鑰協商算法​​》,限于篇幅,這裡不專門讨論。

Diffie-Hellman 密鑰交換算法的安全性依賴于這樣一個事實:雖然計算以一個素數為模的指數相對容易,但計算離散對數卻很困難。對于大的素數,計算出離散對數幾乎是不可能的。

這裡簡要描述一下 DH 共享密鑰的過程如下:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

(其中“密鑰 S”即為最終的共享密鑰)

4.3 采用共享密鑰的原因

端到端加密采用共享密鑰的方式來傳輸會話密鑰有如下幾個原因:

1)如果采用 RSA、ECC 等公鑰加密私鑰解密的方式傳輸密鑰,需要在建立會話時生成臨時密鑰,并通過對方公鑰加密後傳輸到接收端。

這就需要完全保證消息的可靠性,如果該消息在任何一個環節中丢失或損壞,則後續通信都無法進行。或者,需要采用更為可靠的傳輸方案,通常做法為需要接收端線上,通過各種确認來保證這個可靠性。

而采用共享密鑰的方式則隻需要知道對方的公鑰,就可以完成生成共享密鑰,并不一定需要對方線上。

2)如果已經生成的臨時對稱密鑰丢失,則需要重新協商密鑰。而采用共享密鑰的方式則隻需要知道對方的公鑰,就可以完成生成共享密鑰,不需要重新協商。

3)采用公鑰加密私鑰解密的方式至少會比生成共享密鑰方式多一次交換對稱密鑰的通信過程。

4)密鑰協商方式,不僅僅可以完成兩個點之間的密鑰協商,還可以延展到多人之間的共同協商出相同的密鑰,這樣能滿足多人群體溝通的需求。

5、端到端加密的初步實踐方案

我們結合對于 DH 算法(即 Diffie-Hellman 密鑰交換算法)這種共享密鑰方式的認知(即公鑰可随意公開),先設計一個簡單的端到端消息加密的過程。

這個過程的邏輯流程如下:

  • 1)在用戶端 APP 首次安裝時,基于伺服器公開的兩個全局的參數,生成自己的 DH 公鑰和私鑰;
  • 2)将自己的公鑰上傳證書伺服器,證書伺服器上儲存使用者辨別與其公鑰的關系。私鑰則儲存在用戶端上;
  • 3)首次給對方發送消息或首次接收到對方消息時,便到證書伺服器查詢對方的公鑰;
  • 4)根據對方公鑰和自己的私鑰計算出共享密鑰;
  • 5)後續與對方所有的消息都基于這個密鑰和相同的對稱加解密算法進行加密解密操作。

端到端消息加密過程示意:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

至此:我們完成了一個簡單的端到端消息加密方案,在這個方案中我們引入了一個第三方的用于存儲使用者公鑰的角色,這個角色的存在可以讓任何一方都不用關心對方的線上狀态,随時給對方發送加密過消息,而消息轉發伺服器無法解密消息。

接下來,我們針對這個簡單方案存在的各種安全隐患問題,進行逐漸分析和優化。

6、端到端加密實踐方案的進一步優化和演進

6.1 使用HMAC作為消息完整性認證算法

在消息傳輸過程中,雙方需要确認彼此消息的完整性,簡單的做法就是将消息進行 Hash,得到的 Hash 值附加到消息後,随消息一起發送;對端接收後,同樣進行 Hash,來驗證消息是否被篡改。

關鍵點在于不同資料得到的 Hash 值一定不同,其中帶密鑰的 Hash 值就是 MAC算法。

另外,為了避免使用同樣的 Hash 函數對相同資料進行操作總是得出同樣的值,額外加入一個密鑰,這樣使用不同密鑰就可以得出不同的 MAC。當然,這個密鑰是兩個對端都知道的。

這樣,我們就得到了基于加密 Hash 的消息完整性認證的算法——Hash-based MAC(簡稱HMAC)。

基礎知識1:什麼是MAC算法?

全稱Message Authentication Code,即消息認證碼(帶密鑰的Hash函數)。在密碼學中,MAC是通信實體雙方使用的一種驗證機制,是保證消息資料完整性的一種工具。

MAC算法的安全性依賴于Hash函數,故也稱帶密鑰的Hash函數。消息認證碼是基于密鑰和消息摘要“hash”所獲得的一個值,可用于資料源發認證和完整性校驗。

使用 MAC 驗證消息完整性的具體過程是:

  • 1)假設通信雙方 A 和 B 共享密鑰 K,A用消息認證碼算法将 K 和消息 M 計算出消息驗證碼 Mac,然後将 Mac 和 M 一起發送給 B;
  • 2)B 接收到 Mac 和 M 後,利用 M 和 K 計算出新的驗證碼 Mac*,若 Mac*和Mac 相等則驗證成功,證明消息未被篡改。

由于攻ji者沒有密鑰 K,攻ji者修改了消息内容後無法計算出相應的消息驗證碼,是以 B 就能夠發現消息完整性遭到破壞。

簡而言之就是:

  • 1)發送者通過MAC算法計算出消息的MAC值,并和消息一起發給收信者;
  • 2)收信者用同樣的MAC算法計算收到的消息的MAC值,并對比兩者。

下圖是原理示意:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

基礎知識2:什麼是HMAC算法?

HMAC是MAC算法中的一種,其基于加密HASH算法實作。任何加密HASH, 比如MD5、SHA256等,都可以用來實作HMAC算法,其相應的算法稱為HMAC-MD5、HMAC-SHA256等。

6.2 使用ECDH算法替換DH算法

DH 算法是以離散對數的數學難題為基礎的,随着計算機計算能力逐漸增強,我們要不停地使用更大的數以增加破jie難度,目前業界普遍認為至少需要使用 2048 位 DH 算法才具備更好的安全性。

在此我們引入 ECDH 算法替換 DH 算法。ECDH 密鑰協商算法是 ECC 算法和 DH 密鑰交換原理結合使用。ECC 是建立在基于橢圓曲線的離散對數問題上的密碼體制。在相同破jie難度下,ECC 具有更小長度的密鑰和更快的正向計算速度優勢。

我們系統上的 ECDH 可以直接采用目前公開的 sepc256kl 和 Curve25519 曲線,而無需服務再提供公開大數參數。

6.3 提升前向安全性

在消息傳輸過程中,如果協商好的密鑰洩露了,就意味着所有資訊都将暴露于風險之下。

為了防止這種情況發生,我們需要每次加密使用的密鑰都與上一次不同,且不可以反向推導得出之前的密鑰。

此處引入一個 Hash 算法:這個 Hash 算法可以通過輸入一個密鑰導出另外一個離散性更大的密鑰,每次發送消息時都是用上次的消息密鑰進行 Hash 運算得出本次密鑰,由于 Hash 算法具有單向不可逆的特性,是以就無法通過本次的密鑰推導之前的密鑰。

從感觀上,這就像一個棘輪,棘輪就是一種特殊的齒輪,他隻能往一個方向轉下去,而不能往回轉。

我們先來感性認識一下棘輪:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

在技術上,做到"隻能往一個方向轉下去,而不能往回轉",是達到前向安全的關鍵。這就保證了,如果某一輪的密鑰被破jie出來,但前面的密鑰是無法計算出來的,也就是前面的消息無法被解密。

6.4 同時保證前向安全和後向安全性

出于極緻的安全性要求,我們會同時考慮前向安全和後向安全。如何保證在某次通信中,被破jie出來的密鑰,不能破jie出之前的消息,而且在一定周期内,這個破jie出來的密鑰将不會再起作用。

介于此我們再引入另外一個棘輪來保證其向後的安全性。這就是大名鼎鼎的 ​​Signal protocol​​ 中的雙棘輪算法。

Signal protocol 是真正的端到端的通訊加密協定,号稱是世界上最安全的通訊協定,任何第三方包括伺服器都無法檢視通訊内容。

雙棘輪算法包含一個 KDF 棘輪和一個 DH 棘輪。

KDF 全稱(Key derivation function) 密鑰導出函數,用于從一個原始的密鑰導出一個或多個密鑰。本質上就是 Hash 函數,通常用來将短密碼變成長密碼。另外 KDF 需要加“鹽”(salt),用于防彩虹表,出于 Hash 的特性,這個“鹽”的長度至少要大于 Hash 結果長度。

KDF (原密鑰,鹽) = 導出密鑰

KDF 棘輪就是運用 KDF 算法,設計出一種密鑰不斷變化的效果,流程如下:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

首先:将初始密鑰使用 KDF 算法導出新的密鑰,新密鑰被切成兩部分,前半部分作為下一次 KDF 計算的輸入,後半部分作為消息密鑰。

每疊代一次(也可以說棘輪步進一次),就會生成新的消息密鑰。

由于 KDF 算法的單向性,通過這條消息的密鑰無法倒推出上一條消息密鑰,這就保證了密鑰的前向安全。但是如果 KDF 中的鹽被掌握,那麼它就可以按照這種算法計算出以後所有的消息密鑰。

為了保證後向安全,就要設計一種方法,使每次疊代時引入的鹽是随機的,進而保證每次的消息密鑰是不可以向後推算的。

由前面介紹的 DH 算法得知:兩對密鑰對可以通過 DH 協定生成一個安全的協商密鑰,如果更換其中一個密鑰對,新的協商密鑰也會變化。

根據這個方法:我們可以設計出一個安全更新鹽的方法。我們在證書伺服器增加一個臨時公鑰證書,這個臨時證書是按照接收雙方辨別建構的臨時公鑰對,即每個人的每個單人會話都具備一個臨時公鑰。每進行一個消息輪回,就更新一次己方的臨時公鑰,同時根據另外一方的臨時公鑰和己方的私鑰進行協商,并将協商出的密鑰作為鹽,使得 KDF 棘輪算法生成的消息密鑰具有後向安全性。

在初始時我們無法預測出每個人所有的新二人會話:那麼我們就可以規定建立新的二人會話時,發起方首先生成一個新的臨時 DH 公私鑰對,并向伺服器上傳自己的臨時 DH 公鑰;其次發送方用接收方公布的長期公鑰與自己的臨時私鑰協商出密鑰作為消息加密的密鑰,對消息進行加密;最後接收方首次接收到消息後用自己的長期公鑰和發送方的臨時私鑰計算得出消息密鑰,并在首次回複消息時生成臨時公私鑰,同時上傳臨時公鑰。

問題是:如果接收端不線上,而發送端每條消息都去更新己方的臨時公鑰證書,就會導緻發出去的這些消息,在接收端上線并收取後無法被正常解密。

為了解決這個問題,我們需要規定:隻有在發出消息并得到對方回複後才更新臨時證書,若對方不回複消息則不去更新臨時證書。接收端能回複消息就表示其已經上線并接收完消息,這樣就可以保證離線消息或者消息亂序也可以被對方正常解析。這種方法就是雙棘輪算法中的另外一個 DH 棘輪。

6.5 更安全的密鑰交換協定—— X3DH

對比最初的方案,為了滿足消息的前向安全和後向安全,我們增加了雙棘輪算法,在原基礎方案上為每個人增加了一組會話級别臨時 DH 密鑰,每個人都擁有一個長期密鑰和一組臨時密鑰。

但是:由于長期密鑰無法被更換,是以方案依然存在着安全隐患。

是以:Signal protocol 設計了一種更為複雜和安全的 DH 密鑰交換過程,稱之為 X3DH(即 DH 協定的 3 倍擴充版)。

在 X3DH 協定裡,每個人都要建立 3 種密鑰對,分别如下:

  • 1)身份密鑰對(Identity Key Pair):一個長期的符合 DH 協定的密鑰對,使用者注冊時建立,與使用者身份綁定;
  • 2)已簽名的預共享密鑰(Signed Pre Key):一個中期的符合 DH 協定的密鑰對,使用者注冊時建立,由身份密鑰簽名,并定期進行輪換,此密鑰可能是為了保護身份密鑰不被洩露;
  • 3)一次性預共享密鑰(One-Time Pre Keys):一次性使用的​​Curve25519​​ 密鑰對隊列,安裝時生成,不足時補充。

所有人都要将這 3 種密鑰對的公鑰上傳到伺服器上,以便其他人發起會話時使用。

假如 Alice 要給 Bob 發送消息,首先要和 Bob 确定消息密鑰,流程大緻如下:

  • 1)Alice 要建立一個臨時密鑰對(ephemeral key),我們設成 EPK-A,此密鑰對是為了後面棘輪算法準備,在此處作用不大;
  • 2)Alice 從伺服器擷取 Bob 的三種密鑰對的公鑰:身份密鑰對IPK-B、已簽名的預共享密鑰 SPK-B、一次性預共享密鑰 OPK-B;
  • 3)Alice 開始使用 DH 協定計算協商密鑰,要引入參數包括:自己建立的兩個密鑰對的私鑰,以及 Bob 的三個公鑰。然後用類似排列組合的方式,将自己的私鑰與對方的公鑰分别帶入 DH 算法計算。

DH1 = DH(IPK-A, SPK-B)

DH2 = DH(EPK-A, IPK-B)

DH3 = DH(EPK-A, SPK-B)

DH4 = DH(IPK-A, OPK-B)

如圖所示:

即時通訊安全篇(十一):IM聊天系統安全手段之傳輸内容端到端加密技術

然後将計算得到的四個值,前後連接配接起來,就得到了初始密鑰,如下:

DH = DH1 || DH2 || DH3 || DH4

注:“||”代表連接配接符,比如 456 || 123 = 456123

但是 DH 這個密鑰太長,不适合作為消息密鑰,是以對這個初始密鑰進行一次 KDF 計算,以衍生出固定長度的消息密鑰 S:

S = KDF(DH1 || DH2 || DH3 || DH4)

這一步,Alice 終于計算出了消息密鑰 S。

于是:

  • 1)Alice 使用消息密鑰 S 對消息進行加密,連同自己的身份公鑰 IPK-A 和臨時公鑰 EPK-A 一同發給 Bob;
  • 2)Bob 收到 Alice 的資訊後,取出 Alice 的 2 個公鑰,連同自己的密鑰,使用與 Alice 相同的算法計算消息密鑰 S;
  • 3)Bob 和 Alice 使用消息密鑰進行加密通訊。

由上可知:X3DH 實際是複雜版的 DH 協定。

至此:我們簡單介紹了 Signal Protocol 中最為核心的 X3DH 協定與雙棘輪算法,基本上可以滿足前向安全和後向安全。當然,真實的處理過程會更為複雜和安全。

7、IM群聊的端到端加密方案

在即時通訊場景中,除了二人之間的聊天以外,還有一個重要的場景就是群聊,那麼群聊時的多人消息如何做端到端加密呢?

我們再次回到 DH 密鑰協商算法上的推導過程:顯然,多方情況下依然可以繼續使用 DH 密鑰協商算法,這就是群聊中端到端加密的基礎。

而 Signal Protocol 在群組聊天中的設計與二人聊天又有所不同,由于群聊的保密性要求相對低一些,隻采用了 KDF 鍊棘輪+公鑰簽名來進行加密通訊以保障加密的前向安全。

群組聊天的加解密通訊流程如下:

  • 1)每個群組成員都要首先生成随機 32 位元組的 KDF 鍊密鑰(Chain Key),用于生成消息密鑰,以保障消息密鑰的前向安全性,同時還要生成一個随機 Curve25519 簽名密鑰對,用于消息簽名;
  • 2)每個群組成員用向其它成員單獨加密發送鍊密鑰(Chain Key)和簽名公鑰。此時每一個成員都擁有群内所有成員的鍊密鑰和簽名公鑰;
  • 3)當一名成員發送消息時,首先用 KDF 鍊棘輪算法生成的消息密鑰加密消息,然後使用私鑰簽名,再将消息發給伺服器,由伺服器發送給其它成員;
  • 4)其它成員收到加密消息後,首先使用發送人的簽名公鑰驗證,驗證成功後,使用相應的鍊密鑰生成消息密鑰,并用消息密鑰解密;
  • 5)當群組成員離開時,所有的群組成員都清除自己鍊密鑰和簽名公鑰并重新生成,再次單獨發給每一位成員。這樣操作,離開的成員就無法檢視群組内的消息了。

由上可知:一個人在不同的群組裡,會生成不同的鍊密鑰和簽名密鑰對,以保障群組之間的隔離。在每個群組中,每個成員還要存儲其它成員的 KDF 鍊和簽名公鑰,如果群組成員過多,加解密運算量非常大,會影響發送和接收速度,同時密鑰管理資料庫也會非常大,讀取效率也會降低。

是以:群組聊天使用 ​​Signal Protocol 協定​​,群人數不宜太多。

8、端到端加密方案的補充說明

上面我們介紹了即時通信中二人聊天和群組聊天的端到端加密全部過程。但是正常情況下端到端消息加密隻是加密消息的實際負載部分(即隻加密消息“體”部分),而消息的控制層則不會被加密,因為消息轉發伺服器需要根據控制資訊進行消息轉發或路由(否則肯定大大影響IM底層的路由和通信效率,因為需要反複加密解密)。

為了防止消息被定向分析(分析使用者什麼時間向誰發送了消息,或接收了誰的消息),我們依然需要對整體即時通信的長連接配接鍊路進行加密保護(這說的就是上篇文章裡的​​通信連接配接層加密技術​​了),防止資訊被中間網絡裝置截獲并分析。而且為了防止密鑰伺服器被中間人攻ji,也需要開啟鍊路加密保護。

9、參考資料

[1] ​​移動端安全通信的利器——端到端加密(E2EE)技術詳解​​

[2] ​​簡述實時音視訊聊天中端到端加密(E2EE)的工作原理​​

[3] ​​HASH、MAC、HMAC學習​​

[4] ​​一文了解加解密、哈希函數、MAC、數字簽名、證書、CA等​​

[5] ​​雙棘輪算法:端對端加密安全協定,原理以及流程詳解​​

繼續閱讀