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/*
14sha1sum: inspired by md5sum.
15
16SHA-1 in C
17By Steve Reid <steve@edmweb.com>
18100% Public Domain
19
20-----------------
21Modified 7/98
22By James H. Brown <jbrown@burgoyne.com>
23Still 100% Public Domain
24
25bit machines
26Routine SHA1Update changed from
27    void SHA1Update(SHA1_CTX* context, unsigned char* data,
28      unsigned int len)
29to
30    void SHA1Update(SHA1_CTX* context, unsigned char* data,
31      unsigned long len)
32
33The 'len' parameter was declared an int which works fine on 32
34bit machines. However, on 16 bit machines an int is too small
35for the shifts being done against it.  This caused the hash
36function to generate incorrect values if len was greater than
378191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
38
39Since the file IO in main() reads 16K at a time, any file 8K or
40larger would be guaranteed to generate the wrong hash (e.g.
41Test Vector #3, a million "a"s).
42
43I also changed the declaration of variables i & j in SHA1Update
44to unsigned long from unsigned int for the same reason.
45
46These changes should make no difference to any 32 bit
47implementations since an int and a long are the same size in
48those environments.
49
50--
51I also corrected a few compiler warnings generated by Borland
52C.
531. Added #include <process.h> for exit() prototype
542. Removed unused variable 'j' in SHA1Final
553. Changed exit(0) to return(0) at end of main.
56
57ALL changes I made can be located by searching for comments
58containing 'JHB'
59
60-----------------
61Modified 13 August 2000
62By Michael Paul Johnson <mpj@cryptography.org>
63Still 100% Public Domain
64
65Changed command line syntax, added feature to automatically
66check files against their previous SHA-1 check values, kind of
67like md5sum does. Added functions hexval, verifyfile,
68and sha1file. Rewrote main().
69-----------------
70
71Test Vectors (from FIPS PUB 180-1)
72"abc"
73  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
74"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
75  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
76A 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
106static 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
134static void SHA1Transform(unsigned long state[5],
135    const unsigned char buffer[64])
136{
137unsigned long a, b, c, d, e;
138typedef union {
139    unsigned char c[64];
140    unsigned long l[16];
141} CHAR64LONG16;
142CHAR64LONG16* block;
143#ifdef SHA1HANDSOFF
144static 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
193optimizes this out, anyway, and it produces an annoying
194warning. */
195}
196
197
198/* SHA1Init - Initialize new context */
199
200void 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
214void 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
240void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX*
241context)
242{
243unsigned long i;    /* JHB */
244unsigned 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*/
281void 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. */
314unsigned 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. */
328int 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
398void 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
417int 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