des.c revision 296465
1/* crypto/des/des.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <openssl/opensslconf.h>
63#ifndef OPENSSL_SYS_MSDOS
64# ifndef OPENSSL_SYS_VMS
65#  include OPENSSL_UNISTD
66# else                          /* OPENSSL_SYS_VMS */
67#  ifdef __DECC
68#   include <unistd.h>
69#  else                         /* not __DECC */
70#   include <math.h>
71#  endif                        /* __DECC */
72# endif                         /* OPENSSL_SYS_VMS */
73#else                           /* OPENSSL_SYS_MSDOS */
74# include <io.h>
75#endif
76
77#include <time.h>
78#include "des_ver.h"
79
80#ifdef OPENSSL_SYS_VMS
81# include <types.h>
82# include <stat.h>
83#else
84# ifndef _IRIX
85#  include <sys/types.h>
86# endif
87# include <sys/stat.h>
88#endif
89#include <openssl/des.h>
90#include <openssl/rand.h>
91#include <openssl/ui_compat.h>
92
93void usage(void);
94void doencryption(void);
95int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp);
96void uufwriteEnd(FILE *fp);
97int uufread(unsigned char *out, int size, unsigned int num, FILE *fp);
98int uuencode(unsigned char *in, int num, unsigned char *out);
99int uudecode(unsigned char *in, int num, unsigned char *out);
100void DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length,
101                      DES_key_schedule sk1, DES_key_schedule sk2,
102                      DES_cblock *ivec1, DES_cblock *ivec2, int enc);
103#ifdef OPENSSL_SYS_VMS
104# define EXIT(a) exit(a&0x10000000L)
105#else
106# define EXIT(a) exit(a)
107#endif
108
109#define BUFSIZE (8*1024)
110#define VERIFY  1
111#define KEYSIZ  8
112#define KEYSIZB 1024            /* should hit tty line limit first :-) */
113char key[KEYSIZB + 1];
114int do_encrypt, longk = 0;
115FILE *DES_IN, *DES_OUT, *CKSUM_OUT;
116char uuname[200];
117unsigned char uubuf[50];
118int uubufnum = 0;
119#define INUUBUFN        (45*100)
120#define OUTUUBUF        (65*100)
121unsigned char b[OUTUUBUF];
122unsigned char bb[300];
123DES_cblock cksum = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
124
125char cksumname[200] = "";
126
127int vflag, cflag, eflag, dflag, kflag, bflag, fflag, sflag, uflag, flag3,
128    hflag, error;
129
130int main(int argc, char **argv)
131{
132    int i;
133    struct stat ins, outs;
134    char *p;
135    char *in = NULL, *out = NULL;
136
137    vflag = cflag = eflag = dflag = kflag = hflag = bflag = fflag = sflag =
138        uflag = flag3 = 0;
139    error = 0;
140    memset(key, 0, sizeof(key));
141
142    for (i = 1; i < argc; i++) {
143        p = argv[i];
144        if ((p[0] == '-') && (p[1] != '\0')) {
145            p++;
146            while (*p) {
147                switch (*(p++)) {
148                case '3':
149                    flag3 = 1;
150                    longk = 1;
151                    break;
152                case 'c':
153                    cflag = 1;
154                    strncpy(cksumname, p, 200);
155                    cksumname[sizeof(cksumname) - 1] = '\0';
156                    p += strlen(cksumname);
157                    break;
158                case 'C':
159                    cflag = 1;
160                    longk = 1;
161                    strncpy(cksumname, p, 200);
162                    cksumname[sizeof(cksumname) - 1] = '\0';
163                    p += strlen(cksumname);
164                    break;
165                case 'e':
166                    eflag = 1;
167                    break;
168                case 'v':
169                    vflag = 1;
170                    break;
171                case 'E':
172                    eflag = 1;
173                    longk = 1;
174                    break;
175                case 'd':
176                    dflag = 1;
177                    break;
178                case 'D':
179                    dflag = 1;
180                    longk = 1;
181                    break;
182                case 'b':
183                    bflag = 1;
184                    break;
185                case 'f':
186                    fflag = 1;
187                    break;
188                case 's':
189                    sflag = 1;
190                    break;
191                case 'u':
192                    uflag = 1;
193                    strncpy(uuname, p, 200);
194                    uuname[sizeof(uuname) - 1] = '\0';
195                    p += strlen(uuname);
196                    break;
197                case 'h':
198                    hflag = 1;
199                    break;
200                case 'k':
201                    kflag = 1;
202                    if ((i + 1) == argc) {
203                        fputs("must have a key with the -k option\n", stderr);
204                        error = 1;
205                    } else {
206                        int j;
207
208                        i++;
209                        strncpy(key, argv[i], KEYSIZB);
210                        for (j = strlen(argv[i]) - 1; j >= 0; j--)
211                            argv[i][j] = '\0';
212                    }
213                    break;
214                default:
215                    fprintf(stderr, "'%c' unknown flag\n", p[-1]);
216                    error = 1;
217                    break;
218                }
219            }
220        } else {
221            if (in == NULL)
222                in = argv[i];
223            else if (out == NULL)
224                out = argv[i];
225            else
226                error = 1;
227        }
228    }
229    if (error)
230        usage();
231    /*-
232     * We either
233     * do checksum or
234     * do encrypt or
235     * do decrypt or
236     * do decrypt then ckecksum or
237     * do checksum then encrypt
238     */
239    if (((eflag + dflag) == 1) || cflag) {
240        if (eflag)
241            do_encrypt = DES_ENCRYPT;
242        if (dflag)
243            do_encrypt = DES_DECRYPT;
244    } else {
245        if (vflag) {
246#ifndef _Windows
247            fprintf(stderr, "des(1) built with %s\n", libdes_version);
248#endif
249            EXIT(1);
250        } else
251            usage();
252    }
253
254#ifndef _Windows
255    if (vflag)
256        fprintf(stderr, "des(1) built with %s\n", libdes_version);
257#endif
258    if ((in != NULL) && (out != NULL) &&
259#ifndef OPENSSL_SYS_MSDOS
260        (stat(in, &ins) != -1) &&
261        (stat(out, &outs) != -1) &&
262        (ins.st_dev == outs.st_dev) && (ins.st_ino == outs.st_ino))
263#else                           /* OPENSSL_SYS_MSDOS */
264        (strcmp(in, out) == 0))
265#endif
266    {
267        fputs("input and output file are the same\n", stderr);
268        EXIT(3);
269    }
270
271    if (!kflag)
272        if (des_read_pw_string
273            (key, KEYSIZB + 1, "Enter key:", eflag ? VERIFY : 0)) {
274            fputs("password error\n", stderr);
275            EXIT(2);
276        }
277
278    if (in == NULL)
279        DES_IN = stdin;
280    else if ((DES_IN = fopen(in, "r")) == NULL) {
281        perror("opening input file");
282        EXIT(4);
283    }
284
285    CKSUM_OUT = stdout;
286    if (out == NULL) {
287        DES_OUT = stdout;
288        CKSUM_OUT = stderr;
289    } else if ((DES_OUT = fopen(out, "w")) == NULL) {
290        perror("opening output file");
291        EXIT(5);
292    }
293#ifdef OPENSSL_SYS_MSDOS
294    /* This should set the file to binary mode. */
295    {
296# include <fcntl.h>
297        if (!(uflag && dflag))
298            setmode(fileno(DES_IN), O_BINARY);
299        if (!(uflag && eflag))
300            setmode(fileno(DES_OUT), O_BINARY);
301    }
302#endif
303
304    doencryption();
305    fclose(DES_IN);
306    fclose(DES_OUT);
307    EXIT(0);
308}
309
310void usage(void)
311{
312    char **u;
313    static const char *Usage[] = {
314        "des <options> [input-file [output-file]]",
315        "options:",
316        "-v         : des(1) version number",
317        "-e         : encrypt using SunOS compatible user key to DES key conversion.",
318        "-E         : encrypt ",
319        "-d         : decrypt using SunOS compatible user key to DES key conversion.",
320        "-D         : decrypt ",
321        "-c[ckname] : generate a cbc_cksum using SunOS compatible user key to",
322        "             DES key conversion and output to ckname (stdout default,",
323        "             stderr if data being output on stdout).  The checksum is",
324        "             generated before encryption and after decryption if used",
325        "             in conjunction with -[eEdD].",
326        "-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].",
327        "-k key     : use key 'key'",
328        "-h         : the key that is entered will be a hexadecimal number",
329        "             that is used directly as the des key",
330        "-u[uuname] : input file is uudecoded if -[dD] or output uuencoded data if -[eE]",
331        "             (uuname is the filename to put in the uuencode header).",
332        "-b         : encrypt using DES in ecb encryption mode, the default is cbc mode.",
333        "-3         : encrypt using triple DES encryption.  This uses 2 keys",
334        "             generated from the input key.  If the input key is less",
335        "             than 8 characters long, this is equivalent to normal",
336        "             encryption.  Default is triple cbc, -b makes it triple ecb.",
337        NULL
338    };
339    for (u = (char **)Usage; *u; u++) {
340        fputs(*u, stderr);
341        fputc('\n', stderr);
342    }
343
344    EXIT(1);
345}
346
347void doencryption(void)
348{
349#ifdef _LIBC
350    extern unsigned long time();
351#endif
352
353    register int i;
354    DES_key_schedule ks, ks2;
355    DES_cblock iv, iv2;
356    char *p;
357    int num = 0, j, k, l, rem, ll, len, last, ex = 0;
358    DES_cblock kk, k2;
359    FILE *O;
360    int Exit = 0;
361#ifndef OPENSSL_SYS_MSDOS
362    static unsigned char buf[BUFSIZE + 8], obuf[BUFSIZE + 8];
363#else
364    static unsigned char *buf = NULL, *obuf = NULL;
365
366    if (buf == NULL) {
367        if (((buf = OPENSSL_malloc(BUFSIZE + 8)) == NULL) ||
368            ((obuf = OPENSSL_malloc(BUFSIZE + 8)) == NULL)) {
369            fputs("Not enough memory\n", stderr);
370            Exit = 10;
371            goto problems;
372        }
373    }
374#endif
375
376    if (hflag) {
377        j = (flag3 ? 16 : 8);
378        p = key;
379        for (i = 0; i < j; i++) {
380            k = 0;
381            if ((*p <= '9') && (*p >= '0'))
382                k = (*p - '0') << 4;
383            else if ((*p <= 'f') && (*p >= 'a'))
384                k = (*p - 'a' + 10) << 4;
385            else if ((*p <= 'F') && (*p >= 'A'))
386                k = (*p - 'A' + 10) << 4;
387            else {
388                fputs("Bad hex key\n", stderr);
389                Exit = 9;
390                goto problems;
391            }
392            p++;
393            if ((*p <= '9') && (*p >= '0'))
394                k |= (*p - '0');
395            else if ((*p <= 'f') && (*p >= 'a'))
396                k |= (*p - 'a' + 10);
397            else if ((*p <= 'F') && (*p >= 'A'))
398                k |= (*p - 'A' + 10);
399            else {
400                fputs("Bad hex key\n", stderr);
401                Exit = 9;
402                goto problems;
403            }
404            p++;
405            if (i < 8)
406                kk[i] = k;
407            else
408                k2[i - 8] = k;
409        }
410        DES_set_key_unchecked(&k2, &ks2);
411        OPENSSL_cleanse(k2, sizeof(k2));
412    } else if (longk || flag3) {
413        if (flag3) {
414            DES_string_to_2keys(key, &kk, &k2);
415            DES_set_key_unchecked(&k2, &ks2);
416            OPENSSL_cleanse(k2, sizeof(k2));
417        } else
418            DES_string_to_key(key, &kk);
419    } else
420        for (i = 0; i < KEYSIZ; i++) {
421            l = 0;
422            k = key[i];
423            for (j = 0; j < 8; j++) {
424                if (k & 1)
425                    l++;
426                k >>= 1;
427            }
428            if (l & 1)
429                kk[i] = key[i] & 0x7f;
430            else
431                kk[i] = key[i] | 0x80;
432        }
433
434    DES_set_key_unchecked(&kk, &ks);
435    OPENSSL_cleanse(key, sizeof(key));
436    OPENSSL_cleanse(kk, sizeof(kk));
437    /* woops - A bug that does not showup under unix :-( */
438    memset(iv, 0, sizeof(iv));
439    memset(iv2, 0, sizeof(iv2));
440
441    l = 1;
442    rem = 0;
443    /* first read */
444    if (eflag || (!dflag && cflag)) {
445        for (;;) {
446            num = l = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
447            l += rem;
448            num += rem;
449            if (l < 0) {
450                perror("read error");
451                Exit = 6;
452                goto problems;
453            }
454
455            rem = l % 8;
456            len = l - rem;
457            if (feof(DES_IN)) {
458                for (i = 7 - rem; i > 0; i--)
459                    RAND_pseudo_bytes(buf + l++, 1);
460                buf[l++] = rem;
461                ex = 1;
462                len += rem;
463            } else
464                l -= rem;
465
466            if (cflag) {
467                DES_cbc_cksum(buf, &cksum, (long)len, &ks, &cksum);
468                if (!eflag) {
469                    if (feof(DES_IN))
470                        break;
471                    else
472                        continue;
473                }
474            }
475
476            if (bflag && !flag3)
477                for (i = 0; i < l; i += 8)
478                    DES_ecb_encrypt((DES_cblock *)&(buf[i]),
479                                    (DES_cblock *)&(obuf[i]),
480                                    &ks, do_encrypt);
481            else if (flag3 && bflag)
482                for (i = 0; i < l; i += 8)
483                    DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
484                                     (DES_cblock *)&(obuf[i]),
485                                     &ks, &ks2, do_encrypt);
486            else if (flag3 && !bflag) {
487                char tmpbuf[8];
488
489                if (rem)
490                    memcpy(tmpbuf, &(buf[l]), (unsigned int)rem);
491                DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
492                                 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
493                if (rem)
494                    memcpy(&(buf[l]), tmpbuf, (unsigned int)rem);
495            } else {
496                DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
497                if (l >= 8)
498                    memcpy(iv, &(obuf[l - 8]), 8);
499            }
500            if (rem)
501                memcpy(buf, &(buf[l]), (unsigned int)rem);
502
503            i = 0;
504            while (i < l) {
505                if (uflag)
506                    j = uufwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
507                else
508                    j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
509                if (j == -1) {
510                    perror("Write error");
511                    Exit = 7;
512                    goto problems;
513                }
514                i += j;
515            }
516            if (feof(DES_IN)) {
517                if (uflag)
518                    uufwriteEnd(DES_OUT);
519                break;
520            }
521        }
522    } else {                    /* decrypt */
523
524        ex = 1;
525        for (;;) {
526            if (ex) {
527                if (uflag)
528                    l = uufread(buf, 1, BUFSIZE, DES_IN);
529                else
530                    l = fread(buf, 1, BUFSIZE, DES_IN);
531                ex = 0;
532                rem = l % 8;
533                l -= rem;
534            }
535            if (l < 0) {
536                perror("read error");
537                Exit = 6;
538                goto problems;
539            }
540
541            if (bflag && !flag3)
542                for (i = 0; i < l; i += 8)
543                    DES_ecb_encrypt((DES_cblock *)&(buf[i]),
544                                    (DES_cblock *)&(obuf[i]),
545                                    &ks, do_encrypt);
546            else if (flag3 && bflag)
547                for (i = 0; i < l; i += 8)
548                    DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
549                                     (DES_cblock *)&(obuf[i]),
550                                     &ks, &ks2, do_encrypt);
551            else if (flag3 && !bflag) {
552                DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
553                                 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
554            } else {
555                DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
556                if (l >= 8)
557                    memcpy(iv, &(buf[l - 8]), 8);
558            }
559
560            if (uflag)
561                ll = uufread(&(buf[rem]), 1, BUFSIZE, DES_IN);
562            else
563                ll = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
564            ll += rem;
565            rem = ll % 8;
566            ll -= rem;
567            if (feof(DES_IN) && (ll == 0)) {
568                last = obuf[l - 1];
569
570                if ((last > 7) || (last < 0)) {
571                    fputs("The file was not decrypted correctly.\n", stderr);
572                    Exit = 8;
573                    last = 0;
574                }
575                l = l - 8 + last;
576            }
577            i = 0;
578            if (cflag)
579                DES_cbc_cksum(obuf,
580                              (DES_cblock *)cksum, (long)l / 8 * 8, &ks,
581                              (DES_cblock *)cksum);
582            while (i != l) {
583                j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
584                if (j == -1) {
585                    perror("Write error");
586                    Exit = 7;
587                    goto problems;
588                }
589                i += j;
590            }
591            l = ll;
592            if ((l == 0) && feof(DES_IN))
593                break;
594        }
595    }
596    if (cflag) {
597        l = 0;
598        if (cksumname[0] != '\0') {
599            if ((O = fopen(cksumname, "w")) != NULL) {
600                CKSUM_OUT = O;
601                l = 1;
602            }
603        }
604        for (i = 0; i < 8; i++)
605            fprintf(CKSUM_OUT, "%02X", cksum[i]);
606        fprintf(CKSUM_OUT, "\n");
607        if (l)
608            fclose(CKSUM_OUT);
609    }
610 problems:
611    OPENSSL_cleanse(buf, sizeof(buf));
612    OPENSSL_cleanse(obuf, sizeof(obuf));
613    OPENSSL_cleanse(&ks, sizeof(ks));
614    OPENSSL_cleanse(&ks2, sizeof(ks2));
615    OPENSSL_cleanse(iv, sizeof(iv));
616    OPENSSL_cleanse(iv2, sizeof(iv2));
617    OPENSSL_cleanse(kk, sizeof(kk));
618    OPENSSL_cleanse(k2, sizeof(k2));
619    OPENSSL_cleanse(uubuf, sizeof(uubuf));
620    OPENSSL_cleanse(b, sizeof(b));
621    OPENSSL_cleanse(bb, sizeof(bb));
622    OPENSSL_cleanse(cksum, sizeof(cksum));
623    if (Exit)
624        EXIT(Exit);
625}
626
627/*    We ignore this parameter but it should be > ~50 I believe    */
628int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp)
629{
630    int i, j, left, rem, ret = num;
631    static int start = 1;
632
633    if (start) {
634        fprintf(fp, "begin 600 %s\n",
635                (uuname[0] == '\0') ? "text.d" : uuname);
636        start = 0;
637    }
638
639    if (uubufnum) {
640        if (uubufnum + num < 45) {
641            memcpy(&(uubuf[uubufnum]), data, (unsigned int)num);
642            uubufnum += num;
643            return (num);
644        } else {
645            i = 45 - uubufnum;
646            memcpy(&(uubuf[uubufnum]), data, (unsigned int)i);
647            j = uuencode((unsigned char *)uubuf, 45, b);
648            fwrite(b, 1, (unsigned int)j, fp);
649            uubufnum = 0;
650            data += i;
651            num -= i;
652        }
653    }
654
655    for (i = 0; i < (((int)num) - INUUBUFN); i += INUUBUFN) {
656        j = uuencode(&(data[i]), INUUBUFN, b);
657        fwrite(b, 1, (unsigned int)j, fp);
658    }
659    rem = (num - i) % 45;
660    left = (num - i - rem);
661    if (left) {
662        j = uuencode(&(data[i]), left, b);
663        fwrite(b, 1, (unsigned int)j, fp);
664        i += left;
665    }
666    if (i != num) {
667        memcpy(uubuf, &(data[i]), (unsigned int)rem);
668        uubufnum = rem;
669    }
670    return (ret);
671}
672
673void uufwriteEnd(FILE *fp)
674{
675    int j;
676    static const char *end = " \nend\n";
677
678    if (uubufnum != 0) {
679        uubuf[uubufnum] = '\0';
680        uubuf[uubufnum + 1] = '\0';
681        uubuf[uubufnum + 2] = '\0';
682        j = uuencode(uubuf, uubufnum, b);
683        fwrite(b, 1, (unsigned int)j, fp);
684    }
685    fwrite(end, 1, strlen(end), fp);
686}
687
688/*
689 * int size: should always be > ~ 60; I actually ignore this parameter :-)
690 */
691int uufread(unsigned char *out, int size, unsigned int num, FILE *fp)
692{
693    int i, j, tot;
694    static int done = 0;
695    static int valid = 0;
696    static int start = 1;
697
698    if (start) {
699        for (;;) {
700            b[0] = '\0';
701            fgets((char *)b, 300, fp);
702            if (b[0] == '\0') {
703                fprintf(stderr, "no 'begin' found in uuencoded input\n");
704                return (-1);
705            }
706            if (strncmp((char *)b, "begin ", 6) == 0)
707                break;
708        }
709        start = 0;
710    }
711    if (done)
712        return (0);
713    tot = 0;
714    if (valid) {
715        memcpy(out, bb, (unsigned int)valid);
716        tot = valid;
717        valid = 0;
718    }
719    for (;;) {
720        b[0] = '\0';
721        fgets((char *)b, 300, fp);
722        if (b[0] == '\0')
723            break;
724        i = strlen((char *)b);
725        if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) {
726            done = 1;
727            while (!feof(fp)) {
728                fgets((char *)b, 300, fp);
729            }
730            break;
731        }
732        i = uudecode(b, i, bb);
733        if (i < 0)
734            break;
735        if ((i + tot + 8) > num) {
736            /* num to copy to make it a multiple of 8 */
737            j = (num / 8 * 8) - tot - 8;
738            memcpy(&(out[tot]), bb, (unsigned int)j);
739            tot += j;
740            memcpy(bb, &(bb[j]), (unsigned int)i - j);
741            valid = i - j;
742            break;
743        }
744        memcpy(&(out[tot]), bb, (unsigned int)i);
745        tot += i;
746    }
747    return (tot);
748}
749
750#define ccc2l(c,l)      (l =((DES_LONG)(*((c)++)))<<16, \
751                         l|=((DES_LONG)(*((c)++)))<< 8, \
752                         l|=((DES_LONG)(*((c)++))))
753
754#define l2ccc(l,c)      (*((c)++)=(unsigned char)(((l)>>16)&0xff), \
755                    *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
756                    *((c)++)=(unsigned char)(((l)    )&0xff))
757
758int uuencode(unsigned char *in, int num, unsigned char *out)
759{
760    int j, i, n, tot = 0;
761    DES_LONG l;
762    register unsigned char *p;
763    p = out;
764
765    for (j = 0; j < num; j += 45) {
766        if (j + 45 > num)
767            i = (num - j);
768        else
769            i = 45;
770        *(p++) = i + ' ';
771        for (n = 0; n < i; n += 3) {
772            ccc2l(in, l);
773            *(p++) = ((l >> 18) & 0x3f) + ' ';
774            *(p++) = ((l >> 12) & 0x3f) + ' ';
775            *(p++) = ((l >> 6) & 0x3f) + ' ';
776            *(p++) = ((l) & 0x3f) + ' ';
777            tot += 4;
778        }
779        *(p++) = '\n';
780        tot += 2;
781    }
782    *p = '\0';
783    l = 0;
784    return (tot);
785}
786
787int uudecode(unsigned char *in, int num, unsigned char *out)
788{
789    int j, i, k;
790    unsigned int n = 0, space = 0;
791    DES_LONG l;
792    DES_LONG w, x, y, z;
793    unsigned int blank = (unsigned int)'\n' - ' ';
794
795    for (j = 0; j < num;) {
796        n = *(in++) - ' ';
797        if (n == blank) {
798            n = 0;
799            in--;
800        }
801        if (n > 60) {
802            fprintf(stderr, "uuencoded line length too long\n");
803            return (-1);
804        }
805        j++;
806
807        for (i = 0; i < n; j += 4, i += 3) {
808            /*
809             * the following is for cases where spaces are removed from
810             * lines.
811             */
812            if (space) {
813                w = x = y = z = 0;
814            } else {
815                w = *(in++) - ' ';
816                x = *(in++) - ' ';
817                y = *(in++) - ' ';
818                z = *(in++) - ' ';
819            }
820            if ((w > 63) || (x > 63) || (y > 63) || (z > 63)) {
821                k = 0;
822                if (w == blank)
823                    k = 1;
824                if (x == blank)
825                    k = 2;
826                if (y == blank)
827                    k = 3;
828                if (z == blank)
829                    k = 4;
830                space = 1;
831                switch (k) {
832                case 1:
833                    w = 0;
834                    in--;
835                case 2:
836                    x = 0;
837                    in--;
838                case 3:
839                    y = 0;
840                    in--;
841                case 4:
842                    z = 0;
843                    in--;
844                    break;
845                case 0:
846                    space = 0;
847                    fprintf(stderr, "bad uuencoded data values\n");
848                    w = x = y = z = 0;
849                    return (-1);
850                    break;
851                }
852            }
853            l = (w << 18) | (x << 12) | (y << 6) | (z);
854            l2ccc(l, out);
855        }
856        if (*(in++) != '\n') {
857            fprintf(stderr, "missing nl in uuencoded line\n");
858            w = x = y = z = 0;
859            return (-1);
860        }
861        j++;
862    }
863    *out = '\0';
864    w = x = y = z = 0;
865    return (n);
866}
867