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

 

目錄
     簡介
     術語
     客戶端註冊
     會話初始化設置
     接收會話設置
     交換信息
     傳輸媒體和附件
     羣組消息
     通話設置
     狀態
     實時位置 (待填坑)
     驗證密匙
     傳輸安全
     結論
 

簡介
本白皮書提供了 WhatsApp 端到端加密系統的技術說明。請訪問 WhatsApp 的網站 www.whatsapp.com/security 瞭解更多。
WhatsApp Messenger 容許人們自由的交換消息(包括聊天,羣聊,圖片,視頻,語音消息和文件),並在發送者和接收者之間使用端對端加密(在 2016 年 3 月 31 以後的版本)。
Signal 協議是由 Open Whisper Systems (非盈利軟件開發團體)設計,是 WhatsApp 端對端加密的基礎。這種端對端加密協議旨在防止第三方和 WhatsApp 對消息或通話進行明文訪問。更重要的是,即便用戶設備的密鑰泄露,也不能解密以前傳輸的消息。
本文檔概述了 Singal 協議在 WhatsApp 中的應用。java

 

術語
     公鑰類型
  • 身份密鑰對(Identity Key Pair) —— 一個長期 Curve25519 密鑰對,安裝時生成。
  • 已簽名的預共享密鑰(Signed Pre Key) —— 一箇中期 Curve25519 密鑰對,安裝時生成,由身份密鑰簽名,並按期進行輪換。
  • 一次性預共享密鑰(One-Time Pre Keys) —— 一次性使用的 Curve25519 密鑰對隊列,安裝時生成,不足時補充。
     會話密鑰類型
  • 根密鑰(Root Key) ——  32 字節的值,用於建立鏈密鑰。
  • 鏈密鑰(Chain Key) —— 32 字節的值,用於建立消息密鑰。                                                                                                                                                                  
  • 消息密鑰(Message Key) —— 80 個字節的值,用於加密消息內容。32 個字節用於 AES-256 密鑰,32 個字節用於 HMAC-SHA256 密鑰,16 個字節用於 IV。

 
客戶端註冊
     在註冊時,WhatsApp 客戶端將身份公鑰(public Identity Key)、已簽名的預共享公鑰(public Signed Pre Key)和一批一次性預共享公鑰(One-Time Pre Keys)發送給服務器。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 ( Einitiator, 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)」 提供前向安全。git

 

經過鏈密鑰(Chain Key)計算消息密鑰(Message Key)
消息發送者每次須要新的消息密鑰時,計算以下:github

  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)。

全部後續發給該羣組的消息:app

  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)中的 Curve2551九、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/

 

參考

  維基百科:端到端加密

  Signal 協議中的雙棘輪算法

 


 

過年期間翻譯了一下,原本英語就差很是吃力,正好作這塊硬着頭皮試着翻譯一下,但願對英語也很差的朋友有一點幫助。對了,招人,看我博客首頁招 Swifter :) 

相關文章
相關標籤/搜索