Updated init script.
[dtbartle/bnbt.git] / sha1.cpp
1 /*\r
2         100% free public domain implementation of the SHA-1 algorithm\r
3         by Dominik Reichl <dominik.reichl@t-online.de>\r
4         Web: http://www.dominik-reichl.de/\r
5 \r
6         Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)\r
7         - You can set the endianness in your files, no need to modify the\r
8           header file of the CSHA1 class any more\r
9         - Aligned data support\r
10         - Made support/compilation of the utility functions (ReportHash\r
11           and HashFile) optional (useful, if bytes count, for example in\r
12           embedded environments)\r
13 \r
14         Version 1.5 - 2005-01-01\r
15         - 64-bit compiler compatibility added\r
16         - Made variable wiping optional (define SHA1_WIPE_VARIABLES)\r
17         - Removed unnecessary variable initializations\r
18         - ROL32 improvement for the Microsoft compiler (using _rotl)\r
19 \r
20         ======== Test Vectors (from FIPS PUB 180-1) ========\r
21 \r
22         SHA1("abc") =\r
23                 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D\r
24 \r
25         SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =\r
26                 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1\r
27 \r
28         SHA1(A million repetitions of "a") =\r
29                 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F\r
30 */\r
31 \r
32 #include "sha1.h"\r
33 \r
34 #ifdef SHA1_UTILITY_FUNCTIONS\r
35 #define SHA1_MAX_FILE_BUFFER 8000\r
36 #endif\r
37 \r
38 // Rotate x bits to the left\r
39 #ifndef ROL32\r
40 #ifdef _MSC_VER\r
41 #define ROL32(_val32, _nBits) _rotl(_val32, _nBits)\r
42 #else\r
43 #define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))\r
44 #endif\r
45 #endif\r
46 \r
47 #ifdef SHA1_LITTLE_ENDIAN\r
48 #define SHABLK0(i) (m_block->l[i] = \\r
49         (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))\r
50 #else\r
51 #define SHABLK0(i) (m_block->l[i])\r
52 #endif\r
53 \r
54 #define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \\r
55         ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))\r
56 \r
57 // SHA-1 rounds\r
58 #define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }\r
59 #define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }\r
60 #define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }\r
61 #define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }\r
62 #define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }\r
63 \r
64 CSHA1::CSHA1()\r
65 {\r
66         m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;\r
67 \r
68         Reset();\r
69 }\r
70 \r
71 CSHA1::~CSHA1()\r
72 {\r
73         Reset();\r
74 }\r
75 \r
76 void CSHA1::Reset()\r
77 {\r
78         // SHA1 initialization constants\r
79         m_state[0] = 0x67452301;\r
80         m_state[1] = 0xEFCDAB89;\r
81         m_state[2] = 0x98BADCFE;\r
82         m_state[3] = 0x10325476;\r
83         m_state[4] = 0xC3D2E1F0;\r
84 \r
85         m_count[0] = 0;\r
86         m_count[1] = 0;\r
87 }\r
88 \r
89 void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer)\r
90 {\r
91         // Copy state[] to working vars\r
92         UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];\r
93 \r
94         memcpy(m_block, buffer, 64);\r
95 \r
96         // 4 rounds of 20 operations each. Loop unrolled.\r
97         _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);\r
98         _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);\r
99         _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);\r
100         _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);\r
101         _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);\r
102         _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);\r
103         _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);\r
104         _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);\r
105         _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);\r
106         _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);\r
107         _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);\r
108         _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);\r
109         _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);\r
110         _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);\r
111         _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);\r
112         _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);\r
113         _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);\r
114         _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);\r
115         _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);\r
116         _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);\r
117 \r
118         // Add the working vars back into state\r
119         state[0] += a;\r
120         state[1] += b;\r
121         state[2] += c;\r
122         state[3] += d;\r
123         state[4] += e;\r
124 \r
125         // Wipe variables\r
126 #ifdef SHA1_WIPE_VARIABLES\r
127         a = b = c = d = e = 0;\r
128 #endif\r
129 }\r
130 \r
131 // Use this function to hash in binary data and strings\r
132 void CSHA1::Update(UINT_8 *data, UINT_32 len)\r
133 {\r
134         UINT_32 i, j;\r
135 \r
136         j = (m_count[0] >> 3) & 63;\r
137 \r
138         if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;\r
139 \r
140         m_count[1] += (len >> 29);\r
141 \r
142         if((j + len) > 63)\r
143         {\r
144                 i = 64 - j;\r
145                 memcpy(&m_buffer[j], data, i);\r
146                 Transform(m_state, m_buffer);\r
147 \r
148                 for( ; i + 63 < len; i += 64) Transform(m_state, &data[i]);\r
149 \r
150                 j = 0;\r
151         }\r
152         else i = 0;\r
153 \r
154         memcpy(&m_buffer[j], &data[i], len - i);\r
155 }\r
156 \r
157 #ifdef SHA1_UTILITY_FUNCTIONS\r
158 // Hash in file contents\r
159 bool CSHA1::HashFile(char *szFileName)\r
160 {\r
161         unsigned long ulFileSize, ulRest, ulBlocks;\r
162         unsigned long i;\r
163         UINT_8 uData[SHA1_MAX_FILE_BUFFER];\r
164         FILE *fIn;\r
165 \r
166         if(szFileName == NULL) return false;\r
167 \r
168         fIn = fopen(szFileName, "rb");\r
169         if(fIn == NULL) return false;\r
170 \r
171         fseek(fIn, 0, SEEK_END);\r
172         ulFileSize = (unsigned long)ftell(fIn);\r
173         fseek(fIn, 0, SEEK_SET);\r
174 \r
175         if(ulFileSize != 0)\r
176         {\r
177                 ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;\r
178                 ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;\r
179         }\r
180         else\r
181         {\r
182                 ulBlocks = 0;\r
183                 ulRest = 0;\r
184         }\r
185 \r
186         for(i = 0; i < ulBlocks; i++)\r
187         {\r
188                 fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);\r
189                 Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER);\r
190         }\r
191 \r
192         if(ulRest != 0)\r
193         {\r
194                 fread(uData, 1, ulRest, fIn);\r
195                 Update((UINT_8 *)uData, ulRest);\r
196         }\r
197 \r
198         fclose(fIn); fIn = NULL;\r
199         return true;\r
200 }\r
201 #endif\r
202 \r
203 void CSHA1::Final()\r
204 {\r
205         UINT_32 i;\r
206         UINT_8 finalcount[8];\r
207 \r
208         for(i = 0; i < 8; i++)\r
209                 finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)]\r
210                         >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent\r
211 \r
212         Update((UINT_8 *)"\200", 1);\r
213 \r
214         while ((m_count[0] & 504) != 448)\r
215                 Update((UINT_8 *)"\0", 1);\r
216 \r
217         Update(finalcount, 8); // Cause a SHA1Transform()\r
218 \r
219         for(i = 0; i < 20; i++)\r
220         {\r
221                 m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);\r
222         }\r
223 \r
224         // Wipe variables for security reasons\r
225 #ifdef SHA1_WIPE_VARIABLES\r
226         i = 0;\r
227         memset(m_buffer, 0, 64);\r
228         memset(m_state, 0, 20);\r
229         memset(m_count, 0, 8);\r
230         memset(finalcount, 0, 8);\r
231         Transform(m_state, m_buffer);\r
232 #endif\r
233 }\r
234 \r
235 #ifdef SHA1_UTILITY_FUNCTIONS\r
236 // Get the final hash as a pre-formatted string\r
237 void CSHA1::ReportHash(char *szReport, unsigned char uReportType)\r
238 {\r
239         unsigned char i;\r
240         char szTemp[16];\r
241 \r
242         if(szReport == NULL) return;\r
243 \r
244         if(uReportType == REPORT_HEX)\r
245         {\r
246                 sprintf(szTemp, "%02X", m_digest[0]);\r
247                 strcat(szReport, szTemp);\r
248 \r
249                 for(i = 1; i < 20; i++)\r
250                 {\r
251                         sprintf(szTemp, "%02X", m_digest[i]);\r
252                         strcat(szReport, szTemp);\r
253                 }\r
254         }\r
255         else if(uReportType == REPORT_DIGIT)\r
256         {\r
257                 sprintf(szTemp, "%u", m_digest[0]);\r
258                 strcat(szReport, szTemp);\r
259 \r
260                 for(i = 1; i < 20; i++)\r
261                 {\r
262                         sprintf(szTemp, "%u", m_digest[i]);\r
263                         strcat(szReport, szTemp);\r
264                 }\r
265         }\r
266         else strcpy(szReport, "Error: Unknown report type!");\r
267 }\r
268 #endif\r
269 \r
270 // Get the raw message digest\r
271 void CSHA1::GetHash(UINT_8 *puDest)\r
272 {\r
273         memcpy(puDest, m_digest, 20);\r
274 }\r