Back to index

lightning-sunbird  0.9+nobinonly
arcfour.c
Go to the documentation of this file.
00001 /* arcfour.c - the arc four algorithm.
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Netscape security libraries.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /* See NOTES ON UMRs, Unititialized Memory Reads, below. */
00040 
00041 #include "prerr.h"
00042 #include "secerr.h"
00043 
00044 #include "prtypes.h"
00045 #include "blapi.h"
00046 
00047 /* Architecture-dependent defines */
00048 
00049 #if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX)
00050 /* Convert the byte-stream to a word-stream */
00051 #define CONVERT_TO_WORDS
00052 #endif
00053 
00054 #if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
00055 /* Treat array variables as longs, not bytes, on CPUs that take 
00056  * much longer to write bytes than to write longs, or when using 
00057  * assembler code that required it.
00058  */
00059 #define USE_LONG
00060 #endif
00061 
00062 #if defined(_WIN32_WCE)
00063 #undef WORD
00064 #define WORD ARC4WORD
00065 #endif
00066 
00067 #if defined(IS_64) && !defined(__sparc) && !defined(NSS_USE_64) 
00068 typedef unsigned long long WORD;
00069 #else
00070 typedef unsigned long WORD;
00071 #endif
00072 #define WORDSIZE sizeof(WORD)
00073 
00074 #ifdef USE_LONG
00075 typedef unsigned long Stype;
00076 #else
00077 typedef PRUint8 Stype;
00078 #endif
00079 
00080 #define ARCFOUR_STATE_SIZE 256
00081 
00082 #define MASK1BYTE (WORD)(0xff)
00083 
00084 #define SWAP(a, b) \
00085        tmp = a; \
00086        a = b; \
00087        b = tmp;
00088 
00089 /*
00090  * State information for stream cipher.
00091  */
00092 struct RC4ContextStr
00093 {
00094 #if defined(NSS_ARCFOUR_IJ_B4_S) || defined(NSS_BEVAND_ARCFOUR)
00095        Stype i;
00096        Stype j;
00097        Stype S[ARCFOUR_STATE_SIZE];
00098 #else
00099        Stype S[ARCFOUR_STATE_SIZE];
00100        Stype i;
00101        Stype j;
00102 #endif
00103 };
00104 
00105 /*
00106  * array indices [0..255] to initialize cx->S array (faster than loop).
00107  */
00108 static const Stype Kinit[256] = {
00109        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
00110        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
00111        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
00112        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
00113        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
00114        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
00115        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
00116        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
00117        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
00118        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
00119        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
00120        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
00121        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00122        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00123        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
00124        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
00125        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
00126        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
00127        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
00128        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
00129        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
00130        0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
00131        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
00132        0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
00133        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
00134        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
00135        0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
00136        0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
00137        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
00138        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
00139        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
00140        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
00141 };
00142 
00143 RC4Context *
00144 RC4_AllocateContext(void)
00145 {
00146     return PORT_ZNew(RC4Context);
00147 }
00148 
00149 SECStatus   
00150 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
00151                const unsigned char * unused1, int unused2, 
00152               unsigned int unused3, unsigned int unused4)
00153 {
00154        int i;
00155        PRUint8 j, tmp;
00156        PRUint8 K[256];
00157        PRUint8 *L;
00158        /* verify the key length. */
00159        PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
00160        if (len < 0 || len >= ARCFOUR_STATE_SIZE) {
00161               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00162               return SECFailure;
00163        }
00164        if (cx == NULL) {
00165            PORT_SetError(SEC_ERROR_INVALID_ARGS);
00166            return SECFailure;
00167        }
00168        /* Initialize the state using array indices. */
00169        memcpy(cx->S, Kinit, sizeof cx->S);
00170        /* Fill in K repeatedly with values from key. */
00171        L = K;
00172        for (i = sizeof K; i > len; i-= len) {
00173               memcpy(L, key, len);
00174               L += len;
00175        }
00176        memcpy(L, key, i);
00177        /* Stir the state of the generator.  At this point it is assumed
00178         * that the key is the size of the state buffer.  If this is not
00179         * the case, the key bytes are repeated to fill the buffer.
00180         */
00181        j = 0;
00182 #define ARCFOUR_STATE_STIR(ii) \
00183        j = j + cx->S[ii] + K[ii]; \
00184        SWAP(cx->S[ii], cx->S[j]);
00185        for (i=0; i<ARCFOUR_STATE_SIZE; i++) {
00186               ARCFOUR_STATE_STIR(i);
00187        }
00188        cx->i = 0;
00189        cx->j = 0;
00190        return SECSuccess;
00191 }
00192 
00193 
00194 /*
00195  * Initialize a new generator.
00196  */
00197 RC4Context *
00198 RC4_CreateContext(const unsigned char *key, int len)
00199 {
00200     RC4Context *cx = RC4_AllocateContext();
00201     if (cx) {
00202        SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
00203        if (rv != SECSuccess) {
00204            PORT_ZFree(cx, sizeof(*cx));
00205            cx = NULL;
00206        }
00207     }
00208     return cx;
00209 }
00210 
00211 void 
00212 RC4_DestroyContext(RC4Context *cx, PRBool freeit)
00213 {
00214        if (freeit)
00215               PORT_ZFree(cx, sizeof(*cx));
00216 }
00217 
00218 #if defined(NSS_BEVAND_ARCFOUR)
00219 extern void ARCFOUR(RC4Context *cx, unsigned long inputLen, 
00220        const unsigned char *input, unsigned char *output);
00221 #else
00222 /*
00223  * Generate the next byte in the stream.
00224  */
00225 #define ARCFOUR_NEXT_BYTE() \
00226        tmpSi = cx->S[++tmpi]; \
00227        tmpj += tmpSi; \
00228        tmpSj = cx->S[tmpj]; \
00229        cx->S[tmpi] = tmpSj; \
00230        cx->S[tmpj] = tmpSi; \
00231        t = tmpSi + tmpSj;
00232 
00233 #ifdef CONVERT_TO_WORDS
00234 /*
00235  * Straight ARCFOUR op.  No optimization.
00236  */
00237 static SECStatus 
00238 rc4_no_opt(RC4Context *cx, unsigned char *output,
00239            unsigned int *outputLen, unsigned int maxOutputLen,
00240            const unsigned char *input, unsigned int inputLen)
00241 {
00242     PRUint8 t;
00243        Stype tmpSi, tmpSj;
00244        register PRUint8 tmpi = cx->i;
00245        register PRUint8 tmpj = cx->j;
00246        unsigned int index;
00247        PORT_Assert(maxOutputLen >= inputLen);
00248        if (maxOutputLen < inputLen) {
00249               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00250               return SECFailure;
00251        }
00252        for (index=0; index < inputLen; index++) {
00253               /* Generate next byte from stream. */
00254               ARCFOUR_NEXT_BYTE();
00255               /* output = next stream byte XOR next input byte */
00256               output[index] = cx->S[t] ^ input[index];
00257        }
00258        *outputLen = inputLen;
00259        cx->i = tmpi;
00260        cx->j = tmpj;
00261        return SECSuccess;
00262 }
00263 #endif
00264 
00265 #ifndef CONVERT_TO_WORDS
00266 /*
00267  * Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces.
00268  */
00269 static SECStatus 
00270 rc4_unrolled(RC4Context *cx, unsigned char *output,
00271              unsigned int *outputLen, unsigned int maxOutputLen,
00272              const unsigned char *input, unsigned int inputLen)
00273 {
00274        PRUint8 t;
00275        Stype tmpSi, tmpSj;
00276        register PRUint8 tmpi = cx->i;
00277        register PRUint8 tmpj = cx->j;
00278        int index;
00279        PORT_Assert(maxOutputLen >= inputLen);
00280        if (maxOutputLen < inputLen) {
00281               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00282               return SECFailure;
00283        }
00284        for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
00285               ARCFOUR_NEXT_BYTE();
00286               output[0] = cx->S[t] ^ input[0];
00287               ARCFOUR_NEXT_BYTE();
00288               output[1] = cx->S[t] ^ input[1];
00289               ARCFOUR_NEXT_BYTE();
00290               output[2] = cx->S[t] ^ input[2];
00291               ARCFOUR_NEXT_BYTE();
00292               output[3] = cx->S[t] ^ input[3];
00293               ARCFOUR_NEXT_BYTE();
00294               output[4] = cx->S[t] ^ input[4];
00295               ARCFOUR_NEXT_BYTE();
00296               output[5] = cx->S[t] ^ input[5];
00297               ARCFOUR_NEXT_BYTE();
00298               output[6] = cx->S[t] ^ input[6];
00299               ARCFOUR_NEXT_BYTE();
00300               output[7] = cx->S[t] ^ input[7];
00301        }
00302        index = inputLen % 8;
00303        if (index) {
00304               input += index;
00305               output += index;
00306               switch (index) {
00307               case 7:
00308                      ARCFOUR_NEXT_BYTE();
00309                      output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
00310               case 6:
00311                      ARCFOUR_NEXT_BYTE();
00312                      output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
00313               case 5:
00314                      ARCFOUR_NEXT_BYTE();
00315                      output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
00316               case 4:
00317                      ARCFOUR_NEXT_BYTE();
00318                      output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
00319               case 3:
00320                      ARCFOUR_NEXT_BYTE();
00321                      output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
00322               case 2:
00323                      ARCFOUR_NEXT_BYTE();
00324                      output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
00325               case 1:
00326                      ARCFOUR_NEXT_BYTE();
00327                      output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
00328               default:
00329                      /* FALLTHRU */
00330                      ; /* hp-ux build breaks without this */
00331               }
00332        }
00333        cx->i = tmpi;
00334        cx->j = tmpj;
00335        *outputLen = inputLen;
00336        return SECSuccess;
00337 }
00338 #endif
00339 
00340 #ifdef IS_LITTLE_ENDIAN
00341 #define ARCFOUR_NEXT4BYTES_L(n) \
00342        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     ); \
00343        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
00344        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
00345        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
00346 #else
00347 #define ARCFOUR_NEXT4BYTES_B(n) \
00348        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
00349        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
00350        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n +  8); \
00351        ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n     );
00352 #endif
00353 
00354 #if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64)
00355 /* 64-bit wordsize */
00356 #ifdef IS_LITTLE_ENDIAN
00357 #define ARCFOUR_NEXT_WORD() \
00358        { streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
00359 #else
00360 #define ARCFOUR_NEXT_WORD() \
00361        { streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
00362 #endif
00363 #else
00364 /* 32-bit wordsize */
00365 #ifdef IS_LITTLE_ENDIAN
00366 #define ARCFOUR_NEXT_WORD() \
00367        { streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
00368 #else
00369 #define ARCFOUR_NEXT_WORD() \
00370        { streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
00371 #endif
00372 #endif
00373 
00374 #ifdef IS_LITTLE_ENDIAN
00375 #define RSH <<
00376 #define LSH >>
00377 #else
00378 #define RSH >>
00379 #define LSH <<
00380 #endif
00381 
00382 #ifdef CONVERT_TO_WORDS
00383 /* NOTE about UMRs, Uninitialized Memory Reads.
00384  *
00385  * This code reads all input data a WORD at a time, rather than byte at 
00386  * a time, and writes all output data a WORD at a time.  Shifting and 
00387  * masking is used to remove unwanted data and realign bytes when 
00388  * needed.  The first and last words of output are read, modified, and
00389  * written when needed to preserve any unchanged bytes.  This is a huge
00390  * win on machines with high memory latency.  
00391  *
00392  * However, when the input and output buffers do not begin and end on WORD 
00393  * boundaries, and the WORDS in memory that contain the first and last 
00394  * bytes of those buffers contain uninitialized data, then this code will 
00395  * read those uninitialized bytes, causing a UMR error to be reported by 
00396  * some tools.  
00397  *
00398  * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed".
00399  * 
00400  * All the words read and written contain at least one byte that is 
00401  * part of the input data or output data.  No words are read or written
00402  * that do not contain data that is part of the buffer.  Therefore, 
00403  * these UMRs cannot cause page faults or other problems unless the 
00404  * buffers have been assigned to improper addresses that would cause
00405  * page faults with or without UMRs.  
00406  */
00407 static SECStatus 
00408 rc4_wordconv(RC4Context *cx, unsigned char *output,
00409              unsigned int *outputLen, unsigned int maxOutputLen,
00410              const unsigned char *input, unsigned int inputLen)
00411 {
00412        ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
00413        ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
00414        register WORD streamWord, mask;
00415        register WORD *pInWord, *pOutWord;
00416        register WORD inWord, nextInWord;
00417        PRUint8 t;
00418        register Stype tmpSi, tmpSj;
00419        register PRUint8 tmpi = cx->i;
00420        register PRUint8 tmpj = cx->j;
00421        unsigned int byteCount;
00422        unsigned int bufShift, invBufShift;
00423        int i;
00424 
00425        PORT_Assert(maxOutputLen >= inputLen);
00426        if (maxOutputLen < inputLen) {
00427               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00428               return SECFailure;
00429        }
00430        if (inputLen < 2*WORDSIZE) {
00431               /* Ignore word conversion, do byte-at-a-time */
00432               return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
00433        }
00434        *outputLen = inputLen;
00435        pInWord = (WORD *)(input - inOffset);
00436        if (inOffset < outOffset) {
00437               bufShift = 8*(outOffset - inOffset);
00438               invBufShift = 8*WORDSIZE - bufShift;
00439        } else {
00440               invBufShift = 8*(inOffset - outOffset);
00441               bufShift = 8*WORDSIZE - invBufShift;
00442        }
00443        /*****************************************************************/
00444        /* Step 1:                                                       */
00445        /* If the first output word is partial, consume the bytes in the */
00446        /* first partial output word by loading one or two words of      */
00447        /* input and shifting them accordingly.  Otherwise, just load    */
00448        /* in the first word of input.  At the end of this block, at     */
00449        /* least one partial word of input should ALWAYS be loaded.      */
00450        /*****************************************************************/
00451        if (outOffset) {
00452               /* Generate input and stream words aligned relative to the
00453                * partial output buffer.
00454                */
00455               byteCount = WORDSIZE - outOffset; 
00456               pOutWord = (WORD *)(output - outOffset);
00457               mask = streamWord = 0;
00458 #ifdef IS_LITTLE_ENDIAN
00459               for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
00460 #else
00461               for (i = byteCount - 1; i >= 0; --i) {
00462 #endif
00463                      ARCFOUR_NEXT_BYTE();
00464                      streamWord |= (WORD)(cx->S[t]) << 8*i;
00465                      mask |= MASK1BYTE << 8*i;
00466               } /* } */
00467               inWord = *pInWord++; /* UMR? see comments above. */
00468               /* If buffers are relatively misaligned, shift the bytes in inWord
00469                * to be aligned to the output buffer.
00470                */
00471               nextInWord = 0;
00472               if (inOffset < outOffset) {
00473                      /* Have more bytes than needed, shift remainder into nextInWord */
00474                      nextInWord = inWord LSH 8*(inOffset + byteCount);
00475                      inWord = inWord RSH bufShift;
00476               } else if (inOffset > outOffset) {
00477                      /* Didn't get enough bytes from current input word, load another
00478                       * word and then shift remainder into nextInWord.
00479                       */
00480                      nextInWord = *pInWord++;
00481                      inWord = (inWord LSH invBufShift) | 
00482                               (nextInWord RSH bufShift);
00483                      nextInWord = nextInWord LSH invBufShift;
00484               }
00485               /* Store output of first partial word */
00486               *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
00487               /* UMR?  See comments above. */
00488 
00489               /* Consumed byteCount bytes of input */
00490               inputLen -= byteCount;
00491               /* move to next word of output */
00492               pOutWord++;
00493               /* inWord has been consumed, but there may be bytes in nextInWord */
00494               inWord = nextInWord;
00495        } else {
00496               /* output is word-aligned */
00497               pOutWord = (WORD *)output;
00498               if (inOffset) {
00499                      /* Input is not word-aligned.  The first word load of input 
00500                       * will not produce a full word of input bytes, so one word
00501                       * must be pre-loaded.  The main loop below will load in the
00502                       * next input word and shift some of its bytes into inWord
00503                       * in order to create a full input word.  Note that the main
00504                       * loop must execute at least once because the input must
00505                       * be at least two words.
00506                       */
00507                      inWord = *pInWord++; /* UMR? see comments above. */
00508                      inWord = inWord LSH invBufShift;
00509               } else {
00510                      /* Input is word-aligned.  The first word load of input 
00511                       * will produce a full word of input bytes, so nothing
00512                       * needs to be loaded here.
00513                       */
00514                      inWord = 0;
00515               }
00516        }
00517        /* Output buffer is aligned, inOffset is now measured relative to
00518         * outOffset (and not a word boundary).
00519         */
00520        inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE;
00521        /*****************************************************************/
00522        /* Step 2: main loop                                             */
00523        /* At this point the output buffer is word-aligned.  Any unused  */
00524        /* bytes from above will be in inWord (shifted correctly).  If   */
00525        /* the input buffer is unaligned relative to the output buffer,  */
00526        /* shifting has to be done.                                      */
00527        /*****************************************************************/
00528        if (inOffset) {
00529               for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
00530                      nextInWord = *pInWord++;
00531                      inWord |= nextInWord RSH bufShift;
00532                      nextInWord = nextInWord LSH invBufShift;
00533                      ARCFOUR_NEXT_WORD();
00534                      *pOutWord++ = inWord ^ streamWord;
00535                      inWord = nextInWord;
00536               }
00537               if (inputLen == 0) {
00538                      /* Nothing left to do. */
00539                      cx->i = tmpi;
00540                      cx->j = tmpj;
00541                      return SECSuccess;
00542               }
00543               /* If the amount of remaining input is greater than the amount
00544                * bytes pulled from the current input word, need to do another
00545                * word load.  What's left in inWord will be consumed in step 3.
00546                */
00547               if (inputLen > WORDSIZE - inOffset)
00548                      inWord |= *pInWord RSH bufShift; /* UMR?  See above. */
00549        } else {
00550               for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
00551                      inWord = *pInWord++;
00552                      ARCFOUR_NEXT_WORD();
00553                      *pOutWord++ = inWord ^ streamWord;
00554               }
00555               if (inputLen == 0) {
00556                      /* Nothing left to do. */
00557                      cx->i = tmpi;
00558                      cx->j = tmpj;
00559                      return SECSuccess;
00560               } else {
00561                      /* A partial input word remains at the tail.  Load it. 
00562                       * The relevant bytes will be consumed in step 3.
00563                       */
00564                      inWord = *pInWord; /* UMR?  See comments above */
00565               }
00566        }
00567        /*****************************************************************/
00568        /* Step 3:                                                       */
00569        /* A partial word of input remains, and it is already loaded     */
00570        /* into nextInWord.  Shift appropriately and consume the bytes   */
00571        /* used in the partial word.                                     */
00572        /*****************************************************************/
00573        mask = streamWord = 0;
00574 #ifdef IS_LITTLE_ENDIAN
00575        for (i = 0; i < inputLen; ++i) {
00576 #else
00577        for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
00578 #endif
00579               ARCFOUR_NEXT_BYTE();
00580               streamWord |= (WORD)(cx->S[t]) << 8*i;
00581               mask |= MASK1BYTE << 8*i;
00582        } /* } */
00583        /* UMR?  See comments above. */
00584        *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
00585        cx->i = tmpi;
00586        cx->j = tmpj;
00587        return SECSuccess;
00588 }
00589 #endif
00590 #endif /* NSS_BEVAND_ARCFOUR */
00591 
00592 SECStatus 
00593 RC4_Encrypt(RC4Context *cx, unsigned char *output,
00594             unsigned int *outputLen, unsigned int maxOutputLen,
00595             const unsigned char *input, unsigned int inputLen)
00596 {
00597        PORT_Assert(maxOutputLen >= inputLen);
00598        if (maxOutputLen < inputLen) {
00599               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00600               return SECFailure;
00601        }
00602 #if defined(NSS_BEVAND_ARCFOUR)
00603        ARCFOUR(cx, inputLen, input, output);
00604         *outputLen = inputLen;
00605        return SECSuccess;
00606 #elif defined( CONVERT_TO_WORDS )
00607        /* Convert the byte-stream to a word-stream */
00608        return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
00609 #else
00610        /* Operate on bytes, but unroll the main loop */
00611        return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
00612 #endif
00613 }
00614 
00615 SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
00616                       unsigned int *outputLen, unsigned int maxOutputLen,
00617                       const unsigned char *input, unsigned int inputLen)
00618 {
00619        PORT_Assert(maxOutputLen >= inputLen);
00620        if (maxOutputLen < inputLen) {
00621               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00622               return SECFailure;
00623        }
00624        /* decrypt and encrypt are same operation. */
00625 #if defined(NSS_BEVAND_ARCFOUR)
00626        ARCFOUR(cx, inputLen, input, output);
00627         *outputLen = inputLen;
00628        return SECSuccess;
00629 #elif defined( CONVERT_TO_WORDS )
00630        /* Convert the byte-stream to a word-stream */
00631        return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
00632 #else
00633        /* Operate on bytes, but unroll the main loop */
00634        return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
00635 #endif
00636 }
00637 
00638 #undef CONVERT_TO_WORDS
00639 #undef USE_LONG