逆向是不可能逆向的
在正式介紹MD5“破解”的方法前,先說明一點:我們沒辦法把MD5碼還原對應的原文。道理很簡單,任意長度的數據經過MD5處理后,所包含的信息量已經大大減少。要是可以還原的話,那MD5豈不是成為壓縮算法??
所謂的“破解”指的是“碰撞”。即找到一個原文,算出來的MD5碼和已知的MD5碼一樣。接下來介紹一些常見的破解方法。
暴力碰撞:窮舉法&字典法
小標題上寫了兩種方法:窮舉法和字典法。但是我認為它們的本質是一樣的,都是利用計算機的資源嘗試碰撞已知的MD5碼。這里就放在一起了。
窮舉法非常簡單,就是不停地嘗試各種字符的排列組合,看哪一個組合的MD5碼能對上。可惜缺點是太耗費時間了。我們舉個栗子,假設我們要破解一個6位大小寫字母和數字混合的密碼,那么一共有 [公式] 種組合。這個數的大小超過500億。
既然計算如此費時,能不能考慮把計算結果以映射表的形式存放起來,一個蘿卜一個坑,一個原文對應著一個MD5碼呢?可以呀!這就是傳說中的“字典法”。將已知的MD5碼查表,直接反查出原文。字典法體現了算法設計的“以空間換時間”的思想。缺點是比較耗費空間。不過現在硬盤的價格變得白菜價了,空間開銷不算什么。
這是一個用字典法破解MD5的網站:https://www.cmd5.com/password.aspx
時間和空間的折中:哈希鏈表&彩虹表法
如果說窮舉法太耗費時間,字典法太耗費存儲空間的話,我們能不能考慮在時間消耗和空間消耗之間折中呢?我們可以考慮用鏈表將一系列有意義的原文和MD5碼串起來。
要構造這樣的鏈表,我們需要兩個函數:哈希函數H(x)和衰減函數(reduction function)R(x)。哈希函數可以是MD5,也可以是其他的消息摘要算法。H(x)的值域是R(x)的定義域,R(x)的值域是H(x)的定義域。R(x)不是H(x)的反函數。
將一個原文不停地使用H(x)和R(x)交替進行運算k次,再將原文本身和運算結果以鏈表的形式串接起來,就可以得到結點個數為2k+1的鏈表。實際存放的時候只存放首端和末端兩個原文即可。這種鏈表叫做“哈希鏈表”,體現了算法設計的“時空權衡”(Space and Time Tradeoffs)。
舉個栗子,假設原文s=abcabc,經過2次交替運算,得到以下的鏈表:
abcabc->H(x)->3C8B0D7A->R(x)->eopmca->H(x)->7E9F216C->R(x)->rapper
以上數據均為舉例編造的,僅為說明原理使用。那我們存放這個鏈表的時候,只需要記錄abcabc和rapper兩個原文即可。
假設我們要破解的摘要值(哈希鏈表的H(x)不一定是MD5算法,這里用更準確的說法代替MD5碼)是7E9F216C,經過R(x)運算得到rapper,說明我們要尋找的原文就在以rapper為末端的哈希鏈表中。從首端開始經過多次運算,我們發(fā)現eopmca的摘要值就是7E9F216C。于是就反查出7E9F216C對應的原文是eopmca。
如果在生成哈希鏈表的時候依次使用多個不一樣的R(x),此時的哈希鏈表就是“彩虹表”。
這里有已經計算好的彩虹表:http://project-rainbowcrack.com/table.htm
差分攻擊
上面介紹的窮舉法、字典法和彩虹表法都是暴力破解,適用于任何的消息摘要算法。真正意義上MD5算法的破解,是2004年山東大學王小云教授提出的MD5碰撞方法。她所用到的方法正是差分攻擊。
這種方法概括起來說是這樣的:給定一個1024位的原文M1,加上一個特定的常數得到的新的明文M2。M1和M2的MD5碼是一樣的。(出處及具體操作見參考文獻[1])這個特定的常數到底是怎么找出來的?筆者當時在查閱原始文獻的時候也不清楚。因此后來的研究者開始對怎么樣差分進行了各種各樣的研究。這里就不再贅述。
后記
其實還有一種破解MD5的方法——長度擴展攻擊。不過這種方法是在一定條件下(破解加鹽之后產生的MD5碼)才能用的。這種方法由MD5分塊計算的特性而來。
1、算法的公開并不意味著不安全;RSA 的算法也是公開的,AES 也是公開的。現代密碼學的安全性從不是靠算法的保密來保證的。
2、目前沒有軟件能有效地破解 MD5。大多數時候只是把常見字符串的 MD5 存了起來為彩虹表,然后直接反查。
3、再次強調 MD5 只是哈希,而不是加密。MD5 是沒有可能解密的,因為一個 MD5 可能對應無數種可能的明文。
4、MD5 目前來說還是可以用的,尤其是考慮到合適的加鹽以后可以解決大多數彩虹表帶來的危險。當然現在已經很多人提倡用 SHA 系列的哈希算法取代 MD5。
對密碼學一竅不通,以上都是我亂編的,實在編不下去了……