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(uint32_t state[5], const uint8_t buffer[64]);
107
108#define rol(value,bits) \
109 (((value)<<(bits))|((value)>>(32-(bits))))
110
111/* blk0() and blk() perform the initial expand. */
112/* I got the idea of expanding during the round function from
113   SSLeay */
114#ifdef X_LITTLE_ENDIAN
115#define blk0(i) (block->l[i]=(rol(block->l[i],24)&0xFF00FF00) \
116    |(rol(block->l[i],8)&0x00FF00FF))
117#else
118#define blk0(i) block->l[i]
119#endif
120#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
121    ^block->l[(i+2)&15]^block->l[i&15],1))
122
123/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
124#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
125#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
126#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
127#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
128#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
129
130
131/* Hash a single 512-bit block. This is the core of the algorithm. */
132
133static void SHA1Transform(uint32_t state[5],
134    const uint8_t buffer[64])
135{
136uint32_t a, b, c, d, e;
137typedef union {
138    uint8_t c[64];
139    uint32_t l[16];
140} CHAR64LONG16;
141CHAR64LONG16* block;
142#ifdef SHA1HANDSOFF
143static uint8_t workspace[64];
144    block = (CHAR64LONG16*)workspace;
145    memcpy(block, buffer, 64);
146#else
147    block = (CHAR64LONG16*)buffer;
148#endif
149    /* Copy context->state[] to working vars */
150    a = state[0];
151    b = state[1];
152    c = state[2];
153    d = state[3];
154    e = state[4];
155    /* 4 rounds of 20 operations each. Loop unrolled. */
156    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2);
157    R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5);
158    R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8);
159    R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
160    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14);
161    R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17);
162    R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20);
163    R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
164    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26);
165    R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29);
166    R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32);
167    R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
168    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38);
169    R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41);
170    R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44);
171    R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
172    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50);
173    R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53);
174    R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56);
175    R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
176    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62);
177    R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65);
178    R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68);
179    R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
180    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74);
181    R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77);
182    R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
183
184    /* Add the working vars back into context.state[] */
185    state[0] += a;
186    state[1] += b;
187    state[2] += c;
188    state[3] += d;
189    state[4] += e;
190    /* Wipe variables */
191/*    a = b = c = d = e = 0; Nice try, but the compiler
192optimizes this out, anyway, and it produces an annoying
193warning. */
194}
195
196
197/* SHA1Init - Initialize new context */
198
199void SHA1Init(SHA1_CTX* context)
200{
201    /* SHA1 initialization constants */
202    context->state[0] = 0x67452301;
203    context->state[1] = 0xEFCDAB89;
204    context->state[2] = 0x98BADCFE;
205    context->state[3] = 0x10325476;
206    context->state[4] = 0xC3D2E1F0;
207    context->count[0] = context->count[1] = 0;
208}
209
210
211/* Run your data through this. */
212
213void SHA1Update(SHA1_CTX* context, const uint8_t* data,
214    uint32_t len)  /* JHB */
215{
216    uint32_t i, j; /* JHB */
217
218    j = (context->count[0] >> 3) & 63;
219    if ((context->count[0] += len << 3) < (len << 3))
220        context->count[1]++;
221    context->count[1] += (len >> 29);
222    if ((j + len) > 63)
223    {
224        memcpy(&context->buffer[j], data, (i = 64-j));
225        SHA1Transform(context->state, context->buffer);
226        for ( ; i + 63 < len; i += 64) {
227            SHA1Transform(context->state, &data[i]);
228        }
229        j = 0;
230    }
231    else
232        i = 0;
233    memcpy(&context->buffer[j], &data[i], len - i);
234}
235
236
237/* Add padding and return the message digest. */
238
239void SHA1Final(uint8_t digest[HASHSIZE], SHA1_CTX*
240context)
241{
242uint32_t i;    /* JHB */
243uint8_t finalcount[8];
244
245    for (i = 0; i < 8; i++)
246    {
247        finalcount[i] = (uint8_t)((context->count[(i>=4?
248            0:1)]>>((3-(i&3))*8))&255);
249        /* Endian independent */
250    }
251    SHA1Update(context, (uint8_t *)"\200", 1);
252    while ((context->count[0] & 504) != 448) {
253        SHA1Update(context, (uint8_t *)"\0", 1);
254    }
255    SHA1Update(context, finalcount, 8);
256    /* Should cause a SHA1Transform() */
257    for (i = 0; i < HASHSIZE; i++) {
258        digest[i] = (uint8_t)
259         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
260    }
261    /* Wipe variables */
262    memset(context->buffer, 0, 64);
263    memset(context->state, 0, HASHSIZE);
264    memset(context->count, 0, 8);
265    memset(&finalcount, 0, 8);
266#ifdef SHA1HANDSOFF
267    /* make SHA1Transform overwrite it's own static vars */
268    SHA1Transform(context->state, context->buffer);
269#endif
270}
271
272
273
274#ifdef CMDLINE
275
276/* sha1file computes the SHA-1 hash of the named file and puts
277   it in the 20-byte array digest. If fname is NULL, stdin is
278   assumed.
279*/
280void sha1file(char *fname, uint8_t* digest)
281{
282    int bytesread;
283    SHA1_CTX context;
284    uint8_t buffer[16384];
285    FILE* f;
286
287    if (fname)
288    {
289        f = fopen(fname, "rb");
290        if (!f)
291        {
292            fprintf(stderr, "Can't open %s\n", fname);
293            memset(digest, 0, HASHSIZE);
294            return;
295        }
296    }
297    else
298    {
299        f = stdin;
300    }
301    SHA1Init(&context);
302    while (!feof(f))
303    {
304        bytesread = fread(buffer, 1, 16384, f);
305        SHA1Update(&context, buffer, bytesread);
306    }
307    SHA1Final(digest, &context);
308    if (fname)
309        fclose(f);
310}
311
312/* Convert ASCII hexidecimal digit to 4-bit value. */
313uint8_t hexval(char c)
314{
315    uint8_t h;
316
317    c = toupper(c);
318    if (c >= 'A')
319        h = c - 'A' + 10;
320    else
321        h = c - '0';
322    return h;
323}
324
325/* Verify a file created with sha1sum by redirecting output
326   to a file. */
327int verifyfile(char *fname)
328{
329    int j, k;
330    int found = 0;
331    uint8_t digest[HASHSIZE];
332    uint8_t expected_digest[HASHSIZE];
333    FILE *checkfile;
334    char checkline[LINESIZE];
335    char *s;
336    uint8_t err;
337
338    checkfile = fopen(fname, "rt");
339    if (!checkfile)
340    {
341        fprintf(stderr, "Can't open %s\n", fname);
342        return(0);
343    }
344    do
345    {
346        s = fgets(checkline, LINESIZE, checkfile);
347        if (s)
348        {
349            if ((strlen(checkline)>26)&&
350                1 /*(!strncmp(checkline,"SHA1=", 5))*/)
351            {
352                /* Overwrite newline. */
353                checkline[strlen(checkline)-1]=0;
354                found = 1;
355
356                /* Read expected check value. */
357                for (k=0, j=5; k < HASHSIZE; k++)
358                {
359                    expected_digest[k]=hexval(checkline[j++]);
360                    expected_digest[k]=(expected_digest[k]<<4)
361                        +hexval(checkline[j++]);
362                }
363
364                /* Compute fingerprints */
365                s = checkline+46;
366                sha1file(s, digest);
367
368                /* Compare fingerprints */
369                err = 0;
370                for (k=0; k<HASHSIZE; k++)
371                    err |= digest[k]-
372                        expected_digest[k];
373                if (err)
374                {
375                    fprintf(stderr, "FAILED: %s\n"
376                        " EXPECTED: ", s);
377                    for (k=0; k<HASHSIZE; k++)
378                        fprintf(stderr, "%02X",
379                            expected_digest[k]);
380                    fprintf(stderr,"\n    FOUND: ");
381                    for (k=0; k<HASHSIZE; k++)
382                        fprintf(stderr, "%02X", digest[k]);
383                    fprintf(stderr, "\n");
384                }
385                else
386                {
387                    printf("OK: %s\n", s);
388                }
389            }
390        }
391    } while (s);
392    return found;
393}
394
395
396
397void 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
416int main(int argc, char** argv)
417{
418    int i, j, k;
419    int check = 0;
420    int found = 0;
421    uint8_t digest[HASHSIZE];
422    uint8_t 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    uint8_t err;
436    const char *binary_output_file = 0;
437
438    for (i = 1; i < argc; i++)
439    {
440        if (argv[i][0] == '-')
441        {
442            switch (argv[i][1])
443            {
444                case 'B':
445                    ++i;
446                    binary_output_file = argv[i];
447                    break;
448                case 'c':
449                case 'C':
450                    check = 1;
451                    break;
452                case 'g':
453                case 'G':
454                    check = 0;
455                    break;
456                default:
457                    syntax(argv[0]);
458            }
459        }
460    }
461
462    // Read from STDIN
463    sha1file(NULL, digest);
464    if (binary_output_file) {
465      FILE *fout = fopen(binary_output_file, "wb");
466      if (!fout) {
467        fprintf(stderr, "Error: Can not write to %s.\n", binary_output_file);
468        return 1;
469      }
470      fwrite(digest, 1, HASHSIZE, fout);
471      fclose(fout);
472      return 0;
473    }
474    for (j = 0; j < HASHSIZE; j++)
475        printf("%02x", digest[j]);
476    return 0;
477
478    for (i=1; i<argc; i++)
479    {
480        if (argv[i][0] != '-')
481        {
482#ifdef __BORLANDC__
483            fnsplit(argv[i], drive, dir, name, ext);
484            done = findfirst(argv[i], &f, FA_RDONLY |
485                FA_HIDDEN|FA_SYSTEM|FA_ARCH);
486             while (!done)
487            {
488                sprintf(path, "%s%s%s", drive, dir, f.ff_name);
489                s = path;
490#else
491                s = argv[i];
492#endif
493
494                if (check)
495                {   /* Check fingerprint file. */
496                    found |= verifyfile(s);
497                }
498                else
499                {   /* Generate fingerprints & write to
500                       stdout. */
501                    sha1file(s, digest);
502                    //printf("SHA1=");
503                    for (j=0; j<HASHSIZE; j++)
504                        printf("%02x", digest[j]);
505                    printf("  %s\n", s);
506                    found = 1;
507                }
508
509#ifdef __BORLANDC__
510                done = findnext(&f);
511            }
512#endif
513
514        }
515    }
516    if (!found)
517    {
518        if (check)
519        {
520            fprintf(stderr,
521                "No SHA1 lines found in %s\n",
522                argv[i]);
523        }
524        else
525        {
526            fprintf(stderr, "No files checked.\n");
527            syntax(argv[0]);
528        }
529    }
530    return(0);  /* JHB */
531}
532
533#endif  /*CMDLINE*/
534