// DES Encyption CLI
// Scott Dial
// Copyright 2004

#include <stdio.h>
#include <string.h>
#include <des.h>

#define SAFE_FREE(a) if(a != NULL) { free(a); a = NULL; }

#ifndef stricmp
	#include <ctype.h>

	int stricmp(const char *s1, const char *s2)
	{
	    while(toupper(*s1++) == toupper(*s2++))
	        if(*s1 == '\0' && *s2 == '\0')
	            return 0;
	    if(toupper(*s1) < toupper(*s2))
	        return -1;
	    else
	        return 1;
	}
#endif

char *str2key(char *key, const char *str, int width)
{
	int n;
	
	for(n = 0; n < (width/2); n++)
	{
		if(str[2*n] >= 'A')
			key[n] = (str[2*n] - 'A' + 10) * 16;
		else
			key[n] = (str[2*n] - '0') * 16;

		if(str[2*n+1] >= 'A')
			key[n] += (str[2*n+1] - 'A' + 10);
		else
			key[n] += (str[2*n+1] - '0');
	}

	return key;
}

size_t pad_8(char **out, const char *in, size_t len)
{
	size_t newlen;

	if(len % 8 > 0)
		newlen = ((len / 8) + 1) * 8;
	else
		newlen = len;

	(*out) = (char *) malloc(newlen);

	memcpy((*out), in, len);
	memset((*out)+len, 0, newlen-len);

	return newlen;
}

void usage(void)
{
	printf(	"Usage: des [-e/-d] [mode] [key in hex] [inputfile] [outputfile]\n"
			"   des -e ECB 0123456789ABCDEF message.txt secret.des\n"
			"   des -d ECB 0123456789ABCDEF secret.des message.txt\n"
			"- or -\n"
			"   des -e CBC 0123456789ABCDEFFEDCBA986543210 message.txt secret.des\n"
			"   des -d ECB 0123456789ABCDEFFEDCBA986543210 secret.des message.txt\n"
			"Modes: ECB, CBC, CFB, OFB, CTR\n");
	exit(-1);
}

int main(int argc, char *argv[])
{
	int action;
	int mode;
	char key[16];
	FILE *infile, *outfile;
	char *in, *padin = NULL, *out;
	size_t read, padlen;

	if(argc < 6)
		usage();

	if(stricmp(argv[1], "-E") == 0)
		action = DES_ENCRYPT;
	else if(stricmp(argv[1], "-D") == 0)
		action = DES_DECRYPT;
	else
		usage();

	if(stricmp(argv[2], "ECB") == 0)
		mode = DES_ECB;
	else if(stricmp(argv[2], "CBC") == 0)
		mode = DES_CBC;
	else if(stricmp(argv[2], "CFB") == 0)
		mode = DES_CFB;
	else if(stricmp(argv[2], "OFB") == 0)
		mode = DES_OFB;
	else if(stricmp(argv[2], "CTR") == 0)
		mode = DES_CTR;
	else
		usage();

	if(strlen(argv[3]) != (mode == DES_ECB ? 16 : 32))
		usage();

	str2key(key, argv[3], (mode == DES_ECB ? 16 : 32));

	infile = fopen(argv[4], "rb");
	if(infile == NULL)
	{
		printf("Error opening input file!\n");
		usage();
	}

	outfile = fopen(argv[5], "wb");
	if(outfile == NULL)
	{
		printf("Error opening output file!\n");
		usage();
	}

	in = (char *) malloc(4096);
	if(in == NULL)
	{
		printf("Error grabbing enough memory!\n");
		exit(-1);
	}

	while((read = fread(in, 1, 4096, infile)) > 0)
	{
		if(mode == DES_ECB || mode == DES_CBC || mode == DES_CTR)
		{
			padlen = pad_8(&padin, in, read);
		} else {
			padlen = read;
		}
		out = (char *) malloc(padlen);

		if((padlen != read && padin == NULL) || out == NULL)
		{
			printf("Error grabbing enough memory!\n");
			exit(-1);
		}

		if(mode == DES_ECB || mode == DES_CBC || mode == DES_CTR)
			des(out, padin, padlen, key, action, mode);
		else
			des(out, in, read, key, action, mode);

		fwrite(out, 1, padlen, outfile);

		free(out);
		SAFE_FREE(padin);
	}

	fclose(infile);
	fclose(outfile);

	free(in);

	printf("Done!\n");
	return 0;
}
