/*
 *  Jail Cell RC4 (Rivest Cipher #4)
 *  Source by Jeremy Lennert
 *  jcrc4.cpp
 *  Wednesday, February 20, 2002
 *
 *  Implements a modified version of the RC4 cipher.
 *
 *  Usage: encrypt with "jcrc4 -e", decrypt with "jcrc4 -d".
 *  Reads stdin, writes stdout.
 *
 *  Requires a key stored in the file key.txt in
 *  the current directory.
 */

/*
 *  CIPHER OPERATION
 *  
 *  Key Schedule:
 *
 *  A permutation table of the numeric values 0-36 is
 *  constructed using a key consisting of 13 letters, numbers,
 *  and periods.  They key values are converted to values in
 *  the range 0-36 with 0=0, 1=1,...A=10, B=11, C=12,...period=36.
 *
 *  The first value in the key (K[0]) becomes the first value inserted
 *  into the permutation table, and it is inserted in the location
 *  corresponding to the second value in the key (K[1]).  The second
 *  value inserted into the permutation table is K[0]+1 (mod 37), and
 *  is inserted into the position of the previous insertion, offset
 *  by the next value of the key (K[2]).  Insertion continues in this
 *  manner (reusing values of the key as necessary) until all 37 values
 *  have been inserted.  If the table position targeted for insertion is
 *  already occupied, the insertion position is offset again by the
 *  same value of the key.
 *
 *
 *  Keystream Generation:
 *
 *  Two counters, i and j, are both initialized to zero.
 *
 *  To output one keystream value (which is in the range 0-36),
 *	i = i + 1 mod 37
 *	j = j + S[i] mod 37
 *	swap the values in S[i] and S[j]
 *	z = S[i] + S[j] mod 37
 *	output S[j]
 *  Where S[x] is the xth value in the permutation table.
 *
 *  Each letter of the plaintext is then shifted by a different
 *  keystream output to encrypt or reverse-shifted to decrypt.
 *
 *  For security reasons, the first 11 keystream outputs are
 *  not used, because they may not be influenced by every
 *  part of the key.
 */

#include <stdio.h>
#include <fstream.h>

int main(int argc, char **argv) {
    FILE* kin;	    // Key in
    int key[13];    // Translated key
    int s[37];	    // Permutation S-Box used for generated keysteam
    int i, j;	    // i and j counters for generating keystream
    unsigned char c;
    int ic;
    int x, z;
    int encrypt;

    if (argc == 2 && !strcmp(argv[1], "-e"))
      encrypt = 1;
    else if (argc == 2 && !strcmp(argv[1], "-d"))
      encrypt = 0;
    else {
      fprintf(stderr, "usage: jcrc4 [-e|-d]\n");
      exit(1);
    }
    /*
     *	Get the key from key.txt
     *	Assume that the key is 13 characters long
     */
    kin = fopen("key.txt", "rb");  // Read untranslated text
    for (x = 0; x < 13; x++) {
	if ( (ic = getc(kin)) == EOF) {
	    fprintf(stderr, "illegal argument: key too short\n");
	    exit(1);
	}
	c = ic;
	if ((c > '0') && (c <= '9')) {
	    key[x] = c - '0';	    // Convert char digits to integers
	}
	else if ((c >= 'A') && (c <= 'Z')) {
	    key[x] = c - 'A' + 10;  // A=10, B=11, C=12, etc.
	}
	else if ((c >= 'a') && (c <= 'z')) {
	    key[x] = c - 'a' + 10;  // a=10, b=11, c=12, etc.
	}
	else if (c == '.') {
	    key[x] = 36;	    // period = 36
	}
	else {
	  fprintf(stderr, "illegal key: invalid key character %c\n", c);
	  exit(1);
	}
    }

    /*
     *	Initialize S-Box using key
     */
    for (x = 0; x < 37; x++) {
	s[x] = -1;	// Slot has not been filled yet
    }
    i = 1;
    j = key[0];
    x = 0;
    while (true) {
	do {
	    x = (x + key[i]) % 37;
	} while (s[x] != -1);	// Until s[x] is empty
	s[x] = j;

	i++;
	if (i > 12) i = 0;
	j++;
	if (j > 36) j = 0;
	if (j == key[0]) break;	// All values (0-36) assigned
    }

    /*
     *	Warm up keystream generator
     *	The first length-2 = 11 outputs need to be
     *	thrown away to ensure all parts of the key
     *	affect all keystream outputs used in encryption
     */
    i = j = 0;
    for (x = 0; x < 11; x++) {
	i++;
	j = (j + s[i]) % 37;

	z = s[i];
	s[i] = s[j];
	s[j] = z;
    }

    /*
     *	Encrypt Message
     */
    while ((ic = getc(stdin)) != EOF) {	// Until end of file
	if ((ic >= '0') && (ic <= '9')) {
	    ic = ic - '0';	// Convert char digits to integers
	}
	else if ((ic >= 'A') && (ic <= 'Z')) {
	    ic = ic - 'A' + 10;  // A=10, B=11, C=12, etc.
	}
	else if ((ic >= 'a') && (ic <= 'z')) {
	    ic = ic - 'a' + 10;  // a=10, b=11, c=12, etc.
	}
	else if (ic == '.') {
	    ic = 36;    // period = 36
	}
	else continue;  // Invalid character for encryption; drop it from message

	i++;
	j = (j + s[i]) % 37;

	z = s[i];
	s[i] = s[j];
	s[j] = z;

	z = (s[i] + s[j]) % 37;

	if (encrypt)
	    ic = (ic + s[z]) % 37;
	else
	    ic = (ic - s[z] + 37) % 37;
	if (ic <= 9) c = ic + '0';		// Numeric Dig