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