des.c revision 306195
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                    if (RAND_bytes(buf + l++, 1) <= 0)
460                        goto problems;
461                }
462                buf[l++] = rem;
463                ex = 1;
464                len += rem;
465            } else
466                l -= rem;
467
468            if (cflag) {
469                DES_cbc_cksum(buf, &cksum, (long)len, &ks, &cksum);
470                if (!eflag) {
471                    if (feof(DES_IN))
472                        break;
473                    else
474                        continue;
475                }
476            }
477
478            if (bflag && !flag3)
479                for (i = 0; i < l; i += 8)
480                    DES_ecb_encrypt((DES_cblock *)&(buf[i]),
481                                    (DES_cblock *)&(obuf[i]),
482                                    &ks, do_encrypt);
483            else if (flag3 && bflag)
484                for (i = 0; i < l; i += 8)
485                    DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
486                                     (DES_cblock *)&(obuf[i]),
487                                     &ks, &ks2, do_encrypt);
488            else if (flag3 && !bflag) {
489                char tmpbuf[8];
490
491                if (rem)
492                    memcpy(tmpbuf, &(buf[l]), (unsigned int)rem);
493                DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
494                                 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
495                if (rem)
496                    memcpy(&(buf[l]), tmpbuf, (unsigned int)rem);
497            } else {
498                DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
499                if (l >= 8)
500                    memcpy(iv, &(obuf[l - 8]), 8);
501            }
502            if (rem)
503                memcpy(buf, &(buf[l]), (unsigned int)rem);
504
505            i = 0;
506            while (i < l) {
507                if (uflag)
508                    j = uufwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
509                else
510                    j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
511                if (j == -1) {
512                    perror("Write error");
513                    Exit = 7;
514                    goto problems;
515                }
516                i += j;
517            }
518            if (feof(DES_IN)) {
519                if (uflag)
520                    uufwriteEnd(DES_OUT);
521                break;
522            }
523        }
524    } else {                    /* decrypt */
525
526        ex = 1;
527        for (;;) {
528            if (ex) {
529                if (uflag)
530                    l = uufread(buf, 1, BUFSIZE, DES_IN);
531                else
532                    l = fread(buf, 1, BUFSIZE, DES_IN);
533                ex = 0;
534                rem = l % 8;
535                l -= rem;
536            }
537            if (l < 0) {
538                perror("read error");
539                Exit = 6;
540                goto problems;
541            }
542
543            if (bflag && !flag3)
544                for (i = 0; i < l; i += 8)
545                    DES_ecb_encrypt((DES_cblock *)&(buf[i]),
546                                    (DES_cblock *)&(obuf[i]),
547                                    &ks, do_encrypt);
548            else if (flag3 && bflag)
549                for (i = 0; i < l; i += 8)
550                    DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
551                                     (DES_cblock *)&(obuf[i]),
552                                     &ks, &ks2, do_encrypt);
553            else if (flag3 && !bflag) {
554                DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
555                                 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
556            } else {
557                DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
558                if (l >= 8)
559                    memcpy(iv, &(buf[l - 8]), 8);
560            }
561
562            if (uflag)
563                ll = uufread(&(buf[rem]), 1, BUFSIZE, DES_IN);
564            else
565                ll = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
566            ll += rem;
567            rem = ll % 8;
568            ll -= rem;
569            if (feof(DES_IN) && (ll == 0)) {
570                last = obuf[l - 1];
571
572                if ((last > 7) || (last < 0)) {
573                    fputs("The file was not decrypted correctly.\n", stderr);
574                    Exit = 8;
575                    last = 0;
576                }
577                l = l - 8 + last;
578            }
579            i = 0;
580            if (cflag)
581                DES_cbc_cksum(obuf,
582                              (DES_cblock *)cksum, (long)l / 8 * 8, &ks,
583                              (DES_cblock *)cksum);
584            while (i != l) {
585                j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
586                if (j == -1) {
587                    perror("Write error");
588                    Exit = 7;
589                    goto problems;
590                }
591                i += j;
592            }
593            l = ll;
594            if ((l == 0) && feof(DES_IN))
595                break;
596        }
597    }
598    if (cflag) {
599        l = 0;
600        if (cksumname[0] != '\0') {
601            if ((O = fopen(cksumname, "w")) != NULL) {
602                CKSUM_OUT = O;
603                l = 1;
604            }
605        }
606        for (i = 0; i < 8; i++)
607            fprintf(CKSUM_OUT, "%02X", cksum[i]);
608        fprintf(CKSUM_OUT, "\n");
609        if (l)
610            fclose(CKSUM_OUT);
611    }
612 problems:
613    OPENSSL_cleanse(buf, sizeof(buf));
614    OPENSSL_cleanse(obuf, sizeof(obuf));
615    OPENSSL_cleanse(&ks, sizeof(ks));
616    OPENSSL_cleanse(&ks2, sizeof(ks2));
617    OPENSSL_cleanse(iv, sizeof(iv));
618    OPENSSL_cleanse(iv2, sizeof(iv2));
619    OPENSSL_cleanse(kk, sizeof(kk));
620    OPENSSL_cleanse(k2, sizeof(k2));
621    OPENSSL_cleanse(uubuf, sizeof(uubuf));
622    OPENSSL_cleanse(b, sizeof(b));
623    OPENSSL_cleanse(bb, sizeof(bb));
624    OPENSSL_cleanse(cksum, sizeof(cksum));
625    if (Exit)
626        EXIT(Exit);
627}
628
629/*    We ignore this parameter but it should be > ~50 I believe    */
630int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp)
631{
632    int i, j, left, rem, ret = num;
633    static int start = 1;
634
635    if (start) {
636        fprintf(fp, "begin 600 %s\n",
637                (uuname[0] == '\0') ? "text.d" : uuname);
638        start = 0;
639    }
640
641    if (uubufnum) {
642        if (uubufnum + num < 45) {
643            memcpy(&(uubuf[uubufnum]), data, (unsigned int)num);
644            uubufnum += num;
645            return (num);
646        } else {
647            i = 45 - uubufnum;
648            memcpy(&(uubuf[uubufnum]), data, (unsigned int)i);
649            j = uuencode((unsigned char *)uubuf, 45, b);
650            fwrite(b, 1, (unsigned int)j, fp);
651            uubufnum = 0;
652            data += i;
653            num -= i;
654        }
655    }
656
657    for (i = 0; i < (((int)num) - INUUBUFN); i += INUUBUFN) {
658        j = uuencode(&(data[i]), INUUBUFN, b);
659        fwrite(b, 1, (unsigned int)j, fp);
660    }
661    rem = (num - i) % 45;
662    left = (num - i - rem);
663    if (left) {
664        j = uuencode(&(data[i]), left, b);
665        fwrite(b, 1, (unsigned int)j, fp);
666        i += left;
667    }
668    if (i != num) {
669        memcpy(uubuf, &(data[i]), (unsigned int)rem);
670        uubufnum = rem;
671    }
672    return (ret);
673}
674
675void uufwriteEnd(FILE *fp)
676{
677    int j;
678    static const char *end = " \nend\n";
679
680    if (uubufnum != 0) {
681        uubuf[uubufnum] = '\0';
682        uubuf[uubufnum + 1] = '\0';
683        uubuf[uubufnum + 2] = '\0';
684        j = uuencode(uubuf, uubufnum, b);
685        fwrite(b, 1, (unsigned int)j, fp);
686    }
687    fwrite(end, 1, strlen(end), fp);
688}
689
690/*
691 * int size: should always be > ~ 60; I actually ignore this parameter :-)
692 */
693int uufread(unsigned char *out, int size, unsigned int num, FILE *fp)
694{
695    int i, j, tot;
696    static int done = 0;
697    static int valid = 0;
698    static int start = 1;
699
700    if (start) {
701        for (;;) {
702            b[0] = '\0';
703            fgets((char *)b, 300, fp);
704            if (b[0] == '\0') {
705                fprintf(stderr, "no 'begin' found in uuencoded input\n");
706                return (-1);
707            }
708            if (strncmp((char *)b, "begin ", 6) == 0)
709                break;
710        }
711        start = 0;
712    }
713    if (done)
714        return (0);
715    tot = 0;
716    if (valid) {
717        memcpy(out, bb, (unsigned int)valid);
718        tot = valid;
719        valid = 0;
720    }
721    for (;;) {
722        b[0] = '\0';
723        fgets((char *)b, 300, fp);
724        if (b[0] == '\0')
725            break;
726        i = strlen((char *)b);
727        if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) {
728            done = 1;
729            while (!feof(fp)) {
730                fgets((char *)b, 300, fp);
731            }
732            break;
733        }
734        i = uudecode(b, i, bb);
735        if (i < 0)
736            break;
737        if ((i + tot + 8) > num) {
738            /* num to copy to make it a multiple of 8 */
739            j = (num / 8 * 8) - tot - 8;
740            memcpy(&(out[tot]), bb, (unsigned int)j);
741            tot += j;
742            memcpy(bb, &(bb[j]), (unsigned int)i - j);
743            valid = i - j;
744            break;
745        }
746        memcpy(&(out[tot]), bb, (unsigned int)i);
747        tot += i;
748    }
749    return (tot);
750}
751
752#define ccc2l(c,l)      (l =((DES_LONG)(*((c)++)))<<16, \
753                         l|=((DES_LONG)(*((c)++)))<< 8, \
754                         l|=((DES_LONG)(*((c)++))))
755
756#define l2ccc(l,c)      (*((c)++)=(unsigned char)(((l)>>16)&0xff), \
757                    *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
758                    *((c)++)=(unsigned char)(((l)    )&0xff))
759
760int uuencode(unsigned char *in, int num, unsigned char *out)
761{
762    int j, i, n, tot = 0;
763    DES_LONG l;
764    register unsigned char *p;
765    p = out;
766
767    for (j = 0; j < num; j += 45) {
768        if (j + 45 > num)
769            i = (num - j);
770        else
771            i = 45;
772        *(p++) = i + ' ';
773        for (n = 0; n < i; n += 3) {
774            ccc2l(in, l);
775            *(p++) = ((l >> 18) & 0x3f) + ' ';
776            *(p++) = ((l >> 12) & 0x3f) + ' ';
777            *(p++) = ((l >> 6) & 0x3f) + ' ';
778            *(p++) = ((l) & 0x3f) + ' ';
779            tot += 4;
780        }
781        *(p++) = '\n';
782        tot += 2;
783    }
784    *p = '\0';
785    l = 0;
786    return (tot);
787}
788
789int uudecode(unsigned char *in, int num, unsigned char *out)
790{
791    int j, i, k;
792    unsigned int n = 0, space = 0;
793    DES_LONG l;
794    DES_LONG w, x, y, z;
795    unsigned int blank = (unsigned int)'\n' - ' ';
796
797    for (j = 0; j < num;) {
798        n = *(in++) - ' ';
799        if (n == blank) {
800            n = 0;
801            in--;
802        }
803        if (n > 60) {
804            fprintf(stderr, "uuencoded line length too long\n");
805            return (-1);
806        }
807        j++;
808
809        for (i = 0; i < n; j += 4, i += 3) {
810            /*
811             * the following is for cases where spaces are removed from
812             * lines.
813             */
814            if (space) {
815                w = x = y = z = 0;
816            } else {
817                w = *(in++) - ' ';
818                x = *(in++) - ' ';
819                y = *(in++) - ' ';
820                z = *(in++) - ' ';
821            }
822            if ((w > 63) || (x > 63) || (y > 63) || (z > 63)) {
823                k = 0;
824                if (w == blank)
825                    k = 1;
826                if (x == blank)
827                    k = 2;
828                if (y == blank)
829                    k = 3;
830                if (z == blank)
831                    k = 4;
832                space = 1;
833                switch (k) {
834                case 1:
835                    w = 0;
836                    in--;
837                case 2:
838                    x = 0;
839                    in--;
840                case 3:
841                    y = 0;
842                    in--;
843                case 4:
844                    z = 0;
845                    in--;
846                    break;
847                case 0:
848                    space = 0;
849                    fprintf(stderr, "bad uuencoded data values\n");
850                    w = x = y = z = 0;
851                    return (-1);
852                    break;
853                }
854            }
855            l = (w << 18) | (x << 12) | (y << 6) | (z);
856            l2ccc(l, out);
857        }
858        if (*(in++) != '\n') {
859            fprintf(stderr, "missing nl in uuencoded line\n");
860            w = x = y = z = 0;
861            return (-1);
862        }
863        j++;
864    }
865    *out = '\0';
866    w = x = y = z = 0;
867    return (n);
868}
869