"MD5"加密演算法全解析
大家好,我們現在來講解關於加密方面的知識,說到加密我認為不得不提MD5,因為這是一種特殊的加密方式,它到底特殊在哪,現在我們就開始學習它
全稱:message-digest algorithm 5
翻譯過來就是:資訊 摘要 演算法 5
1.特點
1.長度固定:
不管多長的字串,加密後長度都是一樣長
作用:方便平時資訊的統計和管理2.易計算:
字串和檔案加密的過程是容易的.
作用: 開發者很容易理解和做出加密工具3.細微性
一個檔案,不管多大,小到幾k,大到幾G,你只要改變裡面某個字元,那麼都會導致MD5值改變.
作用:很多軟體和應用在網站提供下載資源,其中包含了對檔案的MD5碼4.不可逆性
你明明知道密文和加密方式,你卻無法反向計算出原密碼.
作用:基於這個特點,很多安全的加密方式都是用到.大大提高了資料的安全性
2.後續講解
關於撞庫破解:
這是概率極低的破解方法,原理就是:
1.建立一個大型的資料庫,把日常的各個語句,通過MD5加密成為密文,不斷的積累大量的句子,放在一個龐大的資料庫裡.
2.比如一個人拿到了別人的密文,想去查詢真實的密碼,就需要那這個密文去到提供這個資料庫的公司網站去查詢.
這就是撞庫的概念.
3.關於MD5加鹽:
比如我的銀行密碼是”12345”
1.得到的MD5是:827ccb0eea8a706c4c34a16891f84e7b
2.一個人擷取到這個密文,那麼通過撞庫肯定容易撞出12345.
3.我們要做的就是加鹽,銀行密碼還是”12345”,然後我把銀行密碼加上我特定的字串才計算MD5
所以密碼還是那個密碼,但是變成求”12345密碼加密987”的MD5值,然後再得到MD5,那麼這個MD5起碼可以確認那個資料庫不會有.
說了那麼多我們開始我們的MD5工具的製作
我們一般加密都是加密字串或者檔案,所以我們的工具就有加密字串和檔案的兩種方法,兩個方法同名,通過過載完成
1.加密字串
邏輯思維:
1.獲取資訊摘要物件:md5
通過資訊摘要單例的建構函式獲取:
MessageDigest md5 = MessageDigest.getInstance("MD5");
2.資訊摘要物件是對位元組陣列進行摘要的,所以先獲取字串的位元組陣列.
byte[] bytes = str.getBytes();
3.資訊摘要物件對位元組陣列進行摘要,得到摘要位元組陣列:
byte[] digest = md5.digest(bytes);
4.把摘要陣列中的每一個位元組轉換成16進位制,並拼在一起就得到了MD5值.
(PS,有些轉換過來得到的是前面有6個f的情況,如:ffffff82,這是因為前面有6組4個1,所以提前把這6組1111先變成0就好了,然後再轉16進位制就沒有f了)
(其實也可以在後面續把f去掉)
2.加密檔案
方法傳入的是檔案物件 : file
1.因為是檔案不是方法,所以不是像剛才那樣通過摘要獲取字串.
2.使用到另一個方法即可:就是資訊摘要物件更新:md5.update(byte[] input)方法,用法是通過讀取流,不斷的更新從流中讀到的”資訊陣列”.
3.然後通過”資訊摘要物件”獲取摘要,不用引數:md5.digest(),此時返回的陣列就已經是包含內容的摘要陣列了
以下是詳細程式碼:
public class MD5Tool {
public static void main(String[] args) throws Exception {
/*--------------字串--------------*/
String str = "12345";
String md1 = getMD5(str);
System.out.println(md1);//827ccb0eea8a706c4c34a16891f84e7b
/*--------------檔案--------------*/
File file = new File("D:\\1.mp3");
String md2 = getMD5(file);
System.out.println(md2);//9068aaead9a5b75e6a54395d8183ec9
}
/**
* 邏輯:
*
* 1.獲取md5物件,通過"資訊摘要"獲取例項構造("MD5").
* 2.md5物件對("字串的"位元組形式"-得到的陣列)進行摘要",那麼會返回一個"摘要的位元組陣列"
* 3.摘要位元組陣列中的"每個二進位制值"位元組形式,"轉成十六進位制形式",然後再把這些值給拼接起來,就是MD5值了
* (PS:為了便於閱讀,把多餘的fff去掉,並且單個字元前加個0)
*
*/
public static String getMD5(String str) throws Exception {
String MD5 = "";
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = str.getBytes();
byte[] digest = md5.digest(bytes);
for (int i = 0; i < digest.length; i++) {
//摘要位元組陣列中各個位元組的"十六進位制"形式.
int j = digest[i];
j = j & 0x000000ff;
String s1 = Integer.toHexString(j);
if (s1.length() == 1) {
s1 = "0" + s1;
}
MD5 += s1;
}
return MD5;
}
//過載,所以使用者傳入"字串"或者"檔案"都可以解決.
/**
* 處理邏輯:
* 1.現在傳入的是"檔案",不是字串
* 2.所以資訊摘要物件.進行摘要得到陣列不能像上面獲得:md5.digest(bytes),因為不是str.getBytes得到bytes
* 3.其實還是通過mdt.digest();獲取到位元組陣列,但是前期必須要有一個方法必須是md5.update(),即"資訊摘要物件"要先更新
* 4."資訊摘要更新"裡面有(byte[] input),說明是讀取流獲取到的陣列,所以我們就用這個方法.
* 5.所以最終的邏輯就是:
*
* 1.獲取檔案的讀取流
* 2.不停的讀取流中的"內容"放入字串,放一部分就"更新"一部分.直到全部完畢
* 3.然後呼叫md5.digest();就會得到有內容的位元組陣列,剩下的就和上邊一樣了.
*/
public static String getMD5(File file) throws Exception {
String MD5 = "";
MessageDigest md5 = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[1024 * 5];
int len = -1;
while ((len=fis.read(bytes))!=-1) {
//一部分一部分更新
md5.update(bytes, 0, len);
}
byte[] digest = md5.digest();
for (int i = 0; i <digest.length; i++) {
int n = digest[i] & 0x000000ff;
String s = Integer.toHexString(n);
MD5 += s;
}
return MD5;
}
}
拓展
0xfffffff代表的含義:
0x:代表16進位制;
一個f代表:4個1,即(1111);
所以0xffffffff代表:8組4個1
1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111
所以剛才的0xffffff82就是前面6組都是1,後面兩組是
1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 0111 - 0010
所以先與上0x000000ff,即
0000 - 0000 - 0000 - 0000 - 0000 - 0000 - 1111 - 1111
就得到了82了
上面的方法也可以寫寫成:
for (int i = 0; i < digest.length; i++) {
//摘要位元組陣列中各個位元組的"十六進位制"形式.
String s1 = Integer.toHexString( digest[i]);
//如果是8個長度的,把前面的6個f去掉,只獲取後面的
if (s1.length() == 8) {
s1 = s1.substring(6);
}
if (s1.length() == 1) {
s1 = "0" + s1;
}
MD5 += s1;
}