0x00 前言
SHA1算法也是哈希算法的一種,只要理解了MD5算法,SHA1也很快就能理解。
MD5算法可以參考:MD5算法詳解
MD5算法得出的MD5值長度為16個字節(8*16=128位)
SHA1算法得出的SHA1值長度為20個字節(8*20=160位)
0x01 填充信息
和MD5算法類似,對信息的第一步也是填充信息直至滿足條件。
填充的過程如下:
1.先判斷文件(消息)的大小(長度) mod 512 == 448 mod 512 ,就是大小(長度)對512求余等于448。(這里的512、448是“位”為單位,轉成“字節”就是64、56,即mod 64 == 56 mod 64)
2.如果大小(長度)滿足 mod 512 == 448 mod 512,就在文件(消息)的末尾處添加64位(8字節)的值,值的內容是原消息的長度(以位為單位)
3.如果大小(長度)不滿足要求,就執行以下操作:
(1)填充1個1
(2)填充0,直到滿足滿足過程的第一步。
注意:這里是以位為單位,假如是以字節為單位,第一個填充的是0x80(1000 0000),然后就填0x0
舉例:消息內容為“gnubd”,就能得到以下內容
67 6E 62 75 64 80 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28
還需要注意到的是最后原消息的長度是以大端存儲的方式存到內存中的,這里與MD5的存儲是有區別的。
0x02 數據說明
這里列舉出所用到的數據
DWORD sha1::A = 0x67452301;
DWORD sha1::B = 0xEFCDAB89;
DWORD sha1::C = 0x98BADCFE;
DWORD sha1::D = 0x10325476;
DWORD sha1::E = 0xC3D2E1F0;
這里相對MD5算法多了4個字節。(因為SHA1值就是比MD5值多4個字節嘛)
常量:
DWORD sha1::k[4] = {0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
MD5就有64個,這個就簡單一點,4個
0x03 處理信息
和MD5算法類似,也是需要將消息分組,每64個字節(512位)一組,分成多個組(n個)。
對與每一組MiMi(0 < i <= n)都要做如下處理。
將64個字節分成16組w0w0-w15w15,每組剛好4個字節
然后生成w16w16-w79w79,生成的方法如下:
for(DWORD i = 16;i<80;i++){DWORD temp = w[i-3]^w[i-8]^w[i-14]^w[i-16];w[i] = temp<<1 | temp>>31;}
接下來就是做核心運算了。
將a、b、c、d、e分別賦值為上面的A、B、C、D、E,作為MiMi的初始值
然后循環80次,從0-79:
for(DWORD j = 0;j<80;j++){DWORD temp;DWORD temp2 = a<<5|a>>27; //循環左移5位,等下需要用到switch(j/20){ case 0: //0-19步執行這里temp = (b&c)|((~(b))&d);temp += sha1::k[0]; //這個是常數break;case 1: //20-39步執行這里temp = (b^c^d);temp += sha1::k[1];break;case 2: //40-59步執行這里temp = (b&c)|(b&d)|(c&d);temp += sha1::k[2];break;case 3: //60-79步執行這里temp = (b^c^d);temp += sha1::k[3];break;}temp += temp2 + e + w[j]; //這里就是上面生成的80個分組了e = d;d = c;c = b<<30 | b>>2; //循環左移30位b = a;a = temp;}A+=a;B+=b;C+=c;D+=d;E+=e;
注意最后這里和MD5類似,也是再將abcde分別加上初始值ABCDE,作為下一個消息分組Mi+1Mi+1的初始值,直到最后一個分組MnMn計算完后,得出的結果就是SHA1值。
即:
MnAMnBMnCMnDMnEMnAMnBMnCMnDMnE
這里只需按直接輸出就好了,不必像md5那樣調整字節位置后再輸出,