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