/* The following ARCFour code was extracted from BitchX sources... thanks! */
/*  S-box initialization fixed */
/*  OBTW, take the comment "This cipher is secure, proven," with a grain of salt. */
/*  "easy to impliment, and quite fast."  -- now that's true!  */


/*  ARCFour - a symmetric streaming cipher - Implimentation by Humble
 *
 *  This is a variable-key-length symmetric stream cipher developed in 1987
 *  by Ron Rivest (the R in RSA). It used to be proprietary but was reverse
 *  engineered and released publicly in September 1994. The cipher is now
 *  freely available but the name RC4 is a trademark of RSA Data Security
 *  Inc. This cipher is secure, proven, easy to impliment, and quite fast.
 */

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

typedef unsigned char arcword;		/* 8-bit groups */

typedef struct {
   arcword state[256], i, j;
} arckey;


void arcfourInit(arckey *arc, char *userkey, unsigned short len)
{
	int n;
	register arcword *S = arc->state, x = 0, y = 0, pos = 0, tmp;

	/* Seed the S-box linearly, then mix in the key while stiring briskly */
	arc->i = arc->j = 0;				 /* Initialize i and j to 0 */

	for (n=0; n<256; n++) { S[n]= n; }     /* Initialize S-box */

	/* Note: Some of these optimizations REQUIRE arcword to be 8-bit unsigned */
	do {						 /* Spread user key into real key */
		y += S[x] + userkey[pos];			 /* Keys, shaken, not stirred */
		tmp = S[x]; S[x] = S[y]; S[y] = tmp;  /* Swap S[i] and S[j] */
		if (++pos >= len)	pos = 0;		 /* Repeat user key to fill array */
	} while(++x);				 /* ++x is faster than x++ */
}

char *arcfourCrypt(arckey *arc, char *data, int len)
{
	register arcword *S = arc->state, i = arc->i, j = arc->j, tmp;
	register int c = 0;

	do {
		j += S[++i];				/* Shake S-box, stir well */
		tmp = S[i]; S[i] = S[j]; S[j] = tmp; /* Swap S[i] and S[j] */
		data[c] ^= S[255&(S[i] + S[j])];		/* XOR the crypto into our data */
	} while (++c < len);				/* Neat, ++x is faster then x++ */

	arc->i = i;					/* Save modified i and j counters */
	arc->j = j;					/* Continue where we left off */
	return data;					/* Return pointer to ciphertext */
}

arckey key;
char buf[4096];

int main(int argc, char** argv)
{
    if (argc != 2) {
	fprintf(stderr, "Usage:  $s key <instream >outstream\n" );
	return 2;
    }

    arcfourInit( &key, argv[1], strlen( argv[1] ) );

    while (1) {
	int cc= fread( buf, 1, sizeof buf, stdin );
	if (cc<1) break;

	arcfourCrypt( &key, buf, cc );

	fwrite( buf, 1, cc, stdout );
    }
	
    fflush(stdout);
    return 0;
}
