586aed72378cc1ecc8d762b9fbe504c028ae8b97
[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                     if (RAND_pseudo_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    */
630 int 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
675 void 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  */
693 int 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
760 int 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
789 int 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 }