一、目標
李老板:什么叫白盒AES算法?
奮飛: 將密鑰進行白盒化處理,融入到整個加密過程中,使密鑰無法跟蹤還原,保障密鑰安全。簡單的說,就是你可以明明白白的調試整個算法過程,怎么看都像是AES算法,但卻是怎么也找不到密鑰在哪里?
AES算法的介紹請參照
http://91fans.com.cn/post/ilikeaes/
DFA(Differential Fault Analysis) 的原理和算法推導過程,請參照文末的鏈接。
我們今天用一個源碼實例來操作一下,還原白盒AES算法的密鑰
二、步驟
構造缺陷數據
DFA攻擊簡單來說就是在倒數第一輪列混合和倒數第二輪列混合之間(在AES-128中也就是第8輪和第9輪之間,因為最后第10輪不做列混合),修改此時中間結果的一個字節,會導致最終密文和正確密文有4個字節的不同。通過多次的修改,得到多組錯誤的密文,然后通過正確密文和這些錯誤密文能夠推算出第10輪的密鑰(加密模式下),繼而能推算出原始密鑰。
所以實際應用中,就需要先找準列混合的函數位置,然后在他之前去插入缺陷數據。
今天我們主要走一遍DFA還原白盒密鑰的流程,所以,我們找了一個AES的源碼來做演示,這份源碼的AES加密流程一目了然,最適合學習AES算法了。
我們先跑一遍源碼,輸出加密結果是
Output:
cypher: c8 e1 58 1f 08 6c 8b ac 01 b8 37 e1 65 9c 72 46
然后在最后一次做 aes_mix_columns 之前,插入缺陷數據
最后運行一次看結果
cypher: a2 e1 58 1f 08 6c 8b 0a 01 b8 75 e1 65 f6 72 46
和之前的正確結果相比,正好有四個字節不同,說明我們找的位置是對的。
有源碼嘛,肯定能找對了。在實際樣本分析中 如果 結果全部不同,說明時機太早了; 只有一個不同則說明時機太晚了。
然后依次改動 s的下標 s[0…15]
最后我們得到了一組正確的結果,和16組錯誤的結果
c8 e1 58 1f 08 6c 8b ac 01 b8 37 e1 65 9c 72 46
a2 e1 58 1f 08 6c 8b 0a 01 b8 75 e1 65 f6 72 46
d9 e1 58 1f 08 6c 8b 57 01 b8 05 e1 65 0d 72 46
9f e1 58 1f 08 6c 8b 96 01 b8 f5 e1 65 aa 72 46
43 e1 58 1f 08 6c 8b 6c 01 b8 e1 e1 65 4d 72 46
c8 09 58 1f 39 6c 8b ac 01 b8 37 ac 65 9c 33 46
c8 c1 58 1f b7 6c 8b ac 01 b8 37 a3 65 9c 39 64
c8 c0 58 1f 8b 6c 8b ac 01 b8 37 57 65 9c 11 46
c8 55 58 1f 76 6c 8b ac 01 b8 37 64 65 9c 68 46
c8 e1 72 1f 08 e7 8b ac 92 b8 37 e1 65 9c 72 c8
c8 e1 2f 1f 08 d1 8b ac e8 b8 37 e1 65 9c 72 01
95 a0 d2 e8 7f 09 85 bd 2e cd a6 b0 0d f7 72 ab
c8 e1 47 1f 08 9b 8b ac 81 b8 37 e1 65 9c 72 58
c8 e1 58 61 08 6c 31 ac 01 e2 37 e1 76 9c 72 46
c8 e1 58 6c 08 6c c0 ac 01 77 37 e1 2c 9c 72 46
c8 e1 58 2f 08 6c f8 ac 01 ee 37 e1 84 9c 72 46
c8 e1 58 97 08 6c 99 ac 01 66 37 e1 68 9c 72 46
phoenixAES 還原輪密鑰
有了這17組數據,我們就可以把AES-128的第10輪的輪密鑰給還原出來。 (AES-128會把原始密鑰擴展成10組密鑰)
with open('tracefile', 'wb') as t:
t.write("""
c8e1581f086c8bac01b837e1659c7246
a2e1581f086c8b0a01b875e165f67246
d9e1581f086c8b5701b805e1650d7246
9fe1581f086c8b9601b8f5e165aa7246
43e1581f086c8b6c01b8e1e1654d7246
c809581f396c8bac01b837ac659c3346
c8c1581fb76c8bac01b837a3659c3964
c8c0581f8b6c8bac01b83757659c1146
c855581f766c8bac01b83764659c6846
c8e1721f08e78bac92b837e1659c72c8
c8e12f1f08d18bace8b837e1659c7201
95a0d2e87f0985bd2ecda6b00df772ab
c8e1471f089b8bac81b837e1659c7258
c8e15861086c31ac01e237e1769c7246
c8e1586c086cc0ac017737e12c9c7246
c8e1582f086cf8ac01ee37e1849c7246
c8e15897086c99ac016637e1689c7246
""".encode('utf8'))
phoenixAES.crack_file('tracefile',verbose=0)
把正確密文和錯誤密文喂進去,第10輪的輪密鑰就出來了。 數學就是這么神奇。
Last round key #N found:
13111D7FE3944A17F307A78B4D2B30C5
Stark 從任意一輪的AES-128輪密鑰,來還原原始密鑰
活還沒干完,我們拿到的僅僅是第10輪的輪密鑰,但是我們的最終目標是原始密鑰。
https://github.com/SideChannelMarvels/Stark
Stark就是干這個的,編譯好之后,傳入參數, 輪密鑰 和 輪數
./main 13111D7FE3944A17F307A78B4D2B30C5 10
K00: 000102030405060708090A0B0C0D0E0F
K01: D6AA74FDD2AF72FADAA678F1D6AB76FE
K02: B692CF0B643DBDF1BE9BC5006830B3FE
K03: B6FF744ED2C2C9BF6C590CBF0469BF41
K04: 47F7F7BC95353E03F96C32BCFD058DFD
K05: 3CAAA3E8A99F9DEB50F3AF57ADF622AA
K06: 5E390F7DF7A69296A7553DC10AA31F6B
K07: 14F9701AE35FE28C440ADF4D4EA9C026
K08: 47438735A41C65B9E016BAF4AEBF7AD2
K09: 549932D1F08557681093ED9CBE2C974E
K10: 13111D7FE3944A17F307A78B4D2B30C5
我愛死數學了,它真的把每一輪密鑰都還原出來了,源碼里面我們的原始key就是
BYTE bKey16[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
完事,收工,不要走開,仔細看總結。
三、總結
1、DFA的原理和數學推導請參考下列資料,還有白龍寫的 白盒 AES 密碼學系列 也非常棒。
https://bbs.pediy.com/thread-254042.htm
https://blog.quarkslab.com/differential-fault-analysis-on-white-box-aes-implementations.html
2、真實樣本中,尋找插入缺陷數據的位置非常重要,能明顯的看到加密經過了10次循環或者15次循環就比較簡單。我就遇到一個樣本,只要5次循環,他做了一些等價運算來合并了一些操作,這時候就要記口訣了 結果全部不同,說明時機太早了; 只有一個不同則說明時機太晚了
3、AES-128可以從一組輪密鑰來還原原始密鑰,AES-256就需要兩組密鑰了,AES-256下如何進行DFA攻擊,我還沒有驗證過。
4、分析加密算法,最好找個清晰的源碼實現,然后和樣本里的邏輯相互對照。
美妙人生的關鍵在于你能迷上什么東西。