Wi-Fi 新標準 WPA3 蜻蜓 (Dragonfly) 金鑰交換協議分析
背景
在2018年1月8日美國拉斯維加斯的國際消費電子展(CES)上,Wi-Fi聯盟釋出了最新的WPA3加密協議,作為WPA2技術的的後續版本,並在2018年6月26日,WiFi聯盟宣佈WPA3協議已最終完成。與WPA3相關的最核心的文件為RFC7664,其中描述的是WPA3中最大的改進,就是將原來的四次握手協議換成了新的“蜻蜓祕鑰交換協議”(Dragonfly Key Exchange),該協議將認證和祕鑰交換兩個功能合成於一個協議。號稱可以解決WPA2中未解決的幾個安全問題:
1.離線密碼破解——獲得WPA2的四次握手包即可進行離線字典攻擊,破解無線密碼。 2.轉發安全(Forward Secracy)——已知4次握手和無線密碼的情況下,可以解密目標的所有通訊流量。 3.KRACK等其他已知攻擊方法。
由於WPA3還尚未普及,想來目前無論公眾還是相關研究人員對WPA3的協議的實施細節所知應該並不多,所以筆者在仔細閱讀RFC7664文件後,在此文中將做詳細的分析討論,以及指出可能的攻擊方法,供其他相關研究人員參考。
WPA3簡介
本節中我們簡單介紹一下WPA3相關的基本知識,在WPA2的基礎上討論在WPA3協議中做了哪些關鍵改進以及改進後在安全方面會有哪些提升。
根據Wi-Fi聯盟官方釋出的文件,WPA3仍然分為WPA3個人級和WPA3企業級兩種標準,其中,WPA3企業級認證與WPA2相比差別不大,僅僅將金鑰長度增加到了192位(WPA2使用的是128位的加密金鑰)仍然採用EAP-SSL,EAP-SIM/EAP-AKA之類的基於認證伺服器的認證方法。
那麼此次協議改進最大的地方在哪裡呢?沒錯,改動最大的地方就是WPA3個人級相對於WPA2個人級的改進,根據官方的說法,WPA3個人級有如下幾個提升:
1.更強的基於密碼的認證安全(官方聲稱即使使用者使用弱密碼,仍然可以得到良好的保護。) 2.使用等量同步認證——一種更安全的裝置間金鑰交換協議,即蜻蜓協議,可以防止通通訊流量被竊聽,即使被攻擊者獲取了握手過程,也無法解密流量。 3.金鑰長度擴充套件到192位。
其中官方宣稱的第1點建立的基礎就是因為引入了蜻蜓祕鑰交換協議,該協議作者在該協議的說明中聲稱可以避免離線字典攻擊,這一點應該就是以上第1所述的可保護弱密碼的原理。至於3,其實128位的對稱金鑰已經足夠,此處提升僅僅有理論上的安全提升。看來WPA3上最明顯的改進就是替換了金鑰交換演算法,在接下來的章節中我們就著重分析一下這個蜻蜓演算法。
WPA2-PSK回顧
在開始分析蜻蜓演算法之前,為了更有效的對比WPA2和WPA3金鑰交換演算法的差異,這裡先簡單介紹一下WPA2協議中裝置入網認證的過程,見下圖。
事實上一次完整的WPA2入網過程中,在上圖所述的金鑰交換過程之前還需要3次互動,分別是客戶端傳送Probe Request,伺服器迴應Probe Response,客戶端傳送Authentication Request伺服器迴應Authentication Response,接著客戶端傳送Association Request,伺服器迴應Association Response,接著開始上圖所示金鑰交換過程。金鑰交換過程分為如下幾步:
1.AP傳送一個隨機數AP Nonce給STA,STA通過AP的ESSID,以及自己的MAC地址,AP的MAC地址,PSK,AP傳送的隨機數以及自己生成的STA Nonce,這6個引數生成PMK和PTK。 2.STA傳送第1步生成的隨機數STA Nonce給AP,並使用上一步生成的PTK生成該資料包的訊息校驗值MIC附在資料包後面傳送給AP,AP通過包括STA Nonce在內的同樣6個引數生成自己的PMK和PTK,並用PTK校驗STA傳送的資料包的MIC值是否匹配,如果匹配則說明PSK正確認證通過。 3.AP將組金鑰(即GTK用於加密廣播以及組播包的金鑰)用PMK加密並附上MIC傳送給STA。 4.STA校驗MIC後裝入GTK並回復ACK,金鑰交換結束開始加密通訊。
如果你覺得以上寫的太糾結,為了照顧大家特此附上程式碼:
#!/usr/bin/env python import hmac from hashlib import pbkdf2_hmac,sha1,md5 def PRF(key,A,B): nByte = 48 i = 0 R = '' while ( i <= ((nByte*8 + 159)/160)): hmacsha1 = hmac.new(key,A+"\x00" + B + chr(i),sha1) R += hmacsha1.digest() i += 1 return R[0:nByte] def MakeAB(aNonce,sNonce,apMac,cliMac): A = "Pairwise key expansion" B = min(apMac,cliMac) + max(apMac,cliMac) + min(aNonce, sNonce) + max(aNonce, sNonce) return (A,B) def MakeMIC(pwd,ssid,A,B,data,wpa = False): pmk = pbkdf2_hmac('sha1',pwd,ssid,4096,32) ptk = PRF(pmk,A,B) hmacFunc = md5 if wpa else sha1 mics = [hmac.new(ptk[0:16],i,hmacFunc).digest() for i in data] return (mics,ptk,pmk) def calcKey(essid,psk,apMac,cliMac,data0,data1,data2,data3): ssid = essid #print ssid aNonce = data0[17:17+32] #print aNonce.encode('hex') sNonce = data1[17:17+32] #print sNonce.encode('hex') apMac = apMac.replace(':','').decode("hex") cliMac = cliMac.replace(':','').decode("hex") mic1 = data1[81:81+16] data1 = data1.replace(mic1,'\x00'*16) mic2 = data2[81:81+16] data2 = data2.replace(mic2,'\x00'*16) mic3 = data3[81:81+16] data3 = data3.replace(mic3,'\x00'*16) A,B = MakeAB(aNonce,sNonce,apMac,cliMac) mics,ptk,pmk = MakeMIC(psk,ssid,A,B,[data1,data2,data3]) print "pmk:",pmk.encode('hex') print "ptk:",ptk.encode('hex'),"len:",len(ptk)*8 print "desired mic1:",mic1.encode('hex') print "acture mic1:",mics[0].encode('hex')[:-8] if (mic1==mics[0][:-4]): print "MIC1 MATCHED" print "desired mic2:",mic2.encode('hex') print "acture mic2:",mics[1].encode('hex')[:-8] if (mic2==mics[1][:-4]): print "MIC2 MATCHED" print "desired mic3:",mic3.encode('hex') print "acture mic3:",mics[2].encode('hex')[:-8] if (mic3==mics[2][:-4]): print "MIC3 MATCHED" return ptk
從上面的過程可以看出,其中最重要的引數就是PTK,每個STA和AP之間通訊的PTK是不同的,這也意味著一旦PTK被獲知,就可以解密該STA和AP之間通訊的所有流量。那麼縱觀整個交換過程,最重要的引數就是PSK,PSK參與了金鑰的計算,且AP和STA對於PTK金鑰的計算演算法是對稱的,這或許就是WPA2不提供轉發安全的最重要原因,那就是,只要握手過程被獲取,任何知道PSK的人都可以計算出PTK,從而解密所有通訊流量。並且,由於演算法是對稱的,只要抓取握手包,就可以通過離線校驗MIC的方式來驗證PSK的正確性,這就是aircrack-ng抓取握手包跑包破解WIFI密碼的原理。
好了,至此我們可以看出,對稱的金鑰生成演算法或許是WPA2安全性的最大缺陷!因為這一點,導致WPA2可以被離線字典攻擊,同時,在PSK公開的網路中,例如星巴克,酒店之類的場景,PSK被很多人都知道,且一旦金鑰被攻擊者獲取,就無法保證使用者的資料安全!
WPA3 Dragonfly(蜻蜓)金鑰交換演算法
在大致瞭解了WPA3的改進以及WPA2優劣後,我們可以進入正題,分析WPA3中最核心的演算法——蜻蜓祕鑰交換演算法,分析的過程中會牽扯到一些非對稱加密的知識,後面我會一一說明。
蜻蜓演算法從本質上說也是一個基於離散對數這個難解問題的演算法,也就是說蜻蜓演算法可以使用普通的整數有限域或者橢圓曲線來實現,由此可見,蜻蜓演算法和Diffie-Hellman演算法十分相似。我們可以很容易的先對比D-H演算法中的離散對數,為了簡單起見,下面的討論我們以有限域上的情況來做例子,橢圓曲線的實現同理可以類比。首先我們取一個大質數p,通常1024位以上,我們通常記Z_p^表示模p的剩餘類乘法群,Q是一個Z_p^上的q階(q也是素數)子群。那麼蜻蜓演算法的金鑰交換和認證過程如下:
前3次互動,即Probe+Authentication+Association過程同WPA2。金鑰交換第一步,對於一次正常的認證過程,AP和STA共享了同樣的一個PSK,我們首先要將這個PSK對映為Q上的一個元素P,對映演算法有很多種,可以保證PSK到P的唯一對映,具體方法這裡不做詳細討論,即我們只要知道對映完成之後,我們可以通過PSK得到一個唯一的整數P即可。
第二步,AP生成隨機的兩個引數r_A和m_A,(1<r_A,m_A<q),然後計算出引數secret記作s_A,其中s_A=(r_A+m_A ) mod p和引數E_A=P^(-m_A ) mod p,然後將s_A和 E_A傳送給STA。
第三步,STA同樣生成r_B和m_B,(1<r_B,m_B<q),secret引數s_B=(r_B+m_B ) mod p q,以及E_B=P^(-m_B ) mod p,然後將s_B和 E_B傳送給AP。
第四步,AP計算ss=〖(P^(s_B ) E_B)〗^(r_A )=P^(r_A r_B ) mod p。kck|mk=KDF-n(ss,”Dragonfly Key Derivation”), KDF-n是一個金鑰匯出演算法。
第五步,STA計算ss=〖(P^(s_A ) E_A)〗^(r_B )=P^(r_A r_B ) mod p,kck|mk=KDF-n(ss,”Dragonfly Key Derivation”) 。
第六步,AP計算引數A=H(kck|sA|sB|EA|EB|idA)傳送給STA,其中H是一個hash演算法。其中idA是AP的傳送方標識,可以通過密碼以及雙方引數通過固定演算法計算所得。
第七步,STA計算引數B=H(kck|sB|sA|EB|EA|idB)傳送給AP,idB同理
第八步,AP和STA分別使用自己的引數計算對方的hash的值,並與對方傳送過來的值想比較,如果相等,則通過認證,否則斷開連線。
第九步,若第八步的驗證通過,則雙方交換的相同金鑰為第5,6步中mk。
更直觀的過程大家看下圖:
上面就是WPA3中蜻蜓金鑰交換演算法的主要內容了,由於WPA3尚未大規模商用,因此有很多實現細節還尚不清楚,要真正的實際使用還有很多工程方面的工作需要考慮,這些不是本文所關心的。因此後面我們僅做一個理論性的討論,上面的過程是對RFC7664裡面所述協議的簡化模型,源文件寫的非常冗長,但核心就在上面的過程裡,如果對協議細節有興趣可以參考原文件。
蜻蜓演算法安全性分析
從上面的金鑰交換過程可見,這個演算法確實如之前介紹所說,將認證和金鑰交換兩個功能合二為一,首先進行PSK認證,認證通過了金鑰才會生成,而對於WPA2,前兩次握手已經計算出金鑰了,後第3第4次握手是在對金鑰是否一致進行校驗,由此可見WPA3的新協議確實對於提高安全性有一定幫助。
關於轉發安全的分析
而對於轉發安全的保證在於,即使知道PSK,攻擊者可以推知P,但由於攻擊者並不知道r_A或者r_B,因此攻擊者無法通過E_A或者E_B計算ss,因為要知道r_A或r_B必須先知道m_A或m_B,而通過E_A求m_A是一個離散對數問題,這是個難解問題,知道m_A求E_A很容易,但是反過來很難,用這個非對稱性質來保證即使攻擊者知道PSK也無法根據握手過程計算出K,從而保證轉發安全。
關於中間人攻擊
從以上金鑰交換演算法的細節可以看出,對於同樣知道PSK的攻擊者來說,這種演算法也存在D-H金鑰交換演算法的毛病,就是無法防止中間人攻擊!不過考慮到無線通道想要完成中間人劫持並不容易,所以這樣考慮也尚且合情合理,不過話說回來,WiFi網路裡中間人攻擊並不是完全不可能的,只是實施有一定條件而已,因此在這一點上,我認為仍然重蹈了WPA2中“只能保證PSK不洩露情況下安全”的覆轍。
關於離線字典攻擊
接下來我們來看看字典攻擊的情況,事實上蜻蜓演算法的作者並沒有給出蜻蜓演算法可以杜絕離線字典攻擊的嚴格證明,僅僅給出了一個主觀性的分析:
首先,作為攻擊者只能被動監聽流量的情況,則如上面所說的,攻擊者無法得知r_A和r_B,要得到r_A和r_B需要計算離散對數,這是一個難解的問題,缺少這兩個引數使得攻擊者無法做僅僅代入密碼驗證的方式,因此,僅僅抓取握手包,字典攻擊無法進行。
然後,討論主動的攻擊者,攻擊者此時能夠主動和AP或者STA進行虛假的互動,此時作者假設攻擊者會選擇一個隨機的m_B值,計算P=G^(m_B )傳送給AP,其中G是Q的一個群生成元,這時候密碼可以表示成G的某個冪次,這時候AP計算的ss值則是密碼P的某個冪次,這時候假設攻擊者期望代入P進行校驗,即使成功求出正確的ss,要計算密碼也需要計算離散對數,這是個難解問題,因此作者認為此時離線字典攻擊也沒有意義。
最後,我們再看看在D-H演算法中的小子群攻擊對蜻蜓演算法是否有效,小子群攻擊也需要攻擊者主動發起一次互動,類比D-H演算法中的小子群攻擊的思想,我們知道,如果用S表示Q的一個小子群Q’中的元素,那麼S的任意次方也是Q’中的元素,因為Q是質數階群,所以子群一定存在,只要我們能找到一個元素個數足夠小的子群,取元素S,並且隨機選擇s_B,將E_B=S傳送給AP,這時候AP會計算ss=〖(P^(s_B ) E_B)〗^(r_A )=P^(s_B r_A ) S^(R_A )=〖(P^(r_A ))〗^(s_B ) R的雜湊值,併發送給STA,上式中,由於S是子群元素,所以S的r_A次方我們記作R,仍然是小子群中元素,而r_A雖然不知道,但是P^(r_A )=P^(s_A-m_A )=P^(s_A ) E_A,即可以使用s_A和E_A來計算,這時候我們未知的引數只有P和R,我們可以通過PSK生成離線字典P,然後計算ss的值,並且作hash比較,直至找出P,只要S的規模足夠小,這種離線攻擊方式還是有實施的可能性的,只不過要完成這種攻擊,攻擊者需要主動和STA或者AP完成至少一次互動,提高了攻擊成本。但實際上對於弱密碼來說,仍然是不安全的!
結論
本文詳細分析了WPA3中的蜻蜓金鑰交換演算法,雖然對於工程化的實施細節尚不明確,本文從理論角度對於其安全性得出的結論總結如下:
1.WPA3使用蜻蜓演算法,可以防止被動的攻擊者竊取資料,即可以提供轉發安全。 2.因為WPA3個人級並不建立在公鑰信任的基礎上,因此對於同樣知道PSK的攻擊者來說,無法防止中間人攻擊。 3.無法完全防止離線字典攻擊,一定條件下字典攻擊是可以實施的,不過相比WPA2,提高了攻擊成本,但如果期待WPA3協議能很好的保護12345678這種弱密碼,那還是想多了。 4.至於對KRACK之類的金鑰重灌攻擊的防禦,由於對握手過程的丟包處理機制細節還不明確,因此不確定能否防止此類攻擊,但從中間人攻擊的角度,此類攻擊在WPA3中仍然存在可能性。
*本文作者:阿里安全技術,轉載請註明來自FreeBuf.COM