/*
 * simple.c
 *
 * Single block encryption, and ensuing decryption.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include <twofish.h>

#define INDATA "tre fula fiskar "

#ifndef FIXEDKEYSTR
#  define FIXEDKEYSTR "fisker"
#endif

void to_hex(char hex[2], int ch) {
	char nibble = ch & 0x0f;

	hex[0] = '0' + nibble;
	if ( nibble > 0x09 )
		hex[0] += 'a' - '0' - 0x0a;

	nibble = ch >> 4;
	hex[1] = '0' + nibble;
	if ( nibble > 0x09 )
		hex[1] += 'a' - '0' - 0x0a;

	return;
}

int main(int argc, char * argv[]) {
	int keylen, j, rounds = 1, failures = 0;
	int first_time = 1;
	char hex[2];
	Twofish_Byte key[32];
	Twofish_key xkey;
	Twofish_Byte inblock[16], intermediary[16], outblock[16];

#ifndef FIXEDKEY 
	const int multiple = sizeof(key) / sizeof(long int);
	long int seed;

	keylen = multiple * sizeof(long int);
#endif

	j = 1;

	while ( j < argc ) {
		if ( strcmp(argv[j], "-h") == 0 ) {
#ifndef FIXEDKEY
			printf("Usage:  %s [runs]\n\t%s -h\n\n"
					"Here 'runs' is the desired number of"
					" encryption rounds.\n"
					"Maximum is set to 50 rounds.\n",
					argv[0], argv[0]);
#else
			printf("Usage:  %s\n\t%s -h\n\n",
					argv[0], argv[0]);
#endif
			return 0;
		}
		rounds = atoi(argv[j]);
		if (rounds < 1)
			rounds = 1;
		else if (rounds > 50)
			rounds = 50;
		j++;
	}

	srandom(time(NULL));

	Twofish_initialise();

	memset(key, 0, sizeof(key));

	memset(inblock, 0, sizeof(inblock));
	memcpy(inblock, INDATA, sizeof(inblock));

	failures = rounds;

	while ( rounds ) {
#if FIXEDKEY
		memcpy(key, FIXEDKEYSTR, sizeof(FIXEDKEYSTR));
		/* Override values. */
		keylen = sizeof(FIXEDKEYSTR);
		rounds = 1;
		failures = rounds;
#else
		for (j=0; j < multiple; j++) {
			seed = random();
			memcpy(key + j * sizeof(seed), &seed, sizeof(seed));
		}
#endif

		Twofish_prepare_key(key, keylen, &xkey);

		Twofish_encrypt(&xkey, inblock, intermediary);
		Twofish_decrypt(&xkey, intermediary, outblock);

		if ( first_time ) {
			printf("Called for %d rounds. "
					"Intermediary blocks:\n\t", rounds);
			first_time = 0;
		} else
			printf("\t");

		for (j=0; j<16; j++) {
			to_hex(hex, intermediary[j]);
			printf("%c%c", hex[1], hex[0]);
		}
		printf("\n");

		/* Check if successful crypto-action. */
		if ( memcmp(inblock, outblock, sizeof(inblock)) == 0 )
			failures--;

		rounds--;
	}

	if ( failures == 0 ) {
		puts("\nEncryption was reversible. Luckily!");
		return 0;
	} else {
		printf("\nFailure: %d failures between encryption and decryption!",
				failures);
		return 1;
	}
}

