//
//crypt-a4.c
//
//Implements the ARCFOUR (Alleged RC-4) encyption method.
//
//
//-UserX 2001/12/09

#include <string.h>
#include "crypt/arcfour.h"
#include "base/mem.h"

#define SWAP(x, y) {x ^= y; y ^= x; x ^= y;}

ArcfourContext *arcfourMake(void) {
	ArcfourContext *a4 = memAlloc(sizeof(ArcfourContext), "ARC4", NULL);//ximalloc(sizeof(ArcfourContext));
	arcfourReset(a4);
	return a4;
}

void arcfourFree(ArcfourContext *a4) {
	memFree(a4);//xifree(a4);
}

void arcfourReset(ArcfourContext *a4) {
	int i;
	a4->i = 0;
	a4->j = 0;
	for(i = 0; i < 256; i++) {
		a4->S[i] = i;
	}
	a4->ki = 0;
	a4->kj = 0;
	//memset(a4->K, 0, 256);
}

//apply the encryption/decryption
void arcfourCrypt(ArcfourContext *a4, uint8 *buffer, int length) {
	int i;
	for(i = 0; i < length; i++) {
		a4->i = (a4->i + 1) & 0xff;
		a4->j = (a4->j + a4->S[a4->i]) & 0xff;
		SWAP(a4->S[a4->i], a4->S[a4->j]);
		buffer[i] ^= a4->S[(a4->S[a4->i] + a4->S[a4->j]) & 0xff];
	}
}

//generate a buffer of output
void arcfourBuffer(ArcfourContext *a4, uint8 *buffer, int length) {
	//do it the lazy way
	memset(buffer, 0, length);
	arcfourCrypt(a4, buffer, length);
}


//Sets the key.
//note does not reset the context's state before adding the key
void arcfourKey(ArcfourContext *a4, uint8 *buffer, int keylength) {
	int k;
	for(k = 256; k > keylength; k -= keylength) {
		arcfourAddKey(a4, buffer, keylength);
	}
	arcfourAddKey(a4, buffer, k);
}


//Normally called by arcfourKey to do the actual keying of the context
//
//note: Could be used for adding a small amounts of new key material
//after it has keyed normally. The actual security of such key adding
//should be consider suspect.
void arcfourAddKey(ArcfourContext *a4, uint8 *buffer, int keylength) {
	int k;
	for(k = 0; k < keylength; k++) {
		a4->ki = (a4->ki + 1) & 0xff;
		a4->kj = (a4->kj + a4->S[a4->ki] + buffer[k]) & 0xff;
		SWAP(a4->S[a4->ki], a4->S[a4->kj]);
	}
}

