SHA1計算過程

參考資料,按字節的角度(加密的數據是字節數組,不是位數組),理解大致過程是:

1. 原字節數組補字節,使得字節數爲64的倍數,且補的部分第一個字節是0x80,最後的8個字節存儲原字節數組的總位數。

2. 補後的字節數組,每64字節爲一塊,循環計算。

3. 每64字節的一塊再分16份,每份4字節,這16份會擴展計算,和自身的16分,組成80份,再循環計算。

4. 這80份的每份,按公式計算得到結果。

5. 之前各處計算的結果不斷累計,即爲結果。

 

 


import org.apache.commons.codec.digest.DigestUtils;

public class MySHA1Test {

	public static void main(String[] args) {
		String str = "hello";
//		System.out.println(DigestUtils.md5Hex("hello"));
		System.out.println(DigestUtils.shaHex(str));
		byte[] data = str.getBytes();
//		data = new byte[448];
		System.out.println(hexToString(sha(data)));
	}

	public static String sha(String data) {
		return hexToString(sha(data.getBytes()));
	}

	public static byte[] sha(byte[] bytes_data) {
		byte[] bytes_all = appendBytes(bytes_data);
		return computeBytes(bytes_all);
	}

	public static byte[] appendBytes(byte[] bytes_src) {
		// 原始數據補字節,補後整體是64字節(512位)的整數倍。
		// 補的部分,第一bit是1,後面至少有8個字節(64位)用來存放原始數據長度,這樣至少補9字節
		int length_src = bytes_src.length;
		int length_append = 64 - length_src % 64;
		if (length_append < 9) {
			length_append = 64 + length_append;
		}

		// 補的數據
		byte[] bytes_append = new byte[length_append];
		// 第一位是1,其他位是0
		bytes_append[0] = (byte) 0x80;
		// 後面8字節(64位)存儲的是按bit算的長度
		long length_src1 = length_src * 8;
		bytes_append[length_append - 8] = (byte)(length_src1 >>> 56);
		bytes_append[length_append - 7] = (byte)(length_src1 >>> 48);
		bytes_append[length_append - 6] = (byte)(length_src1 >>> 40);
		bytes_append[length_append - 5] = (byte)(length_src1 >>> 32);
		bytes_append[length_append - 4] = (byte)(length_src1 >>> 24);
		bytes_append[length_append - 3] = (byte)(length_src1 >>> 16);
		bytes_append[length_append - 2] = (byte)(length_src1 >>>  8);
		bytes_append[length_append - 1] = (byte)(length_src1 >>>  0);

		// 組裝完整數據
		byte[] bytes_all = new byte[length_src + length_append];
		System.arraycopy(bytes_src, 0, bytes_all, 0, length_src);
		System.arraycopy(bytes_append, 0, bytes_all, length_src, length_append);

//		System.out.println("原始:" + hexToString(bytes_data));
//		System.out.println("擴充:" + hexToString(bytes_append));
//		System.out.println("結果:" + hexToString(bytes_all));

		return bytes_all;
	}

	public static byte[] computeBytes(byte[] bytes_all) {

		int k0 = 0x5A827999; // (0 <= t <= 19)
		int k1 = 0x6ED9EBA1; // (20 <= t <= 39)
		int k2 = 0x8F1BBCDC; // (40 <= t <= 59)
		int k3 = 0xCA62C1D6; // (60 <= t <= 79).

		int H0 = 0x67452301;
		int H1 = 0xEFCDAB89;
		int H2 = 0x98BADCFE;
		int H3 = 0x10325476;
		int H4 = 0xC3D2E1F0;

		int A = 0;
		int B = 0;
		int C = 0;
		int D = 0;
		int E = 0;
		int A1 = 0;

		// 整體數據,按每塊64字節512位切分,循環處理每個分塊
		int block_size = 64;
		int block_count = bytes_all.length / block_size;
		byte[] block_data = new byte[block_size];
		int[] W = new int[80];
		for (int block_index = 0;  block_index < block_count; block_index++) {
			// 取得分塊數據
			System.arraycopy(bytes_all, block_index * block_size, block_data, 0, block_size);

			// 分塊數據轉爲80個子分塊
			for (int t = 0; t < 80; t++) {
				if (t < 16) {
					// 前16個子分塊,切分16分直接轉換得到
					int tmp = t * 4;
					W[t] = (
							((block_data[0 + tmp] << 24) & 0xff000000)
							+ ((block_data[1 + tmp] << 16) & 0xff0000)
							+ ((block_data[2 + tmp] << 8) & 0xff00)
							+ ((block_data[3 + tmp] << 0) & 0xff)
							);
				} else {
					// 後面的子分塊,計算得到
					// W[t] = S1(W[t-3] XOR W[t-8] XOR W[t-14] XOR W[t-16]).
					W[t] = leftShiftLoop((W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]), 1);
				}
			}

			// 80個子分塊計算ABCDE,並累加
			A = H0;
			B = H1;
			C = H2;
			D = H3;
			E = H4;
			for (int t = 0; t < 80; t++) {
				// 計算ABCDE:A, B, C, D, E ← [(A<<<5)+ ft(B,C,D)+E+Wt+Kt], A, (B<<<30), C, D
				if (t < 20) {
					A1 = leftShiftLoop(A, 5)
							+ ((B & C) | ((~B) & D)) // (B AND C) or ((NOT B) AND D)
							+ E + W[t] + k0;
				} else if (t < 40) {
					A1 = leftShiftLoop(A, 5)
							+ (B ^ C ^ D) // B XOR C XOR D
							+ E + W[t] + k1;
				} else if (t < 60) {
					A1 = leftShiftLoop(A, 5)
							+ ((B & C) | (B & D) | (C & D)) // (B AND C) or (B AND D) or (C AND D)
							+ E + W[t] + k2;
				} else {
					A1 = leftShiftLoop(A, 5)
							+ (B ^ C ^ D) // B XOR C XOR D
							+ E + W[t] + k3;
				}
				E = D;
				D = C;
				C = leftShiftLoop(B, 30);
				B = A;
				A = A1;
			}
			H0 = H0 + A;
			H1 = H1 + B;
			H2 = H2 + C;
			H3 = H3 + D;
			H4 = H4 + E;
		}

		// ABCDE轉爲結果
		byte[] bytes_ret = new byte[20];
		int index_ret = 0;
		A1 = H0;
		bytes_ret[index_ret++] = (byte) ((A1 >>> 24) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>> 16) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  8) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  0) & 0xFF);
		A1 = H1;
		bytes_ret[index_ret++] = (byte) ((A1 >>> 24) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>> 16) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  8) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  0) & 0xFF);
		A1 = H2;
		bytes_ret[index_ret++] = (byte) ((A1 >>> 24) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>> 16) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  8) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  0) & 0xFF);
		A1 = H3;
		bytes_ret[index_ret++] = (byte) ((A1 >>> 24) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>> 16) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  8) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  0) & 0xFF);
		A1 = H4;
		bytes_ret[index_ret++] = (byte) ((A1 >>> 24) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>> 16) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  8) & 0xFF);
		bytes_ret[index_ret++] = (byte) ((A1 >>>  0) & 0xFF);
		//
		return bytes_ret;
	}

	public static int leftShiftLoop(int d, int n) {
		return (d << n) | (d >>> (32 - n));
	}

	//
	private static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7',
			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	public static String hexToString(byte[] data) {
		int l = data.length;

		char[] out = new char[l << 1];

		int i = 0;
		for (int j = 0; i < l; ++i) {
			out[(j++)] = digits[((0xF0 & data[i]) >>> 4)];
			out[(j++)] = digits[(0xF & data[i])];
		}
		return new String(out);
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章