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