/*******************************************************************************
*
* arc4.c -- a simple ARC4 implementation
* by timdoug -- timdoug@gmail.com -- http://www.timdoug.com -- 2008-07-08
* see http://en.wikipedia.org/wiki/RC4
*
********************************************************************************
*
* Copyright (c) 2008, timdoug(@gmail.com) -- except for the encryption algorithm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * The name of the author may not be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY timdoug ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL timdoug BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
********************************************************************************
*
* the encryption algorithm is unchanged (except for whitespace) from:
* http://cypherpunks.venona.com/date/1994/09/msg00304.html
* I have no idea about its copyright status or viability....
*
* compile with:
* gcc -Wall -Werror -pedantic -ansi -g -O2 arc4.c -o arc4
*
* some example timings/usage (Mac OS X 10.5, MacBook Pro, 2.4GHz Core 2 Duo):
* $ time ./arc4 mykey <ubuntu.iso >ubuntu.iso.enc
* real	0m24.446s
* user	0m10.512s
* sys	0m4.294s
* $ time ./arc4 mykey <ubuntu.iso.enc >ubuntu.iso.out
* real	0m43.177s
* user	0m11.782s
* sys	0m4.793s
* $ md5 ubuntu.iso ubuntu.iso.out
* MD5 (ubuntu.iso) = b78ef719e3361e726b89bab78c526ad0
* MD5 (ubuntu.iso.out) = b78ef719e3361e726b89bab78c526ad0
*
*******************************************************************************/

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

#define BLOCK_SIZE 256

typedef struct rc4_key {
	unsigned char state[256];
	unsigned char x;
	unsigned char y;
} rc4_key;

void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key);
void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key);
static void swap_byte(unsigned char *a, unsigned char *b);

int main(int argc, char *argv[])
{
	unsigned char buf[BLOCK_SIZE];
	rc4_key key;
	size_t len;
	
	if (argc != 2) {
		printf("usage: %s enckey <infile >outfile\n", argv[0]);
		exit(-1);
	}
	
	prepare_key((unsigned char *)argv[1], strlen(argv[1]), &key);
	
	do {
		rc4(buf, (len = fread(buf, 1, BLOCK_SIZE, stdin)), &key);
		fwrite(buf, 1, len, stdout);
	} while (len != 0);
	
	return 0;
}

void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key)
{
	unsigned char index1;
	unsigned char index2;
	unsigned char *state;
	short counter;
	
	state = &key->state[0];
	
	for (counter = 0; counter < 256; counter++)
		state[counter] = counter;
	
	key->x = 0;     
	key->y = 0;     
	index1 = 0;     
	index2 = 0;             
	
	for (counter = 0; counter < 256; counter++) {               
		index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
		swap_byte(&state[counter], &state[index2]);
		index1 = (index1 + 1) % key_data_len;
	}
}

void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key)
{ 
	unsigned char x;
	unsigned char y;
	unsigned char *state;
	unsigned char xorIndex;
	short counter;
	
	x = key->x;
	y = key->y;
	state = &key->state[0];
	
	for (counter = 0; counter < buffer_len; counter++) {
		x = (x + 1) % 256;
		y = (state[x] + y) % 256;
		swap_byte(&state[x], &state[y]);
		xorIndex = state[x] + (state[y]) % 256;
		buffer_ptr[counter] ^= state[xorIndex];
	}
	
	key->x = x;
	key->y = y;
}

static void swap_byte(unsigned char *a, unsigned char *b)
{
	unsigned char swapByte;
	
	swapByte = *a;
	*a = *b;
	*b = swapByte;
}
