md5已經不安全了,中國山東大學女學霸王小云破解了一系列密碼,當真是巾幗不讓須眉.說是破解,其實就是給你一個md5碼,讓你求出這個md5碼所對應的原始信息,顯然一個md5對應無數種原始信息.而md5的特性就是難以還原初始信息,但是王小云可以迅速找到給定md5碼的可行解.md5的解空間雖然巨大,但是卻難以捕捉到解.
md5雖然已經不安全了,但是仍然可以用于校驗.
md5不是編碼,編碼是能夠還原初始信息的,而md5只是固定的16byte,它只能從總體上反映初始信息的一些特征,卻無法完整的還原出來,因為初始信息到md5碼是一個多對一映射.
md5中大量使用小頭序,這點十分坑.還好java中有神奇偉大的ByteBuffer.ByteBuffer有四個索引:mark,limit,position,capacity.
mark表示標記;limit表示position最大可以讀到哪里;position表示當前位置;capacity表示最大容量.
ByteBuffer這個類支持"流式"編程,比如put(byte)函數返回值仍然是ByteBuffer,這樣就可以接著put了.
ByteBuffer這個類最重要的就是4個指針,玩轉了四個指針就學會了控制ByteBuffer,例如:
flip()將limit置為當前position,將position置為0,準備從頭讀取數據,注意只能讀取0~limit這一部分數據;
rewind()將position置為0;
mark()標記當前position,可以使用reset()將position重置為mark時的位置.
compact()將當前postion之前的字節清空.
clear()清空一切,將limit移動到copacity處,準備讀入數據.
明白了如何操作這些指針,就明白了ByteBuffer.
當不了解md5的時候,聽人們說md5的某些特性,覺得還是道聽途說,只有親自實現之后才能自己總結出md5有哪些特點.
下面給出md5信息摘要算法
import static java.lang.Math.abs; import static java.lang.Math.floor; import static java.lang.Math.pow; import static java.lang.Math.sin;import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5 {// 移位的位數,分成4種,每種4個數,每種重復4次.不知道為啥是這些數字int[] s = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9,14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4,11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15,21, 6, 10, 15, 21, 6, 10, 15, 21};// 在init函數中初始化k[i]int k[] = new int[64];void init() {for (int i = 0; i < 64; i++) {long x = (long) floor(abs(sin(i + 1)) * pow(2, 32));k[i] = (int) (x & 0xffffffff);}}// 循環左移操作,比如4位的1011,循環左移一位相當于0110|1int leftRotate(int x, int n) {return (x << n) | (x >>> (32 - n));}byte[] digest(byte[] srcData) throws IOException {// 原數據字節數+8byte的原始長度表示=l,l有點偏短,如果它不是64的倍數,那么會舍棄一些,所以要加上一;如果它是64的倍數,那么需要補上一個字節,至少要添加一個chunk.// 一個chunk為64byte,其中最后一個chunk的前56byte為數據+補齊的數據,最后8byte為long類型的數據,表示原始數據長度.// 整個md5都是基于小頭序的int chunkCount = (srcData.length + 8) / 64 + 1;ByteBuffer buffer = ByteBuffer.allocate(chunkCount * 64).order(ByteOrder.LITTLE_ENDIAN);buffer.put(srcData).put((byte) 0x80).position(buffer.limit() - 8);buffer.putLong(8 * srcData.length).flip();//flip準備讀取數據int a0 = 0x67452301, b0 = 0xefcdab89, c0 = 0x98badcfe, d0 = 0x10325476;while (buffer.hasRemaining()) {int m[] = new int[16];for (int i = 0; i < 16; i++) {m[i] = buffer.getInt();}int a = a0, b = b0, c = c0, d = d0;int f, g;for (int i = 0; i < 64; i++) {if (i < 16) {f = (b & c) | (~b & d);g = i;} else if (i < 32) {f = (d & b) | (~d & c);g = (5 * i + 1) % 16;} else if (i < 48) {f = b ^ c ^ d;g = (3 * i + 5) % 16;} else {f = c ^ (b | ~d);g = (7 * i) % 16;}int dd = d;d = c;c = b;b = b + leftRotate(a + f + k[i] + m[g], s[i]);a = dd;}a0 += a;b0 += b;c0 += c;d0 += d;}return ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN).putInt(a0).putInt(b0).putInt(c0).putInt(d0).array();}static void show(byte[] b) {for (byte i : b) {System.out.printf("%02X", i);}System.out.println();}public static void main(String[] args)throws NoSuchAlgorithmException, IOException {byte[] b = "魏印福".getBytes();MessageDigest md5 = MessageDigest.getInstance("MD5");md5.update(b);byte[] res = md5.digest();show(res);MD5 m = new MD5();m.init();res = m.digest(b);show(res);} }
?跟md5一樣,SHA也有好多版本,SHA1,SHA2,SHA3,其中SHA2,SHA3又分成了好多版本.SHA加密強度比md5更強,它名叫Secure Hash Algorithm.md5校驗碼位長相當于4個int,SHA的位長相當于5個int.二者都是以64Byte為一個chunk進行處理.
下面給出java中如何使用庫函數自帶的SHA
public class SHA {static String tos(byte[] b) {String ans = "";for (int i = 0; i < b.length; i++) {ans += String.format("%02X", b[i]);}return ans;}public static void main(String[] args) throws Exception {byte[] data = "魏印福".getBytes();MessageDigest digest = MessageDigest.getInstance("SHA");byte[] ans = digest.digest(data);System.out.println(tos(ans));System.out.println(tos(MessageDigest.getInstance("SHA-1").digest(data)));} }
?