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