SHA1摘要算法原理以及代码实现
1. 术语解释:
SHA1算法需要用到一系列的位运算,以下介绍位运算的符号表示:
XOR 异或 A XOR B
OR 或 A OR B
AND 与 A AND B
NOT 非 NOT A
<< 左移 A>>n(n为常数,下同)
>> 右移 A<<n
另外这里还需要用到一种较为复杂的位运算,我们称之为循环左移:
Sn(X)= (X<<n)OR(X>>32-n) 循环左移
例如,1001循环左移1位: S1(1001)=0011
即将数据左移1位,然后用左边溢出的位去填补右边需要补充的位。
2. 数据前期处理:
当我们得到一个消息信息,需要对其进行一系列的处理,主要有补位、补长度及分块。
1)补位:令我们得到的消息为字符串"bob",我们先以字符为单位将其转换为十六进制Ascii码的排列。b--62,o--6f,b--62。即现在的消息信息为626f62。再将其转换为二进制排列,可得:01100010 01101111 01100010。可见,这是一个长度为24位的数据。现在进行补位操作,首先在我们的数据后加上一个1。得到:01100010 01101111 01100010 1。目前的长度L=25,计算长度L对512的取余运算,及X=L%512,若X不等于448,就在数据末尾加上一个0,一直循环到X=448为止。此时数据的长度应为512的n倍加上448,即L'=512*n+448。补位结束。
2)补长度与分块:现在我们得到一个长度L为512*n+448位的二进制字符串,我们在这个二进制字符串的末尾添加上一个长度为64位的二进制字符串,用来表示原消息数据的长度,如上文中的"bob"长度为24位,其二进制表示:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00011000
如此,我们最终得到一个长度L''=512*n(即长度为512的倍数)的二进制字符串。最后,我们判断这个二进制字符串的长度是否大于512位(即n是否为1)。若大于512位,我们则需要将其分割为长度为512位的多个字符串,这里用M[i](M[0],M[1]……)表示。若不大于,则直接用M0保存。到此,补长度与分块结束。
3.算法需要的各常量的值及函数表达式:
1)常量:
Kt = 0x5A827999 (0 <= t <= 19)
Kt = 0x6ED9EBA1 (20 <= t <= 39)
Kt = 0x8F1BBCDC (40 <= t <= 59)
Kt = 0xCA62C1D6 (60 <= t <= 79)
2)函数表达式:
ft(B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19)
ft(B,C,D) = B XOR C XOR D (20 <= t <= 39)
ft(B,C,D) = (B AND C) OR (B AND D) OR (C AND D) (40 <= t <= 59)
ft(B,C,D) = B XOR C XOR D (60 <= t <= 79).
4.算法:
1)缓冲区:
处理上述的二进制字符串需要一些缓冲区,下面我们详细列出各缓冲区的规格:
a.32位的缓冲区5个:A,B,C,D,E
b.32位的缓冲区80个:W[0]~W[79]
c.32位的缓冲区5个:H[0]~H[4]
d.32位的缓冲区1个:TEMP
首先我们将缓冲区H[]进行初始化赋值:
H[0]=0x67452301
H[1]=0xEFCDAB89
H[2]=0x98BADCFE
H[3]=0x10325476
H[4]=0xC3D2E1F0
2)针对每个M[i]进行循环:
a.将M[i]从左到右分割为16个32位的字符串,转换为uint型的数值分别存储在缓冲区W[0]~W[15]中。
b.对于W[16]~W[79],我们进行如下循环:
W[i] = S1(W[i-3] XOR W[i-8] XOR W[i- 14] XOR W[i-16])
至此,我们的W[]缓冲区已经全部赋值完毕。
c.对缓冲区A,B,C,D,E分别进行赋值:
A=H[0]
B=H[1]
C=H[2]
D=H[3]
E=H[4]
d.对于W[0]~W[79],我们再进行如下循环:
TEMP = S5(A) + ft(B,C,D) + E + W[i] + K[i]
E=D
D=C
C=S30(B)
B=A
A=TEMP
e.我们再对缓冲区H[]进行操作:
H[0]=H[0]+A
H[1]=H[1]+B
H[2]=H[2]+C
H[3]=H[3]+D
H[4]=H[4]+E
3)如此完成每一个M[i]的循环后,最终得到的消息摘要为:
H[0] H[1] H[2] H[3] H[4]
此处缓冲区H[]中的数值全部转换为16进制数用字符串形式表示,以上述格式排列即为我们最终计算出的消息摘要。
最后贴上SHA-1算法实现源代码:
SHA1.h
[cpp] view plain copy
1. #ifndef SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
2. #define SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
3.
4. #if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
5. #define SHA1_UTILITY_FUNCTIONS
6. #endif
7.
8. #if !defined(SHA1_STL_FUNCTIONS) && !defined(SHA1_NO_STL_FUNCTIONS)
9. #define SHA1_STL_FUNCTIONS
10. #if !defined(SHA1_UTILITY_FUNCTIONS)
11. #error STL functions require SHA1_UTILITY_FUNCTIONS.
12. #endif
13. #endif
14.
15. #include <memory.h>
16. #include <limits.h>
17.
18. #ifdef SHA1_UTILITY_FUNCTIONS
19. #include <stdio.h>
20. #include <string.h>
21. #endif
22.
23. #ifdef SHA1_STL_FUNCTIONS
24. #include <string>
25. #endif
26.
27. #ifdef _MSC_VER
28. #include <stdlib.h>
29. #endif
30.
31. // You can define the endian mode in your files without modifying the SHA-1
32. // source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
33. // in your files, before including the SHA1.h header file. If you don't
34. // define anything, the class defaults to little endian.
35. #if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
36. #define SHA1_LITTLE_ENDIAN
37. #endif
38.
39. // If you want variable wiping, #define SHA1_WIPE_VARIABLES, if not,
40. // #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
41. // defaults to wiping.
42. #if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
43. #define SHA1_WIPE_VARIABLES
44. #endif
45.
46. #if defined(SHA1_HAS_TCHAR)
47. #include <tchar.h>
48. #else
49. #ifdef _MSC_VER
50. #include <tchar.h>
51. #else
52. #ifndef TCHAR
53. #define TCHAR char
54. #endif
55. #ifndef _T
56. #define _T(__x) (__x)
57. #define _tmain main
58. #define _tprintf printf
59. #define _getts gets
60. #define _tcslen strlen
61. #define _tfopen fopen
62. #define _tcscpy strcpy
63. #define _tcscat strcat
64. #define _sntprintf snprintf
65. #endif
66. #endif
67. #endif
68.
69. ///
70. // Define variable types
71.
72. #ifndef UINT_8
73. #ifdef _MSC_VER // Compiling with Microsoft compiler
74. #define UINT_8 unsigned __int8
75. #else // !_MSC_VER
76. #define UINT_8 unsigned char
77. #endif // _MSC_VER
78. #endif
79.
80. #ifndef UINT_32
81. #ifdef _MSC_VER // Compiling with Microsoft compiler
82. #define UINT_32 unsigned __int32
83. #else // !_MSC_VER
84. #if (ULONG_MAX == 0xFFFFFFFFUL)
85. #define UINT_32 unsigned long
86. #else
87. #define UINT_32 unsigned int
88. #endif
89. #endif // _MSC_VER
90. #endif // UINT_32
91.
92. #ifndef INT_64
93. #ifdef _MSC_VER // Compiling with Microsoft compiler
94. #define INT_64 __int64
95. #else // !_MSC_VER
96. #define INT_64 long long
97. #endif // _MSC_VER
98. #endif // INT_64
99.
100. #ifndef UINT_64
101. #ifdef _MSC_VER // Compiling with Microsoft compiler
102. #define UINT_64 unsigned __int64
103. #else // !_MSC_VER
104. #define UINT_64 unsigned long long
105. #endif // _MSC_VER
106. #endif // UINT_64
107.
108. ///
109. // Declare SHA-1 workspace
110.
111. typedef union
112. {
113. UINT_8 c[64];
114. UINT_32 l[16];
115. } SHA1_WORKSPACE_BLOCK;
116.
117. class CSHA1
118. {
119. public:
120. #ifdef SHA1_UTILITY_FUNCTIONS
121. // Different formats for ReportHash(Stl)
122. enum REPORT_TYPE
123. {
124. REPORT_HEX = 0,
125. REPORT_DIGIT = 1,
126. REPORT_HEX_SHORT = 2
127. };
128. #endif
129.
130. // Constructor and destructor
131. CSHA1();
132.
133. #ifdef SHA1_WIPE_VARIABLES
134. ~CSHA1();
135. #endif
136.
137. void Reset();
138.
139. // Hash in binary data and strings
140. void Update(const UINT_8* pbData, UINT_32 uLen);
141.
142. #ifdef SHA1_UTILITY_FUNCTIONS
143. // Hash in file contents
144. bool HashFile(const TCHAR* tszFileName);
145. #endif
146.
147. // Finalize hash; call it before using ReportHash(Stl)
148. void Final();
149.
150. #ifdef SHA1_UTILITY_FUNCTIONS
151. bool ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const;
152. #endif
153.
154. #ifdef SHA1_STL_FUNCTIONS
155. bool ReportHashStl(std::basic_string<TCHAR>& strOut, REPORT_TYPE rtReportType =
156. REPORT_HEX) const;
157. #endif
158.
159. // Get the raw message digest (20 bytes)
160. bool GetHash(UINT_8* pbDest20) const;
161.
162. private:
163. // Private SHA-1 transformation
164. void Transform(UINT_32* pState, const UINT_8* pBuffer);
165.
166. // Member variables
167. UINT_32 m_state[5];
168. UINT_32 m_count[2];
169. UINT_32 m_reserved0[1]; // Memory alignment padding
170. UINT_8 m_buffer[64];
171. UINT_8 m_digest[20];
172. UINT_32 m_reserved1[3]; // Memory alignment padding
173.
174. UINT_8 m_workspace[64];
175. SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above
176. };
177.
178. #endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
SHA1.cpp
[cpp] view plain copy
1. #define _CRT_SECURE_NO_WARNINGS
2. #include "SHA1.h"
3.
4. #define SHA1_MAX_FILE_BUFFER (32 * 20 * 820)
5.
6. // Rotate p_val32 by p_nBits bits to the left
7. #ifndef ROL32
8. #ifdef _MSC_VER
9. #define ROL32(p_val32,p_nBits) _rotl(p_val32,p_nBits)
10. #else
11. #define ROL32(p_val32,p_nBits) (((p_val32)<<(p_nBits))|((p_val32)>>(32-(p_nBits))))
12. #endif
13. #endif
14.
15. #ifdef SHA1_LITTLE_ENDIAN
16. #define SHABLK0(i) (m_block->l[i] = \
17. (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
18. #else
19. #define SHABLK0(i) (m_block->l[i])
20. #endif
21.
22. #define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ \
23. m_block->l[(i+8)&15] ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
24.
25. // SHA-1 rounds
26. #define S_R0(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
27. #define S_R1(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
28. #define S_R2(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5);w=ROL32(w,30);}
29. #define S_R3(v,w,x,y,z,i) {z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5);w=ROL32(w,30);}
30. #define S_R4(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5);w=ROL32(w,30);}
31.
32. #pragma warning(push)
33. // Disable compiler warning 'Conditional expression is constant'
34. #pragma warning(disable: 4127)
35.
36. CSHA1::CSHA1()
37. {
38. m_block = (SHA1_WORKSPACE_BLOCK*)m_workspace;
39.
40. Reset();
41. }
42.
43. #ifdef SHA1_WIPE_VARIABLES
44. CSHA1::~CSHA1()
45. {
46. Reset();
47. }
48. #endif
49.
50. void CSHA1::Reset()
51. {
52. // SHA1 initialization constants
53. m_state[0] = 0x67452301;
54. m_state[1] = 0xEFCDAB89;
55. m_state[2] = 0x98BADCFE;
56. m_state[3] = 0x10325476;
57. m_state[4] = 0xC3D2E1F0;
58.
59. m_count[0] = 0;
60. m_count[1] = 0;
61. }
62.
63. void CSHA1::Transform(UINT_32* pState, const UINT_8* pBuffer)
64. {
65. UINT_32 a = pState[0], b = pState[1], c = pState[2], d = pState[3], e = pState[4];
66.
67. memcpy(m_block, pBuffer, 64);
68.
69. // 4 rounds of 20 operations each, loop unrolled
70. S_R0(a,b,c,d,e, 0); S_R0(e,a,b,c,d, 1); S_R0(d,e,a,b,c, 2); S_R0(c,d,e,a,b, 3);
71. S_R0(b,c,d,e,a, 4); S_R0(a,b,c,d,e, 5); S_R0(e,a,b,c,d, 6); S_R0(d,e,a,b,c, 7);
72. S_R0(c,d,e,a,b, 8); S_R0(b,c,d,e,a, 9); S_R0(a,b,c,d,e,10); S_R0(e,a,b,c,d,11);
73. S_R0(d,e,a,b,c,12); S_R0(c,d,e,a,b,13); S_R0(b,c,d,e,a,14); S_R0(a,b,c,d,e,15);
74. S_R1(e,a,b,c,d,16); S_R1(d,e,a,b,c,17); S_R1(c,d,e,a,b,18); S_R1(b,c,d,e,a,19);
75. S_R2(a,b,c,d,e,20); S_R2(e,a,b,c,d,21); S_R2(d,e,a,b,c,22); S_R2(c,d,e,a,b,23);
76. S_R2(b,c,d,e,a,24); S_R2(a,b,c,d,e,25); S_R2(e,a,b,c,d,26); S_R2(d,e,a,b,c,27);
77. S_R2(c,d,e,a,b,28); S_R2(b,c,d,e,a,29); S_R2(a,b,c,d,e,30); S_R2(e,a,b,c,d,31);
78. S_R2(d,e,a,b,c,32); S_R2(c,d,e,a,b,33); S_R2(b,c,d,e,a,34); S_R2(a,b,c,d,e,35);
79. S_R2(e,a,b,c,d,36); S_R2(d,e,a,b,c,37); S_R2(c,d,e,a,b,38); S_R2(b,c,d,e,a,39);
80. S_R3(a,b,c,d,e,40); S_R3(e,a,b,c,d,41); S_R3(d,e,a,b,c,42); S_R3(c,d,e,a,b,43);
81. S_R3(b,c,d,e,a,44); S_R3(a,b,c,d,e,45); S_R3(e,a,b,c,d,46); S_R3(d,e,a,b,c,47);
82. S_R3(c,d,e,a,b,48); S_R3(b,c,d,e,a,49); S_R3(a,b,c,d,e,50); S_R3(e,a,b,c,d,51);
83. S_R3(d,e,a,b,c,52); S_R3(c,d,e,a,b,53); S_R3(b,c,d,e,a,54); S_R3(a,b,c,d,e,55);
84. S_R3(e,a,b,c,d,56); S_R3(d,e,a,b,c,57); S_R3(c,d,e,a,b,58); S_R3(b,c,d,e,a,59);
85. S_R4(a,b,c,d,e,60); S_R4(e,a,b,c,d,61); S_R4(d,e,a,b,c,62); S_R4(c,d,e,a,b,63);
86. S_R4(b,c,d,e,a,64); S_R4(a,b,c,d,e,65); S_R4(e,a,b,c,d,66); S_R4(d,e,a,b,c,67);
87. S_R4(c,d,e,a,b,68); S_R4(b,c,d,e,a,69); S_R4(a,b,c,d,e,70); S_R4(e,a,b,c,d,71);
88. S_R4(d,e,a,b,c,72); S_R4(c,d,e,a,b,73); S_R4(b,c,d,e,a,74); S_R4(a,b,c,d,e,75);
89. S_R4(e,a,b,c,d,76); S_R4(d,e,a,b,c,77); S_R4(c,d,e,a,b,78); S_R4(b,c,d,e,a,79);
90.
91. // Add the working vars back into state
92. pState[0] += a;
93. pState[1] += b;
94. pState[2] += c;
95. pState[3] += d;
96. pState[4] += e;
97.
98. // Wipe variables
99. #ifdef SHA1_WIPE_VARIABLES
100. a = b = c = d = e = 0;
101. #endif
102. }
103.
104. void CSHA1::Update(const UINT_8* pbData, UINT_32 uLen)
105. {
106. UINT_32 j = ((m_count[0] >> 3) & 0x3F);
107.
108. if((m_count[0] += (uLen << 3)) < (uLen << 3))
109. ++m_count[1]; // Overflow
110.
111. m_count[1] += (uLen >> 29);
112.
113. UINT_32 i;
114. if((j + uLen) > 63)
115. {
116. i = 64 - j;
117. memcpy(&m_buffer[j], pbData, i);
118. Transform(m_state, m_buffer);
119.
120. for( ; (i + 63) < uLen; i += 64)
121. Transform(m_state, &pbData[i]);
122.
123. j = 0;
124. }
125. else i = 0;
126.
127. if((uLen - i) != 0)
128. memcpy(&m_buffer[j], &pbData[i], uLen - i);
129. }
130.
131. #ifdef SHA1_UTILITY_FUNCTIONS
132. bool CSHA1::HashFile(const TCHAR* tszFileName)
133. {
134. if(tszFileName == NULL) return false;
135.
136. FILE* fpIn = _tfopen(tszFileName, _T("rb"));
137. if(fpIn == NULL) return false;
138.
139. UINT_8* pbData = new UINT_8[SHA1_MAX_FILE_BUFFER];
140. if(pbData == NULL) { fclose(fpIn); return false; }
141.
142. bool bSuccess = true;
143. while(true)
144. {
145. const size_t uRead = fread(pbData, 1, SHA1_MAX_FILE_BUFFER, fpIn);
146.
147. if(uRead > 0)
148. Update(pbData, static_cast<UINT_32>(uRead));
149.
150. if(uRead < SHA1_MAX_FILE_BUFFER)
151. {
152. if(feof(fpIn) == 0) bSuccess = false;
153. break;
154. }
155. }
156.
157. fclose(fpIn);
158. delete[] pbData;
159. return bSuccess;
160. }
161. #endif
162.
163. void CSHA1::Final()
164. {
165. UINT_32 i;
166.
167. UINT_8 pbFinalCount[8];
168. for(i = 0; i < 8; ++i)
169. pbFinalCount[i] = static_cast<UINT_8>((m_count[((i >= 4) ? 0 : 1)] >>
170. ((3 - (i & 3)) * 8) ) & 0xFF); // Endian independent
171.
172. Update((UINT_8*)"\200", 1);
173.
174. while((m_count[0] & 504) != 448)
175. Update((UINT_8*)"\0", 1);
176.
177. Update(pbFinalCount, 8); // Cause a Transform()
178.
179. for(i = 0; i < 20; ++i)
180. m_digest[i] = static_cast<UINT_8>((m_state[i >> 2] >> ((3 -
181. (i & 3)) * 8)) & 0xFF);
182.
183. // Wipe variables for security reasons
184. #ifdef SHA1_WIPE_VARIABLES
185. memset(m_buffer, 0, 64);
186. memset(m_state, 0, 20);
187. memset(m_count, 0, 8);
188. memset(pbFinalCount, 0, 8);
189. Transform(m_state, m_buffer);
190. #endif
191. }
192.
193. #ifdef SHA1_UTILITY_FUNCTIONS
194. bool CSHA1::ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType) const
195. {
196. if(tszReport == NULL) return false;
197.
198. TCHAR tszTemp[16];
199.
200. if((rtReportType == REPORT_HEX) || (rtReportType == REPORT_HEX_SHORT))
201. {
202. _sntprintf(tszTemp, 15, _T("%02X"), m_digest[0]);
203. _tcscpy(tszReport, tszTemp);
204.
205. const TCHAR* lpFmt = ((rtReportType == REPORT_HEX) ? _T(" %02X") : _T("%02X"));
206. for(size_t i = 1; i < 20; ++i)
207. {
208. _sntprintf(tszTemp, 15, lpFmt, m_digest[i]);
209. _tcscat(tszReport, tszTemp);
210. }
211. }
212. else if(rtReportType == REPORT_DIGIT)
213. {
214. _sntprintf(tszTemp, 15, _T("%u"), m_digest[0]);
215. _tcscpy(tszReport, tszTemp);
216.
217. for(size_t i = 1; i < 20; ++i)
218. {
219. _sntprintf(tszTemp, 15, _T(" %u"), m_digest[i]);
220. _tcscat(tszReport, tszTemp);
221. }
222. }
223. else return false;
224.
225. return true;
226. }
227. #endif
228.
229. #ifdef SHA1_STL_FUNCTIONS
230. bool CSHA1::ReportHashStl(std::basic_string<TCHAR>& strOut, REPORT_TYPE rtReportType) const
231. {
232. TCHAR tszOut[84];
233. const bool bResult = ReportHash(tszOut, rtReportType);
234. if(bResult) strOut = tszOut;
235. return bResult;
236. }
237. #endif
238.
239. bool CSHA1::GetHash(UINT_8* pbDest20) const
240. {
241. if(pbDest20 == NULL) return false;
242. memcpy(pbDest20, m_digest, 20);
243. return true;
244. }
245.
246. #pragma warning(pop)