2018 一月重大資安事件新聞-2
作者:專案研究員 林漢洲
LINE 的加密協定的介紹與解析
一、前言
針對目前在台灣最多人使用的即時通軟體LINE, 所使用的加密協定。研究和探討LINE利用的演算法,如對稱與非對稱的金鑰加解密及簽章的詳細流程,以及建立用戶端和合法LINE伺服器的握手協定,為本報告的主要核心。特別的是,我們著重於點對點的加密(LINE 叫它Letter Sealing), 一對一的訊息傳送,或是一對多群組。點對點的加密,理論上,因為私鑰是不會離開使用者端, 使用者加密的訊息,傳輸的過程,就算經過任何中繼伺服器(例如:LINE的伺服器),也是無法被即時通訊提供者解密。這和以前訊息都是明文方式存在伺服器比較起來(雖然在傳送過程有用TLS協定加密,到達目的地再解密),安全性大幅加強。
二、LINE 使用的 lightweight handshake 協定 (protocol)
為了保障手機和LINE伺服器的傳輸安全,LINE 使用輕量握手協定,以在不影響安全性的前提,減少傳輸的計算量和占用資源,以增加系統的可靠性與效率。當初What’s App 在台灣會被LINE迎頭趕上的一個重要原因,大致可歸因為LINE 的記憶體管理和速度上都優於What’s App。 在使用者經驗方面領先,也是Secure messenger 除了在安全性強度,也需注意的一個環節。
確保使用者端是連結到正確的LINE伺服器,LINE 使用静態橢圓曲線金鑰(ECC key pairs)。
私鑰存在LINE 伺服器,對應的公鑰則存在LINE 用戶端的程式。0-RTT (zero round-trip time) 可以達成是因為用戶端已在安裝時儲放了静態ECDH金鑰,所以可節省第一次傳輸的時間。接下來是伺服器和用戶端交換訊息(稱為”握手”),以建立共同的金鑰(transport key), 用來加密互傳的資料。
用戶端Hello
1. 產用初始的一次性 ECDH 金鑰對 和 16 位元長的用戶nonce. (nonce 是用來保證握手程序不會被惡意第三者盜取了伺服器用戶間的通訊,用來重覆使用,因為nonce是一次性的隨機亂數)
(c_initpublic, c_initprivate) = ECDH generate()
cnonce = randomsecure()
2. 產生暫時的傳輸金鑰和初始向量。HKDF (hash-based key derivation function) 是用來產生衍生鑰。HKDF ex 是extract (萃取,即產生較小的output)。HKDF exp是 expand (擴大)。
lenkey =16
leniv = 16
sharedtemp = ECDH(c_initprivate, static public)
MS temp = HKDFex(c public || c nonce, shared temp)
keyiv temp = HKDFexp(MS temp, “legy temp key”, len key + len iv)
iv temp = keyiv temp[16:31]
3. 產用用戶端的 ECDH 金鑰對
(c public, c private) = ECDH generate()
4. 用key temp 和 iv temp 加密這二個 c public 和 app data
data enc = ENC (key temp, iv temp, c public|| app data)
5. 送這五個到伺服器[static key version, c public, c nonce, c_init public, data enc] 。static key version 是為了讓伺服器能用和用戶端相對應的静態鑰,所以要指定對的版本。(作者註:LINE的Whitepaper少了加 c_init public
伺服器 Hello
1. 用伺服器端的静態ECDH鑰 和 用戶端初始一次鑰算出暫時傳輸金鑰和初始向量
shared temp = ECDH(static private, c_init public)
MStemp = HKDFex(cpublic||cnonce, shared temp)
keyiv temp = HKDFexp(MStemp, “legy temp key”, len key+ leniv)
key temp = keyiv temp [0:15]
iv temp = keyiv temp[16:31]
2. 用key temp 解密,並求出c public
3. 產生一對一次性金鑰對和16 位元的伺服器nonce
(s private, s public) = ECDH generate()
s nonce = random secure()
4. 算出forward-secure(FS) 傳輸鑰和IV
len key = 16
len iv = 16
shared FS = ECDH(s private, c public)
MS FS = HKDFex(s nonce || c nonce, shared FS)
keyiv FS = HKDFexp(MS FS, “legy temp key”, len key + len iv)
keyFS = keyivFS[0:15]
iv FS = keyivFS[16:31]
5. 算出handshake state, 並用伺服器静態簽章私鑰加上簽章
state = SHA256(c public|| c nonce ||s public || s nonce)
state sign = ECDSA sign(state, sign private)
6. 用key FS 和 iv FS 加密app data
Data enc = ENC(key FS, iv FS, app data)
7. 送到用戶端
[s public, s nonce, state sign, data enc]
用戶端最後的階段
1. 檢查handshake 簽章是否一致,
valid = ECDSA verfiy(state sign, sign public)
2. 算出key FS 和 iv FS
MS FS = HKDF ex(c nonce || s nonce, shared FS)
keyiv FS = HKDF exp(MS FS, “legy fs key”, len key + len iv)
key FS = keyivFS[0:15]
iv FS = keyivFS[16:31]
3. 用key FS 和 iv FS 加密之後的application data