/* Encrypt/decrypt command compatible with Sun's "des" command */
#include <stdio.h>
#ifdef DOS
#define readone(A)  getc(A)
#define writeone(c,A) putc(c,A)
    FILE		*disk_file;
    FILE		*disk_file2;
#endif

#ifdef UNIX
#include <ctype.h>
#define readone(A)  getc(A)
#define writeone(c,A) putc(c,A)
    FILE		*disk_file;
    FILE		*disk_file2;
#endif

#ifdef VAXC
    char		readone();
    int			disk_file;
    int			disk_file2;
#endif

    int			char_cnt=0;
    char		iv[8];	/* Initial vector for CBC mode */
    int			block;
    char 		h[16] = {'0','1','2','3','4','5','6','7','8'
				,'9','A','B','C','D','E','F'};

main(argc,argv)
    int 		argc;
    char 		*argv[];
{
	int 		c,cnt,encrypt,decrypt;
	register int 	i;
	char 		key[8],tkey1[8],tkey2[8],*akey,mode,xchar,*getkey();

    
    if (argc < 3)
      {
        printf("Usage:  CRYPT <infile> <outfile>\n");
        return;
      }
    openfiles(argv,&disk_file,&disk_file2);

    block = encrypt = decrypt = 0;
    akey = NULL;
    desinit(0);

    if(akey == NULL){
	/* No key on command line, prompt for it */
	memset(tkey1,0,8);
	memset(tkey2,0,8);
	for(;;){
		printf(" Enter key: ");
		memcpy(tkey1,getkey(),8);
		printf("\n Enter key again: ");
		memcpy(tkey2,getkey(),8);
		printf("\n");
		if(memcmp(tkey1,tkey2,8) != 0){
			fprintf(stderr,"Key mistyped, try again\n");
		} else
			break;
		}
		akey = tkey1;
	}
	/* Set up key, determine parity bit */
	strncpy(key,akey,8);
	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;
	}
	setkey(key);

    do 
	{
        printf("\n%s","Encrypt or Decrypt?  ");
        xchar = getchar();
	mode =(char) toupper((int)xchar);}
    while ((mode != 'D') && (mode != 'E'));

    if (mode == 'D'){
	decrypt++;}
    else if (mode == 'E'){
	encrypt++;}


	/* Blot out keys */
	memset(key,0,8);
	memset(tkey1,0,8);
	memset(tkey2,0,8);

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

	if(encrypt){
		doencrypt();
	} else if(decrypt){
		dodecrypt();
	} else {
		printf("Problems see system manager\n");
		exit(1);
	}
    
}
/* Encrypt standard input to standard output */
doencrypt()
{
	char 		work[8],*cp,*cp1;
	int 		cnt,i,j;

	for(;;){
		if((cnt = readdata(work,8,disk_file)) != 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);
		}
		dowrite(work,8,disk_file2);
		if(cnt != 8)
			break;
	}
    writeone('\r',disk_file2);
    writeone('\n',disk_file2);
}
dodecrypt()
{
	char 		work[8],nwork[8],ivtmp[8],*cp,*cp1;
	int 		cnt,i;


	cnt = doread(work,8,disk_file);	/* 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 = doread(work,8,disk_file);
		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)
				write(disk_file2,nwork,cnt);
			exit(1);
		} else {
			/* Now okay to write previous buffer */
			writedata(nwork,8,disk_file2);
		}

	}
}
#ifdef	DEBUG
put8(cp)
	register char 	*cp;
{
	int i;

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

doread(buffer,length,file_ptr)

/* This routine reads in data from the input file, which is expected to be in 
 * HEX format and unHEXes the data before returning it to the calling program.
 * This routine is based on the program  UNHEX by Christine Gianone, 
 * October 20, 1986
 */

#ifdef DOS
    FILE		*file_ptr;
#endif

#ifdef UNIX
    FILE		*file_ptr;
#endif

#ifdef VAXC
    int			file_ptr;
#endif
	int 		length;
	unsigned char 	*buffer;

{
int a,b,c,i,j;
    i = 0;
    while (((a = readone(file_ptr)) != EOF) && (i < length)) {
        if (a == '\n' || a == '\r')   /* Skip newlines & carriage returns */
	  if ((a = readone(file_ptr)) == EOF)
	    break;
	    if (a == '\n' || a == '\r')   /* Skip newlines & carriage returns */
	  if ((a = readone(file_ptr)) == EOF)
	    break;
        if((b = readone(file_ptr)) == EOF)	/* Get second hex nibble */
	  break;			/* get out of the while loop */
	if(a >= '0' && a <= '9')
	  a -= 0x30;			/* a = a - 30 hex */
	else if(a >='A' && a <= 'F' )
	  a -= 0x37;			/* a = a - 37 */

	if(b >= '0' && b <= '9')
	  b -= 0x30;			
	else if(b >='A' && b <= 'F' )
	  b -= 0x37;			

	buffer[i] = ((a * 16) & 0xF0) + (b & 0xF);
	i++;
	if (i>=length) 
	  break;
        }
#ifdef DEBUG 
   for(j=0;j<i;j++)
	{ printf(" buffer[%d] = %d \n",j,buffer[j]); }
   printf(" returning i = %d \n",i);
#endif
   return(i);
}        

dowrite(buffer,length,file_ptr)
/* This routine takes the encrypted buffer and outputs in HEX format.
 * This routine is based on HEX.C by Christine Gianone October 20, 1986
 */

#ifdef DOS
    FILE		*file_ptr;
#endif

#ifdef UNIX
    FILE		*file_ptr;
#endif

#ifdef VAXC
    int			file_ptr;
#endif
	unsigned char 	*buffer;
	int 		length;

{
int a,b,c,i,j;

    i = 0;
#ifdef DEBUG 
   for(j=0;j<length;j++)
	{ printf(" buffer[%d] = %d \n",j,buffer[j]); }
#endif
    while (i < length) {
        c = buffer[i++]; 
	b = c & 0xF;
	a = c / 16;
	writeone(h[a],file_ptr);
        writeone(h[b],file_ptr);
	char_cnt += 2;
	if (char_cnt == 72) {
	    writeone('\r',file_ptr);
	    writeone('\n',file_ptr);
	    char_cnt = 0;
        }
    }
}

readdata(buffer,length,file_ptr)

#ifdef DOS
    FILE		*file_ptr;
#endif

#ifdef UNIX
    FILE		*file_ptr;
#endif

#ifdef VAXC
    int			file_ptr;
#endif
	int 		length;
	unsigned char 	*buffer;

{
int a,b,c,i,j;
    i = 0;
    while (((a = readone(file_ptr)) != EOF) && (i < length)) {
	buffer[i] = a;
	i++;
	if (i>=length) 
	  break;
        }
#ifdef DEBUG 
   for(j=0;j<i;j++)
	{ printf(" buffer[%d] = %d \n",j,buffer[j]); }
   printf(" returning i = %d \n",i);
#endif
   return(i);
}        

writedata(buffer,length,file_ptr)

#ifdef DOS
    FILE		*file_ptr;
#endif

#ifdef UNIX
    FILE		*file_ptr;
#endif

#ifdef VAXC
    int			file_ptr;
#endif
	int 		length;
	unsigned char 	*buffer;

{
int i;
    i = 0;
    while (i < length) {
	writeone(buffer[i],file_ptr);
	i++;
        }
}        
