OSDN Git Service

TypeRef, not ClassRef.
[android-x86/dalvik.git] / libdex / sha1.c
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@edmweb.com>
16 100% Public Domain
17
18 -----------------
19 Modified 7/98
20 By James H. Brown <jbrown@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@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 typedef union {
140     unsigned char c[64];
141     unsigned long l[16];
142 } CHAR64LONG16;
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*/