/*
This routine is an exact implementation of Boris Hagelin's
cryptographic machine.  See U. S. Patent #2,089,603.
*/

int	cagetable[] { 0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 8, 8, 9, 10, 12, 16,
	16, 17, 18, 20, 24, 32, 32, 33, 34, 36, 40, 48};
int	warr1[52];
int	warr2[50];
int	warr3[46];
int	warr4[42];
int	warr5[38];
int	warr6[34];
int	*wheel1 warr1;
int	*wheel2 warr2;
int	*wheel3 warr3;
int	*wheel4 warr4;
int	*wheel5 warr5;
int	*wheel6 warr6;
char	key[130];
int	xxx;


/*
subroutine to manufacture a wheel
*/

setup(list,n) int list[];
	{int *lp;
	lp = list;
	while(--n){
		*lp = lp+2;
		lp[1] = getbit();
		if(xxx) putchar(lp[1]+'0');
		lp = lp + 2;
		}
	*lp = list;
	lp[1] = getbit();
	if(xxx){
		putchar(lp[1]+'0');
		putchar('\n');
		}
	}



/*
subroutine to return the next bit from the main routines
argument
*/

getbit(){
	static i,j;
	int b;
	b = (key[j] >> i) & 1;
	if (i++ > 5) {
		j++;
		i = 0;
		}
	return (b);
	}




main(ncooky,cookyp)
	int ncooky;
	char *cookyp[];
	{
	char *ip, *jp;
	int temp;
	int random;
	int i,j;
	int precious;
	int crypt;
	int cage[27];
	xxx = 0;



/*
copy input key and pad with clever junk
*/

	jp = key;
	*jp++ = 004;
	*jp++ = 034;
	if(ncooky > 1){
		while (*jp++ = *cookyp[1]) *cookyp[1]++ = 4;
		jp--;
		}
	ip = key;
	while (jp < key+128) {
		*jp = jp[-1] ^ *ip++;
		jp++;
	}


/*
manufacture six wheels of various length
*/

	setup(wheel1,26);
	setup(wheel2,25);
	setup(wheel3,23);
	setup(wheel4,21);
	setup(wheel5,19);
	setup(wheel6,17);

/*
set up the cage bars from the key area
*/

	jp = key;
	i = 27;
	while (i--){
	cage[i] = cagetable[*jp++ % 28];
	if(xxx && (cage[i] != 0)){
		putchar( cage[i]/8 + '0');
		putchar( cage[i]%8 + '0');
		putchar(' ');
		}
	}
	if(xxx) putchar('\n');


/*
the internal settings are now complete
it's time to turn the crank, running the cage
bars against the wheel lugs.
*/


while ((precious = getchar()) >=0){
	temp = 040*wheel1[1] + 020*wheel2[1] + 010*wheel3[1]
		+ 004*wheel4[1] + 002*wheel5[1] + 001*wheel6[1];
	wheel1 = *wheel1;
	wheel2 = *wheel2;
	wheel3 = *wheel3;
	wheel4 = *wheel4;
	wheel5 = *wheel5;
	wheel6 = *wheel6;

	random = 0;
	i = 27;
	while (i--){
		random = random + ((temp & cage[i]) != 0);
		}
	random =% 26;

/*
now we have a random number to use to encrypt the input
it is done in such a way that the process is its own
inverse.
*/


	if ( precious=='\n' || precious==' ')
		crypt = precious;
	else{
		crypt = ('a' + 'z' - precious + random)%0400;
		if (crypt >= 'a' && crypt <= 'z' && precious > 'z')
			crypt =+ 26;
		if (crypt > 'z' && precious >= 'a' & precious <= 'z')
			crypt =- 26;
		if (crypt == '\n' || crypt == ' ')
			crypt = precious;
		}
	putchar(crypt);
	}
flush();
return;
}

char	ibuf[512];
char	obuf[512];
char	*ibufp;
int	icnt;
int	ocnt;
getchar()
{

	if(icnt == 0) {
		icnt = read(0, ibuf, 512);
		if(icnt <= 0)
			return(-1);
		ibufp = ibuf;
	}
	icnt --;
	return(*ibufp++ & 0377);
}

putchar(c)
{

	obuf[ocnt++] = c;
	if(ocnt >= 512)
		flush();
}

flush()
{

	if(ocnt > 0)
		write(1, obuf, ocnt);
	ocnt = 0;
}
