參考連接:java
https://blog.csdn.net/u012611878/article/details/54000607git
https://blog.csdn.net/worm0527/article/details/69939307算法
https://blog.csdn.net/qq_32714913/article/details/50358204數組
Hash,通常翻譯作"散列",也有直接音譯爲"哈希"的,就是把任意長度的輸入,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。
MD5與SHA1都是Hash算法,MD5輸出是128位的,SHA1輸出是160位的,MD5比SHA1快,SHA1比MD5強度高。安全
Hash是一種特殊的算法,MD5就是其中經常使用的一種。它的算法的特徵是不可逆性,而且才計算的時候全部的數據都參與了運算,其中任何一個數據變化了都會致使計算出來的Hash值徹底不一樣,因此一般用來校驗數據是否正確或用做身份驗證。常見的,論壇裏面用戶的密碼是通過MD5等Hash算法算出來的Hash值進行保存的。app
MD5ide
概述:函數
(message digest arithmetic)消息摘要算法,一種被普遍使用的密碼雜湊函數,能夠產生出一個128位元(16位元組)的散列值,用於確保信息傳輸完整一致測試
功能:ui
輸入任意長度的信息,通過處理輸出爲128位的信息;
不一樣的輸入獲得不一樣的結果
安全與不可逆:
MD5沒有解密算法。MD5不可逆的緣由是其實一種散列函數,使用的是hash算法,在計算過程當中原文的部分信息是丟失了的。
一個MD5理論上的確是可能對應無數多個原文的,由於MD5是有限多個的而原文能夠是無數多個。好比主流使用的MD5將任意長度的「字節串映射爲一個128bit的大整數。也就是一共有2^128種可能,大概是3.4*10^38,這個數字是有限多個的,而可是世界上能夠被用來加密的原文則會有無數的可能性。目前,MD5最有效的攻擊方式就是彩虹表,窮舉方式。
用途:
一、防止被修改,一段時間先後物品MD5不變說明它未被篡改
二、防止直接看明文,好比密碼的存儲
三、數字簽名
算法過程:


對MD5算法簡要的敘述能夠爲:MD5以512位分組來處理輸入的信息,且每一分組又被劃分爲16個32位子分組,通過了一系列的處理後,算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位散列值。 第一步、填充:若是輸入信息的長度(bit)對512求餘的結果不等於448,就須要填充使得對512求餘的結果等於448。填充的方法是填充一個1和n個0。填充完後,信息的長度就爲N*512+448(bit); 第二步、記錄信息長度:用64位來存儲填充前信息長度。這64位加在第一步結果的後面,這樣信息長度就變爲N*512+448+64=(N+1)*512位。 第三步、裝入標準的幻數(四個整數):標準的幻數(物理順序)是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。若是在程序中定義應該是: (A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。有點暈哈,其實想想就明白了。 第四步、四輪循環運算:循環的次數是分組的個數(N+1) 1)將每一512字節細分紅16個小組,每一個小組64位(8個字節) 2)先認識四個線性函數(&是與,|是或,~是非,^是異或) F(X,Y,Z)=(X&Y)|((~X)&Z) G(X,Y,Z)=(X&Z)|(Y&(~Z)) H(X,Y,Z)=X^Y^Z I(X,Y,Z)=Y^(X|(~Z)) 1 2 3 4 3)設Mj表示消息的第j個子分組(從0到15),<< FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s) GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s) HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s) II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s) 1 2 3 4 4)四輪運算 第一輪 a=FF(a,b,c,d,M0,7,0xd76aa478) b=FF(d,a,b,c,M1,12,0xe8c7b756) c=FF(c,d,a,b,M2,17,0x242070db) d=FF(b,c,d,a,M3,22,0xc1bdceee) a=FF(a,b,c,d,M4,7,0xf57c0faf) b=FF(d,a,b,c,M5,12,0x4787c62a) c=FF(c,d,a,b,M6,17,0xa8304613) d=FF(b,c,d,a,M7,22,0xfd469501) a=FF(a,b,c,d,M8,7,0x698098d8) b=FF(d,a,b,c,M9,12,0x8b44f7af) c=FF(c,d,a,b,M10,17,0xffff5bb1) d=FF(b,c,d,a,M11,22,0x895cd7be) a=FF(a,b,c,d,M12,7,0x6b901122) b=FF(d,a,b,c,M13,12,0xfd987193) c=FF(c,d,a,b,M14,17,0xa679438e) d=FF(b,c,d,a,M15,22,0x49b40821) 第二輪 a=GG(a,b,c,d,M1,5,0xf61e2562) b=GG(d,a,b,c,M6,9,0xc040b340) c=GG(c,d,a,b,M11,14,0x265e5a51) d=GG(b,c,d,a,M0,20,0xe9b6c7aa) a=GG(a,b,c,d,M5,5,0xd62f105d) b=GG(d,a,b,c,M10,9,0x02441453) c=GG(c,d,a,b,M15,14,0xd8a1e681) d=GG(b,c,d,a,M4,20,0xe7d3fbc8) a=GG(a,b,c,d,M9,5,0x21e1cde6) b=GG(d,a,b,c,M14,9,0xc33707d6) c=GG(c,d,a,b,M3,14,0xf4d50d87) d=GG(b,c,d,a,M8,20,0x455a14ed) a=GG(a,b,c,d,M13,5,0xa9e3e905) b=GG(d,a,b,c,M2,9,0xfcefa3f8) c=GG(c,d,a,b,M7,14,0x676f02d9) d=GG(b,c,d,a,M12,20,0x8d2a4c8a) 第三輪 a=HH(a,b,c,d,M5,4,0xfffa3942) b=HH(d,a,b,c,M8,11,0x8771f681) c=HH(c,d,a,b,M11,16,0x6d9d6122) d=HH(b,c,d,a,M14,23,0xfde5380c) a=HH(a,b,c,d,M1,4,0xa4beea44) b=HH(d,a,b,c,M4,11,0x4bdecfa9) c=HH(c,d,a,b,M7,16,0xf6bb4b60) d=HH(b,c,d,a,M10,23,0xbebfbc70) a=HH(a,b,c,d,M13,4,0x289b7ec6) b=HH(d,a,b,c,M0,11,0xeaa127fa) c=HH(c,d,a,b,M3,16,0xd4ef3085) d=HH(b,c,d,a,M6,23,0x04881d05) a=HH(a,b,c,d,M9,4,0xd9d4d039) b=HH(d,a,b,c,M12,11,0xe6db99e5) c=HH(c,d,a,b,M15,16,0x1fa27cf8) d=HH(b,c,d,a,M2,23,0xc4ac5665) 第四輪 a=II(a,b,c,d,M0,6,0xf4292244) b=II(d,a,b,c,M7,10,0x432aff97) c=II(c,d,a,b,M14,15,0xab9423a7) d=II(b,c,d,a,M5,21,0xfc93a039) a=II(a,b,c,d,M12,6,0x655b59c3) b=II(d,a,b,c,M3,10,0x8f0ccc92) c=II(c,d,a,b,M10,15,0xffeff47d) d=II(b,c,d,a,M1,21,0x85845dd1) a=II(a,b,c,d,M8,6,0x6fa87e4f) b=II(d,a,b,c,M15,10,0xfe2ce6e0) c=II(c,d,a,b,M6,15,0xa3014314) d=II(b,c,d,a,M13,21,0x4e0811a1) a=II(a,b,c,d,M4,6,0xf7537e82) b=II(d,a,b,c,M11,10,0xbd3af235) c=II(c,d,a,b,M2,15,0x2ad7d2bb) d=II(b,c,d,a,M9,21,0xeb86d391) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 5)每輪循環後,將A,B,C,D分別加上a,b,c,d,而後進入下一循環。 若是上面的過程用JAVA代碼來實現的話,代碼以下: public class MD5 { static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; //標準的幻數 private static final long A=0x67452301L; private static final long B=0xefcdab89L; private static final long C=0x98badcfeL; private static final long D=0x10325476L; //下面這些S11-S44其實是一個4*4的矩陣,在四輪循環運算中用到 static final int S11 = 7; static final int S12 = 12; static final int S13 = 17; static final int S14 = 22; static final int S21 = 5; static final int S22 = 9; static final int S23 = 14; static final int S24 = 20; static final int S31 = 4; static final int S32 = 11; static final int S33 = 16; static final int S34 = 23; static final int S41 = 6; static final int S42 = 10; static final int S43 = 15; static final int S44 = 21; //java不支持無符號的基本數據(unsigned) private long [] result={A,B,C,D};//存儲hash結果,共4×32=128位,初始化值爲(幻數的級聯) public static void main(String []args){ MD5 md=new MD5(); System.out.println("md5(abc)="+md.digest("abc")); } private String digest(String inputStr){ byte [] inputBytes=inputStr.getBytes(); int byteLen=inputBytes.length;//長度(字節) int groupCount=0;//完整分組的個數 groupCount=byteLen/64;//每組512位(64字節) long []groups=null;//每一個小組(64字節)再細分後的16個小組(4字節) //處理每個完整 分組 for(int step=0;step<groupCount;step++){ groups=divGroup(inputBytes,step*64); trans(groups);//處理分組,核心算法 } //處理完整分組後的尾巴 int rest=byteLen%64;//512位分組後的餘數 byte [] tempBytes=new byte[64]; if(rest<=56){ for(int i=0;i<rest;i++) tempBytes[i]=inputBytes[byteLen-rest+i]; if(rest<56){ tempBytes[rest]=(byte)(1<<7); for(int i=1;i<56-rest;i++) tempBytes[rest+i]=0; } long len=(long)(byteLen<<3); for(int i=0;i<8;i++){ tempBytes[56+i]=(byte)(len&0xFFL); len=len>>8; } groups=divGroup(tempBytes,0); trans(groups);//處理分組 }else{ for(int i=0;i<rest;i++) tempBytes[i]=inputBytes[byteLen-rest+i]; tempBytes[rest]=(byte)(1<<7); for(int i=rest+1;i<64;i++) tempBytes[i]=0; groups=divGroup(tempBytes,0); trans(groups);//處理分組 for(int i=0;i<56;i++) tempBytes[i]=0; long len=(long)(byteLen<<3); for(int i=0;i<8;i++){ tempBytes[56+i]=(byte)(len&0xFFL); len=len>>8; } groups=divGroup(tempBytes,0); trans(groups);//處理分組 } //將Hash值轉換成十六進制的字符串 String resStr=""; long temp=0; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ temp=result[i]&0x0FL; String a=hexs[(int)(temp)]; result[i]=result[i]>>4; temp=result[i]&0x0FL; resStr+=hexs[(int)(temp)]+a; result[i]=result[i]>>4; } } return resStr; } /** * 從inputBytes的index開始取512位,做爲新的分組 * 將每個512位的分組再細分紅16個小組,每一個小組64位(8個字節) * @param inputBytes * @param index * @return */ private static long[] divGroup(byte[] inputBytes,int index){ long [] temp=new long[16]; for(int i=0;i<16;i++){ temp[i]=b2iu(inputBytes[4*i+index])| (b2iu(inputBytes[4*i+1+index]))<<8| (b2iu(inputBytes[4*i+2+index]))<<16| (b2iu(inputBytes[4*i+3+index]))<<24; } return temp; } /** * 這時不存在符號位(符號位存儲再也不是表明正負),因此須要處理一下 * @param b * @return */ public static long b2iu(byte b){ return b < 0 ? b & 0x7F + 128 : b; } /** * 主要的操做,四輪循環 * @param groups[]--每個分組512位(64字節) */ private void trans(long[] groups) { long a = result[0], b = result[1], c = result[2], d = result[3]; /*第一輪*/ a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L); /* 1 */ d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L); /* 2 */ c = FF(c, d, a, b, groups[2], S13, 0x242070dbL); /* 3 */ b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL); /* 4 */ a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL); /* 5 */ d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL); /* 6 */ c = FF(c, d, a, b, groups[6], S13, 0xa8304613L); /* 7 */ b = FF(b, c, d, a, groups[7], S14, 0xfd469501L); /* 8 */ a = FF(a, b, c, d, groups[8], S11, 0x698098d8L); /* 9 */ d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL); /* 10 */ c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L); /* 11 */ b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL); /* 12 */ a = FF(a, b, c, d, groups[12], S11, 0x6b901122L); /* 13 */ d = FF(d, a, b, c, groups[13], S12, 0xfd987193L); /* 14 */ c = FF(c, d, a, b, groups[14], S13, 0xa679438eL); /* 15 */ b = FF(b, c, d, a, groups[15], S14, 0x49b40821L); /* 16 */ /*第二輪*/ a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L); /* 17 */ d = GG(d, a, b, c, groups[6], S22, 0xc040b340L); /* 18 */ c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L); /* 19 */ b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL); /* 20 */ a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL); /* 21 */ d = GG(d, a, b, c, groups[10], S22, 0x2441453L); /* 22 */ c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L); /* 23 */ b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L); /* 24 */ a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L); /* 25 */ d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L); /* 26 */ c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L); /* 27 */ b = GG(b, c, d, a, groups[8], S24, 0x455a14edL); /* 28 */ a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L); /* 29 */ d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L); /* 30 */ c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L); /* 31 */ b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL); /* 32 */ /*第三輪*/ a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L); /* 33 */ d = HH(d, a, b, c, groups[8], S32, 0x8771f681L); /* 34 */ c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L); /* 35 */ b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL); /* 36 */ a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L); /* 37 */ d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L); /* 38 */ c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L); /* 39 */ b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L); /* 40 */ a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L); /* 41 */ d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL); /* 42 */ c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L); /* 43 */ b = HH(b, c, d, a, groups[6], S34, 0x4881d05L); /* 44 */ a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L); /* 45 */ d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L); /* 46 */ c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L); /* 47 */ b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L); /* 48 */ /*第四輪*/ a = II(a, b, c, d, groups[0], S41, 0xf4292244L); /* 49 */ d = II(d, a, b, c, groups[7], S42, 0x432aff97L); /* 50 */ c = II(c, d, a, b, groups[14], S43, 0xab9423a7L); /* 51 */ b = II(b, c, d, a, groups[5], S44, 0xfc93a039L); /* 52 */ a = II(a, b, c, d, groups[12], S41, 0x655b59c3L); /* 53 */ d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L); /* 54 */ c = II(c, d, a, b, groups[10], S43, 0xffeff47dL); /* 55 */ b = II(b, c, d, a, groups[1], S44, 0x85845dd1L); /* 56 */ a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL); /* 57 */ d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L); /* 58 */ c = II(c, d, a, b, groups[6], S43, 0xa3014314L); /* 59 */ b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L); /* 60 */ a = II(a, b, c, d, groups[4], S41, 0xf7537e82L); /* 61 */ d = II(d, a, b, c, groups[11], S42, 0xbd3af235L); /* 62 */ c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL); /* 63 */ b = II(b, c, d, a, groups[9], S44, 0xeb86d391L); /* 64 */ /*加入到以前計算的結果當中*/ result[0] += a; result[1] += b; result[2] += c; result[3] += d; result[0]=result[0]&0xFFFFFFFFL; result[1]=result[1]&0xFFFFFFFFL; result[2]=result[2]&0xFFFFFFFFL; result[3]=result[3]&0xFFFFFFFFL; } /** * 下面是處理要用到的線性函數 */ private static long F(long x, long y, long z) { return (x & y) | ((~x) & z); } private static long G(long x, long y, long z) { return (x & z) | (y & (~z)); } private static long H(long x, long y, long z) { return x ^ y ^ z; } private static long I(long x, long y, long z) { return y ^ (x | (~z)); } private static long FF(long a, long b, long c, long d, long x, long s, long ac) { a += (F(b, c, d)&0xFFFFFFFFL) + x + ac; a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >>> (32 - s)); a += b; return (a&0xFFFFFFFFL); } private static long GG(long a, long b, long c, long d, long x, long s, long ac) { a += (G(b, c, d)&0xFFFFFFFFL) + x + ac; a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); a += b; return (a&0xFFFFFFFFL); } private static long HH(long a, long b, long c, long d, long x, long s, long ac) { a += (H(b, c, d)&0xFFFFFFFFL) + x + ac; a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); a += b; return (a&0xFFFFFFFFL); } private static long II(long a, long b, long c, long d, long x, long s, long ac) { a += (I(b, c, d)&0xFFFFFFFFL) + x + ac; a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); a += b; return (a&0xFFFFFFFFL); } }
Java的實現:
算法過程我是看不太懂,Java的面向對象思想不錯,Java中也提供了進行MD5加密的對象。
包java.security有個類MessageDigest。官方文檔以下:
此 MessageDigest 類爲應用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數,它接收任意大小的數據,並輸出固定長度的哈希值。
MessageDigest 對象開始被初始化。該對象經過使用 update
方法處理數據。任什麼時候候均可以調用 reset
方法重置摘要。一旦全部須要更新的數據都已經被更新了,應該調用 digest
方法之一完成哈希計算。
對於給定數量的更新數據,digest
方法只能被調用一次。在調用 digest
以後,MessageDigest 對象被從新設置成其初始狀態。
public static void main(String[] args) {try{ MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update("abc".getBytes()); System.out.println("md5(abc)=" + byte2HexStr(md5.digest())); }catch (NoSuchAlgorithmException e){ } }
這裏注意:獲得的輸出結果通常展現爲16進制的字符串,而不是簡單的new String(bytes). 好像說16進制是通用的加密表示方法。
byte[]與16進制字符串的轉換:


package kunpu.arithmetic.encryption; /** * @author zhen * @Date 2018/4/4 10:29 */ public class Byte2Hex { private final static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * 方法一 * @param b * @return */ private static String byteArrayToHexString(byte[] b) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) { resultSb.append(byteToHexString(b[i])); } return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n = 256 + n; int d1 = n / 16; int d2 = n % 16; return "" + hexDigits[d1] + hexDigits[d2]; } /** * 方法二: * byte[] to hex string * * @param bytes * @return */ public static String bytesToHexFun2(byte[] bytes) { char[] buf = new char[bytes.length * 2]; int index = 0; for(byte b : bytes) { // 利用位運算進行轉換,能夠看做方法一的變種 buf[index++] = hexDigits[b >>> 4 & 0xf]; buf[index++] = hexDigits[b & 0xf]; } return new String(buf); } /** * 方法三: * byte[] to hex string * * @param bytes * @return */ public static String bytesToHexFun3(byte[] bytes) { StringBuilder buf = new StringBuilder(bytes.length * 2); for(byte b : bytes) { // 使用String的format方法進行轉換 buf.append(String.format("%02x", new Integer(b & 0xff))); } return buf.toString(); } /** * 將16進制字符串轉換爲byte[] * * @param str * @return */ public static byte[] toBytes(String str) { if(str == null || str.trim().equals("")) { return new byte[0]; } byte[] bytes = new byte[str.length() / 2]; for(int i = 0; i < str.length() / 2; i++) { String subStr = str.substring(i * 2, i * 2 + 2); bytes[i] = (byte) Integer.parseInt(subStr, 16); } return bytes; } }
SHA家族
概述:
安全散列算法(英語:Secure Hash Algorithm,縮寫爲SHA)是一個密碼散列函數家族,是FIPS所認證的安全散列算法。能計算出一個數字消息所對應到的,長度固定的字符串(又稱消息摘要)的算法。且若輸入的消息不一樣,它們對應到不一樣字符串的機率很高。
SHA(Security Hash Algorithm)是美國的NIST和NSA設計的一種標準的Hash算法,SHA用於數字簽名的標準算法的DSS中,也是安全性很高的一種Hash算法,該算法的輸入消息長度小於2^64bit,最終輸出的結果值是160bit
算法的Java實現:


package kunpu.arithmetic.encryption; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * @author zhen * @Date 2018/4/4 10:50 */ public class SHA1Simulate { private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; // 摘要數據存儲數組 private int[] digestInt = new int[5]; // 計算過程當中的臨時數據存儲數組 private int[] tmpData = new int[80]; // 計算sha-1摘要 private int process_input_bytes(byte[] bytedata) { // 初試化常量 System.arraycopy(abcde, 0, digestInt, 0, abcde.length); // 格式化輸入字節數組,補10及長度數據 byte[] newbyte = byteArrayFormatData(bytedata); // 獲取數據摘要計算的數據單元個數 int MCount = newbyte.length / 64; // 循環對每一個數據單元進行摘要計算 for (int pos = 0; pos < MCount; pos++) { // 將每一個單元的數據轉換成16個整型數據,並保存到tmpData的前16個數組元素中 for (int j = 0; j < 16; j++) { tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4)); } //摘要計算函數 encrypt(); } return 20; } // 格式化輸入字節數組格式 private byte[] byteArrayFormatData(byte[] bytedata) { // 補0數量 int zeros = 0; // 補位後總位數 int size = 0; // 原始數據長度 int n = bytedata.length; // 模64後的剩餘位數 int m = n % 64; // 計算添加0的個數以及添加10後的總長度 if (m < 56) { zeros = 55 - m; size = n - m + 64; } else if (m == 56) { zeros = 63; size = n + 8 + 64; } else { zeros = 63 - m + 56; size = (n + 64) - m + 64; } // 補位後生成的新數組內容 byte[] newbyte = new byte[size]; // 複製數組的前面部分 System.arraycopy(bytedata, 0, newbyte, 0, n); // 得到數組Append數據元素的位置 int l = n; // 補1操做 newbyte[l++] = (byte) 0x80; // 補0操做 for (int i = 0; i < zeros; i++) { newbyte[l++] = (byte) 0x00; } // 計算數據長度,補數據長度位共8字節,長整型 long N = (long) n * 8; byte h8 = (byte) (N & 0xFF); byte h7 = (byte) ((N >> 8) & 0xFF); byte h6 = (byte) ((N >> 16) & 0xFF); byte h5 = (byte) ((N >> 24) & 0xFF); byte h4 = (byte) ((N >> 32) & 0xFF); byte h3 = (byte) ((N >> 40) & 0xFF); byte h2 = (byte) ((N >> 48) & 0xFF); byte h1 = (byte) (N >> 56); newbyte[l++] = h1; newbyte[l++] = h2; newbyte[l++] = h3; newbyte[l++] = h4; newbyte[l++] = h5; newbyte[l++] = h6; newbyte[l++] = h7; newbyte[l++] = h8; return newbyte; } private int f1(int x, int y, int z) { return (x & y) | (~x & z); } private int f2(int x, int y, int z) { return x ^ y ^ z; } private int f3(int x, int y, int z) { return (x & y) | (x & z) | (y & z); } private int f4(int x, int y) { return (x << y) | x >>> (32 - y); } //單元摘要計算函數 private void encrypt() { for (int i = 16; i <= 79; i++) { tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^ tmpData[i - 16], 1); } int[] tmpabcde = new int[5]; for (int i1 = 0; i1 < tmpabcde.length; i1++) { tmpabcde[i1] = digestInt[i1]; } for (int j = 0; j <= 19; j++) { int tmp = f4(tmpabcde[0], 5) + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[j] + 0x5a827999; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int k = 20; k <= 39; k++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[k] + 0x6ed9eba1; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int l = 40; l <= 59; l++) { int tmp = f4(tmpabcde[0], 5) + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[l] + 0x8f1bbcdc; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int m = 60; m <= 79; m++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[m] + 0xca62c1d6; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int i2 = 0; i2 < tmpabcde.length; i2++) { digestInt[i2] = digestInt[i2] + tmpabcde[i2]; } for (int n = 0; n < tmpData.length; n++) { tmpData[n] = 0; } } // 4字節數組轉換爲整數 private int byteArrayToInt(byte[] bytedata, int i) { return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); } // 整數轉換爲4字節數組 private void intToByteArray(int intValue, byte[] byteData, int i) { byteData[i] = (byte) (intValue >>> 24); byteData[i + 1] = (byte) (intValue >>> 16); byteData[i + 2] = (byte) (intValue >>> 8); byteData[i + 3] = (byte) intValue; } // 將字節轉換爲十六進制字符串 private static String byteToHexString(byte ib) { char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } // 將字節數組轉換爲十六進制字符串 private static String byteArrayToHexString(byte[] bytearray) { String strDigest = ""; for (int i = 0; i < bytearray.length; i++) { strDigest += byteToHexString(bytearray[i]); } return strDigest; } // 計算sha-1摘要,返回相應的字節數組 public byte[] getDigestOfBytes(byte[] byteData) { process_input_bytes(byteData); byte[] digest = new byte[20]; for (int i = 0; i < digestInt.length; i++) { intToByteArray(digestInt[i], digest, i * 4); } return digest; } // 計算sha-1摘要,返回相應的十六進制字符串 public String getDigestOfString(byte[] byteData) { return byteArrayToHexString(getDigestOfBytes(byteData)); } //測試 public static void main(String[] args) { String param = "wxzzs"; System.out.println("加密前:" + param); String digest = new SHA1Simulate().getDigestOfString(param.getBytes()); System.out.println("加密後:" + digest); try { MessageDigest messageDigest = MessageDigest.getInstance("sha1"); messageDigest.update(param.getBytes()); String digest1 = byteArrayToHexString(messageDigest.digest()); System.out.println("加密後:" + digest1); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } }
其實我不懂實現,嘿嘿。面向對象,Java MessageDigest類:
try { MessageDigest messageDigest = MessageDigest.getInstance("sha1"); messageDigest.update(param.getBytes()); String digest1 = byteArrayToHexString(messageDigest.digest()); System.out.println("加密後:" + digest1); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
最近接阿里接口加密使用的是sha1算法