1. 程式人生 > >【翻譯】WhatsApp 加密概述(技術白皮書)

【翻譯】WhatsApp 加密概述(技術白皮書)

會話初始化設定      要與另一個 WhatsApp 使用者通訊,WhatsApp 客戶端需要先建立一個加密會話。加密會話一旦被建立,客戶端就不需要再重複建立會話,除非會話失效(例如重新安裝應用或更換裝置)。      建立會話:
  1. 會話發起人為接收人申請身份公鑰(public Identity Key)、已簽名的預共享公鑰(public Signed Pre Key)和一個一次性預共享金鑰(One-Time Pre Key)。
  2. 伺服器返回所請求的公鑰。一次性預共享金鑰(One-Time Pre Key)僅使用一次,因此請求完成後將從伺服器刪除。如果一次性預共享金鑰(One-Time Pre Key)被用完且尚未補充,則返回空。
  3. 發起人將接收人的身份金鑰(Identity Key)存為 Irecipient,將已簽名的預共享金鑰(Signed Pre Key)存為 Srecipient,將一次性預共享金鑰(One-Time Pre Key)存為 Orecipient。
  4. 發起者生成一個臨時的 Curve25519 金鑰對 —— Einitiator
  5. 發起者載入自己的身份金鑰(Identity Key)作為 Iinitiator
  6. 發起者計算主金鑰 master_secret = ECDH ( Iinitiator, Srecipient ) || ECDH ( Einitiator, Irecipient ) || ECDH ( E
    initiator, Srecipient )  || ECDH ( Einitiator, Orecipient ) 。如果沒有一次性預共享金鑰(One-Time Pre Key),最終 ECDH 將被忽略。
  7. 發起者使用 HKDF 演算法從 master_secret 建立一個根金鑰(Root Key)和鏈金鑰(Chain Keys)。
接收會話設定      在建立長期加密會話後,發起人可以立即向接收人傳送訊息,即使接收人處理離線狀態。在接收方響應之前,發起方所有的訊息都會包含建立會話所需的資訊(在訊息的 header 裡)。其中包括髮起人的 Einitiator 和 Iinitiator 。當接收方收到包含會話設定的訊息時:
  1. 接收人使用自己的私鑰和訊息 header 裡的公鑰來計算相應的主金鑰
  2. 接收人刪除發起人使用的一次性預共享金鑰(One-Time Pre Key)
  3. 發起人使用 HKDF 演算法從主金鑰派生出相應的根金鑰(Root Key)和鏈金鑰(Chain Keys)

交換訊息
  一旦建立了會話,通過 AES256 訊息金鑰加密(CbC 模式)和 HMAC-SHA256 驗證來保護客戶端交換訊息。
  訊息金鑰是短暫的且在每次傳送訊息後都會變化,使得用於加密訊息的訊息金鑰不能從已傳送或已接收後的會話狀態中重建。
  訊息金鑰在傳送訊息時對傳送人的鏈金鑰(Chain Key)進行向前的“棘輪(ratchets)”派生而來。此外,每次訊息巡迴都執行一個新的 ECDH 協議以建立一個新的鏈金鑰(Chain Key)。通過組合即時 “雜湊棘輪(hash ratchet)” 和巡迴 “DH 棘輪(DH ratchet)” 提供前向安全。

通過鏈金鑰(Chain Key)計算訊息金鑰(Message Key)
  訊息傳送者每次需要新的訊息金鑰時,計算如下:

  1. 訊息金鑰(Message Key)= HMAC-SHA256(Chain Key, 0x01)
  2. 鏈金鑰(Chain Key)隨後更新為: 鏈金鑰(Chain Key) = HMAC-SHA256(Chain Key, 0x02)

  這樣形成向前“棘輪(ratchets)”鏈金鑰(Chain Key),這也意味不能使用儲存的訊息金鑰推匯出當前或過去的鏈金鑰(Chain Key)值。

通過根金鑰(Root Key)計算鏈金鑰(Chain Key)
  每一條傳送的訊息都附帶一個短期的 Curve25519 公鑰。一旦收到響應,新的鏈金鑰(Chain Key)計算如下:

  1. ephemeral_secret = ECDH(Ephemeralsender, Ephemeralrecipient)
  2. 鏈金鑰(Chain Key),根金鑰(Root Key)= HKDF(Root Key, ephemeral_secret)

  一個鏈金鑰只能給一個使用者發訊息,所以訊息金鑰不能被重用。由於訊息金鑰和鏈金鑰(Chain Keys)的計算方式,訊息可能會延遲、亂序或完全丟失而不會有問題。

傳輸媒體和附件
  任何型別的大附件(視訊,音訊,影象或檔案)也都是端對端加密的:

  1. 發件人(發訊息的 WhatsApp 使用者)生成一個 32 位元組的 AES256 臨時金鑰和一個 32 位元組HMAC-SHA256 臨時金鑰。
  2. 發件人通過 AES256 金鑰(CBC 模式)和隨機 IV 給附件加密,然後附加使用 HMAC-SHA256 密文的 MAC。
  3. 發件人將加密的附件以上傳到伺服器以二進位制儲存。
  4. 發件人給收件人傳送一個包含加密金鑰、HMAC 金鑰、加密二進位制的 SHA256 雜湊值和指向二進位制儲存的指標的加密訊息
  5. 收件人解密訊息,從伺服器檢索加密的二進位制資料,驗證 AES256 雜湊,驗證 MAC並解密為明文。

群組訊息
  傳統未加密的聊天應用通常對群組訊息使用“伺服器扇出(server-side fan-out)”來發群組訊息。當一個使用者向群組發訊息時,伺服器將訊息分發給每一個群組成員。
  而“客戶端扇出(client-side fan-out)”是客戶端將訊息發給每一個群組成員。
  WhatsApp 的群組訊息基於上面列出的成對加密會話構建,以便高效實現大量群組訊息通過伺服器扇出(server-side fan-out)。這是通過 Signal 傳輸協議(Signal Messaging Protocol)的 “傳送者金鑰(Sender Keys)”來完成的。
  WhatsApp 群組成員第一次發訊息到群組:

  1. 傳送人生成一個隨機 32 位元組的鏈金鑰(Chain Key)。
  2. 傳送人生成一個隨機 Curve25519 簽名金鑰對。
  3. 傳送人將 32 位鏈金鑰(Chain Key)和簽名金鑰中的公鑰組合成訊息傳送人金鑰(Sender Key)。
  4. 發件人用成對傳輸協議為每個群組成員單獨加密傳送人金鑰(Sender Keys)。

  所有後續發給該群組的訊息:

  1. 傳送人從鏈金鑰(Chain Key)中獲取訊息金鑰(Message Key)並更新鏈金鑰(Chain Key)
  2. 傳送人在 CbC 模式下使用 AES256 加密訊息
  3. 傳送人使用簽名金鑰(Signature Key)簽名密文
  4. 傳送人將單個密文訊息發給伺服器,伺服器將訊息分發給所有群組成員

  訊息傳送人鏈金鑰(Chain Key)的“雜湊棘輪(hash ratchet)”提供向前安全。當群組成員離開時時,所有剩下的群組成員都清除傳送人金鑰(Sender Key)並重新生成。

通話設定
  WhatsApp 語音和視訊通話也是端對端加密。當 WhatsApp 使用者發起語音或視訊通話時:

  1. 發起人與接收人建立加密會話(如果還沒有建立過)
  2. 發起人生成一個隨機 32 位元組的安全實時傳輸協議(SRTP) 主金鑰(master secret)
  3. 發起人向接收人傳送一個包含安全實時傳輸協議(SRTP)主金鑰的加密訊息用於發通話訊號
  4. 如果應答了呼叫,跟著發起安全實時傳輸協議(SRTP)呼叫

狀態
  WhatsApp 狀態加密方式和群組訊息非常相似。給指定的一組接收人第一次髮狀態遵循向群組第一次發訊息相同的步驟。類似地,給同一組接收人傳送後續狀態也遵循發群組訊息相同的步驟。當狀態傳送人更改狀態隱私設定或從地址簿種刪除號碼來刪除接收人時,狀態傳送人會清除傳送人金鑰(Sender Key)並重新生成。

驗證金鑰
  WhatsApp 使用者還可以驗證與之通訊使用者的金鑰,以便他們能夠確認未授權的第三方(或 WhatsApp)未發起中間人攻擊。通過掃描二維碼或通過比較 60 位數字來完成。
二維碼包括:

  1. 版本號
  2. 雙方的使用者身份
  3. 雙方完整的 32 位元組身份公鑰

  當用戶掃描對方的二維碼時,將比較這些金鑰以確保二維碼中的身份金鑰與伺服器檢索到的相匹配。
  通過拼接兩個使用者身份金鑰的 30 位數字指紋來計算 60 位數字號碼。計算 30 位數字指紋步驟:

  1. 重複 SHA-512 雜湊身份公鑰和使用者識別符號 5200 次
  2. 獲取最後輸出雜湊的前 30 個位元組
  3. 將 30 個位元組分成 6 組每組 5 位元組的資料塊
  4. 通過解析每組 5 位元組資料塊為 big-endian 無符號整形並且取模 10 萬次轉換為 5 個數字
  5. 把六組每組 5 個數字連線成 30 位數字

傳輸安全
  WhatsApp 客戶端和伺服器之間所有通訊都在單獨的加密通道內分層。在 Windows Phone、iPhone 和 Android 上,這些端對端加密客戶端可以使用噪音管道(Noise Pipes),使用噪聲協議框架(Noise Protocol Framework)中的 Curve25519、AES-GCM 和 SHA256 實現長期執行的互動連線。
這位客戶端提供了一些不錯的熟悉:

  1. 極快的輕量級連線設定和恢復
  2. 加密隱藏元資料防止未授權的網路監聽。沒有透露連線使用者身份相關的資訊。
  3. 伺服器上不儲存客戶端的安全認證資訊。客戶端使用 Curve25519 金鑰進行身份驗證,因此伺服器僅儲存客戶端認證公鑰(public authentication key)。如果伺服器的使用者資料庫被入侵,也不會洩露個人認證憑證。

結論
  WhatsApp 使用者之間的訊息受到端對端加密協議的保護,因此第三方和 WhatsApp 都無法獲知訊息內容,訊息只能由接收人解密。所有 WhatsApp 訊息(包括聊天、群聊、圖片、視訊、語音訊息和檔案)和 WhatsApp 通話都受到端對端加密的保護。
  WhatsApp 伺服器無法訪問 WhatsApp 使用者的私鑰,並且 WhatsApp 使用者可以選擇驗證金鑰以確保其通訊完整。
  WhatsApp 使用的 Signal 協議庫是開源的,程式碼:https://github.com/whispersystems/libsignal-protocol-java/

參考

過年期間翻譯了一下,本來英語就差非常吃力,正好做這塊硬著頭皮試著翻譯一下,希望對英語也不好的朋友有一點幫助。對了,招人,看我部落格首頁招 Swifter :)