blob: 62892488a99658c630a44525bb12cd49d4c202ad [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Tweaked in various ways for Google/Android:
3 * - Changed from .cpp to .c.
4 * - Made argument to SHA1Update a const pointer, and enabled
5 * SHA1HANDSOFF. This incurs a speed penalty but prevents us from
6 * trashing the input.
7 * - Include <endian.h> to get endian info.
8 * - Split a small piece into a header file.
9 */
10
11/*
12sha1sum: inspired by md5sum.
13
14SHA-1 in C
15By Steve Reid <steve@edmweb.com>
16100% Public Domain
17
18-----------------
19Modified 7/98
20By James H. Brown <jbrown@burgoyne.com>
21Still 100% Public Domain
22
23bit machines
24Routine SHA1Update changed from
25 void SHA1Update(SHA1_CTX* context, unsigned char* data,
26 unsigned int len)
27to
28 void SHA1Update(SHA1_CTX* context, unsigned char* data,
29 unsigned long len)
30
31The 'len' parameter was declared an int which works fine on 32
32bit machines. However, on 16 bit machines an int is too small
33for the shifts being done against it. This caused the hash
34function to generate incorrect values if len was greater than
358191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
36
37Since the file IO in main() reads 16K at a time, any file 8K or
38larger would be guaranteed to generate the wrong hash (e.g.
39Test Vector #3, a million "a"s).
40
41I also changed the declaration of variables i & j in SHA1Update
42to unsigned long from unsigned int for the same reason.
43
44These changes should make no difference to any 32 bit
45implementations since an int and a long are the same size in
46those environments.
47
48--
49I also corrected a few compiler warnings generated by Borland
50C.
511. Added #include <process.h> for exit() prototype
522. Removed unused variable 'j' in SHA1Final
533. Changed exit(0) to return(0) at end of main.
54
55ALL changes I made can be located by searching for comments
56containing 'JHB'
57
58-----------------
59Modified 13 August 2000
60By Michael Paul Johnson <mpj@cryptography.org>
61Still 100% Public Domain
62
63Changed command line syntax, added feature to automatically
64check files against their previous SHA-1 check values, kind of
65like md5sum does. Added functions hexval, verifyfile,
66and sha1file. Rewrote main().
67-----------------
68
69Test Vectors (from FIPS PUB 180-1)
70"abc"
71 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
72"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
73 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
74A million repetitions of "a"
75 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
76*/
77
78#define SHA1HANDSOFF /*Copies data before messing with it.*/
79
80/*#define CMDLINE * include main() and file processing */
81
82#include "sha1.h"
83
84#include <stdio.h>
85#include <string.h>
86#ifdef __BORLANDC__
87#include <dir.h>
88#include <dos.h>
89#include <process.h> /* prototype for exit() - JHB
90 needed for Win32, but chokes Linux - MPJ */
91#define X_LITTLE_ENDIAN /* This should be #define'd if true.*/
92#else
93# include <unistd.h>
94# include <stdlib.h>
95//# include <endian.h>
96
97#include "DexFile.h" // want common byte ordering def
98
99# if __BYTE_ORDER == __LITTLE_ENDIAN
100# define X_LITTLE_ENDIAN
101# endif
102#endif
103#include <ctype.h>
104
105#define LINESIZE 2048
106
107static void SHA1Transform(unsigned long state[5],
108 const unsigned char buffer[64]);
109
110#define rol(value,bits) \
111 (((value)<<(bits))|((value)>>(32-(bits))))
112
113/* blk0() and blk() perform the initial expand. */
114/* I got the idea of expanding during the round function from
115 SSLeay */
116#ifdef X_LITTLE_ENDIAN
117#define blk0(i) (block->l[i]=(rol(block->l[i],24)&0xFF00FF00) \
118 |(rol(block->l[i],8)&0x00FF00FF))
119#else
120#define blk0(i) block->l[i]
121#endif
122#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
123 ^block->l[(i+2)&15]^block->l[i&15],1))
124
125/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
126#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
127#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
128#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
129#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
130#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
131
132
133/* Hash a single 512-bit block. This is the core of the algorithm. */
134
135static void SHA1Transform(unsigned long state[5],
136 const unsigned char buffer[64])
137{
138unsigned long a, b, c, d, e;
139typedef union {
140 unsigned char c[64];
141 unsigned long l[16];
142} CHAR64LONG16;
143CHAR64LONG16* block;
144#ifdef SHA1HANDSOFF
145static unsigned char workspace[64];
146 block = (CHAR64LONG16*)workspace;
147 memcpy(block, buffer, 64);
148#else
149 block = (CHAR64LONG16*)buffer;
150#endif
151 /* Copy context->state[] to working vars */
152 a = state[0];
153 b = state[1];
154 c = state[2];
155 d = state[3];
156 e = state[4];
157 /* 4 rounds of 20 operations each. Loop unrolled. */
158 R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2);
159 R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5);
160 R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8);
161 R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
162 R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14);
163 R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17);
164 R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20);
165 R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
166 R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26);
167 R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29);
168 R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32);
169 R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
170 R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38);
171 R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41);
172 R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44);
173 R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
174 R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50);
175 R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53);
176 R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56);
177 R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
178 R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62);
179 R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65);
180 R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68);
181 R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
182 R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74);
183 R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77);
184 R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
185
186 /* Add the working vars back into context.state[] */
187 state[0] += a;
188 state[1] += b;
189 state[2] += c;
190 state[3] += d;
191 state[4] += e;
192 /* Wipe variables */
193/* a = b = c = d = e = 0; Nice try, but the compiler
194optimizes this out, anyway, and it produces an annoying
195warning. */
196}
197
198
199/* SHA1Init - Initialize new context */
200
201void SHA1Init(SHA1_CTX* context)
202{
203 /* SHA1 initialization constants */
204 context->state[0] = 0x67452301;
205 context->state[1] = 0xEFCDAB89;
206 context->state[2] = 0x98BADCFE;
207 context->state[3] = 0x10325476;
208 context->state[4] = 0xC3D2E1F0;
209 context->count[0] = context->count[1] = 0;
210}
211
212
213/* Run your data through this. */
214
215void SHA1Update(SHA1_CTX* context, const unsigned char* data,
216 unsigned long len) /* JHB */
217{
218 unsigned long i, j; /* JHB */
219
220 j = (context->count[0] >> 3) & 63;
221 if ((context->count[0] += len << 3) < (len << 3))
222 context->count[1]++;
223 context->count[1] += (len >> 29);
224 if ((j + len) > 63)
225 {
226 memcpy(&context->buffer[j], data, (i = 64-j));
227 SHA1Transform(context->state, context->buffer);
228 for ( ; i + 63 < len; i += 64) {
229 SHA1Transform(context->state, &data[i]);
230 }
231 j = 0;
232 }
233 else
234 i = 0;
235 memcpy(&context->buffer[j], &data[i], len - i);
236}
237
238
239/* Add padding and return the message digest. */
240
241void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX*
242context)
243{
244unsigned long i; /* JHB */
245unsigned char finalcount[8];
246
247 for (i = 0; i < 8; i++)
248 {
249 finalcount[i] = (unsigned char)((context->count[(i>=4?
250 0:1)]>>((3-(i&3))*8))&255);
251 /* Endian independent */
252 }
253 SHA1Update(context, (unsigned char *)"\200", 1);
254 while ((context->count[0] & 504) != 448) {
255 SHA1Update(context, (unsigned char *)"\0", 1);
256 }
257 SHA1Update(context, finalcount, 8);
258 /* Should cause a SHA1Transform() */
259 for (i = 0; i < HASHSIZE; i++) {
260 digest[i] = (unsigned char)
261 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
262 }
263 /* Wipe variables */
264 memset(context->buffer, 0, 64);
265 memset(context->state, 0, HASHSIZE);
266 memset(context->count, 0, 8);
267 memset(&finalcount, 0, 8);
268#ifdef SHA1HANDSOFF
269 /* make SHA1Transform overwrite it's own static vars */
270 SHA1Transform(context->state, context->buffer);
271#endif
272}
273
274
275
276#ifdef CMDLINE
277
278/* sha1file computes the SHA-1 hash of the named file and puts
279 it in the 20-byte array digest. If fname is NULL, stdin is
280 assumed.
281*/
282void sha1file(char *fname, unsigned char* digest)
283{
284 int bytesread;
285 SHA1_CTX context;
286 unsigned char buffer[16384];
287 FILE* f;
288
289 if (fname)
290 {
291 f = fopen(fname, "rb");
292 if (!f)
293 {
294 fprintf(stderr, "Can't open %s\n", fname);
295 memset(digest, 0, HASHSIZE);
296 return;
297 }
298 }
299 else
300 {
301 f = stdin;
302 }
303 SHA1Init(&context);
304 while (!feof(f))
305 {
306 bytesread = fread(buffer, 1, 16384, f);
307 SHA1Update(&context, buffer, bytesread);
308 }
309 SHA1Final(digest, &context);
310 if (fname)
311 fclose(f);
312}
313
314/* Convert ASCII hexidecimal digit to 4-bit value. */
315unsigned char hexval(char c)
316{
317 unsigned char h;
318
319 c = toupper(c);
320 if (c >= 'A')
321 h = c - 'A' + 10;
322 else
323 h = c - '0';
324 return h;
325}
326
327/* Verify a file created with sha1sum by redirecting output
328 to a file. */
329int verifyfile(char *fname)
330{
331 int j, k;
332 int found = 0;
333 unsigned char digest[HASHSIZE];
334 unsigned char expected_digest[HASHSIZE];
335 FILE *checkfile;
336 char checkline[LINESIZE];
337 char *s;
338 unsigned char err;
339
340 checkfile = fopen(fname, "rt");
341 if (!checkfile)
342 {
343 fprintf(stderr, "Can't open %s\n", fname);
344 return(0);
345 }
346 do
347 {
348 s = fgets(checkline, LINESIZE, checkfile);
349 if (s)
350 {
351 if ((strlen(checkline)>26)&&
352 1 /*(!strncmp(checkline,"SHA1=", 5))*/)
353 {
354 /* Overwrite newline. */
355 checkline[strlen(checkline)-1]=0;
356 found = 1;
357
358 /* Read expected check value. */
359 for (k=0, j=5; k < HASHSIZE; k++)
360 {
361 expected_digest[k]=hexval(checkline[j++]);
362 expected_digest[k]=(expected_digest[k]<<4)
363 +hexval(checkline[j++]);
364 }
365
366 /* Compute fingerprints */
367 s = checkline+46;
368 sha1file(s, digest);
369
370 /* Compare fingerprints */
371 err = 0;
372 for (k=0; k<HASHSIZE; k++)
373 err |= digest[k]-
374 expected_digest[k];
375 if (err)
376 {
377 fprintf(stderr, "FAILED: %s\n"
378 " EXPECTED: ", s);
379 for (k=0; k<HASHSIZE; k++)
380 fprintf(stderr, "%02X",
381 expected_digest[k]);
382 fprintf(stderr,"\n FOUND: ");
383 for (k=0; k<HASHSIZE; k++)
384 fprintf(stderr, "%02X", digest[k]);
385 fprintf(stderr, "\n");
386 }
387 else
388 {
389 printf("OK: %s\n", s);
390 }
391 }
392 }
393 } while (s);
394 return found;
395}
396
397
398
399void syntax(char *progname)
400{
401 printf("\nsyntax:\n"
402 "%s [-c|-h][-q] file name[s]\n"
403 " -c = check files against previous check values\n"
404 " -g = generate SHA-1 check values (default action)\n"
405 " -h = display this help\n"
406 "For example,\n"
407 "sha1sum test.txt > check.txt\n"
408 "generates check value for test.txt in check.txt, and\n"
409 "sha1sum -c check.txt\n"
410 "checks test.txt against the check value in check.txt\n",
411 progname);
412 exit(1);
413}
414
415
416/**********************************************************/
417
418int main(int argc, char** argv)
419{
420 int i, j, k;
421 int check = 0;
422 int found = 0;
423 unsigned char digest[HASHSIZE];
424 unsigned char expected_digest[HASHSIZE];
425 FILE *checkfile;
426 char checkline[LINESIZE];
427 char *s;
428#ifdef __BORLANDC__
429 struct ffblk f;
430 int done;
431 char path[MAXPATH];
432 char drive[MAXDRIVE];
433 char dir[MAXDIR];
434 char name[MAXFILE];
435 char ext[MAXEXT];
436#endif
437 unsigned char err;
438
439 for (i = 1; i < argc; i++)
440 {
441 if (argv[i][0] == '-')
442 {
443 switch (argv[i][1])
444 {
445 case 'c':
446 case 'C':
447 check = 1;
448 break;
449 case 'g':
450 case 'G':
451 check = 0;
452 break;
453 default:
454 syntax(argv[0]);
455 }
456 }
457 }
458
459 for (i=1; i<argc; i++)
460 {
461 if (argv[i][0] != '-')
462 {
463#ifdef __BORLANDC__
464 fnsplit(argv[i], drive, dir, name, ext);
465 done = findfirst(argv[i], &f, FA_RDONLY |
466 FA_HIDDEN|FA_SYSTEM|FA_ARCH);
467 while (!done)
468 {
469 sprintf(path, "%s%s%s", drive, dir, f.ff_name);
470 s = path;
471#else
472 s = argv[i];
473#endif
474
475 if (check)
476 { /* Check fingerprint file. */
477 found |= verifyfile(s);
478 }
479 else
480 { /* Generate fingerprints & write to
481 stdout. */
482 sha1file(s, digest);
483 //printf("SHA1=");
484 for (j=0; j<HASHSIZE; j++)
485 printf("%02x", digest[j]);
486 printf(" %s\n", s);
487 found = 1;
488 }
489
490#ifdef __BORLANDC__
491 done = findnext(&f);
492 }
493#endif
494
495 }
496 }
497 if (!found)
498 {
499 if (check)
500 {
501 fprintf(stderr,
502 "No SHA1 lines found in %s\n",
503 argv[i]);
504 }
505 else
506 {
507 fprintf(stderr, "No files checked.\n");
508 syntax(argv[0]);
509 }
510 }
511 return(0); /* JHB */
512}
513
514#endif /*CMDLINE*/