//使用MD5演算法對密碼加密之後,會得到一個唯一的並且是無法復原轉的字串編碼<br />//將加密後所得到的字串編碼作為密碼標識符儲存在資料庫中,可以防止密碼在資料庫中被盜竊<br />//並且加密後的字串編碼是不能再轉換到原有密碼,這就保證了儲存在資料庫中的密碼的安全性<br />//所以在使用者校正時,不能直接把登入密碼和資料庫中儲存的密碼標識符進行比較<br />//而是需要將使用者的登入密碼也進行MD5轉換,然後才可以進行比較<br />//下面的代碼就實現了MD5演算法對字串進行加密的功能</p><p>/**<br /> * 實現了MD5演算法對字串進行加密的功能<br /> * @see 直接調用MD5類中的toMD5()方法<br /> * @see 即可對需要加密的字串進行加密<br /> */<br />public class MD5 {<br />//下面這些S11-S44實際上是一個4*4的矩陣,在原始的C實現中是用#define實現的<br />//這裡把它們實現成為static final是表示唯讀,且能在同一個進程空間內的多個Instance間共用<br />static final int S11 = 7;<br />static final int S12 = 12;<br />static final int S13 = 17;<br />static final int S14 = 22;<br />static final int S21 = 5;<br />static final int S22 = 9;<br />static final int S23 = 14;<br />static final int S24 = 20;<br />static final int S31 = 4;<br />static final int S32 = 11;<br />static final int S33 = 16;<br />static final int S34 = 23;<br />static final int S41 = 6;<br />static final int S42 = 10;<br />static final int S43 = 15;<br />static final int S44 = 21;<br />static final byte[] PADDING = {-128, 0, 0, 0, 0, 0, 0, 0, 0,<br />0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,<br />0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,<br />0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};</p><p>/**<br /> * 下面的3個成員是MD5計算過程中用到的3個核心資料,在原始的C實現中被定義到MD5_CTX結構中<br /> */<br />private long[] state = new long[4]; //state()<br />private long[] count = new long[2]; //number of bits, modulo 2^64 (Isb first)<br />private byte[] buffer = new byte[64]; //input buffer</p><p>//digestHexStr是MD5.java的唯一一個公用成員,是最新一次計算結果的十六進位ASCII表示<br />//即此變數中存放了將輸入串進行MD5運算後的128位MD5碼的ASCII碼�<br />public String digestHexStr;</p><p>//digest是最新一次計算結果的二進位內部表示,表示128bit的MD5值<br />private byte[] digest = new byte[16];</p><p>/**<br /> * 這是類MD5最主要的公用方法<br /> * @param inbuf 入口參數是你想要進行MD5變換的字串<br /> * @return 返回變換完的結果,該結果是從公用成員digestHexStr取得的<br /> */<br />public String getMD5ofStr(String inbuf){<br />md5Init();<br />md5Update(inbuf.getBytes(), inbuf.length());<br />md5Final();<br />digestHexStr = "";<br />for(int i=0; i<16; i++){<br />digestHexStr += byteHEX(digest[i]);<br />}<br />return digestHexStr;<br />}</p><p>/**<br /> * 這是MD5類的標準建構函式,JavaBean要求有一個public的並且沒有參數的建構函式<br /> */<br />public MD5(){<br />md5Init();<br />return;<br />}</p><p>/**<br /> * 這是一個初始化函數,初始化核心變數,裝入標準的函數<br /> */<br />private void md5Init(){<br />count[0] = 0L;<br />count[1] = 0L;<br />//Load magic initialization constants<br />state[0] = 0x67452301L;<br />state[1] = 0xefcdab89L;<br />state[2] = 0x98badcfeL;<br />state[3] = 0x10325476L;<br />}</p><p>//F, G, H, I是4個基本的MD5函數<br />//在原始的MD5的C實現中,由於它們是簡單的位元運算,可能出於效率的考慮把它們實現成了宏<br />//在Java中,我們把它們實現成了private方法,名字保持了原來C中的<br />private long F(long x, long y, long z){<br />return (x&y) | ((~x)&z);<br />}<br />private long G(long x, long y, long z){<br />return (x&z) | (y&(~z));<br />}<br />private long H(long x, long y, long z){<br />return x ^ y ^ z;<br />}<br />private long I(long x, long y, long z){<br />return y ^ (x | (~z));<br />}</p><p>//FF, GG, HH和II將調用F, G, H, I進行進一步變換<br />//FF, GG, HH and II transformations for rounds 1,2,3 and 4<br />//Rotation is separate from addition to prevent recomputation<br />private long FF(long a, long b, long c, long d, long x, long s, long ac){<br />a += F(b, c, d) + x + ac;<br />a = ((int)a << s) | ((int)a >>> (32-s));<br />a += b;<br />return a;<br />}<br />private long GG(long a, long b, long c, long d, long x, long s, long ac){<br />a += G(b, c, d) + x + ac;<br />a = ((int)a << s) | ((int)a >>> (32-s));<br />a += b;<br />return a;<br />}<br />private long HH(long a, long b, long c, long d, long x, long s, long ac){<br />a += H(b, c, d) + x + ac;<br />a = ((int)a << s) | ((int)a >>> (32-s));<br />a += b;<br />return a;<br />}<br />private long II(long a, long b, long c, long d, long x, long s, long ac){<br />a += I(b, c, d) + x + ac;<br />a = ((int)a << s) | ((int)a >>> (32-s));<br />a += b;<br />return a;<br />}</p><p>/**<br /> * 這是MD5的主計算過程。該函數由getMD5ofStr調用<br /> * @see 該函數在被調用之前需要調用md5Init,因此把它設計成private的<br /> * @param inbuf 要進行MD5加密的位元組串<br /> * @param inputLen 字串長度<br /> */<br />private void md5Update(byte[] inbuf, int inputLen){<br />int i, index, partLen;<br />byte[] block = new byte[64];<br />index = (int)(count[0]>>>3) & 0x3F;<br />//Update number of bits<br />if((count[0] += (inputLen<<3)) < (inputLen << 3))<br />count[1]++;<br />count[1] += (inputLen >>> 29);<br />partLen = 64 - index;<br />//Transform as many times as possible<br />if(inputLen >= partLen){<br />md5Memcpy(buffer, inbuf, index, 0, partLen);<br />md5Transform(buffer);<br />for(i=partLen; i+63<inputLen; i+=64){<br />md5Memcpy(block, inbuf, 0, i, 64);<br />md5Transform(block);<br />}<br />index = 0;<br />}else<br />i = 0;<br />//Buffer remaining input<br />md5Memcpy(buffer, inbuf, index, i, inputLen-i);<br />}</p><p>/**<br /> * 整理和填寫輸出結果<br /> * @see 將得到的128位(16位元組)的MD5碼存放在digest數組<br /> */<br />private void md5Final(){<br />byte[] bits = new byte[8];<br />int index, padLen;<br />//Save number of bits<br />Encode(bits, count, 8);<br />//Pad out to 56 mod 64<br />index = (int)(count[0]>>>3) & 0x3f;<br />padLen = (index<56) ? (56-index) : (120-index);<br />md5Update(PADDING, padLen);<br />//Append length (before padding)<br />md5Update(bits, 8);<br />//Store state in digest<br />Encode(digest, state, 16);<br />}</p><p>/**<br /> * 這是一個內部使用的byte數組的塊複製函數<br /> * @see 從input的inpos開始把len長度的位元組複製到output的outpos位置開始<br /> */<br />private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len){<br />int i;<br />for(i=0; i<len; i++)<br />output[outpos+i] = input[inpos+i];<br />}</p><p>/**<br /> * 這是MD5核心變換程式。由md5Update調用<br /> * @param block 分塊的原始位元組<br /> */<br />private void md5Transform(byte block[]){<br />long a=state[0], b=state[1], c=state[2], d=state[3];<br />long[] x = new long[16];<br />Decode(x, block, 64);<br />/*Round 1*/<br />a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); // 1<br />d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); // 2<br />c = FF(c, d, a, b, x[2], S13, 0x242070dbL); // 3<br />b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); // 4<br />a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); // 5<br />d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); // 6<br />c = FF(c, d, a, b, x[6], S13, 0xa8304613L); // 7<br />b = FF(b, c, d, a, x[7], S14, 0xfd469501L); // 8<br />a = FF(a, b, c, d, x[8], S11, 0x698098d8L); // 9<br />d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); //10<br />c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); //11<br />b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); //12<br />a = FF(a, b, c, d, x[12], S11, 0x6b901122L); //13<br />d = FF(d, a, b, c, x[13], S12, 0xfd987193L); //14<br />c = FF(c, d, a, b, x[14], S13, 0xa679438eL); //15<br />b = FF(b, c, d, a, x[15], S14, 0x49b40821L); //16<br />/*Round 2*/<br />a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); //17<br />d = GG(d, a, b, c, x[6], S22, 0xc040b340L); //18<br />c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); //19<br />b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); //20<br />a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); //21<br />d = GG(d, a, b, c, x[10], S22, 0x2441453L); //22<br />c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); //23<br />b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); //24<br />a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); //25<br />d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); //26<br />c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); //27<br />b = GG(b, c, d, a, x[8], S24, 0x455a14edL); //28<br />a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); //29<br />d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); //30<br />c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); //31<br />b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); //32<br />/*Round 3*/<br />a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); //33<br />d = HH(d, a, b, c, x[8], S32, 0x8771f681L); //34<br />c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); //35<br />b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); //36<br />a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); //37<br />d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); //38<br />c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); //39<br />b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); //40<br />a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); //41<br />d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); //42<br />c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); //43<br />b = HH(b, c, d, a, x[6], S34, 0x4881d05L); //44<br />a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); //45<br />d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); //46<br />c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); //47<br />b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); //48<br />/*Round 4*/<br />a = II(a, b, c, d, x[0], S41, 0xf4292244L); //49<br />d = II(d, a, b, c, x[7], S42, 0x432aff97L); //50<br />c = II(c, d, a, b, x[14], S43, 0xab9423a7L); //51<br />b = II(b, c, d, a, x[5], S44, 0xfc93a039L); //52<br />a = II(a, b, c, d, x[12], S41, 0x655b59c3L); //53<br />d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); //54<br />c = II(c, d, a, b, x[10], S43, 0xfeff47dL); //55<br />b = II(b, c, d, a, x[1], S44, 0x85845dd1L); //56<br />a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); //57<br />d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); //58<br />c = II(c, d, a, b, x[6], S43, 0xa3014314L); //59<br />b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); //60<br />a = II(a, b, c, d, x[4], S41, 0xf7537e82L); //61<br />d = II(d, a, b, c, x[11], S42, 0xbd3af235L); //62<br />c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); //63<br />b = II(b, c, d, a, x[9], S44, 0xeb86d391L); //64<br />state[0] += a;<br />state[1] += b;<br />state[2] += c;<br />state[3] += d;<br />}</p><p>/**<br /> * 把long數組按順序拆成byte數組<br /> * @see 因為Java的long類型是64bit的,只拆低32bit,以適應原始C實現的用途<br /> */<br />private void Encode(byte[] output, long[] input, int len){<br />int i, j;<br />for(i=0,j=0; j<len; i++,j+=4){<br />output[j] = (byte)(input[i] & 0xffL);<br />output[j+1] = (byte)((input[i]>>>8) & 0xffL);<br />output[j+2] = (byte)((input[i]>>>16) & 0xffL);<br />output[j+3] = (byte)((input[i]>>>24) & 0xffL);<br />}<br />}</p><p>/**<br /> * 把byte數組按順序合成long數組<br /> * @see 因為Java的long類型是64bit的,只合成低32bit,高32bit清零,以適應原始C實現的用途<br /> */<br />private void Decode(long[] output, byte[] input, int len){<br />int i, j;<br />for(i=0,j=0; j<len; i++,j+=4)<br />output[i] = b2iu(input[j]) | (b2iu(input[j+1])<<8) | (b2iu(input[j+2])<<16) | (b2iu(input[j+3])<<24);<br />return;<br />}</p><p>/**<br /> * 將一位元組的有符號數轉換成一無符號的long型值<br /> * @see 該方法是一個把byte按照不考慮加號或減號的原則的"升位"程式<br /> * @see 因為Java沒有unsigned運算<br /> */<br />public static long b2iu(byte b){<br />//或者寫成return b >= 0 ? b : b & 0xff;<br />return b<0 ? b&0x7F+128 : b;<br />}</p><p>/**<br /> * 該方法用來把一個byte類型的數轉換成十六進位的ASCII表示<br /> * @see 因為Java中的byte的toString無法實現這一點<br /> * @see 而我們又沒有C語言中的sprintf(outbuf, "%02X", ib)<br /> */<br />public static String byteHEX(byte ib){<br />char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};<br />char[] ob = new char[2];<br />ob[0] = Digit[(ib>>>4) & 0X0F];<br />ob[1] = Digit[ib & 0X0F];<br />String s = new String(ob);<br />return s;<br />}</p><p>/**<br /> * 對需要加密的字串進行加密<br /> * @see 即對字串source進行MD5運算,返回該串的MD5字串<br /> */<br />public static String toMD5(String source){<br />MD5 md5 = new MD5();<br />return md5.getMD5ofStr(source);<br />}</p><p>public static void main(String[] args) {<br />System.out.println(toMD5("My name is Jadyer"));<br />}<br />}