Home | History | Annotate | Download | only in Support
      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 (at) edmweb.com>
     18 100% Public Domain
     19 
     20 -----------------
     21 Modified 7/98
     22 By James H. Brown <jbrown (at) 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 (at) 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 
    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 
    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 
    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 
    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 */
    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. */
    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. */
    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 
    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 
    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