/*	$NetBSD: arc4.c,v 1.6 2005/12/11 12:20:48 christos Exp $	*/

/*
 * ARC4 implementation
 *	A Stream Cipher Encryption Algorithm "Arcfour"
 *	<draft-kaukonen-cipher-arcfour-03.txt>
 */

/*        This code illustrates a sample implementation
 *                 of the Arcfour algorithm
 *         Copyright (c) April 29, 1997 Kalle Kaukonen.
 *                    All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that this copyright
 * notice and disclaimer are retained.
 *
 * THIS SOFTWARE IS PROVIDED BY KALLE KAUKONEN AND CONTRIBUTORS ``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 KALLE
 * KAUKONEN OR CONTRIBUTORS 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: arc4.c,v 1.6 2005/12/11 12:20:48 christos Exp $");

#include <sys/types.h>

#include <crypto/arc4/arc4.h>

struct arc4_ctx {
	unsigned int	x;
	unsigned int	y;
	unsigned int	state[256];
	/* was unsigned char, changed to int for performance -- onoe */
};

int
arc4_ctxlen(void)
{
	return sizeof(struct arc4_ctx);
}

void
arc4_setkey(void *ctxp, const u_char *key, u_int keylen)
{
	struct arc4_ctx *ctx = ctxp;
	unsigned int i, t, u, ki, si;
	unsigned int *state;

	state = ctx->state;
	ctx->x = 0;
	ctx->y = 0;
	for (i = 0; i < 256; i++)
	       state[i] = i;
	ki = si = 0;
	for (i = 0; i < 256; i++) {
		t = state[i];
		si = (si + key[ki] + t) & 0xff;
		u = state[si];
		state[si] = t;
		state[i] = u;
		if (++ki >= keylen)
			ki = 0;
	}
}

void
arc4_encrypt(void *ctxp, u_char *dst, const u_char *src, int len)
{
	struct arc4_ctx *ctx = ctxp;
	unsigned int x, y, sx, sy;
	unsigned int *state;
	const unsigned char *endsrc;

	state = ctx->state;
	x = ctx->x;
	y = ctx->y;
	for (endsrc = src + len; src != endsrc; src++, dst++) {
		x = (x + 1) & 0xff;
		sx = state[x];
		y = (sx + y) & 0xff;
		state[x] = sy = state[y];
		state[y] = sx;
		*dst = *src ^ state[(sx + sy) & 0xff];
	}
	ctx->x = x;
	ctx->y = y;
}

void
arc4_decrypt(void *ctxp, u_char *dst, const u_char *src, int len)
{

	arc4_encrypt(ctxp, dst, src, len);
}
