Run util/openssl-format-source -v -c .
[openssl.git] / crypto / des / des.c
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
93 void usage(void);
94 void doencryption(void);
95 int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp);
96 void uufwriteEnd(FILE *fp);
97 int uufread(unsigned char *out, int size, unsigned int num, FILE *fp);
98 int uuencode(unsigned char *in, int num, unsigned char *out);
99 int uudecode(unsigned char *in, int num, unsigned char *out);
100 void 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 :-) */
113 char key[KEYSIZB + 1];
114 int do_encrypt, longk = 0;
115 FILE *DES_IN, *DES_OUT, *CKSUM_OUT;
116 char uuname[200];
117 unsigned char uubuf[50];
118 int uubufnum = 0;
119 #define INUUBUFN        (45*100)
120 #define OUTUUBUF        (65*100)
121 unsigned char b[OUTUUBUF];
122 unsigned char bb[300];
123 DES_cblock cksum = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
124
125 char cksumname[200] = "";
126
127 int vflag, cflag, eflag, dflag, kflag, bflag, fflag, sflag, uflag, flag3,
128     hflag, error;
129
130 int 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
310 void 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
347 void 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    */
628 int 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
673 void 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  */
691 int 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
758 int 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
787 int 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 }