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
93void usage(void);
94void doencryption(void);
95int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp);
96void uufwriteEnd(FILE *fp);
97int uufread(unsigned char *out,int size,unsigned int num,FILE *fp);
98int uuencode(unsigned char *in,int num,unsigned char *out);
99int uudecode(unsigned char *in,int num,unsigned char *out);
100void 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 :-) */
113char key[KEYSIZB+1];
114int do_encrypt,longk=0;
115FILE *DES_IN,*DES_OUT,*CKSUM_OUT;
116char uuname[200];
117unsigned char uubuf[50];
118int uubufnum=0;
119#define INUUBUFN	(45*100)
120#define OUTUUBUF	(65*100)
121unsigned char b[OUTUUBUF];
122unsigned char bb[300];
123DES_cblock cksum={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
124char cksumname[200]="";
125
126int vflag,cflag,eflag,dflag,kflag,bflag,fflag,sflag,uflag,flag3,hflag,error;
127
128int 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
322void 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.",
349NULL
350};
351	for (u=(char **)Usage; *u; u++)
352		{
353		fputs(*u,stderr);
354		fputc('\n',stderr);
355		}
356
357	EXIT(1);
358	}
359
360void 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		OPENSSL_cleanse(k2,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			OPENSSL_cleanse(k2,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	OPENSSL_cleanse(key,sizeof(key));
461	OPENSSL_cleanse(kk,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		}
668problems:
669	OPENSSL_cleanse(buf,sizeof(buf));
670	OPENSSL_cleanse(obuf,sizeof(obuf));
671	OPENSSL_cleanse(&ks,sizeof(ks));
672	OPENSSL_cleanse(&ks2,sizeof(ks2));
673	OPENSSL_cleanse(iv,sizeof(iv));
674	OPENSSL_cleanse(iv2,sizeof(iv2));
675	OPENSSL_cleanse(kk,sizeof(kk));
676	OPENSSL_cleanse(k2,sizeof(k2));
677	OPENSSL_cleanse(uubuf,sizeof(uubuf));
678	OPENSSL_cleanse(b,sizeof(b));
679	OPENSSL_cleanse(bb,sizeof(bb));
680	OPENSSL_cleanse(cksum,sizeof(cksum));
681	if (Exit) EXIT(Exit);
682	}
683
684/*    We ignore this parameter but it should be > ~50 I believe    */
685int 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
738void 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 :-)    */
755int 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
827int 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
857int 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	}
933