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