MD5演算法如何被破解
小明:老師,上次您講了MD5演算法。用它生成的資訊摘要,真的可以被破解嗎?
老師:有很多種方法可以破解,不過需要明確一點,這裡所謂的破解,並非把摘要還原成原文。為什麼呢?因為固定128位的摘要是有窮的,而原文數量是無窮的,每一個摘要都可以由若干個原文通過Hash得到。
小明:如果是這樣的話,網上所說的MD5破解到底是怎麼回事呢?
老師:對於MD5的破解,實際上都屬於【碰撞】。比如原文A通過MD5可以生成摘要M,我們並不需要把X還原成A,只需要找到原文B,生成同樣的摘要M即可。
設MD5的雜湊函式是H(X),那麼:
H(A) = M
H(B) = M
任意一個B即為破解結果。
B有可能等於A,也可能不等於A。
用一個形象的說法,A和B的MD5結果“殊途同歸”。
MD5碰撞通常用於登陸密碼的破解。應用系統的資料庫中儲存的使用者密碼通常都是原密碼的MD5雜湊值,每當使用者登入時,驗簽過程如下:
如果我們得到了使用者ABC的密碼雜湊值E10ADC3949BA59ABBE56E057F20F883E,並不需要還原出原密碼123456,只需要“碰撞”出另一個原文654321(只是舉例)即可。登入時,完全可以使用654321作為登陸密碼,欺騙過應用系統的驗籤。
小明:那麼,具體如何來實現MD5摘要的碰撞呢?
老師:MD5碰撞的方法有很多,主要包括暴力列舉法、字典法、彩虹表法等等。
暴力列舉法:
老師:暴力列舉法顧名思義,就是簡單粗暴地枚舉出所有原文,並計算出它們的雜湊值,看看哪個雜湊值和給定的資訊摘要一致。這種方法雖然簡單,但是時間複雜度極高。想象一下,僅僅長度8位的密碼就有多少種排列組合的可能性?
小明:只考慮大小寫字母和數字,每一位有62種可能,那麼8位密碼的排列組合就是62的8次方,218340105584800,約等於二百萬億!
老師:是的,這樣的資料量如果使用普通的單機來破解,恐怕頭髮白了也破解不完。不過,我們也可以做一些取巧,優先嚐試生日和有意義的單詞,這樣就可以把窮舉範圍縮小很多。
字典法:
老師:如果說暴力列舉法是ongoing時間換空間,那麼字典法則是用空間換時間。黑客利用一個巨大的字典,儲存儘可能多的原文和對應的雜湊值。每次用給定的資訊摘要查詢字典,即可快速找到碰撞的結果。
不過,這樣做雖然每次破解速度很快,但是生成字典需要巨大的空間。仍然以8位密碼舉例,需要多大空間呢?
小明:剛才計算過有218340105584800種可能性,每一對對映佔192(128+64)bit。那麼大約需要4.65PB的儲存空間。
老師:沒錯,這樣做的儲存成本實在太大了。當然,我們同樣可以取巧,優先儲存那些常用的密碼及其摘要。
小明:那麼,有沒有什麼方法可以做到時間和空間的均衡呢?
老師:有一種方法可以,那就是下面我要介紹的【彩虹表發】。
彩虹表法:
老師:彩虹表法可以說是對字典法的優化,它採用了一種有趣的資料結構:【彩虹表】。在學習彩虹表之前,我們先來了解兩個基本函式:H(X)和R(X)。
H(X):生成資訊摘要的雜湊函式,比如MD5,比如SHA256。
R(X):從資訊摘要轉換成另一個字串的衰減函式(Reduce)。其中R(X)的定義域是H(X)的值域,R(X)的值域是H(X)的定義域。但要注意的是,R(X)並非H(X)的反函式。
通過交替運算H和R若干次,可以形成一個原文和雜湊值的鏈條。假設原文是aaaaaa,雜湊值長度32bit,那麼雜湊連結串列就是下面的樣子:
這個鏈條有多長呢?假設H(X)和R(X)的交替重複K次,那麼鏈條長度就是2K+1。同時,我們只需把連結串列的首段和末端存入雜湊表中:
小明:這什麼跟什麼啊,衰減函式和雜湊鏈條,到底是幹什麼用的?
老師:別急,我們來演示一次破解過程,你就明白它們的意義了。
給定資訊摘要:920ECF10
如何得到原文呢?只需進行R(X)運算:
R(920ECF10)= kiebgt
查詢雜湊表可以找到末端kiebgt對應的首端是aaaaaa,因此摘要920ECF10的原文“極有可能”在aaaaaa到kiebgt的這個鏈條當中。
接下來從aaaaaa開始,重新交替運算R(X)與H(X),看一看摘要值920ECF10是否是其中一次H(X)的結果。從鏈條看來,答案是肯定的,因此920ECF10的原文就是920ECF10的前置節點sgfnyd。
需要補充的是,如果給定的摘要值經過一次R(X)運算,結果在雜湊表中找不到,可以繼續交替H(X)R(X)直到第K次為止。
簡單來說,雜湊連結串列代表了一組對映關係,其中每組包含K對對映,但只需要儲存鏈條首位兩個字串。假設K=10,那麼儲存空間只有全量字典的十分之一,代價則是破解一個摘要的運算次數也提高了十倍。這就是時間和空間的取捨。雖然做了取捨,但是雜湊鏈條存在一個致命的缺陷:R(X)函式的可靠性。雖然我們儘量把R(X)設計成結果均勻分佈的函式,但是再完美的函式也難免會有碰撞的情況,比如下面這樣:
給定資訊摘要:FB107E70
經過多次R(X),H(X)運算,得到結果kiebgt
通過雜湊表查詢末端kiebgt,可以找出首端aaaaaa
但是,FB107E70並不在aaaaaa到kiebgt的雜湊鏈條當中,這就是R(X)的碰撞造成的。
這個問題看似沒什麼影響,既然找不到就重新生成一組首尾對映即可。但是想象一下,當K值較大的時候,雜湊鏈很長,一旦兩條不同的雜湊鏈在某個節點出現碰撞,後面所有的明文和雜湊值全都變成了一毛一樣的值。
這樣造成的後果就是冗餘儲存。原本兩條雜湊鏈可以儲存 2K個對映,由於重複,真正儲存的對映數量不足2K。
這個時候,我們設計了彩虹表。彩虹表對雜湊鏈進行了改進,把原先的R(X)的函式改進成從R1(X)到Rk(X)一共K個衰減函式。這樣一來雖然也可能發生碰撞,但是碰撞只會發生在同一級運算,如R1和R1碰撞,R3和R3碰撞,大大減小了儲存重複的機率。
小明:好複雜,聽的頭都暈了。那想要破解MD5演算法,有沒有比彩虹表更厲害的方法呢?
老師:還真有。
2004年,王小云教授提出了非常高效的MD5碰撞方法。
2009年,馮登國、謝濤利用差分攻擊,將MD5的碰撞演算法複雜度進一步降低。
有興趣的小夥伴可以通過資料進行更深入的學習。
幾點補充:
對於單機來說,暴力列舉法的時間成本很高,字典法的空間成本很高。但是利用分散式計算和分散式儲存,仍然可以有效破解MD5演算法。因此這兩種方法同樣被黑客們廣泛使用。
關注微信公眾號和今日頭條,精彩文章持續更新中。。。。。