xref: /haiku/src/bin/unzip/cryptf.c (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2   Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2000-Apr-09 or later
5   (the contents of which are also included in zip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*
10   cryptf.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]
11 	*** This is only needed to build funzip correctly and is a direct copy
12 	of crypt.c. Don't forget to update here if you update crypt.c!! ***
13 
14   This encryption/decryption source code for Info-Zip software was
15   originally written in Europe.  The whole source package can be
16   freely distributed, including from the USA.  (Prior to January 2000,
17   re-export from the US was a violation of US law.)
18 
19   NOTE on copyright history:
20   Previous versions of this source package (up to version 2.8) were
21   not copyrighted and put in the public domain.  If you cannot comply
22   with the Info-Zip LICENSE, you may want to look for one of those
23   public domain versions.
24  */
25 
26 /*
27   This encryption code is a direct transcription of the algorithm from
28   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
29   file (appnote.txt) is distributed with the PKZIP program (even in the
30   version without encryption capabilities).
31  */
32 
33 #define FUNZIP
34 #define ZCRYPT_INTERNAL
35 #include "zip.h"
36 #include "crypt.h"
37 #include "ttyio.h"
38 
39 #if CRYPT
40 
41 #ifndef FALSE
42 #  define FALSE 0
43 #endif
44 
45 #ifdef ZIP
46    /* For the encoding task used in Zip (and ZipCloak), we want to initialize
47       the crypt algorithm with some reasonably unpredictable bytes, see
48       the crypthead() function. The standard rand() library function is
49       used to supply these `random' bytes, which in turn is initialized by
50       a srand() call. The srand() function takes an "unsigned" (at least 16bit)
51       seed value as argument to determine the starting point of the rand()
52       pseudo-random number generator.
53       This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with
54       Seed1 supplied by the current time (= "(unsigned)time()") and Seed2
55       as some (hopefully) nondeterministic bitmask. On many (most) systems,
56       we use some "process specific" number, as the PID or something similar,
57       but when nothing unpredictable is available, a fixed number may be
58       sufficient.
59       NOTE:
60       1.) This implementation requires the availability of the following
61           standard UNIX C runtime library functions: time(), rand(), srand().
62           On systems where some of them are missing, the environment that
63           incorporates the crypt routines must supply suitable replacement
64           functions.
65       2.) It is a very bad idea to use a second call to time() to set the
66           "Seed2" number! In this case, both "Seed1" and "Seed2" would be
67           (almost) identical, resulting in a (mostly) "zero" constant seed
68           number passed to srand().
69 
70       The implementation environment defined in the "zip.h" header should
71       supply a reasonable definition for ZCR_SEED2 (an unsigned number; for
72       most implementations of rand() and srand(), only the lower 16 bits are
73       significant!). An example that works on many systems would be
74            "#define ZCR_SEED2  (unsigned)getpid()".
75       The default definition for ZCR_SEED2 supplied below should be regarded
76       as a fallback to allow successful compilation in "beta state"
77       environments.
78     */
79 #  include <time.h>     /* time() function supplies first part of crypt seed */
80    /* "last resort" source for second part of crypt seed pattern */
81 #  ifndef ZCR_SEED2
82 #    define ZCR_SEED2 (unsigned)3141592654L     /* use PI as default pattern */
83 #  endif
84 #  ifdef GLOBAL         /* used in Amiga system headers, maybe others too */
85 #    undef GLOBAL
86 #  endif
87 #  define GLOBAL(g) g
88 #else /* !ZIP */
89 #  define GLOBAL(g) G.g
90 #endif /* ?ZIP */
91 
92 
93 #ifdef UNZIP
94    /* char *key = (char *)NULL; moved to globals.h */
95 #  ifndef FUNZIP
96      local int testp OF((__GPRO__ ZCONST uch *h));
97      local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key));
98 #  endif
99 #endif /* UNZIP */
100 
101 #ifndef UNZIP             /* moved to globals.h for UnZip */
102    local ulg keys[3];     /* keys defining the pseudo-random sequence */
103 #endif /* !UNZIP */
104 
105 #ifndef Trace
106 #  ifdef CRYPT_DEBUG
107 #    define Trace(x) fprintf x
108 #  else
109 #    define Trace(x)
110 #  endif
111 #endif
112 
113 #ifndef CRC_32_TAB
114 #  define CRC_32_TAB     crc_32_tab
115 #endif
116 
117 #define CRC32(c, b) (CRC_32_TAB[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
118 
119 /***********************************************************************
120  * Return the next byte in the pseudo-random sequence
121  */
122 int decrypt_byte(__G)
123     __GDEF
124 {
125     unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
126                      * unpredictable manner on 16-bit systems; not a problem
127                      * with any known compiler so far, though */
128 
129     temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2;
130     return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
131 }
132 
133 /***********************************************************************
134  * Update the encryption keys with the next byte of plain text
135  */
136 int update_keys(__G__ c)
137     __GDEF
138     int c;                      /* byte of plain text */
139 {
140     GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c);
141     GLOBAL(keys[1]) += GLOBAL(keys[0]) & 0xff;
142     GLOBAL(keys[1]) = GLOBAL(keys[1]) * 134775813L + 1;
143     {
144       register int keyshift = (int)(GLOBAL(keys[1]) >> 24);
145       GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift);
146     }
147     return c;
148 }
149 
150 
151 /***********************************************************************
152  * Initialize the encryption keys and the random header according to
153  * the given password.
154  */
155 void init_keys(__G__ passwd)
156     __GDEF
157     ZCONST char *passwd;        /* password string with which to modify keys */
158 {
159     GLOBAL(keys[0]) = 305419896L;
160     GLOBAL(keys[1]) = 591751049L;
161     GLOBAL(keys[2]) = 878082192L;
162     while (*passwd != '\0') {
163         update_keys(__G__ (int)*passwd);
164         passwd++;
165     }
166 }
167 
168 
169 #ifdef ZIP
170 
171 /***********************************************************************
172  * Write encryption header to file zfile using the password passwd
173  * and the cyclic redundancy check crc.
174  */
175 void crypthead(passwd, crc, zfile)
176     ZCONST char *passwd;         /* password string */
177     ulg crc;                     /* crc of file being encrypted */
178     FILE *zfile;                 /* where to write header */
179 {
180     int n;                       /* index in random header */
181     int t;                       /* temporary */
182     int c;                       /* random byte */
183     int ztemp;                   /* temporary for zencoded value */
184     uch header[RAND_HEAD_LEN-2]; /* random header */
185     static unsigned calls = 0;   /* ensure different random header each time */
186 
187     /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
188      * output of rand() to get less predictability, since rand() is
189      * often poorly implemented.
190      */
191     if (++calls == 1) {
192         srand((unsigned)time(NULL) ^ ZCR_SEED2);
193     }
194     init_keys(passwd);
195     for (n = 0; n < RAND_HEAD_LEN-2; n++) {
196         c = (rand() >> 7) & 0xff;
197         header[n] = (uch)zencode(c, t);
198     }
199     /* Encrypt random header (last two bytes is high word of crc) */
200     init_keys(passwd);
201     for (n = 0; n < RAND_HEAD_LEN-2; n++) {
202         ztemp = zencode(header[n], t);
203         putc(ztemp, zfile);
204     }
205     ztemp = zencode((int)(crc >> 16) & 0xff, t);
206     putc(ztemp, zfile);
207     ztemp = zencode((int)(crc >> 24) & 0xff, t);
208     putc(ztemp, zfile);
209 }
210 
211 
212 #ifdef UTIL
213 
214 /***********************************************************************
215  * Encrypt the zip entry described by z from file source to file dest
216  * using the password passwd.  Return an error code in the ZE_ class.
217  */
218 int zipcloak(z, source, dest, passwd)
219     struct zlist far *z;    /* zip entry to encrypt */
220     FILE *source, *dest;    /* source and destination files */
221     ZCONST char *passwd;    /* password string */
222 {
223     int c;                  /* input byte */
224     int res;                /* result code */
225     ulg n;                  /* holds offset and counts size */
226     ush flag;               /* previous flags */
227     int t;                  /* temporary */
228     int ztemp;              /* temporary storage for zencode value */
229 
230     /* Set encrypted bit, clear extended local header bit and write local
231        header to output file */
232     if ((n = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP;
233     z->off = n;
234     flag = z->flg;
235     z->flg |= 1,  z->flg &= ~8;
236     z->lflg |= 1, z->lflg &= ~8;
237     z->siz += RAND_HEAD_LEN;
238     if ((res = putlocal(z, dest)) != ZE_OK) return res;
239 
240     /* Initialize keys with password and write random header */
241     crypthead(passwd, z->crc, dest);
242 
243     /* Skip local header in input file */
244     if (fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext),
245               SEEK_CUR)) {
246         return ferror(source) ? ZE_READ : ZE_EOF;
247     }
248 
249     /* Encrypt data */
250     for (n = z->siz - RAND_HEAD_LEN; n; n--) {
251         if ((c = getc(source)) == EOF) {
252             return ferror(source) ? ZE_READ : ZE_EOF;
253         }
254         ztemp = zencode(c, t);
255         putc(ztemp, dest);
256     }
257     /* Skip extended local header in input file if there is one */
258     if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) {
259         return ferror(source) ? ZE_READ : ZE_EOF;
260     }
261     if (fflush(dest) == EOF) return ZE_TEMP;
262     return ZE_OK;
263 }
264 
265 /***********************************************************************
266  * Decrypt the zip entry described by z from file source to file dest
267  * using the password passwd.  Return an error code in the ZE_ class.
268  */
269 int zipbare(z, source, dest, passwd)
270     struct zlist far *z;  /* zip entry to encrypt */
271     FILE *source, *dest;  /* source and destination files */
272     ZCONST char *passwd;  /* password string */
273 {
274     int c0, c1;           /* last two input bytes */
275     ulg offset;           /* used for file offsets */
276     ulg size;             /* size of input data */
277     int r;                /* size of encryption header */
278     int res;              /* return code */
279     ush flag;             /* previous flags */
280 
281     /* Save position and skip local header in input file */
282     if ((offset = (ulg)ftell(source)) == (ulg)-1L ||
283         fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext),
284               SEEK_CUR)) {
285         return ferror(source) ? ZE_READ : ZE_EOF;
286     }
287     /* Initialize keys with password */
288     init_keys(passwd);
289 
290     /* Decrypt encryption header, save last two bytes */
291     c1 = 0;
292     for (r = RAND_HEAD_LEN; r; r--) {
293         c0 = c1;
294         if ((c1 = getc(source)) == EOF) {
295             return ferror(source) ? ZE_READ : ZE_EOF;
296         }
297         Trace((stdout, " (%02x)", c1));
298         zdecode(c1);
299         Trace((stdout, " %02x", c1));
300     }
301     Trace((stdout, "\n"));
302 
303     /* If last two bytes of header don't match crc (or file time in the
304      * case of an extended local header), back up and just copy. For
305      * pkzip 2.0, the check has been reduced to one byte only.
306      */
307 #ifdef ZIP10
308     if ((ush)(c0 | (c1<<8)) !=
309         (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) {
310 #else
311     c0++; /* avoid warning on unused variable */
312     if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) {
313 #endif
314         if (fseek(source, offset, SEEK_SET)) {
315             return ferror(source) ? ZE_READ : ZE_EOF;
316         }
317         if ((res = zipcopy(z, source, dest)) != ZE_OK) return res;
318         return ZE_MISS;
319     }
320 
321     /* Clear encrypted bit and local header bit, and write local header to
322        output file */
323     if ((offset = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP;
324     z->off = offset;
325     flag = z->flg;
326     z->flg &= ~9;
327     z->lflg &= ~9;
328     z->siz -= RAND_HEAD_LEN;
329     if ((res = putlocal(z, dest)) != ZE_OK) return res;
330 
331     /* Decrypt data */
332     for (size = z->siz; size; size--) {
333         if ((c1 = getc(source)) == EOF) {
334             return ferror(source) ? ZE_READ : ZE_EOF;
335         }
336         zdecode(c1);
337         putc(c1, dest);
338     }
339     /* Skip extended local header in input file if there is one */
340     if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) {
341         return ferror(source) ? ZE_READ : ZE_EOF;
342     }
343     if (fflush(dest) == EOF) return ZE_TEMP;
344 
345     return ZE_OK;
346 }
347 
348 
349 #else /* !UTIL */
350 
351 /***********************************************************************
352  * If requested, encrypt the data in buf, and in any case call fwrite()
353  * with the arguments to zfwrite().  Return what fwrite() returns.
354  */
355 unsigned zfwrite(buf, item_size, nb, f)
356     zvoid *buf;                 /* data buffer */
357     extent item_size;           /* size of each item in bytes */
358     extent nb;                  /* number of items */
359     FILE *f;                    /* file to write to */
360 {
361     int t;                      /* temporary */
362 
363     if (key != (char *)NULL) {  /* key is the global password pointer */
364         ulg size;               /* buffer size */
365         char *p = (char*)buf;   /* steps through buffer */
366 
367         /* Encrypt data in buffer */
368         for (size = item_size*(ulg)nb; size != 0; p++, size--) {
369             *p = (char)zencode(*p, t);
370         }
371     }
372     /* Write the buffer out */
373     return fwrite(buf, item_size, nb, f);
374 }
375 
376 #endif /* ?UTIL */
377 #endif /* ZIP */
378 
379 
380 #if (defined(UNZIP) && !defined(FUNZIP))
381 
382 /***********************************************************************
383  * Get the password and set up keys for current zipfile member.
384  * Return PK_ class error.
385  */
386 int decrypt(__G__ passwrd)
387     __GDEF
388     ZCONST char *passwrd;
389 {
390     ush b;
391     int n, r;
392     uch h[RAND_HEAD_LEN];
393 
394     Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt)));
395 
396     /* get header once (turn off "encrypted" flag temporarily so we don't
397      * try to decrypt the same data twice) */
398     GLOBAL(pInfo->encrypted) = FALSE;
399     defer_leftover_input(__G);
400     for (n = 0; n < RAND_HEAD_LEN; n++) {
401         b = NEXTBYTE;
402         h[n] = (uch)b;
403         Trace((stdout, " (%02x)", h[n]));
404     }
405     undefer_input(__G);
406     GLOBAL(pInfo->encrypted) = TRUE;
407 
408     if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */
409         GLOBAL(newzip) = FALSE;
410         if (passwrd != (char *)NULL) { /* user gave password on command line */
411             if (!GLOBAL(key)) {
412                 if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) ==
413                     (char *)NULL)
414                     return PK_MEM2;
415                 strcpy(GLOBAL(key), passwrd);
416                 GLOBAL(nopwd) = TRUE;  /* inhibit password prompting! */
417             }
418         } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */
419             free(GLOBAL(key));
420             GLOBAL(key) = (char *)NULL;
421         }
422     }
423 
424     /* if have key already, test it; else allocate memory for it */
425     if (GLOBAL(key)) {
426         if (!testp(__G__ h))
427             return PK_COOL;   /* existing password OK (else prompt for new) */
428         else if (GLOBAL(nopwd))
429             return PK_WARN;   /* user indicated no more prompting */
430     } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL)
431         return PK_MEM2;
432 
433     /* try a few keys */
434     n = 0;
435     do {
436         r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1,
437                              GLOBAL(zipfn), GLOBAL(filename));
438         if (r == IZ_PW_ERROR) {         /* internal error in fetch of PW */
439             free (GLOBAL(key));
440             GLOBAL(key) = NULL;
441             return PK_MEM2;
442         }
443         if (r != IZ_PW_ENTERED) {       /* user replied "skip" or "skip all" */
444             *GLOBAL(key) = '\0';        /*   We try the NIL password, ... */
445             n = 0;                      /*   and cancel fetch for this item. */
446         }
447         if (!testp(__G__ h))
448             return PK_COOL;
449         if (r == IZ_PW_CANCELALL)       /* User replied "Skip all" */
450             GLOBAL(nopwd) = TRUE;       /*   inhibit any further PW prompt! */
451     } while (n > 0);
452 
453     return PK_WARN;
454 
455 } /* end function decrypt() */
456 
457 
458 
459 /***********************************************************************
460  * Test the password.  Return -1 if bad, 0 if OK.
461  */
462 local int testp(__G__ h)
463     __GDEF
464     ZCONST uch *h;
465 {
466     int r;
467     char *key_translated;
468 
469     /* On systems with "obscure" native character coding (e.g., EBCDIC),
470      * the first test translates the password to the "main standard"
471      * character coding. */
472 
473 #ifdef STR_TO_CP1
474     /* allocate buffer for translated password */
475     if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
476         return -1;
477     /* first try, test password translated "standard" charset */
478     r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key)));
479 #else /* !STR_TO_CP1 */
480     /* first try, test password as supplied on the extractor's host */
481     r = testkey(__G__ h, GLOBAL(key));
482 #endif /* ?STR_TO_CP1 */
483 
484 #ifdef STR_TO_CP2
485     if (r != 0) {
486 #ifndef STR_TO_CP1
487         /* now prepare for second (and maybe third) test with translated pwd */
488         if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
489             return -1;
490 #endif
491         /* second try, password translated to alternate ("standard") charset */
492         r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key)));
493 #ifdef STR_TO_CP3
494         if (r != 0)
495             /* third try, password translated to another "standard" charset */
496             r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key)));
497 #endif
498 #ifndef STR_TO_CP1
499         free(key_translated);
500 #endif
501     }
502 #endif /* STR_TO_CP2 */
503 
504 #ifdef STR_TO_CP1
505     free(key_translated);
506     if (r != 0) {
507         /* last resort, test password as supplied on the extractor's host */
508         r = testkey(__G__ h, GLOBAL(key));
509     }
510 #endif /* STR_TO_CP1 */
511 
512     return r;
513 
514 } /* end function testp() */
515 
516 
517 local int testkey(__G__ h, key)
518     __GDEF
519     ZCONST uch *h;      /* decrypted header */
520     ZCONST char *key;   /* decryption password to test */
521 {
522     ush b;
523 #ifdef ZIP10
524     ush c;
525 #endif
526     int n;
527     uch *p;
528     uch hh[RAND_HEAD_LEN]; /* decrypted header */
529 
530     /* set keys and save the encrypted header */
531     init_keys(__G__ key);
532     memcpy(hh, h, RAND_HEAD_LEN);
533 
534     /* check password */
535     for (n = 0; n < RAND_HEAD_LEN; n++) {
536         zdecode(hh[n]);
537         Trace((stdout, " %02x", hh[n]));
538     }
539 
540     Trace((stdout,
541       "\n  lrec.crc= %08lx  crec.crc= %08lx  pInfo->ExtLocHdr= %s\n",
542       GLOBAL(lrec.crc32), GLOBAL(pInfo->crc),
543       GLOBAL(pInfo->ExtLocHdr) ? "true":"false"));
544     Trace((stdout, "  incnt = %d  unzip offset into zipfile = %ld\n",
545       GLOBAL(incnt),
546       GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf))));
547 
548     /* same test as in zipbare(): */
549 
550 #ifdef ZIP10 /* check two bytes */
551     c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1];
552     Trace((stdout,
553       "  (c | (b<<8)) = %04x  (crc >> 16) = %04x  lrec.time = %04x\n",
554       (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16),
555       ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff))));
556     if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ?
557                            ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) :
558                            (ush)(GLOBAL(lrec.crc32) >> 16)))
559         return -1;  /* bad */
560 #else
561     b = hh[RAND_HEAD_LEN-1];
562     Trace((stdout, "  b = %02x  (crc >> 24) = %02x  (lrec.time >> 8) = %02x\n",
563       b, (ush)(GLOBAL(lrec.crc32) >> 24),
564       ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff));
565     if (b != (GLOBAL(pInfo->ExtLocHdr) ?
566         ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff :
567         (ush)(GLOBAL(lrec.crc32) >> 24)))
568         return -1;  /* bad */
569 #endif
570     /* password OK:  decrypt current buffer contents before leaving */
571     for (n = (long)GLOBAL(incnt) > GLOBAL(csize) ?
572              (int)GLOBAL(csize) : GLOBAL(incnt),
573          p = GLOBAL(inptr); n--; p++)
574         zdecode(*p);
575     return 0;       /* OK */
576 
577 } /* end function testkey() */
578 
579 #endif /* UNZIP && !FUNZIP */
580 
581 #else /* !CRYPT */
582 
583 /* something "externally visible" to shut up compiler/linker warnings */
584 int zcr_dummy;
585 
586 #endif /* ?CRYPT */
587