/*
 * debug -- provide a debugging environment for the DES code
 */
/****************************************************************
 * Copyright notice.						*
 * This software is copyrighted (c) 1991 by Matt Bishop and the *
 * Trustees of Dartmouth College.  All rights reserved.		*
 *								*
 * Author:	Matt Bishop					*
 * Address:	Department of Mathematics and Computer Science	*
 *		Dartmouth College				*
 *		Hanover, NH  03755-1831				*
 *		USA						*
 * telephone:	+1 603 646 3267					*
 * fax:		+1 603 646 1312					*
 * internet:	Matt.Bishop@dartmouth.edu			*
 * usenet:	...!decvax!dartvax!Matt.Bishop			*
 ****************************************************************/
 
#ifndef lint
static char *version = "Version GAMMA 6/31/91 Matt.Bishop@dartmouth.edu";
#endif

#include <stdio.h>
#include <ctype.h>

/*
 * The DES works with strings of 64 bits, so we define this type
 * to make things simple.  We assume "unsigned char" is 8 bits; a
 * dangerous assumption, but ...
 */
typedef unsigned char Uchar;

/*
 * for converting to hex digits
 * and recognizing them
 */
char hex[] = "0123456789abcdef";	/* hex digits */
#define ishex(c) (fromhex(c) != -1)	/* 1 if hex digit, 0 if not */

/*
 * the useful variables
 */
Uchar key[8];			/* key */
Uchar instr[8];			/* input message */
Uchar outstr[8];		/* output message */
int unixcrypt = 0;		/* use UNIX library entry point */
int dircrypt = 0;		/* assume encryption */

/* ARGSUSED 2 */
main(argc, argv)
int argc;
char *argv[];
{
	register int c;			/* input char */
	register int i;			/* counter in a for loop */

	/*
	 * if an argument is provided, see what it is
	 */
	for(i = 1; i < argc; i++){
		if (strcmp(argv[1], "-i") == 0)
			dircrypt = 1;
#ifndef ALONE
		else if (strcmp(argv[1], "-u") == 0)
			unixcrypt = 1;
#endif
		else{
#ifdef ALONE
			fprintf(stderr, "Usage: %s [ -i ]\n", argv[0]);
#else ALONE
			fprintf(stderr, "Usage: %s [ -i ] [ -u ]\n", argv[0]);
#endif ALONE
			exit(1);
		}
	}


	/*
	 * announce what this is
	 */
#ifdef ALONE
	unixcrypt = 1;
	printf("DES Testing: 1 bit base, 1 bit path, 1 bit key permutation (UNIX interface)\n");
#else ALONE
	printf("DES Testing: %d bit base, %d bit path, %d permutation key computation",
		des_bits(), des_path(), des_permkey() ? 1 : 3);
	if (unixcrypt)
		printf(" (UNIX interface)");
	putchar('\n');
#endif ALONE

	/*
	 * loop until user ends it all
	 */
	while(!feof(stdin)){
		/*
		 * prompt
		 */
		printf("des debug> "); (void) fflush(stdout);
		/*
		 * grab first char and decide what to do
		 */
		switch(c = getchar()){
		case 's':
			while(getchar() != '\n')
				;
			printf("Status:\n");
			printf("UNIX interface %s\n", unixcrypt ? "on" : "off");
			printf("direction: %scrypting\n",
						dircrypt ? "de" : "en");
			printf("bits per word: %d\n", des_bits());
			printf("width of EPS path (bits) : %d\n", des_path());
			printf("key computation: %d permutations\n",
						des_permkey() ? 1 : 3);
			printf("**********\n");
			prhex("key:     ", key, 1);
			prhex("message: ", instr, 1);
			printf("**********\n");
			break;
		case 'd':
			while(getchar() != '\n')
				;
			dircrypt = 1;
			printf("direction: %scrypting\n",
						dircrypt ? "de" : "en");
			break;
		case 'e':
			while(getchar() != '\n')
				;
			dircrypt = 0;
			printf("direction: %scrypting\n",
						dircrypt ? "de" : "en");
			break;
		case 'h':
			while(getchar() != '\n')
				;
			printf("Help:\n");
			printf("d\t\tchange to decryption mode\n");
			printf("e\t\tchange to encryption mode\n");
			printf("h\t\thelp\n");
			printf("k [key]\t\tchange key\n");
			printf("m [msg]\t\tchange message\n");
			printf("q\t\tquit\n");
			printf("r\t\trun\n");
			printf("s\t\tstatus\n");
			break;
		case EOF:
			putchar('\n');
			/* FALLS THROUGH */
		case 'q':
			exit(0);
		case 'k':
			getline("enter hex key> ", key);
			prhex("key: ", key, 1);
			break;
		case 'm':
			getline("enter hex message> ", instr);
			prhex("message: ", instr, 1);
			break;
		case 'r':
			while(getchar() != '\n')
				;
			rundes();
			prhex("key: ", key, 0);
			prhex(", message: ", instr, 0);
			prhex(", result: ", outstr, 1);
			break;
		default:
			printf("%c: unknown command; type 'h' for help\n", c);
			while(getchar() != '\n')
				;
			break;
		}
	}
		
	/*
	 * bye!
	 */
	exit(0);
}

/*
 * this prints hex numbers
 */
prhex(str, what, nl)
char *str;				/* prefix string */
Uchar what[];				/* what to print */
int nl;					/* add newline */
{
	register int i;			/* counter in a for loop */

	/*
	 * print out the prefix
	 */
	printf("%s", str);

	/*
	 * now the hex value (8 Uchars)
	 */
	for(i = 0; i < 8; i++){
		putchar(hex[(what[i]>>4)&0xf]);
		putchar(hex[(what[i]   )&0xf]);
	}

	/*
	 * add a newline if need be
	 */
	if (nl)
		putchar('\n');
}

/*
 * read in a string and store appropriately
 */
getline(prompt, where)
char *prompt;				/* prompts user for number */
Uchar where[];				/* where to stick it */
{
	register int c;
	register int i;
	int n[16];

	/*
	 * get to hex number
	 */
	do{
		c = getchar();
	} while(c != '\n' && isspace(c));
	while (c == '\n'){
		printf("%s", prompt);
		do{
			c = getchar();
		} while(c != '\n' && isspace(c));
	}

	/*
	 * got string
	 */
	for(i = 0; ishex(c) && i < 16; c = getchar())
		n[i++] = fromhex(c);
	while(i < 16)
		n[i++] = 0;

	/*
	 * convert it
	 */
	for(i = 0; i < 8; i++)
		where[i] = (n[2*i]<<4)|n[2*i+1];

	/*
	 * eat rest of line
	 */
	while(c != '\n' && c != EOF)
		c = getchar();
}

/*
 * return bit value of hex digit
 */
int fromhex(c)
int c;					/* input char */
{
	switch(c){
	case '0':		return(0x0);
	case '1':		return(0x1);
	case '2':		return(0x2);
	case '3':		return(0x3);
	case '4':		return(0x4);
	case '5':		return(0x5);
	case '6':		return(0x6);
	case '7':		return(0x7);
	case '8':		return(0x8);
	case '9':		return(0x9);
	case 'a': case 'A':	return(0xa);
	case 'b': case 'B':	return(0xb);
	case 'c': case 'C':	return(0xc);
	case 'd': case 'D':	return(0xd);
	case 'e': case 'E':	return(0xe);
	case 'f': case 'F':	return(0xf);
	}
	return(-1);
}

/*
 * this calls the des encryption routine
 */
rundes()
{
	register int j;			/* counter in a for loop */
	char exp[64];			/* used to expand Uchars to bits */

	/*
	 * if unix type encryption, need to pass bit arrays
	 */
#ifndef ALONE
	if (unixcrypt){
#endif !ALONE
		/*
		 * expand and set the key
		 */
	        expand(key, exp);
		setkey(exp);
		/*
		 * expand the plaintext and encrypt it
		 */
		expand(instr, exp);
		encrypt(exp, dircrypt);
		/*
		 * turn encrypted text into Uchars
		 */
		compress(exp, outstr);
#ifndef ALONE
	}
	else{
		/*
		 * use the DES algorithms directly
		 */
		for(j = 0; j < 8; j++)
			outstr[j] = instr[j];
		des_schedule(dircrypt);
		des_key(key);
		des_run(outstr);
	}
#endif !ALONE
}

/* === used to provide compatibility with UNIX DES routines (see crypt(3)) === */
/*
 * change from 8 bits/Uchar to 1 bit/Uchar
 */
expand(from, to)
Uchar from[8];			/* 8bit/Uchar string */
char to[64];			/* 1bit/char string */
{
	register int i, j;		/* counters in for loop */

	for(i = 0; i < 8; i++)
		for(j = 0; j < 8; j++)
			to[i * 8 + j] = (from[i]>>(7-j))&01;
}
/*
 * change from 1 bit/char to 8 bits/Uchar
 */
compress(from, to)
char from[64];			/* 1bit/char string */
Uchar to[8];			/* 8bit/Uchar string */
{
	register int i, j;		/* counters in for loop */

	for(i = 0; i < 8; i++){
	 	to[i] = 0;
		for(j = 0; j < 8; j++)
			to[i] = (from[i * 8 + j]<<(7-j))|to[i];
	}
}
