說到MD5,那我們首先要知道什么是MD5,開始吧
MD5的典型應用是對一段信息(Message)產生信息摘要(Message-Digest),以防止被篡改。比如,在UNIX下有很多軟件在下載的時候都有一個文件名相同,文件擴展名為.md5的文件,在這個文件中通常只有一行文本,大致結構如:
MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461
這就是tanajiya.tar.gz文件的數字簽名。MD5將整個文件當作一個大文本信息,通過其不可逆的字符串變換算法,產生了這個唯一的MD5信息摘要。為了讓讀者朋友對MD5的應用有個直觀的認識,筆者以一個比方和一個實例來簡要描述一下其工作過程:
大家都知道,地球上任何人都有自己獨一無二的指紋,這常常成為公安機關鑒別罪犯身份最值得信賴的方法;與之類似,MD5就可以為任何文件(不管其大小、格式、數量)產生一個同樣獨一無二的“數字指紋”,如果任何人對文件名做了任何改動,其MD5值也就是對應的“數字指紋”都會發生變化。
我們常常在某些軟件下載站點的某軟件信息中看到其MD5值,它的作用就在於我們可以在下載該軟件后,對下載回來的文件用專門的軟件(如Windows MD5 Check等)做一次MD5校驗,以確保我們獲得的文件與該站點提供的文件為同一文件。利用MD5算法來進行文件校驗的方案被大量應用到軟件下載站、論壇數據庫、系統文件安全等方面。
MD5的典型應用是對一段Message(字節串)產生fingerprint(指紋),以防止被“篡改”。舉個例子,你將一段話寫在一個叫 readme.txt文件中,並對這個readme.txt產生一個MD5的值並記錄在案,然后你可以傳播這個文件給別人,別人如果修改了文件中的任何內容,你對這個文件重新計算MD5時就會發現(兩個MD5值不相同)。如果再有一個第三方的認證機構,用MD5還可以防止文件作者的“抵賴”,這就是所謂的數字簽名應用。
MD5還廣泛用於操作系統的登陸認證上,如Unix、各類BSD系統登錄密碼、數字簽名等諸多方。如在UNIX系統中用戶的密碼是以MD5(或其它類似的算法)經Hash運算后存儲在文件系統中。當用戶登錄的時候,系統把用戶輸入的密碼進行MD5 Hash運算,然后再去和保存在文件系統中的MD5值進行比較,進而確定輸入的密碼是否正確。通過這樣的步驟,系統在並不知道用戶密碼的明碼的情況下就可以確定用戶登錄系統的合法性。這可以避免用戶的密碼被具有系統管理員權限的用戶知道。MD5將任意長度的“字節串”映射為一個128bit的大整數,並且是通過該128bit反推原始字符串是困難的,換句話說就是,即使你看到源程序和算法描述,也無法將一個MD5的值變換回原始的字符串,從數學原理上說,是因為原始的字符串有無窮多個,這有點象不存在反函數的數學函數。所以,要遇到了md5密碼的問題,比較好的辦法是:你可以用這個系統中的md5()函數重新設一個密碼,如admin,把生成的一串密碼的Hash值覆蓋原來的Hash值就行了。
正是因為這個原因,現在被黑客使用最多的一種破譯密碼的方法就是一種被稱為"跑字典"的方法。有兩種方法得到字典,一種是日常搜集的用做密碼的字符串表,另一種是用排列組合方法生成的,先用MD5程序計算出這些字典項的MD5值,然后再用目標的MD5值在這個字典中檢索。我們假設密碼的最大長度為8位字節(8 Bytes),同時密碼只能是字母和數字,共26+26+10=62個字符,排列組合出的字典的項數則是P(62,1)+P(62,2)….+P(62,8),那也已經是一個很天文的數字了,存儲這個字典就需要TB級的磁盤陣列,而且這種方法還有一個前提,就是能獲得目標賬戶的密碼MD5值的情況下才可以。這種加密技術被廣泛的應用於UNIX系統中,這也是為什么UNIX系統比一般操作系統更為堅固一個重要原因。
通過上邊的資料我們大概可以知道,MD5是一種難以逆向(逆轉)的加密方式,那么我們在程序中,究竟怎么使用呢??
今天的案例,就來解答的下疑惑吧!
package cn.arebirth.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5 { public static String getMD5(String plainText, int length) { try { MessageDigest md = MessageDigest.getInstance("MD5");//獲取MD5實例 md.update(plainText.getBytes());//此處傳入要加密的byte類型值 byte[] digest = md.digest();//此處得到的是md5加密后的byte類型值 /* 下邊的運算就是自己添加的一些二次小加密,記住這個千萬不能弄錯亂, 否則在解密的時候,你會發現值不對的(舉例:在注冊的時候加密方式是一種, 在我們登錄的時候是不是還需要加密它的密碼然后和數據庫的進行比對,但是 最后我們發現,明明密碼對啊,就是打不到預期效果,這時候你就要想一下,你是否 有改動前后的加密方式) */ int i; StringBuilder sb = new StringBuilder(); for (int offset = 0; offset < digest.length; offset++) { i = digest[offset]; if (i < 0) i += 256; if (i < 16) sb.append(0); sb.append(Integer.toHexString(i));//通過Integer.toHexString方法把值變為16進制 } return sb.toString().substring(0, length);//從下標0開始,length目的是截取多少長度的值 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } }
通過上邊的代碼我們就可以實現一個簡單的注冊和登錄時候的加密解密方式啦!具體實現就不做演示了,把思路留下,不會的小伙伴思考下。
ps:
注冊的時候:我們把密碼的值進行MD5加密后在塞入數據庫
登錄的時候:我們把密碼的值進行MD5加密然后去和數據庫里面的值進行比對