#include "includes.h"

/************************************************************************
 * __xRC4 - RC4 encryption function, By X-N2O
 * Date: 26.02.2009 13:57
 * Do not remove this comment if you use this function
 * RC4 is a symmetric cipher created by Ronald Rivest in 1987.
 * __xRC4 is the implemented version of RC4 in C, by X-N2O
 * RC4 is simple, yet very powerful. You can customize the Substitution
 * Box's (or S-Box's) size, to every value you want, smaller than
 * size_t's size. The default is 256. The S-Box is initialized to the
 * identity permutation. S[0] = 0, S[1] = 1... S[i] = i. Then it is
 * randomized through this operation: 
 * j = (j + _S[i] + key[i % keyLen]) % _sSize;
 * __xswap(S[i], S[j]);
 * Then for each character of the input:
 * i = (i + 1) % _sSize;
 * j = (j + _S[i]) % _sSize;
 * __xswap(S[i], S[j]);
 * ---- Then _S[(_S[i] + _S[j]) % _sSize] is XOR'ed with each of the
 * input characters.
 * Returns 0 if __inp is NULL or it's length is 0; if __outp is NULL;
 * if key is NULL or if it's length is 0; if _sSize is smaller than 2
 * and if the S-Box's allocation of _sSize bytes returns NULL (fails).
 * Returns 1 on success.
 * NOTE: There is a possible buffer overflow if __outp's size is smaller
 * than __inp's length + 1.
 * Encryption speeds tested are < 1 - 15 ms for < 422200 bytes of _sSpeed
 * and 234 ms for 1 million bytes (1000000).
 ** Tested with a 41 byte key and 77 byte plaintext in a Pentium 4 2,4 GHz
 ** machine. RAM type: DDR.
 * Decryption speeds are the same since it is symmetric.
 * This is very fast, given one million bytes for the S-Box, 234 ms is very
 * little. Since the default implementation uses 256 bytes... This is VERY
 * fast and more secure.
 ************************************************************************/
char __xRC4(const unsigned char *__inp,	//The input data to encrypt/decrypt, must not be NULL
			unsigned char *__outp,		//The output buffer, must not be NULL, size must be at least strlen(__inp) + 1
			const unsigned char *key)	//The encryption/decryption key, must not be NULL, must be > 0 characters
{
	unsigned char *_S;
	unsigned int i, j;
	size_t __inpLen, keyLen;
	const size_t _sSize = 256;	//Substitution Box size, must be > 1

	if(__inp == NULL
		|| __outp == NULL
		|| key == NULL
		|| _sSize < 2
		|| (__inpLen = strlen(__inp)) == 0
		|| (keyLen = strlen(key)) == 0)
		return 0;
	if((_S = malloc(_sSize)) == 0)
		return 0;
	for(i = 0; i < _sSize; i++)
		_S[i] = i;
	for(i = j = 0; i < _sSize; i++) {
		j = (j + _S[i] + key[i % keyLen]) % _sSize;
		__xswap(_S[i], _S[j]);
	}
	i = j = 0;
	while(*__inp) {
		i = (i + 1) % _sSize;
		j = (j + _S[i]) % _sSize;
		__xswap(_S[i], _S[j]);
		*__outp++ = _S[(_S[i] + _S[j]) % _sSize] ^ *__inp++;
	}
	*__outp = 0;
	free(_S);
	return 1;
}

/************************************************************************
 * __xtoc function, by X-N2O
 * Date: 26.02.2009 15:50
 * Do not remove this comment if you use the function
 * Converts hex char bytes into 8 bit characters (char's).
 * For example: Given the string "41" inputed as 'h', the function writes
 * the string "A" in c.
 ************************************************************************/
void __xhtoc(unsigned char *h, unsigned char *c)
{
	size_t st_shift = 0;

	if(!h || !c || h == c)
		return;
	while(1) {
		if(sscanf(h + st_shift, "%02X", c + st_shift / 2) <= 0)
			break;
		st_shift += 2;
	}
	*(c + st_shift / 2) = 0;
}

/************************************************************************
 * __xctoh function, by X-N2O
 * Date: 26.02.2009 15:50
 * Do not remove this comment if you use the function
 * Converts 8 bit characters (char's) into hex char bytes.
 * For example: Given the string "A" inputed as 'c', the function writes
 * the string "41" in h.
 ************************************************************************/
void __xctoh(unsigned char *c, unsigned char *h)
{
	size_t st_shift = 0;

	if(!c || !h || c == h)
		return;
	while(*c) {
		sprintf(h + st_shift, "%02X", *c++);
		st_shift += 2;
	}
	*(h + st_shift) = 0;
}

/************************************************************************
 * __xrot13 function, by X-N2O
 * Date: 26.02.2009 15:58
 * Do not remove this comment if you use the function
 * Rotates alphabet characters by 13.
 * For example: A becomes N, B becomes O, C becomes P etc...
 * If the character >= 13 + 'A'/'a', the modulo operation % 26
 * makes it go from the beginning, so N becomes A, O becomes B and so on.
 ************************************************************************/
void __xrot13(unsigned char *__io)
{
	if(!__io)
		return;
	while(*__io) {
		if(isalpha(*__io)) {
			if(isupper(*__io))
				*__io = ((*__io - 'A' + 13) % 26) + 'A';
			else
				*__io = ((*__io - 'a' + 13) % 26) + 'a';
		}
		__io++;
	}
}

int main()
{
	//Testing with wikipedia's first test vector: http://en.wikipedia.org/wiki/RC4#Test_vectors
	unsigned char _key[] = "Key";
	unsigned char _input[] = "Plaintext";
	unsigned char _output[10]; //Length of _input + 1 for the null terminator
	unsigned char _hex_output[18]; //Length of _input * 2 + 1 for the null terminator

	printf("Key: \"%s\"\n"
		"Plaintext: \"%s\"\n",
		_key, _input);
	if(__xRC4(_input, _output, _key) == 0) {
		fprintf(stderr, "__xRC4 failed.\n");
		getchar();
		return 1;
	} else {
		__xctoh(_output, _hex_output);
		printf("__xRC4 succeed.\n"
			"Ciphertext: \"%s\"\n"
			"Ciphertext in hex: %s\n",
			_output, _hex_output);
	}
	getchar();
	return 0;
}