MD5(Message-Digest Algorithm 5) ,是一種使用廣泛的信息摘要算法,是在1992年由美國的密碼學家羅納德·李維斯特首次提出。
為什么有人認為是可以用來加密,有人卻認為是散列呢?到底為什么呢?
MD5到底是什么?
那么MD5算法到底是什么?我們可以將MD5算法看做是一臺處理機器,可以將計算機中種任意的數據放入這臺機器中,然后經過這臺機器處理之后,就會產生一個固定長度為128比特的MD5加密的值,傳入這個機器的可以是字符串,也可以是一張圖片,還可以是一段視頻。
可以看出來上面的這個操作是一個典型的哈希函數式的操作方式,可以將任意的數據內容變成一個固定長度的散列值,同一個輸入,得到的輸出結果始終是相同的,而不同的輸入,得到的輸出結果也是一樣的。
根據這樣的特性,我們可以用它來驗證一個文件是否被修改過了,或者是可以用它來完成用戶登錄操作用戶名和密碼的計算等等。
但是就是這樣一個被廣泛使用的加密算法,卻被人證明已經不再安全了。這到底是怎么回事呢?
MD5到底做了什么?
為什么MD5算法已經被證明不再安全了,但是還是有很多人在使用呢?這就要從MD5算法的原理講起了。
MD5算法生成一個MD5的值,可以分為三個步驟。
- 填充對齊
- 分塊
- 多輪壓縮
填充對齊
我們知道在計算機中存儲的數據最終都是以二進制的0和1的方式進行存儲的。那么當我們拿到一個數據之后第一步需要做的事情就是對數據進行補齊。
舉個例子,假設我們得到了715個Bit的數據那么這個時候,就需要將其補齊為512的整數倍數,這里我們發現715Bit離1024Bit比較近,那么,就需要補上309個Bit,讓其達到1024Bit。然后在用于補齊的數據中最后的64Bit用來表示原始數據的大小。中間剩余的位置從原始數據開始計算,第一個位置填1,其余的位置全部是0。
當然有一種情況,假設,原始數據大小就是接近了1024這個時候并不能填充64個Bit來表示原始數據大小那么該怎么辦呢?那么這個時候,就需要將其補齊到下一個512的倍數,這個也就是1536Bit,然后再按照上面的方法進行補齊。
那么也就是說無論最終數據的大小是多少,只要無法保證上述條件的滿足,就需要進行補齊,即使得到的數據恰好是512的整數倍數,我們依然也要進行上述的操作。補齊之后,就需要進行第二步操作分塊。
分塊
因為通過數據補齊操作,已經將數據補齊成了512的整數倍,所以就一定可以將這些數據以512的大小分為若干的數據塊,而我們知道MD5值最后的輸出是一個128Bit的固定大小。作者將這128個Bit分成了四個部分。并且通過幻數為這四個部分設置了初始值。
為什么是幻數呢?原因很簡單就是為了讓你猜不到。
這樣分塊也就完成了。接下來就是多輪壓縮了。
多輪壓縮
經過上面的操作,我們可以將數據最終分成兩個大塊,并且我們將其中一個大塊數據拿出來,與上面128Bit的四個分塊的值,這里我們標記位A、B、C、D四個值,然后分別用這四個值與數據塊分別進行一系列的或與非以及移位運算。這個過程總共進行四輪。然后每輪壓縮操作之后,就需要分別更新A、B、C、D的值,那么經過四輪計算之后四個值一共被更新了十六次。
完成壓縮操作之后,就將A、B、C、D四個值按照順序放回到原來的位置上,這個時候散列值就被更新完成了。
這個過程之所以被稱為是壓縮,實際上就是將512Bit的數據變成了128Bit四個位置中的某個位置,從512到128,信息被壓縮了。所以整個的過程被稱為是壓縮。
然后繼續用第二個大塊重復上述的工作,這個時候唯一不同的就是128Bit的四個數據值變成了第一個大塊數據計算之后的結果。
如果后續的大塊數據還有很多,那么操作還是跟上面的操作是一樣的。
當我們完成了所有數據的壓縮操作,那么散列值就被更新成了最終的結果。整個MD5加密算法的實現過程是有點復瑣碎的,但是理解起來并不是太復雜。即使使用比較復雜的面向對象的編程語言也可以在百行代碼之內實現它。
既然我們知道了MD5算法的實現細節,那么接下來我們就來看看MD5是如何被攻破的?
MD5是如何被攻破的?
在進行攻擊之前,首先要搞清楚的就是攻擊目標是什么?不然攻擊也就沒有意義了。根據上面的分析我們知道MD5就是一個產生MD5值的計算函數,而并非對數據進行了加密。所以對于MD5的攻擊,其實并非是通過一個密鑰去進行解密。
這個很容易理解,密文之所以能成為密文,前提肯定是信息沒有損失,如果有損失的話就無法通過密文獲取到明文了。顯然MD5并不是這樣。
宏觀上來看,MD5加密之后一個500M的數據被最終壓縮成了128個Bit,然后你想用128Bit的數據恢復500M的數據,傻子才會相信呢?從微觀的角度上來看,很明顯我們在進行補齊操作和分塊操作以及后來的數據壓縮操作的過程中明顯已經改變的數據信息本身,顯然是無法直接進行恢復的。這也就導致MD5值的生成過程是一個不可逆的過程。
那么我們還攻擊個啥呢?
破解MD5的秘密?
上面我們知道了,MD5值是通過一個消息數據計算得到的,并且在數學中我們也知道,如果是一個標準的一次函數f(x)=x這種形式的話,那么一個x就對應一個y的值。也就是說一個消息也就對應了一個唯一的MD5的值。
假設 hello 對應的MD5值是123aba123dddaa3,那么也就是說在hello不變的情況下,MD5的值也是不會發生變化的。但是真的是這樣么?
上面我們提到任意的輸入都會得到一個唯一的輸出,其實這句話包含了兩個限定條件。
- 輸出位數的大小是固定的128Bit,也就是說MD5值是有范圍大小的,從0到2的128次方。
- 輸入是任意的,也就是說輸入的數據是沒有邊界的,也就是說是無窮。
那么在數學概念上來講,假設有100個房子,也就是說MD5值已經被窮舉了,那么有500個人,很顯然,肯定會有多個人住一個房子呀,也就是說很明顯,一個MD5的值可以對應多個輸入的結果呀!
這樣一來,上面我們假設的f(x)=x 的函數操作就是有問題的。那么既然產生了哈希沖突了,在MD5中稱為是碰撞,那么既然無窮對有界,那么對應的無窮也應該是無窮個。只不過,由于數據處理的緣故,我們無法找到產生碰撞的數據罷了。起碼作者在設計MD5的時候可能還沒有想到這一點。
所以顯然就不存在通過MD5值進行逆向的操作了。
既然一個MD5對應了無窮的消息,那么我們是否可以找到一個或者是我們可以窮舉的幾個能夠產生這樣的MD5值的消息呢?很顯然,這只是在理論上可行。但實際操作上,這是不行的,窮舉就是一個不可能完成的操作,畢竟數量級再那里放著2的128次方,相當于大海撈針。
真的沒有辦法了么?
是不是就沒有辦法了呢?
假設我們給定了一個消息“Hello World!”,那么它對應的MD5值我們是可以知道的。那么我們可不可以再找到另外的一個MD5值與之相同的數據呢?在MD4中,面對一些弱口令的時候,這種方式是可行的,但是在MD5中,這種方式還是有點難度的。
其實讓MD5破防的真正原因其實是下面的這個操作。
實驗室給出的破解方式?
我們不需要給定MD5值,也不需要去找到對應的消息,我們只需要制定一個規則,而這個規則就是能夠由兩個消息,產生同一個MD5就可以了。那么這個時候,操作就簡單多了。例如一個二次函數就會出現兩個X值對應一個Y值的情況呀!我們不需要找到無數個,只需要找到兩個即可。當然這只是一個簡單的例子。
那么如何是實現這個操作呢?
- 第一步、就是找到能夠產生局部碰撞的結果。
- 第二步、通過局部碰撞結果找到差分值。
- 第三步、通過差分路徑,通過消息修改,得到結果
- 第四步、通過消息修改來得到最終的碰撞結果。
很抽象,與產生MD5值的過程相比,這個過程看似簡單,實則非常復雜。實際上這也會是信息安全領域的一個關鍵,打破這個規則往往要比制定這個規則要復雜的多得多。
當然上面的操作只是在實驗室給出的操作。但是在真實的工程使用場景中來看,這種方式到底有什么用途呢?
雖然可以找到最終的碰撞值,但是這個碰撞值是通過差分路徑和消息的修改而得到的,所以說,最終得到的值也只是一個值罷了,在工程上并沒有實際的用處,但事實并非如此。
到此為止,我們知道MD5已經不再安全了,
MD5安全問題利用
假設,通過選擇前綴方式,生成了兩個MD5值相同,但是執行效果完全不同的軟件,這個時候,通過MD5校驗之后并不會發現兩個文件會有什么異常,但是你在選擇的時候,正好就選擇了哪個帶有木馬病毒的文件,這個時候,就會出現安全問題了。
在如果,張三和李四,以MD5作為某個關鍵文件的真偽驗證方式,那么很明顯通過選擇前綴的方式張三可以提前就制作出來兩個MD5值相同的文件,這樣在兩個文件內容完全是不一樣的,但是MD5值卻是一樣的,最終產生的結果就是被騙了?
那么什么是選擇前綴呢?
理解起來其實非常簡單,在上面的內容中,我們知道了,如果一個文件大小如果正好是512的話,那么很顯然,需要進行補齊操作,這個時候按照規則,補齊之后,文件后面跟的內容正好就是一串沒有意義的文件。那么如何讓這個文件產生一個MD5值一樣的其他文件呢?
通過上面的方式,我們可以知道,在大批量的數據中去找碰撞的話有點難度,不妨我們讓文件內容是一樣,只讓其中的一部分數據發生變化。這樣可以很容易就找到碰撞了,這就有點類似于,我們將一個函數的定義域給縮小了,這樣在這個小范圍定義域中去找到一個碰撞值,就會很簡單了。
總結
文章篇幅很長,相信看到這里,可能有點迷糊了!不過能認真看完一定會對你理解MD5 算法有所幫助。






