Blame nss/lib/freebl/arcfour.c

Packit 40b132
/* arcfour.c - the arc four algorithm.
Packit 40b132
 *
Packit 40b132
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit 40b132
Packit 40b132
#ifdef FREEBL_NO_DEPEND
Packit 40b132
#include "stubs.h"
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#include "prerr.h"
Packit 40b132
#include "secerr.h"
Packit 40b132
Packit 40b132
#include "prtypes.h"
Packit 40b132
#include "blapi.h"
Packit 40b132
Packit 40b132
/* Architecture-dependent defines */
Packit 40b132
Packit 40b132
#if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \
Packit 40b132
    defined(_WIN64)
Packit 40b132
/* Convert the byte-stream to a word-stream */
Packit 40b132
#define CONVERT_TO_WORDS
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
/* Treat array variables as words, not bytes, on CPUs that take 
Packit 40b132
 * much longer to write bytes than to write words, or when using 
Packit 40b132
 * assembler code that required it.
Packit 40b132
 */
Packit 40b132
#define USE_WORD
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#if defined(IS_64) || defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
typedef PRUint64 WORD;
Packit 40b132
#else
Packit 40b132
typedef PRUint32 WORD;
Packit 40b132
#endif
Packit 40b132
#define WORDSIZE sizeof(WORD)
Packit 40b132
Packit 40b132
#if defined(USE_WORD)
Packit 40b132
typedef WORD Stype;
Packit 40b132
#else
Packit 40b132
typedef PRUint8 Stype;
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#define ARCFOUR_STATE_SIZE 256
Packit 40b132
Packit 40b132
#define MASK1BYTE (WORD)(0xff)
Packit 40b132
Packit 40b132
#define SWAP(a, b) \
Packit 40b132
	tmp = a; \
Packit 40b132
	a = b; \
Packit 40b132
	b = tmp;
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * State information for stream cipher.
Packit 40b132
 */
Packit 40b132
struct RC4ContextStr
Packit 40b132
{
Packit 40b132
#if defined(NSS_ARCFOUR_IJ_B4_S) || defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
	Stype i;
Packit 40b132
	Stype j;
Packit 40b132
	Stype S[ARCFOUR_STATE_SIZE];
Packit 40b132
#else
Packit 40b132
	Stype S[ARCFOUR_STATE_SIZE];
Packit 40b132
	Stype i;
Packit 40b132
	Stype j;
Packit 40b132
#endif
Packit 40b132
};
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * array indices [0..255] to initialize cx->S array (faster than loop).
Packit 40b132
 */
Packit 40b132
static const Stype Kinit[256] = {
Packit 40b132
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Packit 40b132
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
Packit 40b132
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
Packit 40b132
	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
Packit 40b132
	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
Packit 40b132
	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
Packit 40b132
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
Packit 40b132
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
Packit 40b132
	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
Packit 40b132
	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
Packit 40b132
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
Packit 40b132
	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
Packit 40b132
	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
Packit 40b132
	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Packit 40b132
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
Packit 40b132
	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
Packit 40b132
	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
Packit 40b132
	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
Packit 40b132
	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
Packit 40b132
	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
Packit 40b132
	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
Packit 40b132
	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
Packit 40b132
	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
Packit 40b132
	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
Packit 40b132
	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
Packit 40b132
	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
Packit 40b132
	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
Packit 40b132
	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
Packit 40b132
	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
Packit 40b132
	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
Packit 40b132
	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
Packit 40b132
	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
Packit 40b132
};
Packit 40b132
Packit 40b132
RC4Context *
Packit 40b132
RC4_AllocateContext(void)
Packit 40b132
{
Packit 40b132
    return PORT_ZNew(RC4Context);
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus   
Packit 40b132
RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
Packit 40b132
	        const unsigned char * unused1, int unused2, 
Packit 40b132
		unsigned int unused3, unsigned int unused4)
Packit 40b132
{
Packit 40b132
	unsigned int i;
Packit 40b132
	PRUint8 j, tmp;
Packit 40b132
	PRUint8 K[256];
Packit 40b132
	PRUint8 *L;
Packit 40b132
Packit 40b132
	/* verify the key length. */
Packit 40b132
	PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
Packit 40b132
	if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
Packit 40b132
		PORT_SetError(SEC_ERROR_BAD_KEY);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
	if (cx == NULL) {
Packit 40b132
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	    return SECFailure;
Packit 40b132
	}
Packit 40b132
	/* Initialize the state using array indices. */
Packit 40b132
	memcpy(cx->S, Kinit, sizeof cx->S);
Packit 40b132
	/* Fill in K repeatedly with values from key. */
Packit 40b132
	L = K;
Packit 40b132
	for (i = sizeof K; i > len; i-= len) {
Packit 40b132
		memcpy(L, key, len);
Packit 40b132
		L += len;
Packit 40b132
	}
Packit 40b132
	memcpy(L, key, i);
Packit 40b132
	/* Stir the state of the generator.  At this point it is assumed
Packit 40b132
	 * that the key is the size of the state buffer.  If this is not
Packit 40b132
	 * the case, the key bytes are repeated to fill the buffer.
Packit 40b132
	 */
Packit 40b132
	j = 0;
Packit 40b132
#define ARCFOUR_STATE_STIR(ii) \
Packit 40b132
	j = j + cx->S[ii] + K[ii]; \
Packit 40b132
	SWAP(cx->S[ii], cx->S[j]);
Packit 40b132
	for (i=0; i
Packit 40b132
		ARCFOUR_STATE_STIR(i);
Packit 40b132
	}
Packit 40b132
	cx->i = 0;
Packit 40b132
	cx->j = 0;
Packit 40b132
	return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * Initialize a new generator.
Packit 40b132
 */
Packit 40b132
RC4Context *
Packit 40b132
RC4_CreateContext(const unsigned char *key, int len)
Packit 40b132
{
Packit 40b132
    RC4Context *cx = RC4_AllocateContext();
Packit 40b132
    if (cx) {
Packit 40b132
	SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
Packit 40b132
	if (rv != SECSuccess) {
Packit 40b132
	    PORT_ZFree(cx, sizeof(*cx));
Packit 40b132
	    cx = NULL;
Packit 40b132
	}
Packit 40b132
    }
Packit 40b132
    return cx;
Packit 40b132
}
Packit 40b132
Packit 40b132
void 
Packit 40b132
RC4_DestroyContext(RC4Context *cx, PRBool freeit)
Packit 40b132
{
Packit 40b132
	if (freeit)
Packit 40b132
		PORT_ZFree(cx, sizeof(*cx));
Packit 40b132
}
Packit 40b132
Packit 40b132
#if defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
extern void ARCFOUR(RC4Context *cx, WORD inputLen, 
Packit 40b132
	const unsigned char *input, unsigned char *output);
Packit 40b132
#else
Packit 40b132
/*
Packit 40b132
 * Generate the next byte in the stream.
Packit 40b132
 */
Packit 40b132
#define ARCFOUR_NEXT_BYTE() \
Packit 40b132
	tmpSi = cx->S[++tmpi]; \
Packit 40b132
	tmpj += tmpSi; \
Packit 40b132
	tmpSj = cx->S[tmpj]; \
Packit 40b132
	cx->S[tmpi] = tmpSj; \
Packit 40b132
	cx->S[tmpj] = tmpSi; \
Packit 40b132
	t = tmpSi + tmpSj;
Packit 40b132
Packit 40b132
#ifdef CONVERT_TO_WORDS
Packit 40b132
/*
Packit 40b132
 * Straight ARCFOUR op.  No optimization.
Packit 40b132
 */
Packit 40b132
static SECStatus 
Packit 40b132
rc4_no_opt(RC4Context *cx, unsigned char *output,
Packit 40b132
           unsigned int *outputLen, unsigned int maxOutputLen,
Packit 40b132
           const unsigned char *input, unsigned int inputLen)
Packit 40b132
{
Packit 40b132
    PRUint8 t;
Packit 40b132
	Stype tmpSi, tmpSj;
Packit 40b132
	register PRUint8 tmpi = cx->i;
Packit 40b132
	register PRUint8 tmpj = cx->j;
Packit 40b132
	unsigned int index;
Packit 40b132
	PORT_Assert(maxOutputLen >= inputLen);
Packit 40b132
	if (maxOutputLen < inputLen) {
Packit 40b132
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
	for (index=0; index < inputLen; index++) {
Packit 40b132
		/* Generate next byte from stream. */
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		/* output = next stream byte XOR next input byte */
Packit 40b132
		output[index] = cx->S[t] ^ input[index];
Packit 40b132
	}
Packit 40b132
	*outputLen = inputLen;
Packit 40b132
	cx->i = tmpi;
Packit 40b132
	cx->j = tmpj;
Packit 40b132
	return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
#else
Packit 40b132
/* !CONVERT_TO_WORDS */
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces.
Packit 40b132
 */
Packit 40b132
static SECStatus 
Packit 40b132
rc4_unrolled(RC4Context *cx, unsigned char *output,
Packit 40b132
             unsigned int *outputLen, unsigned int maxOutputLen,
Packit 40b132
             const unsigned char *input, unsigned int inputLen)
Packit 40b132
{
Packit 40b132
	PRUint8 t;
Packit 40b132
	Stype tmpSi, tmpSj;
Packit 40b132
	register PRUint8 tmpi = cx->i;
Packit 40b132
	register PRUint8 tmpj = cx->j;
Packit 40b132
	int index;
Packit 40b132
	PORT_Assert(maxOutputLen >= inputLen);
Packit 40b132
	if (maxOutputLen < inputLen) {
Packit 40b132
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
	for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[0] = cx->S[t] ^ input[0];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[1] = cx->S[t] ^ input[1];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[2] = cx->S[t] ^ input[2];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[3] = cx->S[t] ^ input[3];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[4] = cx->S[t] ^ input[4];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[5] = cx->S[t] ^ input[5];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[6] = cx->S[t] ^ input[6];
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		output[7] = cx->S[t] ^ input[7];
Packit 40b132
	}
Packit 40b132
	index = inputLen % 8;
Packit 40b132
	if (index) {
Packit 40b132
		input += index;
Packit 40b132
		output += index;
Packit 40b132
		switch (index) {
Packit 40b132
		case 7:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
Packit 40b132
		case 6:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
Packit 40b132
		case 5:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
Packit 40b132
		case 4:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
Packit 40b132
		case 3:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
Packit 40b132
		case 2:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
Packit 40b132
		case 1:
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
Packit 40b132
		default:
Packit 40b132
			/* FALLTHRU */
Packit 40b132
			; /* hp-ux build breaks without this */
Packit 40b132
		}
Packit 40b132
	}
Packit 40b132
	cx->i = tmpi;
Packit 40b132
	cx->j = tmpj;
Packit 40b132
	*outputLen = inputLen;
Packit 40b132
	return SECSuccess;
Packit 40b132
}
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#ifdef IS_LITTLE_ENDIAN
Packit 40b132
#define ARCFOUR_NEXT4BYTES_L(n) \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     ); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
Packit 40b132
#else
Packit 40b132
#define ARCFOUR_NEXT4BYTES_B(n) \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
Packit 40b132
	ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     );
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64)
Packit 40b132
/* 64-bit wordsize */
Packit 40b132
#ifdef IS_LITTLE_ENDIAN
Packit 40b132
#define ARCFOUR_NEXT_WORD() \
Packit 40b132
	{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
Packit 40b132
#else
Packit 40b132
#define ARCFOUR_NEXT_WORD() \
Packit 40b132
	{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
Packit 40b132
#endif
Packit 40b132
#else
Packit 40b132
/* 32-bit wordsize */
Packit 40b132
#ifdef IS_LITTLE_ENDIAN
Packit 40b132
#define ARCFOUR_NEXT_WORD() \
Packit 40b132
	{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
Packit 40b132
#else
Packit 40b132
#define ARCFOUR_NEXT_WORD() \
Packit 40b132
	{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
Packit 40b132
#endif
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#ifdef IS_LITTLE_ENDIAN
Packit 40b132
#define RSH <<
Packit 40b132
#define LSH >>
Packit 40b132
#else
Packit 40b132
#define RSH >>
Packit 40b132
#define LSH <<
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#ifdef IS_LITTLE_ENDIAN
Packit 40b132
#define LEFTMOST_BYTE_SHIFT 0
Packit 40b132
#define NEXT_BYTE_SHIFT(shift) shift + 8
Packit 40b132
#else
Packit 40b132
#define LEFTMOST_BYTE_SHIFT 8*(WORDSIZE - 1)
Packit 40b132
#define NEXT_BYTE_SHIFT(shift) shift - 8
Packit 40b132
#endif
Packit 40b132
Packit 40b132
#ifdef CONVERT_TO_WORDS
Packit 40b132
static SECStatus 
Packit 40b132
rc4_wordconv(RC4Context *cx, unsigned char *output,
Packit 40b132
             unsigned int *outputLen, unsigned int maxOutputLen,
Packit 40b132
             const unsigned char *input, unsigned int inputLen)
Packit 40b132
{
Packit 40b132
	PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t));
Packit 40b132
	unsigned int inOffset = (PRUword)input % WORDSIZE;
Packit 40b132
	unsigned int outOffset = (PRUword)output % WORDSIZE;
Packit 40b132
	register WORD streamWord;
Packit 40b132
	register const WORD *pInWord;
Packit 40b132
	register WORD *pOutWord;
Packit 40b132
	register WORD inWord, nextInWord;
Packit 40b132
	PRUint8 t;
Packit 40b132
	register Stype tmpSi, tmpSj;
Packit 40b132
	register PRUint8 tmpi = cx->i;
Packit 40b132
	register PRUint8 tmpj = cx->j;
Packit 40b132
	unsigned int bufShift, invBufShift;
Packit 40b132
	unsigned int i;
Packit 40b132
	const unsigned char *finalIn;
Packit 40b132
	unsigned char *finalOut;
Packit 40b132
Packit 40b132
	PORT_Assert(maxOutputLen >= inputLen);
Packit 40b132
	if (maxOutputLen < inputLen) {
Packit 40b132
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
	if (inputLen < 2*WORDSIZE) {
Packit 40b132
		/* Ignore word conversion, do byte-at-a-time */
Packit 40b132
		return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
Packit 40b132
	}
Packit 40b132
	*outputLen = inputLen;
Packit 40b132
	pInWord = (const WORD *)(input - inOffset);
Packit 40b132
	pOutWord = (WORD *)(output - outOffset);
Packit 40b132
	if (inOffset <= outOffset) {
Packit 40b132
		bufShift = 8*(outOffset - inOffset);
Packit 40b132
		invBufShift = 8*WORDSIZE - bufShift;
Packit 40b132
	} else {
Packit 40b132
		invBufShift = 8*(inOffset - outOffset);
Packit 40b132
		bufShift = 8*WORDSIZE - invBufShift;
Packit 40b132
	}
Packit 40b132
	/*****************************************************************/
Packit 40b132
	/* Step 1:                                                       */
Packit 40b132
	/* If the first output word is partial, consume the bytes in the */
Packit 40b132
	/* first partial output word by loading one or two words of      */
Packit 40b132
	/* input and shifting them accordingly.  Otherwise, just load    */
Packit 40b132
	/* in the first word of input.  At the end of this block, at     */
Packit 40b132
	/* least one partial word of input should ALWAYS be loaded.      */
Packit 40b132
	/*****************************************************************/
Packit 40b132
	if (outOffset) {
Packit 40b132
		unsigned int byteCount = WORDSIZE - outOffset; 
Packit 40b132
		for (i = 0; i < byteCount; i++) {
Packit 40b132
			ARCFOUR_NEXT_BYTE();
Packit 40b132
			output[i] = cx->S[t] ^ input[i];
Packit 40b132
		}
Packit 40b132
		/* Consumed byteCount bytes of input */
Packit 40b132
		inputLen -= byteCount;
Packit 40b132
		pInWord++;
Packit 40b132
Packit 40b132
		/* move to next word of output */
Packit 40b132
		pOutWord++;
Packit 40b132
Packit 40b132
		/* If buffers are relatively misaligned, shift the bytes in inWord
Packit 40b132
		 * to be aligned to the output buffer.
Packit 40b132
		 */
Packit 40b132
		if (inOffset < outOffset) {
Packit 40b132
			/* The first input word (which may be partial) has more bytes
Packit 40b132
			 * than needed.  Copy the remainder to inWord.
Packit 40b132
			 */
Packit 40b132
			unsigned int shift = LEFTMOST_BYTE_SHIFT;
Packit 40b132
			inWord = 0;
Packit 40b132
			for (i = 0; i < outOffset - inOffset; i++) {
Packit 40b132
				inWord |= (WORD)input[byteCount + i] << shift;
Packit 40b132
				shift = NEXT_BYTE_SHIFT(shift);
Packit 40b132
			}
Packit 40b132
		} else if (inOffset > outOffset) {
Packit 40b132
			/* Consumed some bytes in the second input word.  Copy the
Packit 40b132
			 * remainder to inWord.
Packit 40b132
			 */
Packit 40b132
			inWord = *pInWord++;
Packit 40b132
			inWord = inWord LSH invBufShift;
Packit 40b132
		} else {
Packit 40b132
			inWord = 0;
Packit 40b132
		}
Packit 40b132
	} else {
Packit 40b132
		/* output is word-aligned */
Packit 40b132
		if (inOffset) {
Packit 40b132
			/* Input is not word-aligned.  The first word load of input 
Packit 40b132
			 * will not produce a full word of input bytes, so one word
Packit 40b132
			 * must be pre-loaded.  The main loop below will load in the
Packit 40b132
			 * next input word and shift some of its bytes into inWord
Packit 40b132
			 * in order to create a full input word.  Note that the main
Packit 40b132
			 * loop must execute at least once because the input must
Packit 40b132
			 * be at least two words.
Packit 40b132
			 */
Packit 40b132
			unsigned int shift = LEFTMOST_BYTE_SHIFT;
Packit 40b132
			inWord = 0;
Packit 40b132
			for (i = 0; i < WORDSIZE - inOffset; i++) {
Packit 40b132
				inWord |= (WORD)input[i] << shift;
Packit 40b132
				shift = NEXT_BYTE_SHIFT(shift);
Packit 40b132
			}
Packit 40b132
			pInWord++;
Packit 40b132
		} else {
Packit 40b132
			/* Input is word-aligned.  The first word load of input 
Packit 40b132
			 * will produce a full word of input bytes, so nothing
Packit 40b132
			 * needs to be loaded here.
Packit 40b132
			 */
Packit 40b132
			inWord = 0;
Packit 40b132
		}
Packit 40b132
	}
Packit 40b132
	/*****************************************************************/
Packit 40b132
	/* Step 2: main loop                                             */
Packit 40b132
	/* At this point the output buffer is word-aligned.  Any unused  */
Packit 40b132
	/* bytes from above will be in inWord (shifted correctly).  If   */
Packit 40b132
	/* the input buffer is unaligned relative to the output buffer,  */
Packit 40b132
	/* shifting has to be done.                                      */
Packit 40b132
	/*****************************************************************/
Packit 40b132
	if (bufShift) {
Packit 40b132
		/* preloadedByteCount is the number of input bytes pre-loaded
Packit 40b132
		 * in inWord.
Packit 40b132
		 */
Packit 40b132
		unsigned int preloadedByteCount = bufShift/8;
Packit 40b132
		for (; inputLen >= preloadedByteCount + WORDSIZE;
Packit 40b132
		     inputLen -= WORDSIZE) {
Packit 40b132
			nextInWord = *pInWord++;
Packit 40b132
			inWord |= nextInWord RSH bufShift;
Packit 40b132
			nextInWord = nextInWord LSH invBufShift;
Packit 40b132
			ARCFOUR_NEXT_WORD();
Packit 40b132
			*pOutWord++ = inWord ^ streamWord;
Packit 40b132
			inWord = nextInWord;
Packit 40b132
		}
Packit 40b132
		if (inputLen == 0) {
Packit 40b132
			/* Nothing left to do. */
Packit 40b132
			cx->i = tmpi;
Packit 40b132
			cx->j = tmpj;
Packit 40b132
			return SECSuccess;
Packit 40b132
		}
Packit 40b132
		finalIn = (const unsigned char *)pInWord - preloadedByteCount;
Packit 40b132
	} else {
Packit 40b132
		for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
Packit 40b132
			inWord = *pInWord++;
Packit 40b132
			ARCFOUR_NEXT_WORD();
Packit 40b132
			*pOutWord++ = inWord ^ streamWord;
Packit 40b132
		}
Packit 40b132
		if (inputLen == 0) {
Packit 40b132
			/* Nothing left to do. */
Packit 40b132
			cx->i = tmpi;
Packit 40b132
			cx->j = tmpj;
Packit 40b132
			return SECSuccess;
Packit 40b132
		}
Packit 40b132
		finalIn = (const unsigned char *)pInWord;
Packit 40b132
	}
Packit 40b132
	/*****************************************************************/
Packit 40b132
	/* Step 3:                                                       */
Packit 40b132
	/* Do the remaining partial word of input one byte at a time.    */
Packit 40b132
	/*****************************************************************/
Packit 40b132
	finalOut = (unsigned char *)pOutWord;
Packit 40b132
	for (i = 0; i < inputLen; i++) {
Packit 40b132
		ARCFOUR_NEXT_BYTE();
Packit 40b132
		finalOut[i] = cx->S[t] ^ finalIn[i];
Packit 40b132
	}
Packit 40b132
	cx->i = tmpi;
Packit 40b132
	cx->j = tmpj;
Packit 40b132
	return SECSuccess;
Packit 40b132
}
Packit 40b132
#endif
Packit 40b132
#endif /* NSS_BEVAND_ARCFOUR */
Packit 40b132
Packit 40b132
SECStatus 
Packit 40b132
RC4_Encrypt(RC4Context *cx, unsigned char *output,
Packit 40b132
            unsigned int *outputLen, unsigned int maxOutputLen,
Packit 40b132
            const unsigned char *input, unsigned int inputLen)
Packit 40b132
{
Packit 40b132
	PORT_Assert(maxOutputLen >= inputLen);
Packit 40b132
	if (maxOutputLen < inputLen) {
Packit 40b132
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
#if defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
	ARCFOUR(cx, inputLen, input, output);
Packit 40b132
        *outputLen = inputLen;
Packit 40b132
	return SECSuccess;
Packit 40b132
#elif defined( CONVERT_TO_WORDS )
Packit 40b132
	/* Convert the byte-stream to a word-stream */
Packit 40b132
	return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
Packit 40b132
#else
Packit 40b132
	/* Operate on bytes, but unroll the main loop */
Packit 40b132
	return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
Packit 40b132
#endif
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
Packit 40b132
                      unsigned int *outputLen, unsigned int maxOutputLen,
Packit 40b132
                      const unsigned char *input, unsigned int inputLen)
Packit 40b132
{
Packit 40b132
	PORT_Assert(maxOutputLen >= inputLen);
Packit 40b132
	if (maxOutputLen < inputLen) {
Packit 40b132
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
Packit 40b132
		return SECFailure;
Packit 40b132
	}
Packit 40b132
	/* decrypt and encrypt are same operation. */
Packit 40b132
#if defined(NSS_BEVAND_ARCFOUR)
Packit 40b132
	ARCFOUR(cx, inputLen, input, output);
Packit 40b132
        *outputLen = inputLen;
Packit 40b132
	return SECSuccess;
Packit 40b132
#elif defined( CONVERT_TO_WORDS )
Packit 40b132
	/* Convert the byte-stream to a word-stream */
Packit 40b132
	return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
Packit 40b132
#else
Packit 40b132
	/* Operate on bytes, but unroll the main loop */
Packit 40b132
	return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
Packit 40b132
#endif
Packit 40b132
}
Packit 40b132
Packit 40b132
#undef CONVERT_TO_WORDS
Packit 40b132
#undef USE_WORD