blob: 0e23c31c49124e6fe71c739e0a8e25a906af9518 [file] [log] [blame]
tanjent@gmail.comf3b78972012-03-01 03:38:55 +00001/*
2SHA-1 in C
3By Steve Reid <sreid@sea-to-sky.net>
4100% Public Domain
5
6-----------------
7Modified 7/98
8By James H. Brown <jbrown@burgoyne.com>
9Still 100% Public Domain
10
11Corrected a problem which generated improper hash values on 16 bit machines
12Routine SHA1Update changed from
13 void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
14len)
15to
16 void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
17long len)
18
19The 'len' parameter was declared an int which works fine on 32 bit machines.
20However, on 16 bit machines an int is too small for the shifts being done
21against
22it. This caused the hash function to generate incorrect values if len was
23greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
24
25Since the file IO in main() reads 16K at a time, any file 8K or larger would
26be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
27"a"s).
28
29I also changed the declaration of variables i & j in SHA1Update to
30unsigned long from unsigned int for the same reason.
31
32These changes should make no difference to any 32 bit implementations since
33an
34int and a long are the same size in those environments.
35
36--
37I also corrected a few compiler warnings generated by Borland C.
381. Added #include <process.h> for exit() prototype
392. Removed unused variable 'j' in SHA1Final
403. Changed exit(0) to return(0) at end of main.
41
42ALL changes I made can be located by searching for comments containing 'JHB'
43-----------------
44Modified 8/98
45By Steve Reid <sreid@sea-to-sky.net>
46Still 100% public domain
47
481- Removed #include <process.h> and used return() instead of exit()
492- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
503- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
51
52-----------------
53Modified 4/01
54By Saul Kravitz <Saul.Kravitz@celera.com>
55Still 100% PD
56Modified to run on Compaq Alpha hardware.
57
58-----------------
59Modified 07/2002
60By Ralph Giles <giles@ghostscript.com>
61Still 100% public domain
62modified for use with stdint types, autoconf
63code cleanup, removed attribution comments
64switched SHA1Final() argument order for consistency
65use SHA1_ prefix for public api
66move public api to sha1.h
67*/
68
69/*
70Test Vectors (from FIPS PUB 180-1)
71"abc"
72 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
73"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
74 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
75A million repetitions of "a"
76 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
77*/
78
79#include <stdio.h>
80#include <string.h>
81#include <stdlib.h>
82
83#include "sha1.h"
84
85#if defined(_MSC_VER)
86#pragma warning(disable : 4267)
87#pragma warning(disable : 4996)
88#pragma warning(disable : 4100)
89#endif
90
91void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
92
93#define rol ROTL32
94
95/* blk0() and blk() perform the initial expand. */
96/* I got the idea of expanding during the round function from SSLeay */
97/* FIXME: can we do this in an endian-proof way? */
98
99#ifdef WORDS_BIGENDIAN
100#define blk0(i) block->l[i]
101#else
102#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) | (rol(block->l[i],8)&0x00FF00FF))
103#endif
104#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^ block->l[(i+2)&15]^block->l[i&15],1))
105
106/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
107#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
108#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
109#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
110#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
111#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
112
113
114/* Hash a single 512-bit block. This is the core of the algorithm. */
115void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
116{
117 uint32_t a, b, c, d, e;
118 typedef union {
119 uint8_t c[64];
120 uint32_t l[16];
121 } CHAR64LONG16;
122 CHAR64LONG16* block;
123
124 block = (CHAR64LONG16*)buffer;
125
126 /* Copy context->state[] to working vars */
127 a = state[0];
128 b = state[1];
129 c = state[2];
130 d = state[3];
131 e = state[4];
132
133 /* 4 rounds of 20 operations each. Loop unrolled. */
134 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);
135 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);
136 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);
137 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);
138 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);
139 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);
140 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);
141 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);
142 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);
143 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);
144 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);
145 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);
146 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);
147 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);
148 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);
149 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);
150 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);
151 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);
152 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);
153 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);
154
155 /* Add the working vars back into context.state[] */
156 state[0] += a;
157 state[1] += b;
158 state[2] += c;
159 state[3] += d;
160 state[4] += e;
161
162 /* Wipe variables */
163 a = b = c = d = e = 0;
164}
165
166
167/* SHA1Init - Initialize new context */
168void SHA1_Init(SHA1_CTX* context)
169{
170 /* SHA1 initialization constants */
171 context->state[0] = 0x67452301;
172 context->state[1] = 0xEFCDAB89;
173 context->state[2] = 0x98BADCFE;
174 context->state[3] = 0x10325476;
175 context->state[4] = 0xC3D2E1F0;
176 context->count[0] = 0;
177 context->count[1] = 0;
178}
179
180
181/* Run your data through this. */
182void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
183{
184 size_t i, j;
185
186 j = (context->count[0] >> 3) & 63;
187 if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
188
189 context->count[1] += (len >> 29);
190
191 if ((j + len) > 63)
192 {
193 memcpy(&context->buffer[j], data, (i = 64-j));
194 SHA1_Transform(context->state, context->buffer);
195
196 for ( ; i + 63 < len; i += 64)
197 {
198 SHA1_Transform(context->state, data + i);
199 }
200
201 j = 0;
202 }
203 else i = 0;
204 memcpy(&context->buffer[j], &data[i], len - i);
205}
206
207
208/* Add padding and return the message digest. */
209void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
210{
211 uint32_t i;
212 uint8_t finalcount[8];
213
214 for (i = 0; i < 8; i++) {
215 finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
216 >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
217 }
218 SHA1_Update(context, (uint8_t *)"\200", 1);
219 while ((context->count[0] & 504) != 448) {
220 SHA1_Update(context, (uint8_t *)"\0", 1);
221 }
222 SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
223 for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
224 digest[i] = (uint8_t)
225 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
226 }
227
228 /* Wipe variables */
229 i = 0;
230 memset(context->buffer, 0, 64);
231 memset(context->state, 0, 20);
232 memset(context->count, 0, 8);
233 memset(finalcount, 0, 8); /* SWR */
234}
235
236//-----------------------------------------------------------------------------
237
238void sha1_32a ( const void * key, int len, uint32_t seed, void * out )
239{
240 SHA1_CTX context;
241
242 uint8_t digest[20];
243
244 SHA1_Init(&context);
245 SHA1_Update(&context, (uint8_t*)key, len);
246 SHA1_Final(&context, digest);
247
248 memcpy(out,&digest[0],4);
249}
250
251//-----------------------------------------------------------------------------
252// self test
253
254//#define TEST
255
256#ifdef TEST
257
258static char *test_data[] = {
259 "abc",
260 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
261 "A million repetitions of 'a'"};
262static char *test_results[] = {
263 "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
264 "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
265 "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"};
266
267
268void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)
269{
270 int i,j;
271 char *c = output;
272
273 for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
274 for (j = 0; j < 4; j++) {
275 sprintf(c,"%02X", digest[i*4+j]);
276 c += 2;
277 }
278 sprintf(c, " ");
279 c += 1;
280 }
281 *(c - 1) = '\0';
282}
283
284int main(int argc, char** argv)
285{
286 int k;
287 SHA1_CTX context;
288 uint8_t digest[20];
289 char output[80];
290
291 fprintf(stdout, "verifying SHA-1 implementation... ");
292
293 for (k = 0; k < 2; k++){
294 SHA1_Init(&context);
295 SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k]));
296 SHA1_Final(&context, digest);
297 digest_to_hex(digest, output);
298
299 if (strcmp(output, test_results[k])) {
300 fprintf(stdout, "FAIL\n");
301 fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
302 fprintf(stderr,"\t%s returned\n", output);
303 fprintf(stderr,"\t%s is correct\n", test_results[k]);
304 return (1);
305 }
306 }
307 /* million 'a' vector we feed separately */
308 SHA1_Init(&context);
309 for (k = 0; k < 1000000; k++)
310 SHA1_Update(&context, (uint8_t*)"a", 1);
311 SHA1_Final(&context, digest);
312 digest_to_hex(digest, output);
313 if (strcmp(output, test_results[2])) {
314 fprintf(stdout, "FAIL\n");
315 fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
316 fprintf(stderr,"\t%s returned\n", output);
317 fprintf(stderr,"\t%s is correct\n", test_results[2]);
318 return (1);
319 }
320
321 /* success */
322 fprintf(stdout, "ok\n");
323 return(0);
324}
325#endif /* TEST */