端對(duì)端加密(E2EE)-參考文章
簡(jiǎn)介
本白皮書(shū)提供了 WhatsApp 端到端加密系統(tǒng)的技術(shù)說(shuō)明枢步。請(qǐng)?jiān)L問(wèn) WhatsApp 的網(wǎng)站 www.whatsapp.com/security 了解更多。
WhatsApp Messenger 允許人們自由的交換消息(包括聊天,群聊植影,圖片喘沿,視頻暑劝,語(yǔ)音消息和文件)铜邮,并在發(fā)送者和接收者之間使用端對(duì)端加密(在 2016 年 3 月 31 之后的版本)舅桩。
Signal 協(xié)議是由 Open Whisper Systems (非盈利軟件開(kāi)發(fā)團(tuán)體)設(shè)計(jì)酱虎,是 WhatsApp 端對(duì)端加密的基礎(chǔ)。這種端對(duì)端加密協(xié)議旨在防止第三方和 WhatsApp 對(duì)消息或通話進(jìn)行明文訪問(wèn)擂涛。更重要的是读串,即使用戶(hù)設(shè)備的密鑰泄露,也不能解密之前傳輸?shù)南ⅰ?br>
本文檔概述了 Singal 協(xié)議在 WhatsApp 中的應(yīng)用撒妈。
術(shù)語(yǔ)
公鑰類(lèi)型
- 身份密鑰對(duì)(Identity Key Pair) —— 一個(gè)長(zhǎng)期 Curve25519 密鑰對(duì)恢暖,安裝時(shí)生成。
- 已簽名的預(yù)共享密鑰(Signed Pre Key) —— 一個(gè)中期 Curve25519 密鑰對(duì)狰右,安裝時(shí)生成杰捂,由身份密鑰簽名,并定期進(jìn)行輪換棋蚌。
- 一次性預(yù)共享密鑰(One-Time Pre Keys) —— 一次性使用的 Curve25519 密鑰對(duì)隊(duì)列嫁佳,安裝時(shí)生成,不足時(shí)補(bǔ)充附鸽。
會(huì)話密鑰類(lèi)型
- 根密鑰(Root Key) —— 32 字節(jié)的值脱拼,用于創(chuàng)建鏈密鑰。
- 鏈密鑰(Chain Key) —— 32 字節(jié)的值坷备,用于創(chuàng)建消息密鑰。
- 消息密鑰(Message Key) —— 80 個(gè)字節(jié)的值情臭,用于加密消息內(nèi)容省撑。32 個(gè)字節(jié)用于 AES-256 密鑰,32 個(gè)字節(jié)用于 HMAC-SHA256 密鑰俯在,16 個(gè)字節(jié)用于 IV竟秫。
客戶(hù)端注冊(cè)
在注冊(cè)時(shí),WhatsApp 客戶(hù)端將身份公鑰(public Identity Key)跷乐、已簽名的預(yù)共享公鑰(public Signed Pre Key)和一批一次性預(yù)共享公鑰(One-Time Pre Keys)發(fā)送給服務(wù)器肥败。WhatsApp 服務(wù)器存儲(chǔ)用戶(hù)身份相關(guān)的公鑰。WhatsApp 服務(wù)器無(wú)法訪問(wèn)任何客戶(hù)端的私鑰愕提。
會(huì)話初始化設(shè)置
要與另一個(gè) WhatsApp 用戶(hù)通信馒稍,WhatsApp 客戶(hù)端需要先建立一個(gè)加密會(huì)話。加密會(huì)話一旦被創(chuàng)建浅侨,客戶(hù)端就不需要再重復(fù)創(chuàng)建會(huì)話纽谒,除非會(huì)話失效(例如重新安裝應(yīng)用或更換設(shè)備)。
建立會(huì)話:
- 會(huì)話發(fā)起人為接收人申請(qǐng)身份公鑰(public Identity Key)如输、已簽名的預(yù)共享公鑰(public Signed Pre Key)和一個(gè)一次性預(yù)共享密鑰(One-Time Pre Key)鼓黔。
- 服務(wù)器返回所請(qǐng)求的公鑰央勒。一次性預(yù)共享密鑰(One-Time Pre Key)僅使用一次,因此請(qǐng)求完成后將從服務(wù)器刪除澳化。如果一次性預(yù)共享密鑰(One-Time Pre Key)被用完且尚未補(bǔ)充崔步,則返回空。
- 發(fā)起人將接收人的身份密鑰(Identity Key)存為 Irecipient缎谷,將已簽名的預(yù)共享密鑰(Signed Pre Key)存為 Srecipient井濒,將一次性預(yù)共享密鑰(One-Time Pre Key)存為 Orecipient。
- 發(fā)起者生成一個(gè)臨時(shí)的 Curve25519 密鑰對(duì) —— Einitiator
- 發(fā)起者加載自己的身份密鑰(Identity Key)作為 Iinitiator
- 發(fā)起者計(jì)算主密鑰 master_secret = ECDH ( Iinitiator, Srecipient ) || ECDH ( Einitiator, Irecipient ) || ECDH ( Einitiator, Srecipient ) || ECDH ( Einitiator, Orecipient ) 慎陵。如果沒(méi)有一次性預(yù)共享密鑰(One-Time Pre Key)眼虱,最終 ECDH 將被忽略。
- 發(fā)起者使用 HKDF 算法從 master_secret 創(chuàng)建一個(gè)根密鑰(Root Key)和鏈密鑰(Chain Keys)席纽。
接收會(huì)話設(shè)置
在建立長(zhǎng)期加密會(huì)話后捏悬,發(fā)起人可以立即向接收人發(fā)送消息,即使接收人處理離線狀態(tài)润梯。在接收方響應(yīng)之前过牙,發(fā)起方所有的消息都會(huì)包含創(chuàng)建會(huì)話所需的信息(在消息的 header 里)。其中包括發(fā)起人的 Einitiator 和 Iinitiator 纺铭。當(dāng)接收方收到包含會(huì)話設(shè)置的消息時(shí):
- 接收人使用自己的私鑰和消息 header 里的公鑰來(lái)計(jì)算相應(yīng)的主密鑰
- 接收人刪除發(fā)起人使用的一次性預(yù)共享密鑰(One-Time Pre Key)
- 發(fā)起人使用 HKDF 算法從主密鑰派生出相應(yīng)的根密鑰(Root Key)和鏈密鑰(Chain Keys)
交換消息
一旦建立了會(huì)話寇钉,通過(guò) AES256 消息密鑰加密(CbC 模式)和 HMAC-SHA256 驗(yàn)證來(lái)保護(hù)客戶(hù)端交換消息。
消息密鑰是短暫的且在每次發(fā)送消息后都會(huì)變化舶赔,使得用于加密消息的消息密鑰不能從已發(fā)送或已接收后的會(huì)話狀態(tài)中重建扫倡。
消息密鑰在發(fā)送消息時(shí)對(duì)發(fā)送人的鏈密鑰(Chain Key)進(jìn)行向前的“棘輪(ratchets)”派生而來(lái)。此外竟纳,每次消息巡回都執(zhí)行一個(gè)新的 ECDH 協(xié)議以創(chuàng)建一個(gè)新的鏈密鑰(Chain Key)撵溃。通過(guò)組合即時(shí) “哈希棘輪(hash ratchet)” 和巡回 “DH 棘輪(DH ratchet)” 提供前向安全。
通過(guò)鏈密鑰(Chain Key)計(jì)算消息密鑰(Message Key)
消息發(fā)送者每次需要新的消息密鑰時(shí)锥累,計(jì)算如下:
- 消息密鑰(Message Key)= HMAC-SHA256(Chain Key, 0x01)
- 鏈密鑰(Chain Key)隨后更新為: 鏈密鑰(Chain Key) = HMAC-SHA256(Chain Key, 0x02)
這樣形成向前“棘輪(ratchets)”鏈密鑰(Chain Key)缘挑,這也意味不能使用存儲(chǔ)的消息密鑰推導(dǎo)出當(dāng)前或過(guò)去的鏈密鑰(Chain Key)值。
通過(guò)根密鑰(Root Key)計(jì)算鏈密鑰(Chain Key)
每一條發(fā)送的消息都附帶一個(gè)短期的 Curve25519 公鑰桶略。一旦收到響應(yīng)语淘,新的鏈密鑰(Chain Key)計(jì)算如下:
- ephemeral_secret = ECDH(Ephemeralsender, Ephemeralrecipient)
- 鏈密鑰(Chain Key),根密鑰(Root Key)= HKDF(Root Key, ephemeral_secret)
一個(gè)鏈密鑰只能給一個(gè)用戶(hù)發(fā)消息际歼,所以消息密鑰不能被重用惶翻。由于消息密鑰和鏈密鑰(Chain Keys)的計(jì)算方式,消息可能會(huì)延遲蹬挺、亂序或完全丟失而不會(huì)有問(wèn)題维贺。
傳輸媒體和附件
任何類(lèi)型的大附件(視頻,音頻巴帮,圖像或文件)也都是端對(duì)端加密的:
- 發(fā)件人(發(fā)消息的 WhatsApp 用戶(hù))生成一個(gè) 32 字節(jié)的 AES256 臨時(shí)密鑰和一個(gè) 32 字節(jié)HMAC-SHA256 臨時(shí)密鑰溯泣。
- 發(fā)件人通過(guò) AES256 密鑰(CBC 模式)和隨機(jī) IV 給附件加密虐秋,然后附加使用 HMAC-SHA256 密文的 MAC。
- 發(fā)件人將加密的附件以上傳到服務(wù)器以二進(jìn)制存儲(chǔ)垃沦。
- 發(fā)件人給收件人發(fā)送一個(gè)包含加密密鑰客给、HMAC 密鑰、加密二進(jìn)制的 SHA256 哈希值和指向二進(jìn)制存儲(chǔ)的指針的加密消息
- 收件人解密消息肢簿,從服務(wù)器檢索加密的二進(jìn)制數(shù)據(jù)靶剑,驗(yàn)證 AES256 哈希,驗(yàn)證 MAC并解密為明文池充。
群組消息
傳統(tǒng)未加密的聊天應(yīng)用通常對(duì)群組消息使用“服務(wù)器扇出(server-side fan-out)”來(lái)發(fā)群組消息桩引。當(dāng)一個(gè)用戶(hù)向群組發(fā)消息時(shí),服務(wù)器將消息分發(fā)給每一個(gè)群組成員收夸。
而“客戶(hù)端扇出(client-side fan-out)”是客戶(hù)端將消息發(fā)給每一個(gè)群組成員坑匠。
WhatsApp 的群組消息基于上面列出的成對(duì)加密會(huì)話構(gòu)建,以便高效實(shí)現(xiàn)大量群組消息通過(guò)服務(wù)器扇出(server-side fan-out)卧惜。這是通過(guò) Signal 傳輸協(xié)議(Signal Messaging Protocol)的 “發(fā)送者密鑰(Sender Keys)”來(lái)完成的厘灼。
WhatsApp 群組成員第一次發(fā)消息到群組:
- 發(fā)送人生成一個(gè)隨機(jī) 32 字節(jié)的鏈密鑰(Chain Key)。
- 發(fā)送人生成一個(gè)隨機(jī) Curve25519 簽名密鑰對(duì)咽瓷。
- 發(fā)送人將 32 位鏈密鑰(Chain Key)和簽名密鑰中的公鑰組合成消息發(fā)送人密鑰(Sender Key)设凹。
- 發(fā)件人用成對(duì)傳輸協(xié)議為每個(gè)群組成員單獨(dú)加密發(fā)送人密鑰(Sender Keys)。
所有后續(xù)發(fā)給該群組的消息:
- 發(fā)送人從鏈密鑰(Chain Key)中獲取消息密鑰(Message Key)并更新鏈密鑰(Chain Key)
- 發(fā)送人在 CbC 模式下使用 AES256 加密消息
- 發(fā)送人使用簽名密鑰(Signature Key)簽名密文
- 發(fā)送人將單個(gè)密文消息發(fā)給服務(wù)器茅姜,服務(wù)器將消息分發(fā)給所有群組成員
消息發(fā)送人鏈密鑰(Chain Key)的“哈希棘輪(hash ratchet)”提供向前安全闪朱。當(dāng)群組成員離開(kāi)時(shí)時(shí),所有剩下的群組成員都清除發(fā)送人密鑰(Sender Key)并重新生成钻洒。
通話設(shè)置
WhatsApp 語(yǔ)音和視頻通話也是端對(duì)端加密监透。當(dāng) WhatsApp 用戶(hù)發(fā)起語(yǔ)音或視頻通話時(shí):
- 發(fā)起人與接收人建立加密會(huì)話(如果還沒(méi)有建立過(guò))
- 發(fā)起人生成一個(gè)隨機(jī) 32 字節(jié)的安全實(shí)時(shí)傳輸協(xié)議(SRTP) 主密鑰(master secret)
- 發(fā)起人向接收人發(fā)送一個(gè)包含安全實(shí)時(shí)傳輸協(xié)議(SRTP)主密鑰的加密消息用于發(fā)通話信號(hào)
- 如果應(yīng)答了呼叫,跟著發(fā)起安全實(shí)時(shí)傳輸協(xié)議(SRTP)呼叫
狀態(tài)
WhatsApp 狀態(tài)加密方式和群組消息非常相似航唆。給指定的一組接收人第一次發(fā)狀態(tài)遵循向群組第一次發(fā)消息相同的步驟。類(lèi)似地院刁,給同一組接收人發(fā)送后續(xù)狀態(tài)也遵循發(fā)群組消息相同的步驟糯钙。當(dāng)狀態(tài)發(fā)送人更改狀態(tài)隱私設(shè)置或從地址簿種刪除號(hào)碼來(lái)刪除接收人時(shí),狀態(tài)發(fā)送人會(huì)清除發(fā)送人密鑰(Sender Key)并重新生成退腥。
驗(yàn)證密鑰
WhatsApp 用戶(hù)還可以驗(yàn)證與之通信用戶(hù)的密鑰任岸,以便他們能夠確認(rèn)未授權(quán)的第三方(或 WhatsApp)未發(fā)起中間人攻擊。通過(guò)掃描二維碼或通過(guò)比較 60 位數(shù)字來(lái)完成狡刘。
二維碼包括:
- 版本號(hào)
- 雙方的用戶(hù)身份
- 雙方完整的 32 字節(jié)身份公鑰
當(dāng)用戶(hù)掃描對(duì)方的二維碼時(shí)享潜,將比較這些密鑰以確保二維碼中的身份密鑰與服務(wù)器檢索到的相匹配。
通過(guò)拼接兩個(gè)用戶(hù)身份密鑰的 30 位數(shù)字指紋來(lái)計(jì)算 60 位數(shù)字號(hào)碼嗅蔬。計(jì)算 30 位數(shù)字指紋步驟:
- 重復(fù) SHA-512 哈希身份公鑰和用戶(hù)標(biāo)識(shí)符 5200 次
- 獲取最后輸出哈希的前 30 個(gè)字節(jié)
- 將 30 個(gè)字節(jié)分成 6 組每組 5 字節(jié)的數(shù)據(jù)塊
- 通過(guò)解析每組 5 字節(jié)數(shù)據(jù)塊為 big-endian 無(wú)符號(hào)整形并且取模 10 萬(wàn)次轉(zhuǎn)換為 5 個(gè)數(shù)字
- 把六組每組 5 個(gè)數(shù)字連接成 30 位數(shù)字
傳輸安全
WhatsApp 客戶(hù)端和服務(wù)器之間所有通信都在單獨(dú)的加密通道內(nèi)分層剑按。在 Windows Phone疾就、iPhone 和 Android 上,這些端對(duì)端加密客戶(hù)端可以使用噪音管道(Noise Pipes)艺蝴,使用噪聲協(xié)議框架(Noise Protocol Framework)中的 Curve25519猬腰、AES-GCM 和 SHA256 實(shí)現(xiàn)長(zhǎng)期運(yùn)行的交互連接。
這為客戶(hù)端提供了一些不錯(cuò)的屬性:
- 極快的輕量級(jí)連接設(shè)置和恢復(fù)
- 加密隱藏元數(shù)據(jù)防止未授權(quán)的網(wǎng)絡(luò)監(jiān)聽(tīng)猜敢。沒(méi)有透露連接用戶(hù)身份相關(guān)的信息姑荷。
- 服務(wù)器上不存儲(chǔ)客戶(hù)端的安全認(rèn)證信息∷趵蓿客戶(hù)端使用 Curve25519 密鑰進(jìn)行身份驗(yàn)證鼠冕,因此服務(wù)器僅保存客戶(hù)端認(rèn)證公鑰(public authentication key)。如果服務(wù)器的用戶(hù)數(shù)據(jù)庫(kù)被入侵胯盯,也不會(huì)泄露個(gè)人認(rèn)證憑證懈费。
結(jié)論
WhatsApp 用戶(hù)之間的消息受到端對(duì)端加密協(xié)議的保護(hù),因此第三方和 WhatsApp 都無(wú)法獲知消息內(nèi)容陨闹,消息只能由接收人解密楞捂。所有 WhatsApp 消息(包括聊天、群聊趋厉、圖片寨闹、視頻、語(yǔ)音消息和文件)和 WhatsApp 通話都受到端對(duì)端加密的保護(hù)君账。
WhatsApp 服務(wù)器無(wú)法訪問(wèn) WhatsApp 用戶(hù)的私鑰繁堡,并且 WhatsApp 用戶(hù)可以選擇驗(yàn)證密鑰以確保其通訊完整。
WhatsApp 使用的 Signal 協(xié)議庫(kù)是開(kāi)源的乡数,代碼:https://github.com/whispersystems/libsignal-protocol-java/