/****************************************************************************
*																			*
*						cryptlib RC4 Encryption Routines					*
*						Copyright Peter Gutmann 1994-2025					*
*																			*
****************************************************************************/

#include "crypt.h"
#if defined( INC_ALL )
  #include "context.h"
  #include "rc4.h"
#else
  #include "context/context.h"
  #include "crypt/rc4.h"
#endif /* Compiler-specific includes */

#ifdef USE_RC4

/* The size of the expanded RC4 keys */

#define RC4_EXPANDED_KEYSIZE	sizeof( RC4_KEY )

/****************************************************************************
*																			*
*								RC4 Self-test Routines						*
*																			*
****************************************************************************/

#ifndef CONFIG_NO_SELFTEST

/* RC4 test vectors from the BSAFE implementation */

static const BYTE testRC4key1[] =
	{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
static const BYTE testRC4plaintext1[] =
	{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
static const BYTE testRC4ciphertext1[] =
	{ 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 };

static const BYTE testRC4key2[] =
	{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
static const BYTE testRC4plaintext2[] =
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const BYTE testRC4ciphertext2[] =
	{ 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 };

static const BYTE testRC4key3[] =
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const BYTE testRC4plaintext3[] =
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const BYTE testRC4ciphertext3[] =
	{ 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A };

#if 0	/* 32-bit key, will fail the key length check */
static const BYTE testRC4key4[] =
	{ 0xEF, 0x01, 0x23, 0x45 };
static const BYTE testRC4plaintext4[] =
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const BYTE testRC4ciphertext4[] =
	{ 0xD6, 0xA1, 0x41, 0xA7, 0xEC, 0x3C, 0x38, 0xDF, 0xBD, 0x61 };
#endif /* 0 */

static const BYTE testRC4key5[] =
	{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
static const BYTE testRC4plaintext5[] =
	{ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
static const BYTE testRC4ciphertext5[] =
	{ 0x75, 0x95, 0xC3, 0xE6, 0x11, 0x4A, 0x09, 0x78,
	  0x0C, 0x4A, 0xD4, 0x52, 0x33, 0x8E, 0x1F, 0xFD,
	  0x9A, 0x1B, 0xE9, 0x49, 0x8F, 0x81, 0x3D, 0x76,
	  0x53, 0x34, 0x49, 0xB6, 0x77, 0x8D, 0xCA, 0xD8,
	  0xC7, 0x8A, 0x8D, 0x2B, 0xA9, 0xAC, 0x66, 0x08,
	  0x5D, 0x0E, 0x53, 0xD5, 0x9C, 0x26, 0xC2, 0xD1,
	  0xC4, 0x90, 0xC1, 0xEB, 0xBE, 0x0C, 0xE6, 0x6D,
	  0x1B, 0x6B, 0x1B, 0x13, 0xB6, 0xB9, 0x19, 0xB8,
	  0x47, 0xC2, 0x5A, 0x91, 0x44, 0x7A, 0x95, 0xE7,
	  0x5E, 0x4E, 0xF1, 0x67, 0x79, 0xCD, 0xE8, 0xBF,
	  0x0A, 0x95, 0x85, 0x0E, 0x32, 0xAF, 0x96, 0x89,
	  0x44, 0x4F, 0xD3, 0x77, 0x10, 0x8F, 0x98, 0xFD,
	  0xCB, 0xD4, 0xE7, 0x26, 0x56, 0x75, 0x00, 0x99,
	  0x0B, 0xCC, 0x7E, 0x0C, 0xA3, 0xC4, 0xAA, 0xA3,
	  0x04, 0xA3, 0x87, 0xD2, 0x0F, 0x3B, 0x8F, 0xBB,
	  0xCD, 0x42, 0xA1, 0xBD, 0x31, 0x1D, 0x7A, 0x43,
	  0x03, 0xDD, 0xA5, 0xAB, 0x07, 0x88, 0x96, 0xAE,
	  0x80, 0xC1, 0x8B, 0x0A, 0xF6, 0x6D, 0xFF, 0x31,
	  0x96, 0x16, 0xEB, 0x78, 0x4E, 0x49, 0x5A, 0xD2,
	  0xCE, 0x90, 0xD7, 0xF7, 0x72, 0xA8, 0x17, 0x47,
	  0xB6, 0x5F, 0x62, 0x09, 0x3B, 0x1E, 0x0D, 0xB9,
	  0xE5, 0xBA, 0x53, 0x2F, 0xAF, 0xEC, 0x47, 0x50,
	  0x83, 0x23, 0xE6, 0x71, 0x32, 0x7D, 0xF9, 0x44,
	  0x44, 0x32, 0xCB, 0x73, 0x67, 0xCE, 0xC8, 0x2F,
	  0x5D, 0x44, 0xC0, 0xD0, 0x0B, 0x67, 0xD6, 0x50,
	  0xA0, 0x75, 0xCD, 0x4B, 0x70, 0xDE, 0xDD, 0x77,
	  0xEB, 0x9B, 0x10, 0x23, 0x1B, 0x6B, 0x5B, 0x74,
	  0x13, 0x47, 0x39, 0x6D, 0x62, 0x89, 0x74, 0x21,
	  0xD4, 0x3D, 0xF9, 0xB4, 0x2E, 0x44, 0x6E, 0x35,
	  0x8E, 0x9C, 0x11, 0xA9, 0xB2, 0x18, 0x4E, 0xCB,
	  0xEF, 0x0C, 0xD8, 0xE7, 0xA8, 0x77, 0xEF, 0x96,
	  0x8F, 0x13, 0x90, 0xEC, 0x9B, 0x3D, 0x35, 0xA5,
	  0x58, 0x5C, 0xB0, 0x09, 0x29, 0x0E, 0x2F, 0xCD,
	  0xE7, 0xB5, 0xEC, 0x66, 0xD9, 0x08, 0x4B, 0xE4,
	  0x40, 0x55, 0xA6, 0x19, 0xD9, 0xDD, 0x7F, 0xC3,
	  0x16, 0x6F, 0x94, 0x87, 0xF7, 0xCB, 0x27, 0x29,
	  0x12, 0x42, 0x64, 0x45, 0x99, 0x85, 0x14, 0xC1,
	  0x5D, 0x53, 0xA1, 0x8C, 0x86, 0x4C, 0xE3, 0xA2,
	  0xB7, 0x55, 0x57, 0x93, 0x98, 0x81, 0x26, 0x52,
	  0x0E, 0xAC, 0xF2, 0xE3, 0x06, 0x6E, 0x23, 0x0C,
	  0x91, 0xBE, 0xE4, 0xDD, 0x53, 0x04, 0xF5, 0xFD,
	  0x04, 0x05, 0xB3, 0x5B, 0xD9, 0x9C, 0x73, 0x13,
	  0x5D, 0x3D, 0x9B, 0xC3, 0x35, 0xEE, 0x04, 0x9E,
	  0xF6, 0x9B, 0x38, 0x67, 0xBF, 0x2D, 0x7B, 0xD1,
	  0xEA, 0xA5, 0x95, 0xD8, 0xBF, 0xC0, 0x06, 0x6F,
	  0xF8, 0xD3, 0x15, 0x09, 0xEB, 0x0C, 0x6C, 0xAA,
	  0x00, 0x6C, 0x80, 0x7A, 0x62, 0x3E, 0xF8, 0x4C,
	  0x3D, 0x33, 0xC1, 0x95, 0xD2, 0x3E, 0xE3, 0x20,
	  0xC4, 0x0D, 0xE0, 0x55, 0x81, 0x57, 0xC8, 0x22,
	  0xD4, 0xB8, 0xC5, 0x69, 0xD8, 0x49, 0xAE, 0xD5,
	  0x9D, 0x4E, 0x0F, 0xD7, 0xF3, 0x79, 0x58, 0x6B,
	  0x4B, 0x7F, 0xF6, 0x84, 0xED, 0x6A, 0x18, 0x9F,
	  0x74, 0x86, 0xD4, 0x9B, 0x9C, 0x4B, 0xAD, 0x9B,
	  0xA2, 0x4B, 0x96, 0xAB, 0xF9, 0x24, 0x37, 0x2C,
	  0x8A, 0x8F, 0xFF, 0xB1, 0x0D, 0x55, 0x35, 0x49,
	  0x00, 0xA7, 0x7A, 0x3D, 0xB5, 0xF2, 0x05, 0xE1,
	  0xB9, 0x9F, 0xCD, 0x86, 0x60, 0x86, 0x3A, 0x15,
	  0x9A, 0xD4, 0xAB, 0xE4, 0x0F, 0xA4, 0x89, 0x34,
	  0x16, 0x3D, 0xDD, 0xE5, 0x42, 0xA6, 0x58, 0x55,
	  0x40, 0xFD, 0x68, 0x3C, 0xBF, 0xD8, 0xC0, 0x0F,
	  0x12, 0x12, 0x9A, 0x28, 0x4D, 0xEA, 0xCC, 0x4C,
	  0xDE, 0xFE, 0x58, 0xBE, 0x71, 0x37, 0x54, 0x1C,
	  0x04, 0x71, 0x26, 0xC8, 0xD4, 0x9E, 0x27, 0x55,
	  0xAB, 0x18, 0x1A, 0xB7, 0xE9, 0x40, 0xB0, 0xC0 };

/* Test vector from the State/Commerce Department */

#if 0	/* 40-bit key, will fail the key length check */
static const BYTE testRC4key6[] =
	{ 0x61, 0x8A, 0x63, 0xD2, 0xFB };
static const BYTE testRC4plaintext6[] =
	{ 0xDC, 0xEE, 0x4C, 0xF9, 0x2C };
static const BYTE testRC4ciphertext6[] =
	{ 0xF1, 0x38, 0x29, 0xC9, 0xDE };
#endif /* 0 */

/* Test the RC4 code against the test vectors from the BSAFE implementation */

CHECK_RETVAL \
static int rc4Test( IN_BUFFER( keySize ) const BYTE *key, 
					IN_LENGTH_SHORT const int keySize,
					IN_BUFFER( length ) const BYTE *plaintext, 
					IN_BUFFER( length ) const BYTE *ciphertext,
					IN_LENGTH_SHORT const int length )
	{
	const CAPABILITY_INFO *capabilityInfo = getRC4Capability();
	CONTEXT_INFO contextInfo;
	CONV_INFO contextData;
	ALIGN_DATA( keyData, RC4_EXPANDED_KEYSIZE, 16 );
	void *keyDataPtr = ALIGN_GET_PTR( keyData, 16 );
	BYTE temp[ 512 + 8 ];
	int status;

	assert( isReadPtrDynamic( key, keySize ) );
	assert( isReadPtrDynamic( plaintext, length ) );
	assert( isReadPtrDynamic( ciphertext, length ) );

	REQUIRES( isShortIntegerRangeNZ( keySize ) );
	REQUIRES( isShortIntegerRangeNZ( length ) );

	memset( keyDataPtr, 0, RC4_EXPANDED_KEYSIZE );	/* Keep static analysers happy */
	status = staticInitContext( &contextInfo, CONTEXT_CONV, capabilityInfo,
								&contextData, sizeof( CONV_INFO ), 
								keyDataPtr );
	if( cryptStatusError( status ) )
		return( status );
	REQUIRES( rangeCheck( length, 1, 512 ) );
	memcpy( temp, plaintext, length );
	status = capabilityInfo->initKeyFunction( &contextInfo, key, keySize );
	if( cryptStatusOK( status ) )
		{
		/* Since RC4 changes its keying state on every en/decrypt, the 
		   encryption function re-checksums the key data after the state has
		   been updated.  Normally the checksumming is handled by higher-
		   level code but since we're calling directly into internal 
		   functions we have to do it explicitly here */
		contextData.keyDataSize = RC4_EXPANDED_KEYSIZE;
		contextData.keyDataChecksum = checksumData( contextData.key, 
													contextData.keyDataSize );
		status = capabilityInfo->encryptCFBFunction( &contextInfo, temp,
													 length );
		}
	staticDestroyContext( &contextInfo );
	if( cryptStatusError( status ) || \
		memcmp( ciphertext, temp, length ) )
		return( CRYPT_ERROR_FAILED );

	return( CRYPT_OK );
	}

CHECK_RETVAL \
static int selfTest( void )
	{
	/* We can't use the standard testCipher() for this test because of the 
	   variable-length plaintext/ciphertext messages (rather than just a 
	   single block for a block cipher) so we have to perform the tests 
	   manually */
	if( rc4Test( testRC4key1, sizeof( testRC4key1 ), testRC4plaintext1,
				 testRC4ciphertext1, sizeof( testRC4plaintext1 ) ) != CRYPT_OK || \
		rc4Test( testRC4key2, sizeof( testRC4key2 ), testRC4plaintext2,
				 testRC4ciphertext2, sizeof( testRC4plaintext2 ) ) != CRYPT_OK || \
		rc4Test( testRC4key3, sizeof( testRC4key3 ), testRC4plaintext3,
				 testRC4ciphertext3, sizeof( testRC4plaintext3 ) ) != CRYPT_OK ||
#if 0	/* 32-bit key, will fail the key length check */
		rc4Test( testRC4key4, sizeof( testRC4key4 ), testRC4plaintext4,
				 testRC4ciphertext4, sizeof( testRC4plaintext4 ) ) != CRYPT_OK ||
#endif /* 0 */
		rc4Test( testRC4key5, sizeof( testRC4key5 ), testRC4plaintext5,
				 testRC4ciphertext5, sizeof( testRC4plaintext5 ) ) != CRYPT_OK
#if 0	/* 40-bit key, will fail the key length check */
		|| \
		rc4Test( testRC4key6, sizeof( testRC4key6 ), testRC4plaintext6,
				 testRC4ciphertext6, sizeof( testRC4plaintext6 ) ) != CRYPT_OK 
#endif /* 0 */
		)
		return( CRYPT_ERROR_FAILED );

	return( CRYPT_OK );
	}
#else
	#define selfTest	NULL
#endif /* !CONFIG_NO_SELFTEST */

/****************************************************************************
*																			*
*								Control Routines							*
*																			*
****************************************************************************/

/* Return context subtype-specific information */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
static int getInfo( IN_ENUM( CAPABILITY_INFO ) \
						const CAPABILITY_INFO_TYPE type, 
					INOUT_PTR_OPT CONTEXT_INFO *contextInfoPtr,
					OUT_PTR void *data, 
					IN_INT_Z const int length )
	{
	assert( contextInfoPtr == NULL || \
			isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( ( length == 0 && isWritePtr( data, sizeof( int ) ) ) || \
			( length > 0 && isWritePtrDynamic( data, length ) ) );

	REQUIRES( isEnumRange( type, CAPABILITY_INFO ) );
	REQUIRES( ( contextInfoPtr == NULL ) || \
			  sanityCheckContext( contextInfoPtr ) );

	if( type == CAPABILITY_INFO_STATESIZE )
		{
		int *valuePtr = ( int * ) data;

		*valuePtr = RC4_EXPANDED_KEYSIZE;

		return( CRYPT_OK );
		}

	return( getDefaultInfo( type, contextInfoPtr, data, length ) );
	}

/****************************************************************************
*																			*
*							RC4 En/Decryption Routines						*
*																			*
****************************************************************************/

/* Encrypt/decrypt data.  Since RC4 is a stream cipher, encryption and
   decryption are the same operation.  We have to append the distinguisher
   'Fn' to the name since some systems already have 'encrypt' and 'decrypt'
   in their standard headers  */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int encryptFn( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
					  INOUT_BUFFER_FIXED( noBytes ) BYTE *buffer, 
					  IN_LENGTH int noBytes )
	{
	CONV_INFO *convInfo = contextInfoPtr->ctxConv;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtrDynamic( buffer, noBytes ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( isIntegerRangeNZ( noBytes ) );

	/* We're about to modify the keying data, make sure that it's still 
	   valid before we start */
	if( checksumData( convInfo->key, \
					  convInfo->keyDataSize ) != convInfo->keyDataChecksum )
		retIntError();

	RC4_crypt( ( RC4_KEY * ) convInfo->key, noBytes, buffer, buffer );

	/* This en/decryption process updates changes the key data, so we have 
	   to update the checksum before we return to the caller */
	convInfo->keyDataChecksum = checksumData( convInfo->key, 
											  convInfo->keyDataSize );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							RC4 Key Management Routines						*
*																			*
****************************************************************************/

/* Create an expanded RC4 key */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int initKey( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
					IN_BUFFER( keyLength ) const void *key, 
					IN_LENGTH_SHORT const int keyLength )
	{
	CONV_INFO *convInfo = contextInfoPtr->ctxConv;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isReadPtrDynamic( key, keyLength ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( isShortIntegerRangeMin( keyLength, MIN_KEYSIZE ) );

	/* Copy the key to internal storage */
	if( convInfo->userKey != key )
		{
		REQUIRES( rangeCheck( keyLength, 1, CRYPT_MAX_KEYSIZE ) );
		memcpy( convInfo->userKey, key, keyLength );
		convInfo->userKeyLength = keyLength;
		}

	RC4_set_key( ( RC4_KEY * ) convInfo->key, keyLength, ( BYTE * ) key );
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Capability Access Routines							*
*																			*
****************************************************************************/

static const CAPABILITY_INFO capabilityInfo = {
	CRYPT_ALGO_RC4, bitsToBytes( 8 ), "RC4", 3,
	MIN_KEYSIZE, bitsToBytes( 128 ), CRYPT_MAX_KEYSIZE,
	selfTest, getInfo, NULL, initGenericParams, initKey, NULL,
	NULL, NULL, NULL, NULL, encryptFn, encryptFn 
	};						/* Pseudo-CFB mode */

CHECK_RETVAL_PTR_NONNULL \
const CAPABILITY_INFO *getRC4Capability( void )
	{
	return( &capabilityInfo );
	}

#endif /* USE_RC4 */
