#include <stdio.h>
#ifdef HASSTDLIB
#include <stdlib.h>
#else
#include <sys/types.h>
#endif
#include <string.h>
#ifdef	__MSDOS__
#include <dos.h>
#else	/* Assume BSD unix */
#include <fcntl.h>
#include <sgtty.h>
#endif
#include "md4.h"
#include "des.h"
#include "skey.h"

#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
 || defined(vax) || defined (MIPSEL) || defined(i386))
#define	LITTLE_ENDIAN	/* Low order bytes are first in memory */
#endif			/* Almost all other machines are big-endian */

extern	char	*getenv();

/* Crunch a key:
 * DES decrypt the user's pad file and then crank it through MD4 and
 * collapse to 64 bits. This is defined as the user's starting key.
 * mjr@tis.com
 */
int
deskeycrunch(result,seed,passwd)
char *result;	/* 8-byte result */
char *seed;	/* Seed, any length */
char *passwd;	/* Password, any length */
{
	MDstruct md;
	char *padfile;
	char desobuf[BUFSIZ];
	char desibuf[BUFSIZ];
	des_key_schedule ks;
	des_cblock kk;
	char iv[8];
	FILE *desfd;
	int i;

	if((padfile = getenv("SKEYPADFILE")) == (char *)0) {
		fprintf(stderr,"No SKEYPADFILE in environment\n");
		return(-1);
	}

	if((desfd = fopen(padfile,"r")) == (FILE *)0) {
		perror(padfile);
		return(-1);
	}

	des_string_to_key(passwd,kk);
	des_set_key(kk,ks);
	bzero(passwd,strlen(passwd));
	bzero(kk,sizeof(kk));
	bzero(iv,sizeof(iv));

	/* decrypt our pad file and MD5 it */
	MDbegin(&md);
	while((i = fread(desibuf,1,64,desfd)) >= 8) {
		if(i % 8 != 0)
			i = i - (i % 8);
		des_cbc_encrypt(desibuf,desobuf,i,ks,iv,DES_DECRYPT);
		MDupdate(&md,(unsigned char *)desobuf,8 * i);
	}
	fclose(desfd);
	if(i < 0) {
		perror("read");
		return(-1);
	}

	/* Fold result from 128 to 64 bits */
	md.buffer[0] ^= md.buffer[2];
	md.buffer[1] ^= md.buffer[3];

#ifdef	LITTLE_ENDIAN
	/* Only works on byte-addressed little-endian machines!! */
	memcpy(result,(char *)md.buffer,8);
#else
	/* Default (but slow) code that will convert to
	 * little-endian byte ordering on any machine
	 */
	for(i=0;i<2;i++){
		register long tmp;
		tmp = md.buffer[i];
		*result++ = tmp;
		tmp >>= 8;
		*result++ = tmp;
		tmp >>= 8;
		*result++ = tmp;
		tmp >>= 8;
		*result++ = tmp;
	}
#endif
	return 0;
}
