/*
 *	ENCRYPTER
 *	By Jeremy Lennert
 *	February 13, 2001
 *	v. 2.0
 *	
 *	encrypt.cpp
 *
 *	Encrypts a block of text loaded from file by one of several
 *	encryption algorithms, using a random key
 *	
 *	Input plaintext: plaintext.txt
 *	Output ciphertext: ciphertext.txt
 */

// COMPILER DIRECTIVES
#include <assert.h>
#include <fstream.h>
#include <stdlib.h>
#include <time.h>

// FUNCTION DEFINITIONS

int main()
{
	ifstream plain;
	ofstream cipher, key;
	unsigned char thischar;
	int type;
	unsigned char ckey;
	unsigned char skey[256];
	long int t;

	srand(time(&t));

	plain.open("plaintext.txt", ifstream::binary | ofstream::out);
	assert(!plain.fail());
	cipher.open("ciphertext.txt", ifstream::binary | ofstream::out);
	assert(!cipher.fail());
	key.open("key.txt");
	assert(!key.fail());

	cout << "Which encryption method should be used?\n"
		<< "  1. XOR\n"
		<< "  2. shift\n"
		<< "  3. substitution\n"
		<< "  0. random!\n";
	cin >> type;
	if (!type) type = (rand() % 3) + 1;
	cout << "Encrypting . . . ";

	switch(type)
	{
	case 1:	// XOR
		ckey = rand() % 256;
		while (true)
		{
			thischar = plain.get();
			if (plain.eof()) break;	// Make sure thischar isn't EOF
			thischar = thischar ^ ckey;
			cipher << thischar;
		}
		key << "XOR Key:\n\n^ " << (int)ckey;
		break;
	case 2:	// shift
		ckey = rand() % 256;
		while (true)
		{
			thischar = plain.get();
			if (plain.eof()) break;	// Make sure thischar isn't EOF
			thischar = (thischar + ckey) % 256;
			cipher << thischar;
		}
		key << "Shift Key:\n\n+ " << (int)ckey;
		break;
	case 3:	// substitution
		int x, y, z;
		for (x = 0; x < 256; x++) skey[x] = x;
		for (x = 0; x < 256; x++)	// Shuffle key table
		{
			y = rand() % 256;
			z = skey[x];
			skey[x] = skey[y];
			skey[y] = z;
		}
		while (true)
		{
			thischar = plain.get();
			if (plain.eof()) break;	// Make sure thischar isn't EOF
			thischar = skey[thischar];
			cipher << thischar;
		}

		key << "Substitution Key:\n  PLAIN | CIPHER\n";
		for (x = 0; x < 256; x++)
		{
			if (!skey[x]) continue;

			if ((x >= 33) && (x <= 126))	// Printable character
			{
				key << (char)x;	// Output ciphertext char
			}
			else
			{
				key << '\0';
			}

			key << " (";

			if (x < 100) key << ' ';	// Add spaces if less than 3 digits
			key << x;	// Output ASCII
			if (x < 10) key << ' ';

			key << ") = ";

			if ((skey[x] >= 33) && (skey[x] <= 126))	// Printable character
			{
				key << (char)(skey[x]);	// Output Decryption
			}
			else
			{
				key << '\0';
			}

			key << " (";

			if (skey[x] < 100) key << ' ';	// Add spaces if less than 3 digits
			key << (int)(skey[x]);	// Output ASCII
			if (skey[x] < 10) key << ' ';

			key << ")\n";
		}
		break;
	}
	cout << "done.\n";

	plain.close();
	cipher.close();
	key.close();

	return 0;
}