Further comment changes for reformat
[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 char cksumname[200]="";
125
126 int vflag,cflag,eflag,dflag,kflag,bflag,fflag,sflag,uflag,flag3,hflag,error;
127
128 int main(int argc, char **argv)
129         {
130         int i;
131         struct stat ins,outs;
132         char *p;
133         char *in=NULL,*out=NULL;
134
135         vflag=cflag=eflag=dflag=kflag=hflag=bflag=fflag=sflag=uflag=flag3=0;
136         error=0;
137         memset(key,0,sizeof(key));
138
139         for (i=1; i<argc; i++)
140                 {
141                 p=argv[i];
142                 if ((p[0] == '-') && (p[1] != '\0'))
143                         {
144                         p++;
145                         while (*p)
146                                 {
147                                 switch (*(p++))
148                                         {
149                                 case '3':
150                                         flag3=1;
151                                         longk=1;
152                                         break;
153                                 case 'c':
154                                         cflag=1;
155                                         strncpy(cksumname,p,200);
156                                         cksumname[sizeof(cksumname)-1]='\0';
157                                         p+=strlen(cksumname);
158                                         break;
159                                 case 'C':
160                                         cflag=1;
161                                         longk=1;
162                                         strncpy(cksumname,p,200);
163                                         cksumname[sizeof(cksumname)-1]='\0';
164                                         p+=strlen(cksumname);
165                                         break;
166                                 case 'e':
167                                         eflag=1;
168                                         break;
169                                 case 'v':
170                                         vflag=1;
171                                         break;
172                                 case 'E':
173                                         eflag=1;
174                                         longk=1;
175                                         break;
176                                 case 'd':
177                                         dflag=1;
178                                         break;
179                                 case 'D':
180                                         dflag=1;
181                                         longk=1;
182                                         break;
183                                 case 'b':
184                                         bflag=1;
185                                         break;
186                                 case 'f':
187                                         fflag=1;
188                                         break;
189                                 case 's':
190                                         sflag=1;
191                                         break;
192                                 case 'u':
193                                         uflag=1;
194                                         strncpy(uuname,p,200);
195                                         uuname[sizeof(uuname)-1]='\0';
196                                         p+=strlen(uuname);
197                                         break;
198                                 case 'h':
199                                         hflag=1;
200                                         break;
201                                 case 'k':
202                                         kflag=1;
203                                         if ((i+1) == argc)
204                                                 {
205                                                 fputs("must have a key with the -k option\n",stderr);
206                                                 error=1;
207                                                 }
208                                         else
209                                                 {
210                                                 int j;
211
212                                                 i++;
213                                                 strncpy(key,argv[i],KEYSIZB);
214                                                 for (j=strlen(argv[i])-1; j>=0; j--)
215                                                         argv[i][j]='\0';
216                                                 }
217                                         break;
218                                 default:
219                                         fprintf(stderr,"'%c' unknown flag\n",p[-1]);
220                                         error=1;
221                                         break;
222                                         }
223                                 }
224                         }
225                 else
226                         {
227                         if (in == NULL)
228                                 in=argv[i];
229                         else if (out == NULL)
230                                 out=argv[i];
231                         else
232                                 error=1;
233                         }
234                 }
235         if (error) usage();
236         /*-
237          * We either
238          * do checksum or
239          * do encrypt or
240          * do decrypt or
241          * do decrypt then ckecksum or
242          * do checksum then encrypt
243          */
244         if (((eflag+dflag) == 1) || cflag)
245                 {
246                 if (eflag) do_encrypt=DES_ENCRYPT;
247                 if (dflag) do_encrypt=DES_DECRYPT;
248                 }
249         else
250                 {
251                 if (vflag) 
252                         {
253 #ifndef _Windows                        
254                         fprintf(stderr,"des(1) built with %s\n",libdes_version);
255 #endif                  
256                         EXIT(1);
257                         }
258                 else usage();
259                 }
260
261 #ifndef _Windows                        
262         if (vflag) fprintf(stderr,"des(1) built with %s\n",libdes_version);
263 #endif                  
264         if (    (in != NULL) &&
265                 (out != NULL) &&
266 #ifndef OPENSSL_SYS_MSDOS
267                 (stat(in,&ins) != -1) &&
268                 (stat(out,&outs) != -1) &&
269                 (ins.st_dev == outs.st_dev) &&
270                 (ins.st_ino == outs.st_ino))
271 #else /* OPENSSL_SYS_MSDOS */
272                 (strcmp(in,out) == 0))
273 #endif
274                         {
275                         fputs("input and output file are the same\n",stderr);
276                         EXIT(3);
277                         }
278
279         if (!kflag)
280                 if (des_read_pw_string(key,KEYSIZB+1,"Enter key:",eflag?VERIFY:0))
281                         {
282                         fputs("password error\n",stderr);
283                         EXIT(2);
284                         }
285
286         if (in == NULL)
287                 DES_IN=stdin;
288         else if ((DES_IN=fopen(in,"r")) == NULL)
289                 {
290                 perror("opening input file");
291                 EXIT(4);
292                 }
293
294         CKSUM_OUT=stdout;
295         if (out == NULL)
296                 {
297                 DES_OUT=stdout;
298                 CKSUM_OUT=stderr;
299                 }
300         else if ((DES_OUT=fopen(out,"w")) == NULL)
301                 {
302                 perror("opening output file");
303                 EXIT(5);
304                 }
305
306 #ifdef OPENSSL_SYS_MSDOS
307         /* This should set the file to binary mode. */
308         {
309 #include <fcntl.h>
310         if (!(uflag && dflag))
311                 setmode(fileno(DES_IN),O_BINARY);
312         if (!(uflag && eflag))
313                 setmode(fileno(DES_OUT),O_BINARY);
314         }
315 #endif
316
317         doencryption();
318         fclose(DES_IN);
319         fclose(DES_OUT);
320         EXIT(0);
321         }
322
323 void usage(void)
324         {
325         char **u;
326         static const char *Usage[]={
327 "des <options> [input-file [output-file]]",
328 "options:",
329 "-v         : des(1) version number",
330 "-e         : encrypt using SunOS compatible user key to DES key conversion.",
331 "-E         : encrypt ",
332 "-d         : decrypt using SunOS compatible user key to DES key conversion.",
333 "-D         : decrypt ",
334 "-c[ckname] : generate a cbc_cksum using SunOS compatible user key to",
335 "             DES key conversion and output to ckname (stdout default,",
336 "             stderr if data being output on stdout).  The checksum is",
337 "             generated before encryption and after decryption if used",
338 "             in conjunction with -[eEdD].",
339 "-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].",
340 "-k key     : use key 'key'",
341 "-h         : the key that is entered will be a hexadecimal number",
342 "             that is used directly as the des key",
343 "-u[uuname] : input file is uudecoded if -[dD] or output uuencoded data if -[eE]",
344 "             (uuname is the filename to put in the uuencode header).",
345 "-b         : encrypt using DES in ecb encryption mode, the default is cbc mode.",
346 "-3         : encrypt using triple DES encryption.  This uses 2 keys",
347 "             generated from the input key.  If the input key is less",
348 "             than 8 characters long, this is equivalent to normal",
349 "             encryption.  Default is triple cbc, -b makes it triple ecb.",
350 NULL
351 };
352         for (u=(char **)Usage; *u; u++)
353                 {
354                 fputs(*u,stderr);
355                 fputc('\n',stderr);
356                 }
357
358         EXIT(1);
359         }
360
361 void doencryption(void)
362         {
363 #ifdef _LIBC
364         extern unsigned long time();
365 #endif
366
367         register int i;
368         DES_key_schedule ks,ks2;
369         DES_cblock iv,iv2;
370         char *p;
371         int num=0,j,k,l,rem,ll,len,last,ex=0;
372         DES_cblock kk,k2;
373         FILE *O;
374         int Exit=0;
375 #ifndef OPENSSL_SYS_MSDOS
376         static unsigned char buf[BUFSIZE+8],obuf[BUFSIZE+8];
377 #else
378         static unsigned char *buf=NULL,*obuf=NULL;
379
380         if (buf == NULL)
381                 {
382                 if (    (( buf=OPENSSL_malloc(BUFSIZE+8)) == NULL) ||
383                         ((obuf=OPENSSL_malloc(BUFSIZE+8)) == NULL))
384                         {
385                         fputs("Not enough memory\n",stderr);
386                         Exit=10;
387                         goto problems;
388                         }
389                 }
390 #endif
391
392         if (hflag)
393                 {
394                 j=(flag3?16:8);
395                 p=key;
396                 for (i=0; i<j; i++)
397                         {
398                         k=0;
399                         if ((*p <= '9') && (*p >= '0'))
400                                 k=(*p-'0')<<4;
401                         else if ((*p <= 'f') && (*p >= 'a'))
402                                 k=(*p-'a'+10)<<4;
403                         else if ((*p <= 'F') && (*p >= 'A'))
404                                 k=(*p-'A'+10)<<4;
405                         else
406                                 {
407                                 fputs("Bad hex key\n",stderr);
408                                 Exit=9;
409                                 goto problems;
410                                 }
411                         p++;
412                         if ((*p <= '9') && (*p >= '0'))
413                                 k|=(*p-'0');
414                         else if ((*p <= 'f') && (*p >= 'a'))
415                                 k|=(*p-'a'+10);
416                         else if ((*p <= 'F') && (*p >= 'A'))
417                                 k|=(*p-'A'+10);
418                         else
419                                 {
420                                 fputs("Bad hex key\n",stderr);
421                                 Exit=9;
422                                 goto problems;
423                                 }
424                         p++;
425                         if (i < 8)
426                                 kk[i]=k;
427                         else
428                                 k2[i-8]=k;
429                         }
430                 DES_set_key_unchecked(&k2,&ks2);
431                 OPENSSL_cleanse(k2,sizeof(k2));
432                 }
433         else if (longk || flag3)
434                 {
435                 if (flag3)
436                         {
437                         DES_string_to_2keys(key,&kk,&k2);
438                         DES_set_key_unchecked(&k2,&ks2);
439                         OPENSSL_cleanse(k2,sizeof(k2));
440                         }
441                 else
442                         DES_string_to_key(key,&kk);
443                 }
444         else
445                 for (i=0; i<KEYSIZ; i++)
446                         {
447                         l=0;
448                         k=key[i];
449                         for (j=0; j<8; j++)
450                                 {
451                                 if (k&1) l++;
452                                 k>>=1;
453                                 }
454                         if (l & 1)
455                                 kk[i]=key[i]&0x7f;
456                         else
457                                 kk[i]=key[i]|0x80;
458                         }
459
460         DES_set_key_unchecked(&kk,&ks);
461         OPENSSL_cleanse(key,sizeof(key));
462         OPENSSL_cleanse(kk,sizeof(kk));
463         /* woops - A bug that does not showup under unix :-( */
464         memset(iv,0,sizeof(iv));
465         memset(iv2,0,sizeof(iv2));
466
467         l=1;
468         rem=0;
469         /* first read */
470         if (eflag || (!dflag && cflag))
471                 {
472                 for (;;)
473                         {
474                         num=l=fread(&(buf[rem]),1,BUFSIZE,DES_IN);
475                         l+=rem;
476                         num+=rem;
477                         if (l < 0)
478                                 {
479                                 perror("read error");
480                                 Exit=6;
481                                 goto problems;
482                                 }
483
484                         rem=l%8;
485                         len=l-rem;
486                         if (feof(DES_IN))
487                                 {
488                                 for (i=7-rem; i>0; i--)
489                                         RAND_pseudo_bytes(buf + l++, 1);
490                                 buf[l++]=rem;
491                                 ex=1;
492                                 len+=rem;
493                                 }
494                         else
495                                 l-=rem;
496
497                         if (cflag)
498                                 {
499                                 DES_cbc_cksum(buf,&cksum,
500                                         (long)len,&ks,&cksum);
501                                 if (!eflag)
502                                         {
503                                         if (feof(DES_IN)) break;
504                                         else continue;
505                                         }
506                                 }
507
508                         if (bflag && !flag3)
509                                 for (i=0; i<l; i+=8)
510                                         DES_ecb_encrypt(
511                                                 (DES_cblock *)&(buf[i]),
512                                                 (DES_cblock *)&(obuf[i]),
513                                                 &ks,do_encrypt);
514                         else if (flag3 && bflag)
515                                 for (i=0; i<l; i+=8)
516                                         DES_ecb2_encrypt(
517                                                 (DES_cblock *)&(buf[i]),
518                                                 (DES_cblock *)&(obuf[i]),
519                                                 &ks,&ks2,do_encrypt);
520                         else if (flag3 && !bflag)
521                                 {
522                                 char tmpbuf[8];
523
524                                 if (rem) memcpy(tmpbuf,&(buf[l]),
525                                         (unsigned int)rem);
526                                 DES_3cbc_encrypt(
527                                         (DES_cblock *)buf,(DES_cblock *)obuf,
528                                         (long)l,ks,ks2,&iv,
529                                         &iv2,do_encrypt);
530                                 if (rem) memcpy(&(buf[l]),tmpbuf,
531                                         (unsigned int)rem);
532                                 }
533                         else
534                                 {
535                                 DES_cbc_encrypt(
536                                         buf,obuf,
537                                         (long)l,&ks,&iv,do_encrypt);
538                                 if (l >= 8) memcpy(iv,&(obuf[l-8]),8);
539                                 }
540                         if (rem) memcpy(buf,&(buf[l]),(unsigned int)rem);
541
542                         i=0;
543                         while (i < l)
544                                 {
545                                 if (uflag)
546                                         j=uufwrite(obuf,1,(unsigned int)l-i,
547                                                 DES_OUT);
548                                 else
549                                         j=fwrite(obuf,1,(unsigned int)l-i,
550                                                 DES_OUT);
551                                 if (j == -1)
552                                         {
553                                         perror("Write error");
554                                         Exit=7;
555                                         goto problems;
556                                         }
557                                 i+=j;
558                                 }
559                         if (feof(DES_IN))
560                                 {
561                                 if (uflag) uufwriteEnd(DES_OUT);
562                                 break;
563                                 }
564                         }
565                 }
566         else /* decrypt */
567                 {
568                 ex=1;
569                 for (;;)
570                         {
571                         if (ex) {
572                                 if (uflag)
573                                         l=uufread(buf,1,BUFSIZE,DES_IN);
574                                 else
575                                         l=fread(buf,1,BUFSIZE,DES_IN);
576                                 ex=0;
577                                 rem=l%8;
578                                 l-=rem;
579                                 }
580                         if (l < 0)
581                                 {
582                                 perror("read error");
583                                 Exit=6;
584                                 goto problems;
585                                 }
586
587                         if (bflag && !flag3)
588                                 for (i=0; i<l; i+=8)
589                                         DES_ecb_encrypt(
590                                                 (DES_cblock *)&(buf[i]),
591                                                 (DES_cblock *)&(obuf[i]),
592                                                 &ks,do_encrypt);
593                         else if (flag3 && bflag)
594                                 for (i=0; i<l; i+=8)
595                                         DES_ecb2_encrypt(
596                                                 (DES_cblock *)&(buf[i]),
597                                                 (DES_cblock *)&(obuf[i]),
598                                                 &ks,&ks2,do_encrypt);
599                         else if (flag3 && !bflag)
600                                 {
601                                 DES_3cbc_encrypt(
602                                         (DES_cblock *)buf,(DES_cblock *)obuf,
603                                         (long)l,ks,ks2,&iv,
604                                         &iv2,do_encrypt);
605                                 }
606                         else
607                                 {
608                                 DES_cbc_encrypt(
609                                         buf,obuf,
610                                         (long)l,&ks,&iv,do_encrypt);
611                                 if (l >= 8) memcpy(iv,&(buf[l-8]),8);
612                                 }
613
614                         if (uflag)
615                                 ll=uufread(&(buf[rem]),1,BUFSIZE,DES_IN);
616                         else
617                                 ll=fread(&(buf[rem]),1,BUFSIZE,DES_IN);
618                         ll+=rem;
619                         rem=ll%8;
620                         ll-=rem;
621                         if (feof(DES_IN) && (ll == 0))
622                                 {
623                                 last=obuf[l-1];
624
625                                 if ((last > 7) || (last < 0))
626                                         {
627                                         fputs("The file was not decrypted correctly.\n",
628                                                 stderr);
629                                         Exit=8;
630                                         last=0;
631                                         }
632                                 l=l-8+last;
633                                 }
634                         i=0;
635                         if (cflag) DES_cbc_cksum(obuf,
636                                 (DES_cblock *)cksum,(long)l/8*8,&ks,
637                                 (DES_cblock *)cksum);
638                         while (i != l)
639                                 {
640                                 j=fwrite(obuf,1,(unsigned int)l-i,DES_OUT);
641                                 if (j == -1)
642                                         {
643                                         perror("Write error");
644                                         Exit=7;
645                                         goto problems;
646                                         }
647                                 i+=j;
648                                 }
649                         l=ll;
650                         if ((l == 0) && feof(DES_IN)) break;
651                         }
652                 }
653         if (cflag)
654                 {
655                 l=0;
656                 if (cksumname[0] != '\0')
657                         {
658                         if ((O=fopen(cksumname,"w")) != NULL)
659                                 {
660                                 CKSUM_OUT=O;
661                                 l=1;
662                                 }
663                         }
664                 for (i=0; i<8; i++)
665                         fprintf(CKSUM_OUT,"%02X",cksum[i]);
666                 fprintf(CKSUM_OUT,"\n");
667                 if (l) fclose(CKSUM_OUT);
668                 }
669 problems:
670         OPENSSL_cleanse(buf,sizeof(buf));
671         OPENSSL_cleanse(obuf,sizeof(obuf));
672         OPENSSL_cleanse(&ks,sizeof(ks));
673         OPENSSL_cleanse(&ks2,sizeof(ks2));
674         OPENSSL_cleanse(iv,sizeof(iv));
675         OPENSSL_cleanse(iv2,sizeof(iv2));
676         OPENSSL_cleanse(kk,sizeof(kk));
677         OPENSSL_cleanse(k2,sizeof(k2));
678         OPENSSL_cleanse(uubuf,sizeof(uubuf));
679         OPENSSL_cleanse(b,sizeof(b));
680         OPENSSL_cleanse(bb,sizeof(bb));
681         OPENSSL_cleanse(cksum,sizeof(cksum));
682         if (Exit) EXIT(Exit);
683         }
684
685 /*    We ignore this parameter but it should be > ~50 I believe    */
686 int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp)
687         {
688         int i,j,left,rem,ret=num;
689         static int start=1;
690
691         if (start)
692                 {
693                 fprintf(fp,"begin 600 %s\n",
694                         (uuname[0] == '\0')?"text.d":uuname);
695                 start=0;
696                 }
697
698         if (uubufnum)
699                 {
700                 if (uubufnum+num < 45)
701                         {
702                         memcpy(&(uubuf[uubufnum]),data,(unsigned int)num);
703                         uubufnum+=num;
704                         return(num);
705                         }
706                 else
707                         {
708                         i=45-uubufnum;
709                         memcpy(&(uubuf[uubufnum]),data,(unsigned int)i);
710                         j=uuencode((unsigned char *)uubuf,45,b);
711                         fwrite(b,1,(unsigned int)j,fp);
712                         uubufnum=0;
713                         data+=i;
714                         num-=i;
715                         }
716                 }
717
718         for (i=0; i<(((int)num)-INUUBUFN); i+=INUUBUFN)
719                 {
720                 j=uuencode(&(data[i]),INUUBUFN,b);
721                 fwrite(b,1,(unsigned int)j,fp);
722                 }
723         rem=(num-i)%45;
724         left=(num-i-rem);
725         if (left)
726                 {
727                 j=uuencode(&(data[i]),left,b);
728                 fwrite(b,1,(unsigned int)j,fp);
729                 i+=left;
730                 }
731         if (i != num)
732                 {
733                 memcpy(uubuf,&(data[i]),(unsigned int)rem);
734                 uubufnum=rem;
735                 }
736         return(ret);
737         }
738
739 void uufwriteEnd(FILE *fp)
740         {
741         int j;
742         static const char *end=" \nend\n";
743
744         if (uubufnum != 0)
745                 {
746                 uubuf[uubufnum]='\0';
747                 uubuf[uubufnum+1]='\0';
748                 uubuf[uubufnum+2]='\0';
749                 j=uuencode(uubuf,uubufnum,b);
750                 fwrite(b,1,(unsigned int)j,fp);
751                 }
752         fwrite(end,1,strlen(end),fp);
753         }
754
755 /* int size:  should always be > ~ 60; I actually ignore this parameter :-)    */
756 int uufread(unsigned char *out, int size, unsigned int num, FILE *fp)
757         {
758         int i,j,tot;
759         static int done=0;
760         static int valid=0;
761         static int start=1;
762
763         if (start)
764                 {
765                 for (;;)
766                         {
767                         b[0]='\0';
768                         fgets((char *)b,300,fp);
769                         if (b[0] == '\0')
770                                 {
771                                 fprintf(stderr,"no 'begin' found in uuencoded input\n");
772                                 return(-1);
773                                 }
774                         if (strncmp((char *)b,"begin ",6) == 0) break;
775                         }
776                 start=0;
777                 }
778         if (done) return(0);
779         tot=0;
780         if (valid)
781                 {
782                 memcpy(out,bb,(unsigned int)valid);
783                 tot=valid;
784                 valid=0;
785                 }
786         for (;;)
787                 {
788                 b[0]='\0';
789                 fgets((char *)b,300,fp);
790                 if (b[0] == '\0') break;
791                 i=strlen((char *)b);
792                 if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd'))
793                         {
794                         done=1;
795                         while (!feof(fp))
796                                 {
797                                 fgets((char *)b,300,fp);
798                                 }
799                         break;
800                         }
801                 i=uudecode(b,i,bb);
802                 if (i < 0) break;
803                 if ((i+tot+8) > num)
804                         {
805                         /* num to copy to make it a multiple of 8 */
806                         j=(num/8*8)-tot-8;
807                         memcpy(&(out[tot]),bb,(unsigned int)j);
808                         tot+=j;
809                         memcpy(bb,&(bb[j]),(unsigned int)i-j);
810                         valid=i-j;
811                         break;
812                         }
813                 memcpy(&(out[tot]),bb,(unsigned int)i);
814                 tot+=i;
815                 }
816         return(tot);
817         }
818
819 #define ccc2l(c,l)      (l =((DES_LONG)(*((c)++)))<<16, \
820                          l|=((DES_LONG)(*((c)++)))<< 8, \
821                          l|=((DES_LONG)(*((c)++))))
822
823 #define l2ccc(l,c)      (*((c)++)=(unsigned char)(((l)>>16)&0xff), \
824                     *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
825                     *((c)++)=(unsigned char)(((l)    )&0xff))
826
827
828 int uuencode(unsigned char *in, int num, unsigned char *out)
829         {
830         int j,i,n,tot=0;
831         DES_LONG l;
832         register unsigned char *p;
833         p=out;
834
835         for (j=0; j<num; j+=45)
836                 {
837                 if (j+45 > num)
838                         i=(num-j);
839                 else    i=45;
840                 *(p++)=i+' ';
841                 for (n=0; n<i; n+=3)
842                         {
843                         ccc2l(in,l);
844                         *(p++)=((l>>18)&0x3f)+' ';
845                         *(p++)=((l>>12)&0x3f)+' ';
846                         *(p++)=((l>> 6)&0x3f)+' ';
847                         *(p++)=((l    )&0x3f)+' ';
848                         tot+=4;
849                         }
850                 *(p++)='\n';
851                 tot+=2;
852                 }
853         *p='\0';
854         l=0;
855         return(tot);
856         }
857
858 int uudecode(unsigned char *in, int num, unsigned char *out)
859         {
860         int j,i,k;
861         unsigned int n=0,space=0;
862         DES_LONG l;
863         DES_LONG w,x,y,z;
864         unsigned int blank=(unsigned int)'\n'-' ';
865
866         for (j=0; j<num; )
867                 {
868                 n= *(in++)-' ';
869                 if (n == blank)
870                         {
871                         n=0;
872                         in--;
873                         }
874                 if (n > 60)
875                         {
876                         fprintf(stderr,"uuencoded line length too long\n");
877                         return(-1);
878                         }
879                 j++;
880
881                 for (i=0; i<n; j+=4,i+=3)
882                         {
883                         /* the following is for cases where spaces are
884                          * removed from lines.
885                          */
886                         if (space)
887                                 {
888                                 w=x=y=z=0;
889                                 }
890                         else
891                                 {
892                                 w= *(in++)-' ';
893                                 x= *(in++)-' ';
894                                 y= *(in++)-' ';
895                                 z= *(in++)-' ';
896                                 }
897                         if ((w > 63) || (x > 63) || (y > 63) || (z > 63))
898                                 {
899                                 k=0;
900                                 if (w == blank) k=1;
901                                 if (x == blank) k=2;
902                                 if (y == blank) k=3;
903                                 if (z == blank) k=4;
904                                 space=1;
905                                 switch (k) {
906                                 case 1: w=0; in--;
907                                 case 2: x=0; in--;
908                                 case 3: y=0; in--;
909                                 case 4: z=0; in--;
910                                         break;
911                                 case 0:
912                                         space=0;
913                                         fprintf(stderr,"bad uuencoded data values\n");
914                                         w=x=y=z=0;
915                                         return(-1);
916                                         break;
917                                         }
918                                 }
919                         l=(w<<18)|(x<<12)|(y<< 6)|(z    );
920                         l2ccc(l,out);
921                         }
922                 if (*(in++) != '\n')
923                         {
924                         fprintf(stderr,"missing nl in uuencoded line\n");
925                         w=x=y=z=0;
926                         return(-1);
927                         }
928                 j++;
929                 }
930         *out='\0';
931         w=x=y=z=0;
932         return(n);
933         }