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