[comp.sources.unix] v10i031: DES encryption routines and a login front-end

rs@uunet.UU.NET (Rich Salz) (07/02/87)

Mod.Sources: Volume 10, Number 31
Submitted by: Bdale Garbee <winfree!bdale>
Archive-name: des

[  Those of you who have a copy of the Volume 6 posting should consider
   this a replacement for it.  Those of you concerned about the legality
   of posting this, don't be --r$  ]

Rich - Here is an updated copy of the DES routines shar file.  Phil found
and fixed a bug in the main.c module that caused the DES program to
occasionally mutilate keys resulting in un-decodable files.  He also has
now included uuencode and uudecode routines, which are helpful for creating
filters into and out of mail systems... since many mailers don't deal with
8-bit data.

Regards,

Bdale Garbee, N3EUA		phone: 303/593-9828 h, 303/590-2868 w
uucp: {bellcore,crash,hp-lsd,hpcsma,ncc,pitt,usafa,vixie}!winfree!bdale
fido: sysop of 128/19		packet: n3eua @ k0hoa, Colorado Springs

- - - - - - - - - -
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\SHAR\EOF\'
CFLAGS=-O -DLITTLE_ENDIAN
all: descalc descycle descert certify radlogin benchmark des uuencode uudecode

des: main.o des.o getpass.o misc.o
	cc -o des main.o des.o getpass.o misc.o

benchmark: benchmark.o des.o
	cc -o benchmark benchmark.o des.o

radlogin: radlogin.o des.o
	cc -o radlogin radlogin.o des.o

descert: descert.o des.o
	cc -o descert descert.o des.o

descalc: descalc.o des.o
	cc -o descalc descalc.o des.o

descycle: descycle.o des.o
	cc -o descycle descycle.o des.o

certify: descert testdata
	descert < testdata
	touch certify

radlogin.o: radlogin.c
	cc -c -O -DUTMP_FILE=\"/etc/utmp\" radlogin.c

uuencode: uuencode.o
	cc -o uuencode uuencode.o

uudecode: uudecode.o
	cc -o uudecode uudecode.o

clean:
	rm -f descalc descycle descert certify radlogin benchmark des *.o
	rm -f uuencode uudecode
\SHAR\EOF\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\SHAR\EOF\'
Late breaking news:
	Versions of uuencode and uudecode now included, which are helpful
	for using this package to send/receive encrypted mail.

Phil asked me to clean this up slightly and package it for distribution.
I've got it running on my Symmetric 4.2bsd system, Phil reports it runs fine
on a variety of systems at Bellcore.  Note that getopt is required but not
provided, as there is already a getopt package in the mod.sources archives.

Bdale Garbee, N3EUA  870401	
winfree!bdale aka bdale%winfree.uucp@flash.bellcore.com

- - - - -

This package contains a DES subroutine library based on the original public
domain code by James Gillogly, but made faster and more flexible. Commands
using this library have been added for testing and for encrypting and
decrypting files (compatible with the DES command under Sun UNIX), among
other things.

Run make. That will compile everything and run test data (from the NBS
certification suite) through it.  It runs as-is under UNIX. It will run
under MS-DOS with a few minor changes: make sure you define LITTLE_ENDIAN
when compiling des.c, and change the name of the console in getpass.c.  If
you have the byte order flag set wrong, you will get ENCRYPT FAIL messages
when the descert test is run.

radlogin.c is an experimental program for secure UNIX login via insecure
channels (like amateur packet radio). Make it and set it up as the login
shell for a special, password-free login (e.g., "radio"). When it starts the
user will be asked his REAL login name, which is then looked up in
/etc/rkeys. (This file must be read protected since it contains DES keys).
The time of day is then printed in hex as a challenge. The user must encrypt
it using DES and his key and type the answer back.  The user may use the
program "descalc" to perform his local calculation. All this is very clumsy;
it works, but after all it's only experimental.

Phil Karn, KA9Q
bellcore!karn aka karn@flash.bellcore.com

- - - - -
Subject: Re:  rkeys file

rkeys:
karn 0123456789abcdef
uid  des_key_in_hex

- - - - -
\SHAR\EOF\
else
  echo "will not over write ./README"
fi
if `test ! -s ./benchmark.c`
then
echo "writing ./benchmark.c"
cat > ./benchmark.c << '\SHAR\EOF\'
/* Just run DES in a loop consuming CPU time; good for benchmarking
 * Phil Karn
 */
#include <stdio.h>
main()
{
	char key[8],work[8];
	long iter,count;

	desinit(0);
	printf("Enter key: ");
	get8(key);
	printf("Setting key: "); put8(key); printf("\n");
	setkey(key);
	printf("Enter starting value: ");
	get8(work);
	printf("Starting value: "); put8(work); printf("\n");
	printf("Number of iterations: ");
	scanf("%ld",&count);

	for(iter = 0;iter < count; iter++)
		endes(work);
}
get8(cp)
char *cp;
{
	int i,t;

	for(i=0;i<8;i++){
		scanf("%2x",&t);
		*cp++ = t;
	}
}
put8(cp)
char *cp;
{
	int i;

	for(i=0;i<8;i++){
		printf("%2x ",*cp++ & 0xff);
	}
}
\SHAR\EOF\
else
  echo "will not over write ./benchmark.c"
fi
if `test ! -s ./des.1`
then
echo "writing ./des.1"
cat > ./des.1 << '\SHAR\EOF\'
.TH DES 1  "24 March 1987"
.SH NAME
des - DES file encryption
.SH SYNOPSIS
.PP
.B des -e|-d [-h] [-k key] [-b]
.SH DESCRIPTION
.B des
is a filter that encrypts or decrypts standard input to standard output
with the Data Encryption Standard (DES).
Either -e (encrypt) or -d (decrypt) must be specified. If the key is not
given on the command line with the -k option the command will prompt for it
twice, suppressing echo and comparing the two responses to guard against
mistyping.
.P
The -h flag controls how the key string is to be interpreted.
Without the -h flag, the key is an ASCII string.
Since DES ignores the low
order bit of each key byte, the
high order bit is set for odd parity, thus retaining the information contained
in the low order bit.
If the -h flag is set, the key string is interpreted as
16 hex/ASCII characters; the low order bit of each byte is again ignored as per
the DES algorithm.
This allows the use of any arbitrary 56-bit key, including bytes representing
control characters that could not be typed if the -h option were not used.
.PP
By default, DES Cipher Block Chaining (CBC) mode is used, with an initial
vector (IV) of all zeros; if the -b option is specified, Electronic Code
Book (ECB) mode is used instead.
.PP
Except for the -h option, this command is compatible with the
.B des
command on the Sun Microsystems workstation.
.SH "SEE ALSO"
Sun Microsystems DES(1) manual page, which describes in detail how
the length of the file is encoded in the last block of ciphertext.
.SH AUTHOR
Phil Karn, KA9Q
\SHAR\EOF\
else
  echo "will not over write ./des.1"
fi
if `test ! -s ./des.3`
then
echo "writing ./des.3"
cat > ./des.3 << '\SHAR\EOF\'
.TH DES 3  "24 March 1987"
.SH NAME
desinit, setkey, endes, dedes, desdone - DES encryption
.SH SYNOPSIS
.PP
.B desinit(mode)
.B int mode;
.PP
.B setkey(key)
.B char *key;
.PP
.B endes(block)
.B char *block;
.PP
.B dedes(block)
.B char *block;
.PP
.B desdone()
.SH DESCRIPTION
These routines implement both standard and modified forms of the NBS Data
Encryption Standard (DES). The user must first call
.B desinit
with one of three operating modes:
.PP
0 - Standard, vanilla DES.
.PP
1 - DES with the initial and final permutations removed.
As these permutations do not strengthen the algorithm,
they are widely regarded as having no purpose other than to slow
down software implementations.
Removing them speeds it up but of course the algorithm is no longer standard
and it will not be compatible with hardware DES chips.
.PP
2 - DES with the initial and final permutations removed, and with independent
48-bit subkeys for each of the 16 rounds. Needless to say this is even
less standard than mode 1, but if properly used (randomize ALL key bytes --
no padding!) it should strengthen the algorithm.
.PP
After calling
.B desinit
the user next calls
.B setkey.
In modes 0 and 1, 8 key bytes are expected, with the low order bit of
each key byte ignored (parity is not checked). This gives a 56-bit key.
In mode 2, 128 key bytes are expected; the high order 2 bits of each byte are
ignored, giving a 768 bit key.
In this mode, the first 8 bytes will be used in the first round, the
second 8 bytes in the second round, and so on.
.PP
Once the key is set, the user may perform in-place encryption and decryption
of 8-byte blocks of data with calls to
.B endes
and
.B dedes.
.PP
To free up memory dynamically allocated by
.B desinit
the user may call
.B desdone.
If further encryption or decryption is to be done,
.B desinit
and
.B setkey
must be called again.
.SH AUTHOR
Phil Karn, KA9Q, building heavily on the earlier public domain code
by Jim Gillogly.


\SHAR\EOF\
else
  echo "will not over write ./des.3"
fi
if `test ! -s ./des.c`
then
echo "writing ./des.c"
cat > ./des.c << '\SHAR\EOF\'
/* Sofware DES functions
 * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted from
 * the 1977 public-domain program by Jim Gillogly
 */
#define	NULL	0

#ifdef	LITTLE_ENDIAN
unsigned long byteswap();
#endif

/* Tables defined in the Data Encryption Standard documents */

/* initial permutation IP */
static char ip[] = {
	58, 50, 42, 34, 26, 18, 10,  2,
	60, 52, 44, 36, 28, 20, 12,  4,
	62, 54, 46, 38, 30, 22, 14,  6,
	64, 56, 48, 40, 32, 24, 16,  8,
	57, 49, 41, 33, 25, 17,  9,  1,
	59, 51, 43, 35, 27, 19, 11,  3,
	61, 53, 45, 37, 29, 21, 13,  5,
	63, 55, 47, 39, 31, 23, 15,  7
};

/* final permutation IP^-1 */
static char fp[] = {
	40,  8, 48, 16, 56, 24, 64, 32,
	39,  7, 47, 15, 55, 23, 63, 31,
	38,  6, 46, 14, 54, 22, 62, 30,
	37,  5, 45, 13, 53, 21, 61, 29,
	36,  4, 44, 12, 52, 20, 60, 28,
	35,  3, 43, 11, 51, 19, 59, 27,
	34,  2, 42, 10, 50, 18, 58, 26,
	33,  1, 41,  9, 49, 17, 57, 25
};

/* expansion operation matrix
 * This is for reference only; it is unused in the code
 * as the f() function performs it implicitly for speed
 */
#ifdef notdef
static char ei[] = {
	32,  1,  2,  3,  4,  5,
	 4,  5,  6,  7,  8,  9,
	 8,  9, 10, 11, 12, 13,
	12, 13, 14, 15, 16, 17,
	16, 17, 18, 19, 20, 21,
	20, 21, 22, 23, 24, 25,
	24, 25, 26, 27, 28, 29,
	28, 29, 30, 31, 32,  1 
};
#endif

/* permuted choice table (key) */
static char pc1[] = {
	57, 49, 41, 33, 25, 17,  9,
	 1, 58, 50, 42, 34, 26, 18,
	10,  2, 59, 51, 43, 35, 27,
	19, 11,  3, 60, 52, 44, 36,

	63, 55, 47, 39, 31, 23, 15,
	 7, 62, 54, 46, 38, 30, 22,
	14,  6, 61, 53, 45, 37, 29,
	21, 13,  5, 28, 20, 12,  4
};

/* number left rotations of pc1 */
static char totrot[] = {
	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
};

/* permuted choice key (table) */
static char pc2[] = {
	14, 17, 11, 24,  1,  5,
	 3, 28, 15,  6, 21, 10,
	23, 19, 12,  4, 26,  8,
	16,  7, 27, 20, 13,  2,
	41, 52, 31, 37, 47, 55,
	30, 40, 51, 45, 33, 48,
	44, 49, 39, 56, 34, 53,
	46, 42, 50, 36, 29, 32
};

/* The (in)famous S-boxes */
static char si[8][64] = {
	/* S1 */
	14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
	 0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
	 4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
	15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,

	/* S2 */
	15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
	 3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
	 0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
	13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,

	/* S3 */
	10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
	13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
	13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
	 1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,

	/* S4 */
	 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
	13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
	10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
	 3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,

	/* S5 */
	 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
	14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
	 4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
	11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,

	/* S6 */
	12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
	10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
	 9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
	 4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,

	/* S7 */
	 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
	13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
	 1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
	 6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,

	/* S8 */
	13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
	 1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
	 7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
	 2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};

/* 32-bit permutation function P used on the output of the S-boxes */
static char p32i[] = {	
	16,  7, 20, 21,
	29, 12, 28, 17,
	 1, 15, 23, 26,
	 5, 18, 31, 10,
	 2,  8, 24, 14,
	32, 27,  3,  9,
	19, 13, 30,  6,
	22, 11,  4, 25
};
/* End of DES-defined tables */

/* Lookup tables initialized once only at startup by desinit() */
static long (*sp)[64];		/* Combined S and P boxes */

static char (*iperm)[16][8];	/* Initial and final permutations */
static char (*fperm)[16][8];

/* 8 6-bit subkeys for each of 16 rounds, initialized by setkey() */
static unsigned char (*kn)[8];

/* bit 0 is left-most in byte */
static int bytebit[] = {
	0200,0100,040,020,010,04,02,01
};

static int nibblebit[] = {
	 010,04,02,01
};
static int desmode;

/* Allocate space and initialize DES lookup arrays
 * mode == 0: standard Data Encryption Algorithm
 * mode == 1: DEA without initial and final permutations for speed
 * mode == 2: DEA without permutations and with 128-byte key (completely
 *            independent subkeys for each round)
 */
desinit(mode)
int mode;
{
	char *malloc();

	if(sp != NULL){
		/* Already initialized */
		return 0;
	}
	desmode = mode;
	
	if((sp = (long (*)[64])malloc(sizeof(long) * 8 * 64)) == NULL){
		return -1;
	}
	spinit();
	kn = (unsigned char (*)[8])malloc(sizeof(char) * 8 * 16);
	if(kn == NULL){
		free((char *)sp);
		return -1;
	}
	if(mode == 1 || mode == 2)	/* No permutations */
		return 0;

	iperm = (char (*)[16][8])malloc(sizeof(char) * 16 * 16 * 8);
	if(iperm == NULL){
		free((char *)sp);
		free((char *)kn);
		return -1;
	}
	perminit(iperm,ip);

	fperm = (char (*)[16][8])malloc(sizeof(char) * 16 * 16 * 8);
	if(fperm == NULL){
		free((char *)sp);
		free((char *)kn);
		free((char *)iperm);
		return -1;
	}
	perminit(fperm,fp);
	
	return 0;
}
/* Free up storage used by DES */
desdone()
{
	if(sp == NULL)
		return;	/* Already done */

	free((char *)sp);
	free((char *)kn);
	if(iperm != NULL)
		free((char *)iperm);
	if(fperm != NULL)
		free((char *)fperm);

	sp = NULL;
	iperm = NULL;
	fperm = NULL;
	kn = NULL;
}
/* Set key (initialize key schedule array) */
setkey(key)
char *key;			/* 64 bits (will use only 56) */
{
	char pc1m[56];		/* place to modify pc1 into */
	char pcr[56];		/* place to rotate pc1 into */
	register int i,j,l;
	int m;

	/* In mode 2, the 128 bytes of subkey are set directly from the
	 * user's key, allowing him to use completely independent
	 * subkeys for each round. Note that the user MUST specify a
	 * full 128 bytes.
	 *
	 * I would like to think that this technique gives the NSA a real
	 * headache, but I'm not THAT naive.
	 */
	if(desmode == 2){
		for(i=0;i<16;i++)
			for(j=0;j<8;j++)
				kn[i][j] = *key++;
		return;
	}
	/* Clear key schedule */
	for (i=0; i<16; i++)
		for (j=0; j<8; j++)
			kn[i][j]=0;

	for (j=0; j<56; j++) {		/* convert pc1 to bits of key */
		l=pc1[j]-1;		/* integer bit location	 */
		m = l & 07;		/* find bit		 */
		pc1m[j]=(key[l>>3] &	/* find which key byte l is in */
			bytebit[m])	/* and which bit of that byte */
			? 1 : 0;	/* and store 1-bit result */
	}
	for (i=0; i<16; i++) {		/* key chunk for each iteration */
		for (j=0; j<56; j++)	/* rotate pc1 the right amount */
			pcr[j] = pc1m[(l=j+totrot[i])<(j<28? 28 : 56) ? l: l-28];
			/* rotate left and right halves independently */
		for (j=0; j<48; j++){	/* select bits individually */
			/* check bit that goes to kn[j] */
			if (pcr[pc2[j]-1]){
				/* mask it in if it's there */
				l= j % 6;
				kn[i][j/6] |= bytebit[l] >> 2;
			}
		}
	}
}
/* In-place encryption of 64-bit block */
endes(block)
char *block;
{
	register int i;
	unsigned long work[2]; 		/* Working data storage */
	long tmp;

	permute(block,iperm,(char *)work);	/* Initial Permutation */
#ifdef LITTLE_ENDIAN
	work[0] = byteswap(work[0]);
	work[1] = byteswap(work[1]);
#endif

	/* Do the 16 rounds */
	for (i=0; i<16; i++)
		round(i,work);

	/* Left/right half swap */
	tmp = work[0];
	work[0] = work[1];	
	work[1] = tmp;

#ifdef LITTLE_ENDIAN
	work[0] = byteswap(work[0]);
	work[1] = byteswap(work[1]);
#endif
	permute((char *)work,fperm,block);	/* Inverse initial permutation */
}
/* In-place decryption of 64-bit block */
dedes(block)
char *block;
{
	register int i;
	unsigned long work[2];	/* Working data storage */
	long tmp;

	permute(block,iperm,(char *)work);	/* Initial permutation */

#ifdef LITTLE_ENDIAN
	work[0] = byteswap(work[0]);
	work[1] = byteswap(work[1]);
#endif

	/* Left/right half swap */
	tmp = work[0];
	work[0] = work[1];	
	work[1] = tmp;

	/* Do the 16 rounds in reverse order */
	for (i=15; i >= 0; i--)
		round(i,work);

#ifdef LITTLE_ENDIAN
	work[0] = byteswap(work[0]);
	work[1] = byteswap(work[1]);
#endif

	permute((char *)work,fperm,block);	/* Inverse initial permutation */
}

/* Permute inblock with perm */
static
permute(inblock,perm,outblock)
char *inblock, *outblock;		/* result into outblock,64 bits */
char perm[16][16][8];			/* 2K bytes defining perm. */
{
	register int i,j;
	register char *ib, *ob;		/* ptr to input or output block */
	register char *p, *q;

	if(perm == NULL){
		/* No permutation, just copy */
		for(i=8; i!=0; i--)
			*outblock++ = *inblock++;
		return;
	}
	/* Clear output block	 */
	for (i=8, ob = outblock; i != 0; i--)
		*ob++ = 0;

	ib = inblock;
	for (j = 0; j < 16; j += 2, ib++) { /* for each input nibble */
		ob = outblock;
		p = perm[j][(*ib >> 4) & 017];
		q = perm[j + 1][*ib & 017];
		for (i = 8; i != 0; i--){   /* and each output byte */
			*ob++ |= *p++ | *q++;	/* OR the masks together*/
		}
	}
}

/* Do one DES cipher round */
static
round(num,block)
int num;				/* i.e. the num-th one	 */
unsigned long *block;
{
	long f();

	/* The rounds are numbered from 0 to 15. On even rounds
	 * the right half is fed to f() and the result exclusive-ORs
	 * the left half; on odd rounds the reverse is done.
	 */
	if(num & 1){
		block[1] ^= f(block[0],kn[num]);
	} else {
		block[0] ^= f(block[1],kn[num]);
	}
}
/* The nonlinear function f(r,k), the heart of DES */
static
long
f(r,subkey)
unsigned long r;		/* 32 bits */
unsigned char subkey[8];	/* 48-bit key for this round */
{
	register unsigned long rval,rt;
#ifdef	TRACE
	unsigned char *cp;
	int i;

	printf("f(%08lx, %02x %02x %02x %02x %02x %02x %02x %02x) = ",
		r,
		subkey[0], subkey[1], subkey[2],
		subkey[3], subkey[4], subkey[5],
		subkey[6], subkey[7]);
#endif
	/* Run E(R) ^ K through the combined S & P boxes
	 * This code takes advantage of a convenient regularity in
	 * E, namely that each group of 6 bits in E(R) feeding
	 * a single S-box is a contiguous segment of R.
	 */
	rt = (r >> 1) | ((r & 1) ? 0x80000000 : 0);
	rval = 0;
	rval |= sp[0][((rt >> 26) ^ *subkey++) & 0x3f];
	rval |= sp[1][((rt >> 22) ^ *subkey++) & 0x3f];
	rval |= sp[2][((rt >> 18) ^ *subkey++) & 0x3f];
	rval |= sp[3][((rt >> 14) ^ *subkey++) & 0x3f];
	rval |= sp[4][((rt >> 10) ^ *subkey++) & 0x3f];
	rval |= sp[5][((rt >> 6) ^ *subkey++) & 0x3f];
	rval |= sp[6][((rt >> 2) ^ *subkey++) & 0x3f];
	rt = (r << 1) | ((r & 0x80000000) ? 1 : 0);
	rval |= sp[7][(rt ^ *subkey) & 0x3f];
#ifdef	TRACE
	printf(" %08lx\n",rval);
#endif
	return rval;
}
/* initialize a perm array */
static
perminit(perm,p)
char perm[16][16][8];			/* 64-bit, either init or final */
char p[64];
{
	register int l, j, k;
	int i,m;

	/* Clear the permutation array */
	for (i=0; i<16; i++)
		for (j=0; j<16; j++)
			for (k=0; k<8; k++)
				perm[i][j][k]=0;

	for (i=0; i<16; i++)		/* each input nibble position */
		for (j = 0; j < 16; j++)/* each possible input nibble */
		for (k = 0; k < 64; k++)/* each output bit position */
		{   l = p[k] - 1;	/* where does this bit come from*/
			if ((l >> 2) != i)  /* does it come from input posn?*/
			continue;	/* if not, bit k is 0	 */
			if (!(j & nibblebit[l & 3]))
			continue;	/* any such bit in input? */
			m = k & 07;	/* which bit is this in the byte*/
			perm[i][j][k>>3] |= bytebit[m];
		}
}

/* Initialize the lookup table for the combined S and P boxes */
static int
spinit()
{
	char pbox[32];
	int p,i,s,j,rowcol;
	long val;

	/* Compute pbox, the inverse of p32i.
	 * This is easier to work with
	 */
	for(p=0;p<32;p++){
		for(i=0;i<32;i++){
			if(p32i[i]-1 == p){
				pbox[p] = i;
				break;
			}
		}
	}
	for(s = 0; s < 8; s++){			/* For each S-box */
		for(i=0; i<64; i++){		/* For each possible input */
			val = 0;
			/* The row number is formed from the first and last
			 * bits; the column number is from the middle 4
			 */
			rowcol = (i & 32) | ((i & 1) ? 16 : 0) | ((i >> 1) & 0xf);
			for(j=0;j<4;j++){	/* For each output bit */
				if(si[s][rowcol] & (8 >> j)){
				 val |= 1L << (31 - pbox[4*s + j]);
				}
			}
			sp[s][i] = val;

#ifdef	DEBUG
			printf("sp[%d][%2d] = %08lx\n",s,i,sp[s][i]);
#endif
		}
	}
}
#ifdef	LITTLE_ENDIAN
/* Byte swap a long */
static
unsigned long
byteswap(x)
unsigned long x;
{
	register char *cp,tmp;

	cp = (char *)&x;
	tmp = cp[3];
	cp[3] = cp[0];
	cp[0] = tmp;

	tmp = cp[2];
	cp[2] = cp[1];
	cp[1] = tmp;

	return x;
}
#endif
\SHAR\EOF\
else
  echo "will not over write ./des.c"
fi
if `test ! -s ./descalc.c`
then
echo "writing ./descalc.c"
cat > ./descalc.c << '\SHAR\EOF\'
/* DES "desk calculator"
 * Phil Karn
 * January 1987
 */
#include <stdio.h>
#include <ctype.h>
main()
{
	char key[8],work[8];
	char line[80];
	int keyset = 0;

	if(desinit(0) == -1){
		printf("DES initialization failed\n");
		exit(1);
	}
	printf("Enter in hexadecimal:\nk <key>\np <plaintext>\nc <ciphertext>\n");
	printf("s - standard DES mode\n");
	printf("f - fast mode (no IP)\n"); 
	for(;;){
		gets(line);
		if(feof(stdin))
			break;
		if(isupper(line[0]))
			line[0] = tolower(line[0]);
		switch(line[0]){
		case 's':
			desdone();
			desinit(0);
			if(keyset)
				setkey(key);
			break;
		case 'f':
			desdone();
			desinit(1);
			if(keyset)
				setkey(key);
			break;
		case 'k':	/* Set key */
			get8(&line[1],key);
			setkey(key);
			keyset = 1;
			break;
		case 'c':	/* Decrypt ciphertext */
			if(!keyset){
				printf("Enter key\n");
				break;
			}
			get8(&line[1],work);
			dedes(work);
			printf("Plaintext: ");
			put8(work);
			printf("\n");
			break;
		case 'p':	/* Encrypt plaintext */
			if(!keyset){
				printf("Enter key\n");
				break;
			}
			get8(&line[1],work);
			endes(work);
			printf("Ciphertext: ");
			put8(work);
			printf("\n");
			break;
		default:
			printf("eh?\n");
			break;
		}
	}
}
get8(buf,cp)
char *buf;
register char *cp;
{
	int ikey[8],i;

	sscanf(buf,"%2x%2x%2x%2x%2x%2x%2x%2x",&ikey[0],&ikey[1],&ikey[2],
		&ikey[3],&ikey[4],&ikey[5],&ikey[6],&ikey[7]);
	for(i=0;i<8;i++)
		*cp++ = ikey[i];
}
put8(cp)
register char *cp;
{
	int i;

	for(i=0;i<8;i++){
		printf("%02x ",*cp++ & 0xff);
	}
}
\SHAR\EOF\
else
  echo "will not over write ./descalc.c"
fi
if `test ! -s ./descert.c`
then
echo "writing ./descert.c"
cat > ./descert.c << '\SHAR\EOF\'
#include <stdio.h>
main()
{
	char key[8],plain[8],cipher[8],answer[8];
	int i;
	int test;
	int fail;

	desinit(0);

	for(test=0;!feof(stdin);test++){

		get8(key);
		printf(" K: "); put8(key);
		setkey(key);

		get8(plain);
		printf(" P: "); put8(plain);

		get8(answer);
		printf(" C: "); put8(answer);

		for(i=0;i<8;i++)
			cipher[i] = plain[i];
		endes(cipher);

		for(i=0;i<8;i++)
			if(cipher[i] != answer[i])
				break;
		fail = 0;
		if(i != 8){
			printf(" Encrypt FAIL");
			fail++;
		}
		dedes(cipher);
		for(i=0;i<8;i++)
			if(cipher[i] != plain[i])
				break;
		if(i != 8){
			printf(" Decrypt FAIL");
			fail++;
		}
		if(fail == 0)
			printf(" OK");
		printf("\n");
	}
}
get8(cp)
char *cp;
{
	int i,t;

	for(i=0;i<8;i++){
		scanf("%2x",&t);
		if(feof(stdin))
			exit(0);
		*cp++ = t;
	}
}
put8(cp)
char *cp;
{
	int i;

	for(i=0;i<8;i++){
		printf("%02x",*cp++ & 0xff);
	}
}
\SHAR\EOF\
else
  echo "will not over write ./descert.c"
fi
if `test ! -s ./descycle.c`
then
echo "writing ./descycle.c"
cat > ./descycle.c << '\SHAR\EOF\'
/* Investigate cycles in DES output feedback mode (experimental)
 * Phil Karn
 */
#include <stdio.h>
main()
{
	char key[8],start[8],work[8];
	long update;
	register int i;
	long iter;

	desinit(0);
	printf("Enter key: ");
	get8(key);
	printf("Setting key: "); put8(key); printf("\n");
	setkey(key);
	printf("Enter starting value: ");
	get8(start);
	printf("Starting value: "); put8(start); printf("\n");
	printf("Update interval: ");
	scanf("%ld",&update);

	for(i=0;i<8;i++)
		work[i] = start[i];

	for(iter = 0;; iter++){

		endes(work);
		if((iter % update) == 0){
			printf("%ld ",iter);
			put8(work); printf("\n");
		}
		for(i=0;i<8;i++){
			if(work[i] != start[i])
				break;
		}
		if(i == 8){
			printf("CYCLE FOUND after %ld iterations\n",iter);
			exit(0);
		}
	}
}
get8(cp)
char *cp;
{
	int i,t;

	for(i=0;i<8;i++){
		scanf("%2x",&t);
		*cp++ = t;
	}
}
put8(cp)
char *cp;
{
	int i;

	for(i=0;i<8;i++){
		printf("%2x ",*cp++ & 0xff);
	}
}
\SHAR\EOF\
else
  echo "will not over write ./descycle.c"
fi
if `test ! -s ./getopt.c`
then
echo "writing ./getopt.c"
cat > ./getopt.c << '\SHAR\EOF\'
/* got this off net.sources */
#include <stdio.h>

/*
 * get option letter from argument vector
 */
int	opterr = 1,		/* useless, never set or used */
	optind = 1,		/* index into parent argv vector */
	optopt;			/* character checked for validity */
char	*optarg;		/* argument associated with option */

#define BADCH	(int)'?'
#define EMSG	""
#define tell(s)	fputs(*nargv,stderr);fputs(s,stderr); \
		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);

getopt(nargc,nargv,ostr)
int	nargc;
char	**nargv,
	*ostr;
{
	static char	*place = EMSG;	/* option letter processing */
	register char	*oli;		/* option letter list index */
	char	*index();

	if(!*place) {			/* update scanning pointer */
		if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
		if (*place == '-') {	/* found "--" */
			++optind;
			return(EOF);
		}
	}				/* option letter okay? */
	if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
		if(!*place) ++optind;
		tell(": illegal option -- ");
	}
	if (*++oli != ':') {		/* don't need argument */
		optarg = NULL;
		if (!*place) ++optind;
	}
	else {				/* need an argument */
		if (*place) optarg = place;	/* no white space */
		else if (nargc <= ++optind) {	/* no arg */
			place = EMSG;
			tell(": option requires an argument -- ");
		}
	 	else optarg = nargv[optind];	/* white space */
		place = EMSG;
		++optind;
	}
	return(optopt);			/* dump back option letter */
}
\SHAR\EOF\
else
  echo "will not over write ./getopt.c"
fi
if `test ! -s ./getpass.c`
then
echo "writing ./getpass.c"
cat > ./getpass.c << '\SHAR\EOF\'
#include <stdio.h>
#include <signal.h>
#include <sgtty.h>

#define	TTY	"/dev/tty"	/* Change to "con" for MS-DOS */

/* Issue prompt and read reply with echo turned off */
char *
getpass(prompt)
char *prompt;
{
	struct sgttyb ttyb,ttysav;
	register char *cp;
	int c;
	FILE *tty;
	static char pbuf[128];
	int (*signal())(),(*sig)();

	if ((tty = fdopen(open(TTY, 2), "r")) == NULL)
		tty = stdin;
	else
		setbuf(tty, (char *)NULL);
	sig = signal(SIGINT, SIG_IGN);
	ioctl(fileno(tty), TIOCGETP, &ttyb);
	ioctl(fileno(tty), TIOCGETP, &ttysav);
	ttyb.sg_flags |= RAW;
	ttyb.sg_flags &= ~ECHO;
	ioctl(fileno(tty), TIOCSETP, &ttyb);
	fprintf(stderr, "%s", prompt);
	fflush(stderr);
	cp = pbuf;
	for (;;) {
		c = getc(tty);
		if(c == '\r' || c == '\n' || c == EOF)
			break;
		if (cp < &pbuf[127])
			*cp++ = c;
	}
	*cp = '\0';
	fprintf(stderr,"\r\n");
	fflush(stderr);
	ioctl(fileno(tty), TIOCSETP, &ttysav);
	signal(SIGINT, sig);
	if (tty != stdin)
		fclose(tty);
	return(pbuf);
}
\SHAR\EOF\
else
  echo "will not over write ./getpass.c"
fi
if `test ! -s ./main.c`
then
echo "writing ./main.c"
cat > ./main.c << '\SHAR\EOF\'
/* Encrypt/decrypt command compatible with Sun's "des" command */
#include <stdio.h>

char iv[8];	/* Initial vector for CBC mode */
int block;

main(argc,argv)
int argc;
char *argv[];
{
	int c,cnt,encrypt,decrypt,hexflag;
	register int i;
	char key[8],tkey1[20],tkey2[20],*akey,*getpass();
	extern char *optarg;

	hexflag = block = encrypt = decrypt = 0;
	akey = NULL;
	while((c = getopt(argc,argv,"hedk:b")) != EOF){
		switch(c){
		case 'h':
			hexflag++;
			break;
		case 'e':
			encrypt++;
			break;
		case 'd':
			decrypt++;
			break;
		case 'k':
			akey = optarg;
			break;
		case 'b':
			block++;
			break;
		}
	}
	if(encrypt == 0 && decrypt == 0){
		fprintf(stderr,"Usage: des -e|-d [-h] [-k key]\n");
		exit(2);
	}
	if(akey == NULL){
		/* No key on command line, prompt for it */
		memset(tkey1,0,sizeof(tkey1));
		memset(tkey2,0,sizeof(tkey2));
		for(;;){
			akey = getpass("Enter key: ");
			strncpy(tkey1,akey,sizeof(tkey1));
			akey = getpass("Enter key again: ");
			strncpy(tkey2,akey,sizeof(tkey2));
			if(strncmp(tkey1,tkey2,sizeof(tkey1)) != 0){
				fprintf(stderr,"Key mistyped, try again\n");
			} else
				break;
		}
		akey = tkey1;
	}
	if(hexflag){
		for(i=0;i<16;i++){
			if(htoa(akey[i]) == -1){
				fprintf(stderr,"Non-hex character in key\n");
				exit(1);
			}
		}
		gethex(key,akey,8);
	} else {
		strncpy(key,akey,8);
		/* Set up key, determine parity bit */
		for(cnt = 0; cnt < 8; cnt++){
			c = 0;
			for(i=0;i<7;i++)
				if(key[cnt] & (1 << i))
					c++;
			if((c & 1) == 0)
				key[cnt] |= 0x80;
			else
				key[cnt] &= ~0x80;
		}
	}
	/* Blot out original key */
	i = strlen(akey);
	i = (i < 8) ? i : 8;
	memset(akey,0,i);

	desinit(0);
	setkey(key);

	/* Initialize IV to all zeros */
	memset(iv,0,8);

	if(encrypt){
		doencrypt();
	} else {
		dodecrypt();
	}
}
/* Encrypt standard input to standard output */
doencrypt()
{
	char work[8],*cp,*cp1;
	int cnt,i;

	for(;;){
		if((cnt = fread(work,1,8,stdin)) != 8){
			/* Put residual byte count in the last block.
			 * Note that garbage is left in the other bytes,
			 * if any; this is a feature, not a bug, since it'll
			 * be stripped out at decrypt time.
			 */
			work[7] = cnt;
		}
		if(!block){
			/* CBC mode; chain in last cipher word */
			cp = work;
			cp1 = iv;
			for(i=8; i!=0; i--)
				*cp++ ^= *cp1++;
		}
		endes(work);	/* Encrypt block */
		if(!block){	/* Save outgoing ciphertext for chain */
			memcpy(iv,work,8);
		}
		fwrite(work,1,8,stdout);
		if(cnt != 8)
			break;
	}
}
dodecrypt()
{
	char work[8],nwork[8],ivtmp[8],*cp,*cp1;
	int cnt,i;


	cnt = fread(work,1,8,stdin);	/* Prime the pump */
	for(;;){
		if(!block){	/* Save incoming ciphertext for chain */
			memcpy(ivtmp,work,8);
		}
		dedes(work);
		if(!block){	/* Unchain block, save ciphertext for next */
			cp = work;
			cp1 = iv;
			for(i=8; i!=0; i--){
				*cp++ ^= *cp1++;
			}
			memcpy(iv,ivtmp,8);
		}
		/* Save buffer pending next read */
		memcpy(nwork,work,8);
		/* Try to read next block */
		cnt = fread(work,1,8,stdin);
		if(cnt != 8){	/* Can "only" be 0 if not 8 */
			/* Prev block was last one, write appropriate number
			 * of bytes
			 */
			cnt = nwork[7];
			if(cnt < 0 || cnt > 7){
				fprintf(stderr,"Corrupted file or wrong key\n");
			} else if(cnt != 0)
				fwrite(nwork,1,cnt,stdout);
			exit(0);
		} else {
			/* Now okay to write previous buffer */
			fwrite(nwork,1,8,stdout);
		}

	}
}
/* Convert hex/ascii nybble to binary */
int
htoa(c)
char c;
{
	if(c >= '0' && c <= '9')
		return c - '0';
	if(c >= 'a' && c <= 'f')
		return 10 + c - 'a';
	if(c >= 'A' && c <= 'F')
		return 10 + c - 'A';
	return -1;
}
/* Convert bytes from hex/ascii to binary */
gethex(result,cp,cnt)
register char *result;
register char *cp;
register int cnt;
{
	while(cnt-- != 0){
		*result = htoa(*cp++) << 4;
		*result++ |= htoa(*cp++);
	}
}
#ifdef	DEBUG
put8(cp)
register char *cp;
{
	int i;

	for(i=0;i<8;i++){
		fprintf(stderr,"%02x ",*cp++ & 0xff);
	}
}
#endif

\SHAR\EOF\
else
  echo "will not over write ./main.c"
fi
if `test ! -s ./misc.c`
then
echo "writing ./misc.c"
cat > ./misc.c << '\SHAR\EOF\'
/* Set block of memory to constant */
memset(blk,val,size)
register char *blk;
register char val;
register unsigned size;
{
	while(size-- != 0)
		*blk++ = val;
}

/* Copy block of memory */
memcpy(dest,src,size)
register char *dest,*src;
register unsigned size;
{
	while(size-- != 0)
		*dest++ = *src++;
}

/* Compare two blocks of memory */
memcmp(a,b,size)
register char *a,*b;
register unsigned size;
{
	while(size-- != 0)
		if(*a++ != *b++)
			return 1;
	return 0;
}

\SHAR\EOF\
else
  echo "will not over write ./misc.c"
fi
if `test ! -s ./radlogin.c`
then
echo "writing ./radlogin.c"
cat > ./radlogin.c << '\SHAR\EOF\'
/*
 * Secure packet radio login command. The system first prompts for the
 * user's name. It then generates and sends a unique "challenge" (a 64-bit
 * hexadecimal integer) based on the time of day. The user encrypts
 * this value using the Data Encryption Standard and his private key and
 * type it back to the system. The system also encrypts the challenge
 * with the user's key and compares the two. If they match, he's in.
 *
 * 18 December 1986 Phil Karn, KA9Q
 *
 * mods:
 *   870318 Bdale, N3EUA     Add code to run user's .login commands.
 *   870317 Bdale, N3EUA     Hacked to remove putenv() by calling execle()
 *                           instead of execl().
 */
#include <stdio.h>
#include <strings.h>
#include <pwd.h>
#include <utmp.h>
#define	KEYFILE	"/etc/rkeys"	/* This file must be read-protected */
main(argc,argv)
int argc;
char *argv[];
{
	struct passwd *pp,*getpwnam();
	unsigned long t;
	FILE *fp;
	char name[64];
	char key[8];
	char work[8];
	char answer[8];
	char fbuf[64];
	char ibuf[64];
	char home[64];
	char login[64];
	char shell[64];
	char user[64];
	char *keyp;
	char *cp,*tty,*ttyname();
	int i,ikey[8];
	struct utmp utmp;
	char *ep[5];               /* we'll build an environment here */

	if((fp = fopen(KEYFILE,"r")) == NULL){
		printf("Can't open key file\n");
		exit(1);
	}
	/* Get user's name and look it up in the database */
	printf("Enter login name: ");
	fgets(ibuf,sizeof(ibuf),stdin);
	if((cp = index(ibuf,'\n')) != NULL)
		*cp = '\0';
	strncpy(name,ibuf,sizeof(name));
	for(;;){
		fgets(fbuf,sizeof(fbuf),fp);
		if(feof(fp)){
			printf("No key for login name\n");
			exit(2);
		}
		if((cp = index(fbuf,'\n')) != NULL)
			*cp = '\0';
		if(strncmp(name,fbuf,strlen(name)) == 0)
			break;
	}
	fclose(fp);
	/* Find the user's DES key */
	if((keyp = index(fbuf,' ')) == NULL){
		printf("Missing key field\n");
		exit(3);
	}
	keyp++;
	/* Initialize DES with the user's key */
	sscanf(keyp,"%2x%2x%2x%2x%2x%2x%2x%2x",
	 &ikey[0], &ikey[1], &ikey[2], &ikey[3], &ikey[4], &ikey[5],
	 &ikey[6], &ikey[7]);

	for(i=0;i<8;i++)
		key[i] = ikey[i];

	desinit(0);
	setkey(key);

	/* Generate and send the challenge */
	time(&t);
	printf("Challenge: %016x\n",t);

	/* Encrypt it locally... */
	for(i=0;i<4;i++)
		work[i] = 0;
	work[4] = t >> 24;
	work[5] = t >> 16;
	work[6] = t >> 8;
	work[7] = t;
	endes(work);
	
	/* ...and see if the user can do the same */
	printf("Response:  ");
	for(i=0;i<8;i++){
		scanf("%2x",&t);
		answer[i] = t;
	}
	printf("\n");     /* I like it better with a blank line here - bdale */
	/* Compare the ciphertexts. If they match, he's in */
	for(i=0; i < 8; i++){
		if(work[i] != answer[i]){
			printf("Wrong response\n");
			exit(4);
		}
	}
	if((pp = getpwnam(name)) == NULL){
		printf("login name \"%s\" not in /etc/passwd\n",name);
		exit(4);
	}
	if((fp = fopen(UTMP_FILE,"r+")) == NULL){
		printf("can't open utmp\n");
		exit(4);
	}
	tty = ttyname(0);
	if((cp = rindex(tty,'/')) != NULL)
		tty = cp + 1;
	while(fread((char *)&utmp,sizeof(struct utmp),1,fp),!feof(fp)){
		if(strncmp(utmp.ut_line,tty,8) == 0){
			strncpy(utmp.ut_name,name,8);
			fseek(fp,(long)-sizeof(struct utmp),1);
			fwrite((char *)&utmp,sizeof(struct utmp),1,fp);
			break;
		}
	}
	fclose(fp);
	chdir(pp->pw_dir);
	setregid(pp->pw_gid,pp->pw_gid);
	setreuid(pp->pw_uid,pp->pw_uid);
	if(pp->pw_shell == NULL || *pp->pw_shell == '\0')
		pp->pw_shell = "/bin/ksh";
	sprintf(home,"HOME=%s",pp->pw_dir);
	sprintf(shell,"SHELL=%s",pp->pw_shell);
	sprintf(user,"USER=%s",name);
	sprintf(login,"%s/.login",pp->pw_dir);
	ep[0] = home;
	ep[1] = shell;
	ep[2] = user;
	ep[3] = (char *) NULL;
	execle(pp->pw_shell,"-",0,ep);
	printf("Exec failed\n");
}
\SHAR\EOF\
else
  echo "will not over write ./radlogin.c"
fi
if `test ! -s ./rkeys.format`
then
echo "writing ./rkeys.format"
cat > ./rkeys.format << '\SHAR\EOF\'
>From bellcore!karn@flash.bellcore.com Sat Mar 14 23:48:50 1987
Received: by flash.bellcore.com (4.12/4.7)
	id AA13633; Sat, 14 Mar 87 00:05:44 est
Date: Sat, 14 Mar 87 00:05:44 est
From: karn@flash.bellcore.com (Phil R. Karn)
Message-Id: <8703140505.AA13633@flash.bellcore.com>
To: bdale@winfree.UUCP
Subject: Re:  rkeys file
Status: R

rkeys:
karn 0123456789abcdef
uid  des_key_in_hex

Phil

\SHAR\EOF\
else
  echo "will not over write ./rkeys.format"
fi
if `test ! -s ./testdata`
then
echo "writing ./testdata"
cat > ./testdata << '\SHAR\EOF\'
0000000000000000 0000000000000000 8CA64DE9C1B123A7
FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58
3000000000000000 1000000000000001 958E6E627A05557B
1111111111111111 1111111111111111 F40379AB9E0EC533
0123456789ABCDEF 1111111111111111 17668DFC7292532D
1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD
0000000000000000 0000000000000000 8CA64DE9C1B123A7
FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4
7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
025816164629B007 480D39006EE762F2 A1F9915541020B56
49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
0101010101010101 0123456789ABCDEF 617B3A0CE8F07100
1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606
E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7
0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451
FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE
0123456789ABCDEF 0000000000000000 D5D44FF720683D0D
FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2
\SHAR\EOF\
else
  echo "will not over write ./testdata"
fi
if `test ! -s ./uudecode.c`
then
echo "writing ./uudecode.c"
cat > ./uudecode.c << '\SHAR\EOF\'
/* uudecode.c - convert ascii-encoded files back to their original form
 * Usage: uudecode [infile]
 *
 * This command differs from the regular UNIX one in that the embedded
 * file name "/dev/stdout" is recognized, allowing it to be used in a pipeline
 *
 * Written and placed in the public domain by Phil Karn, KA9Q 31 March 1987
 */
#include <stdio.h>
#define	LINELEN	80
main(argc,argv)
int argc;
char *argv[];
{
	char linebuf[LINELEN],*index(),*fgets();
	register char *cp;
	int linelen,i;
	FILE *in,*out;
	
	if(argc > 1){
		if((in = fopen(argv[1],"r")) == NULL){
			fprintf(stderr,"Can't read %s\n",argv[1]);
			exit(1);
		}
	} else
		in = stdin;

	/* Find begin line */
	while(fgets(linebuf,LINELEN,in) != NULL){
		if((cp = index(linebuf,'\n')) != NULL)
			*cp = '\0';
		if(strncmp(linebuf,"begin",5) == 0)
			break;
	}
	if(feof(in)){
		fprintf(stderr,"No begin found\n");
		exit(1);
	}
	/* Find beginning of file name */
	cp = &linebuf[6];
	if((cp = index(cp,' ')) != NULL)
		cp++;
	/* Set up output stream */
	if(cp == NULL || strcmp(cp,"/dev/stdout") == 0){
		out = stdout;
	} else if((out = fopen(cp,"w")) == NULL){
			fprintf(stderr,"Can't open %s\n",cp);
			exit(1);
	}
	/* Now crunch the input file */
	while(fgets(linebuf,LINELEN,in) != NULL){
		linelen = linebuf[0] - ' ';
		if(linelen == 0 || strncmp(linebuf,"end",3) == 0)
			break;
		for(cp = &linebuf[1];linelen > 0;cp += 4){
			for(i=0;i<4;i++)
				cp[i] -= ' ';
			putc((cp[0] << 2) | ((cp[1] >> 4) & 0x3),out);
			if(--linelen > 0)
				putc((cp[1] << 4) | ((cp[2] >> 2) & 0xf),out);
			if(--linelen > 0)
				putc((cp[2] << 6) | cp[3],out);
			linelen--;
		}
	}
	fclose(out);
}

\SHAR\EOF\
else
  echo "will not over write ./uudecode.c"
fi
if `test ! -s ./uuencode.c`
then
echo "writing ./uuencode.c"
cat > ./uuencode.c << '\SHAR\EOF\'
/* uuencode.c - convert files to ascii-encoded form
 * Usage: uuencode [filename] < infile
 *
 * If [filename] isn't specified, "/dev/stdout" is the default.  This allows
 * use of my uudecode as a pipeline filter.
 *
 * Written and placed in the public domain by Phil Karn, KA9Q
 * 31 March 1987
 */
#include <stdio.h>
#define	LINELEN	45
main(argc,argv)
int argc;
char *argv[];
{
	char linebuf[LINELEN];
	register char *cp;
	int linelen;

	if(argc > 1)
		printf("begin 0666 %s\n",argv[1]);
	else
		printf("begin 0666 /dev/stdout\n");
	for(;;){
		linelen = fread(linebuf,1,LINELEN,stdin);
		if(linelen <= 0)
			break;
		putchar(' ' + linelen);	/* Record length */
		for(cp = linebuf; cp < &linebuf[linelen]; cp += 3){
		        putchar(' ' + ((cp[0] >> 2) & 0x3f));
			putchar(' ' + (((cp[0] << 4) & 0x30) | ((cp[1] >> 4) & 0xf)));
			putchar(' ' + (((cp[1] << 2) & 0x3c) | ((cp[2] >> 6) & 0x3)));
			putchar(' ' + (cp[2] & 0x3f));
		}
		putchar('\n');
	}
	printf(" \n");	/* 0-length null record */
	printf("end\n");
}

\SHAR\EOF\
else
  echo "will not over write ./uuencode.c"
fi
echo "Finished archive 1 of 1NEcp;
{