/************************************************************************
 *   IRC - Internet Relay Chat, src/rc4.c
 *   Copyright (C) 2000 Lucas Madar
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: rc4.c,v 1.3 2005/07/05 03:17:53 sheik Exp $ */

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

#include "memcount.h"

/*
 * Transparent rc4 implementation
 * Based upon sample in crypto++ library,
 * which was based upon an anonymous usenet posting.
 * Implemented by Lucas Madar <lucas@dal.net>
 *
 * Remember that it is IMPERITAVE to generate a new key
 * for each state. DO NOT USE THE SAME KEY FOR ANY TWO STATES.
 */

typedef unsigned char RC4BYTE;
typedef unsigned int RC4DWORD;

struct rc4_state
{
    RC4BYTE mstate[256];
    RC4BYTE x;
    RC4BYTE y;
};

void *rc4_initstate(unsigned char *key, int keylen)
{
   RC4DWORD i;
   RC4BYTE tmp, idx1, idx2;
   struct rc4_state *rc4;
   
   if(sizeof(RC4BYTE) != 1)  abort(); /* MUST BE 1 BYTE! */
   if(sizeof(RC4DWORD) != 4) abort(); /* MUST BE 4 BYTES! */
   
   rc4 = (struct rc4_state *) MyMalloc(sizeof(struct rc4_state));
   memset(rc4, 0, sizeof(struct rc4_state));
   
   for(i = 0; i < 256; i++) /* initialize our state array */
       rc4->mstate[i] = (RC4BYTE) i;
   
   for(i = 0, idx1 = idx2 = 0; i < 256; i++)
   {
       idx2 = (key[idx1++] + rc4->mstate[i] + idx2);
       
      tmp = rc4->mstate[i];
      rc4->mstate[i] = rc4->mstate[idx2];
      rc4->mstate[idx2] = tmp;
      
      if(idx1 >= keylen)
	  idx1 = 0;
   }
   
   return (void *) rc4;
}

void rc4_process_stream(void *rc4_context, unsigned char *istring,
			unsigned int stringlen)
{
    struct rc4_state *rc4 = (struct rc4_state *) rc4_context;
    RC4BYTE *s = rc4->mstate;
    RC4DWORD x = rc4->x, y = rc4->y;
    
    while(stringlen--)
    {
	RC4DWORD a, b;
	
	x = (x+1) & 0xFF;
	a = s[x];
	y = (y+a) & 0xFF;
	b = s[y];
	s[x] = b;
	s[y] = a;
	*istring++ ^= s[(a + b) & 0xFF];
    }
    
    rc4->x = (RC4BYTE) x;
    rc4->y = (RC4BYTE) y;
}

void rc4_process_stream_to_buf(void *rc4_context, 
			       const unsigned char *istring, 
                               unsigned char *ostring, unsigned int stringlen)
{
    struct rc4_state *rc4 = (struct rc4_state *) rc4_context;
    RC4BYTE *s = rc4->mstate;
    RC4DWORD x = rc4->x, y = rc4->y;
    
    while(stringlen--)
    {
	RC4DWORD a, b;
	
	x = (x+1) & 0xFF;
	a = s[x];
	y = (y+a) & 0xFF;
	b = s[y];
	s[x] = b;
	s[y] = a;
	*ostring++ = *istring++ ^ s[(a + b) & 0xFF];
    }
    
    rc4->x = (RC4BYTE) x;
    rc4->y = (RC4BYTE) y;
}

void rc4_destroystate(void *a)
{
    memset(a, 0, sizeof(struct rc4_state));
    MyFree(a);
}

u_long
memcount_rc4(MCrc4 *mc)
{
    mc->file = __FILE__;

    mc->m_rc4state_size = sizeof(struct rc4_state);

    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1