上一篇文章整理了Base64算法的相關知識,嚴格來說,Base64只能算是一種編碼方式而非加密算法,這一篇要說的MD5,其實也不算是加密算法,而是一種哈希算法,即將目標文本轉化為固定長度,不可逆的字符串(消息摘要).
簡單了解
MD5(Message Digest Algorithm 5),翻譯過來是消息摘要算法第五版,按照慣例,我們推理可能也有MD2,MD3這樣名字的歷史版本..
即使完全不了解這個算法的原理,我們也可以從命名中看出一些眉道,所謂摘要,就是一個簡短的概括,像我寫過的畢業論文,上來第一部分就是摘要,它對后面長篇大論的文章做了一個簡短有力的概括,其實MD5的作用也有點這樣的味道,我們來看一段關於描述MD5算法作用的文字:
MD5的作用是讓大容量信息在用數字簽名軟件簽署私人密匙前被"壓縮"成一種保密的格式(就是把一個任意長度的字節串變換成一定長的大整數),它主要用於確保數據傳輸的完整性和一致性.
假設A要給遠方的B發送一個文本文件,有100萬字,當B收到文件的時候,該怎么知道這個文件在傳過來的途中有沒有被篡改呢,要是有人中途截斷並篡改了文件內容那就不太妙了,這時候MD5就派上用場了,不管多大的文件,通過MD5加密之后都會得到一個定長的字符串,一般是32位,這時候A先對文件用MD5加密一下,得到的一串密文順便也傳給B,當B收到后文件,同樣對文件用MD5加密一下,看看得到的密文是否和A傳過來的一致,如果一致,說明這個文件是安全的.這樣就確保了數據傳輸的完整性.
事實上,我們從網絡上下載文件的時候,有時候下載的文件后面都有一段MD5的密文,比如 MD5(e8027a87676ea48b3a3c9b0a4d8d87a0),作用和上面我舉得例子類似(我覺得是這樣....).
MD5是一種公開的不可逆的算法,意味着是沒有辦法直接破解密文得到源數據信息的,md5可以對一個對一個任意大小的文件進行哈希運算,得到一個唯一的32位字符串.
簡單了解了MD5的功能,就可以直接看代碼了.
java代碼實現MD5
package com.wang.encryption; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; import java.security.MessageDigest; /** * @author yogo.wang * @date 2016/11/04-下午1:02. */ public class MD5Test { public static String md5Encode(String msg) throws Exception{ byte[] msgBytes = msg.getBytes("utf-8"); /** * 聲明使用Md5算法,獲得MessaDigest對象 */ MessageDigest md5 = MessageDigest.getInstance("MD5"); /** * 使用指定的字節更新摘要 */ md5.update(msgBytes); /** * 完成哈希計算,獲得密文 */ byte[] digest = md5.digest(); /** * 以上兩行代碼等同於 byte[] digest = md5.digest(msgBytes); */ return bytesToHexString(digest); } /** * 將byte數組轉化為16進制字符串形式 * @param bys * @return */ public static String byteArr2hexString(byte[] bys){ StringBuffer hexVal=new StringBuffer(); int val=0; for (int i = 0; i < bys.length; i++) { //將byte轉化為int 如果byte是一個負數就必須要和16進制的0xff做一次與運算 val=((int)bys[i]) & 0xff; if(val<16){ hexVal.append("0"); } hexVal.append(Integer.toHexString(val)); } return hexVal.toString(); } public static void main(String[] args) throws Exception { String msg="helloworld"; String result=md5Encode(msg); String result1=md5Encode(msg); System.out.println(result); System.out.println(result1); } }
運行代碼,得到的輸出結果如下:
fc5e038d38a57032085441e7fe7010b0
fc5e038d38a57032085441e7fe7010b0
可見,對同一個字段進行加密,得到的密文總是一致的.接下來看一下MD5實現的原理和應用.
MD5實現原理及應用
我看了一些網上的朋友自己實現的md5哈希的代碼,只能說半知半解,這里貼一下,網絡上的一些實現的步驟介紹(隨便看看就好).
MD5算法的原理主要分為以下幾個步驟,
1)填充:首先將輸入信息的長度(bit)進行填充,使得對512求余的結果等於448。填充的方法是填充一個1和n個0。
2)記錄信息長度:用64位來存儲填充前信息長度。這64位加在第一步結果的后面,這樣信息長度就變為N*512+448+64=(N+1)*512位。
3)裝入標准的幻數:標准的幻數是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。如果在程序中定義應該是(A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。
4)四輪循環運算:循環的次數是分組的個數(N+1)。
這里主要介紹一下,java中MessageDigest這個類,查看jdk的開發文檔,可以看到該類位於java.security包下,文檔對MessageDigest的描述如下:
public abstract class MessageDigest
extends MessageDigestSpi
此 MessageDigest 類為應用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數,它接收任意大小的數據,輸出固定長度的哈希值。
MessageDigest 對象開始被初始化。該對象通過使用 update 方法處理數據。任何時候都可以調用 reset 方法重置摘要。一旦所有需要更新的數據都已經被更新了,應該調用 digest 方法之一完成哈希計算。
對於給定數量的更新數據,digest 方法只能被調用一次。digest 被調用后,MessageDigest 對象被重新設置成其初始狀態。
實現可隨意選擇是否實現 Cloneable 接口。客戶端應用程可以通過嘗試復制和捕獲 CloneNotSupportedException 測試可復制性:
MessageDigest md = MessageDigest.getInstance("SHA");
try {
md.update(toChapter1);
MessageDigest tc1 = md.clone();
byte[] toChapter1Digest = tc1.digest();
md.update(toChapter2);
...etc.
} catch (CloneNotSupportedException cnse) {
throw new DigestException("couldn't make digest of partial content");
}
注意,如果給定的實現是不可復制的,而事先已知摘要的數目,則仍然能夠通過實例化幾個實例計算中間摘要。
主要方法的作用,在上面代碼的注釋中已經給出,這里就不在介紹了.
MD5的應用領域主要可以分為以下幾類:
1、防止被篡改(文件完整性驗證),比如我提供文件下載,為了防止不法分子在安裝程序中添加木馬,我可以在網站上公布由安裝文件得到的MD5輸出結果。
2、防止直接看到明文(口令加密),現在很多網站在數據庫存儲用戶的密碼的時候都是存儲用戶密碼的MD5值。這樣就算不法分子得到數據庫的用戶密碼的MD5值,也無法知道用戶的密碼。
3、防止抵賴(數字簽名),例如A寫了一個文件,認證機構對此文件用MD5算法產生摘要信息並做好記錄。這樣可以防止出現以后A不承認此事而帶來的麻煩。
雖然MD5是一種不可逆的算法,但並不意味着不可破解,大多數用戶設置密碼時都會使用比較有特殊意義的字段,比如生日,名字簡拼,等,如果我把你的相關的信息,猜測出你可能會使用的密碼,然后把他們都用MD5加密一遍,就得到很多個密文,再拿到你的密碼的密文和我的密文庫里一一對比,如果密文能匹配,那么你的密碼本身也就不攻自破了.同樣的道理,現在有很多網站有提供了一些在線的MD5值查詢功能,輸入MD5密碼值后,如果在數據庫中存在,那么可以很快獲取其密碼值,道理也是一樣的,比如上面代碼中我是對"helloworld"這個字符串進行MD5加密,理論上你只知道密文是不可能破解我的原始數據的,但事實上真的是這樣嗎? 來看一個網站http://pmd5.com/
我輸入上面代碼生成的密文之后,網站一下子就破解了,原理也就很簡單了.
關於MD5更詳細的文字資料,可以移步百度百科,介紹的挺詳細的,值得一看.
相關鏈接