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(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 
    133 static void SHA1Transform(uint32_t state[5],
    134     const uint8_t buffer[64])
    135 {
    136 uint32_t a, b, c, d, e;
    137 typedef union {
    138     uint8_t c[64];
    139     uint32_t l[16];
    140 } CHAR64LONG16;
    141 CHAR64LONG16* block;
    142 #ifdef SHA1HANDSOFF
    143 static 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
    192 optimizes this out, anyway, and it produces an annoying
    193 warning. */
    194 }
    195 
    196 
    197 /* SHA1Init - Initialize new context */
    198 
    199 void 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 
    213 void 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 
    239 void SHA1Final(uint8_t digest[HASHSIZE], SHA1_CTX*
    240 context)
    241 {
    242 uint32_t i;    /* JHB */
    243 uint8_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 */
    280 void 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. */
    313 uint8_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. */
    327 int 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 
    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 
    416 int 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