security/nss/lib/freebl/arcfour.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* arcfour.c - the arc four algorithm.
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifdef FREEBL_NO_DEPEND
michael@0 8 #include "stubs.h"
michael@0 9 #endif
michael@0 10
michael@0 11 #include "prerr.h"
michael@0 12 #include "secerr.h"
michael@0 13
michael@0 14 #include "prtypes.h"
michael@0 15 #include "blapi.h"
michael@0 16
michael@0 17 /* Architecture-dependent defines */
michael@0 18
michael@0 19 #if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \
michael@0 20 defined(_WIN64)
michael@0 21 /* Convert the byte-stream to a word-stream */
michael@0 22 #define CONVERT_TO_WORDS
michael@0 23 #endif
michael@0 24
michael@0 25 #if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
michael@0 26 /* Treat array variables as words, not bytes, on CPUs that take
michael@0 27 * much longer to write bytes than to write words, or when using
michael@0 28 * assembler code that required it.
michael@0 29 */
michael@0 30 #define USE_WORD
michael@0 31 #endif
michael@0 32
michael@0 33 #if defined(IS_64) || defined(NSS_BEVAND_ARCFOUR)
michael@0 34 typedef PRUint64 WORD;
michael@0 35 #else
michael@0 36 typedef PRUint32 WORD;
michael@0 37 #endif
michael@0 38 #define WORDSIZE sizeof(WORD)
michael@0 39
michael@0 40 #if defined(USE_WORD)
michael@0 41 typedef WORD Stype;
michael@0 42 #else
michael@0 43 typedef PRUint8 Stype;
michael@0 44 #endif
michael@0 45
michael@0 46 #define ARCFOUR_STATE_SIZE 256
michael@0 47
michael@0 48 #define MASK1BYTE (WORD)(0xff)
michael@0 49
michael@0 50 #define SWAP(a, b) \
michael@0 51 tmp = a; \
michael@0 52 a = b; \
michael@0 53 b = tmp;
michael@0 54
michael@0 55 /*
michael@0 56 * State information for stream cipher.
michael@0 57 */
michael@0 58 struct RC4ContextStr
michael@0 59 {
michael@0 60 #if defined(NSS_ARCFOUR_IJ_B4_S) || defined(NSS_BEVAND_ARCFOUR)
michael@0 61 Stype i;
michael@0 62 Stype j;
michael@0 63 Stype S[ARCFOUR_STATE_SIZE];
michael@0 64 #else
michael@0 65 Stype S[ARCFOUR_STATE_SIZE];
michael@0 66 Stype i;
michael@0 67 Stype j;
michael@0 68 #endif
michael@0 69 };
michael@0 70
michael@0 71 /*
michael@0 72 * array indices [0..255] to initialize cx->S array (faster than loop).
michael@0 73 */
michael@0 74 static const Stype Kinit[256] = {
michael@0 75 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
michael@0 76 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
michael@0 77 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
michael@0 78 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
michael@0 79 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
michael@0 80 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
michael@0 81 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
michael@0 82 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
michael@0 83 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
michael@0 84 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
michael@0 85 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
michael@0 86 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
michael@0 87 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
michael@0 88 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
michael@0 89 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
michael@0 90 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
michael@0 91 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
michael@0 92 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
michael@0 93 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
michael@0 94 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
michael@0 95 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
michael@0 96 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
michael@0 97 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
michael@0 98 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
michael@0 99 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
michael@0 100 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
michael@0 101 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
michael@0 102 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
michael@0 103 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
michael@0 104 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
michael@0 105 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
michael@0 106 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
michael@0 107 };
michael@0 108
michael@0 109 RC4Context *
michael@0 110 RC4_AllocateContext(void)
michael@0 111 {
michael@0 112 return PORT_ZNew(RC4Context);
michael@0 113 }
michael@0 114
michael@0 115 SECStatus
michael@0 116 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
michael@0 117 const unsigned char * unused1, int unused2,
michael@0 118 unsigned int unused3, unsigned int unused4)
michael@0 119 {
michael@0 120 unsigned int i;
michael@0 121 PRUint8 j, tmp;
michael@0 122 PRUint8 K[256];
michael@0 123 PRUint8 *L;
michael@0 124
michael@0 125 /* verify the key length. */
michael@0 126 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
michael@0 127 if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
michael@0 128 PORT_SetError(SEC_ERROR_BAD_KEY);
michael@0 129 return SECFailure;
michael@0 130 }
michael@0 131 if (cx == NULL) {
michael@0 132 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 133 return SECFailure;
michael@0 134 }
michael@0 135 /* Initialize the state using array indices. */
michael@0 136 memcpy(cx->S, Kinit, sizeof cx->S);
michael@0 137 /* Fill in K repeatedly with values from key. */
michael@0 138 L = K;
michael@0 139 for (i = sizeof K; i > len; i-= len) {
michael@0 140 memcpy(L, key, len);
michael@0 141 L += len;
michael@0 142 }
michael@0 143 memcpy(L, key, i);
michael@0 144 /* Stir the state of the generator. At this point it is assumed
michael@0 145 * that the key is the size of the state buffer. If this is not
michael@0 146 * the case, the key bytes are repeated to fill the buffer.
michael@0 147 */
michael@0 148 j = 0;
michael@0 149 #define ARCFOUR_STATE_STIR(ii) \
michael@0 150 j = j + cx->S[ii] + K[ii]; \
michael@0 151 SWAP(cx->S[ii], cx->S[j]);
michael@0 152 for (i=0; i<ARCFOUR_STATE_SIZE; i++) {
michael@0 153 ARCFOUR_STATE_STIR(i);
michael@0 154 }
michael@0 155 cx->i = 0;
michael@0 156 cx->j = 0;
michael@0 157 return SECSuccess;
michael@0 158 }
michael@0 159
michael@0 160
michael@0 161 /*
michael@0 162 * Initialize a new generator.
michael@0 163 */
michael@0 164 RC4Context *
michael@0 165 RC4_CreateContext(const unsigned char *key, int len)
michael@0 166 {
michael@0 167 RC4Context *cx = RC4_AllocateContext();
michael@0 168 if (cx) {
michael@0 169 SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
michael@0 170 if (rv != SECSuccess) {
michael@0 171 PORT_ZFree(cx, sizeof(*cx));
michael@0 172 cx = NULL;
michael@0 173 }
michael@0 174 }
michael@0 175 return cx;
michael@0 176 }
michael@0 177
michael@0 178 void
michael@0 179 RC4_DestroyContext(RC4Context *cx, PRBool freeit)
michael@0 180 {
michael@0 181 if (freeit)
michael@0 182 PORT_ZFree(cx, sizeof(*cx));
michael@0 183 }
michael@0 184
michael@0 185 #if defined(NSS_BEVAND_ARCFOUR)
michael@0 186 extern void ARCFOUR(RC4Context *cx, WORD inputLen,
michael@0 187 const unsigned char *input, unsigned char *output);
michael@0 188 #else
michael@0 189 /*
michael@0 190 * Generate the next byte in the stream.
michael@0 191 */
michael@0 192 #define ARCFOUR_NEXT_BYTE() \
michael@0 193 tmpSi = cx->S[++tmpi]; \
michael@0 194 tmpj += tmpSi; \
michael@0 195 tmpSj = cx->S[tmpj]; \
michael@0 196 cx->S[tmpi] = tmpSj; \
michael@0 197 cx->S[tmpj] = tmpSi; \
michael@0 198 t = tmpSi + tmpSj;
michael@0 199
michael@0 200 #ifdef CONVERT_TO_WORDS
michael@0 201 /*
michael@0 202 * Straight ARCFOUR op. No optimization.
michael@0 203 */
michael@0 204 static SECStatus
michael@0 205 rc4_no_opt(RC4Context *cx, unsigned char *output,
michael@0 206 unsigned int *outputLen, unsigned int maxOutputLen,
michael@0 207 const unsigned char *input, unsigned int inputLen)
michael@0 208 {
michael@0 209 PRUint8 t;
michael@0 210 Stype tmpSi, tmpSj;
michael@0 211 register PRUint8 tmpi = cx->i;
michael@0 212 register PRUint8 tmpj = cx->j;
michael@0 213 unsigned int index;
michael@0 214 PORT_Assert(maxOutputLen >= inputLen);
michael@0 215 if (maxOutputLen < inputLen) {
michael@0 216 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 217 return SECFailure;
michael@0 218 }
michael@0 219 for (index=0; index < inputLen; index++) {
michael@0 220 /* Generate next byte from stream. */
michael@0 221 ARCFOUR_NEXT_BYTE();
michael@0 222 /* output = next stream byte XOR next input byte */
michael@0 223 output[index] = cx->S[t] ^ input[index];
michael@0 224 }
michael@0 225 *outputLen = inputLen;
michael@0 226 cx->i = tmpi;
michael@0 227 cx->j = tmpj;
michael@0 228 return SECSuccess;
michael@0 229 }
michael@0 230
michael@0 231 #else
michael@0 232 /* !CONVERT_TO_WORDS */
michael@0 233
michael@0 234 /*
michael@0 235 * Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces.
michael@0 236 */
michael@0 237 static SECStatus
michael@0 238 rc4_unrolled(RC4Context *cx, unsigned char *output,
michael@0 239 unsigned int *outputLen, unsigned int maxOutputLen,
michael@0 240 const unsigned char *input, unsigned int inputLen)
michael@0 241 {
michael@0 242 PRUint8 t;
michael@0 243 Stype tmpSi, tmpSj;
michael@0 244 register PRUint8 tmpi = cx->i;
michael@0 245 register PRUint8 tmpj = cx->j;
michael@0 246 int index;
michael@0 247 PORT_Assert(maxOutputLen >= inputLen);
michael@0 248 if (maxOutputLen < inputLen) {
michael@0 249 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 250 return SECFailure;
michael@0 251 }
michael@0 252 for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
michael@0 253 ARCFOUR_NEXT_BYTE();
michael@0 254 output[0] = cx->S[t] ^ input[0];
michael@0 255 ARCFOUR_NEXT_BYTE();
michael@0 256 output[1] = cx->S[t] ^ input[1];
michael@0 257 ARCFOUR_NEXT_BYTE();
michael@0 258 output[2] = cx->S[t] ^ input[2];
michael@0 259 ARCFOUR_NEXT_BYTE();
michael@0 260 output[3] = cx->S[t] ^ input[3];
michael@0 261 ARCFOUR_NEXT_BYTE();
michael@0 262 output[4] = cx->S[t] ^ input[4];
michael@0 263 ARCFOUR_NEXT_BYTE();
michael@0 264 output[5] = cx->S[t] ^ input[5];
michael@0 265 ARCFOUR_NEXT_BYTE();
michael@0 266 output[6] = cx->S[t] ^ input[6];
michael@0 267 ARCFOUR_NEXT_BYTE();
michael@0 268 output[7] = cx->S[t] ^ input[7];
michael@0 269 }
michael@0 270 index = inputLen % 8;
michael@0 271 if (index) {
michael@0 272 input += index;
michael@0 273 output += index;
michael@0 274 switch (index) {
michael@0 275 case 7:
michael@0 276 ARCFOUR_NEXT_BYTE();
michael@0 277 output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
michael@0 278 case 6:
michael@0 279 ARCFOUR_NEXT_BYTE();
michael@0 280 output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
michael@0 281 case 5:
michael@0 282 ARCFOUR_NEXT_BYTE();
michael@0 283 output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
michael@0 284 case 4:
michael@0 285 ARCFOUR_NEXT_BYTE();
michael@0 286 output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
michael@0 287 case 3:
michael@0 288 ARCFOUR_NEXT_BYTE();
michael@0 289 output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
michael@0 290 case 2:
michael@0 291 ARCFOUR_NEXT_BYTE();
michael@0 292 output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
michael@0 293 case 1:
michael@0 294 ARCFOUR_NEXT_BYTE();
michael@0 295 output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
michael@0 296 default:
michael@0 297 /* FALLTHRU */
michael@0 298 ; /* hp-ux build breaks without this */
michael@0 299 }
michael@0 300 }
michael@0 301 cx->i = tmpi;
michael@0 302 cx->j = tmpj;
michael@0 303 *outputLen = inputLen;
michael@0 304 return SECSuccess;
michael@0 305 }
michael@0 306 #endif
michael@0 307
michael@0 308 #ifdef IS_LITTLE_ENDIAN
michael@0 309 #define ARCFOUR_NEXT4BYTES_L(n) \
michael@0 310 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n ); \
michael@0 311 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
michael@0 312 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
michael@0 313 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
michael@0 314 #else
michael@0 315 #define ARCFOUR_NEXT4BYTES_B(n) \
michael@0 316 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
michael@0 317 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
michael@0 318 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
michael@0 319 ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n );
michael@0 320 #endif
michael@0 321
michael@0 322 #if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64)
michael@0 323 /* 64-bit wordsize */
michael@0 324 #ifdef IS_LITTLE_ENDIAN
michael@0 325 #define ARCFOUR_NEXT_WORD() \
michael@0 326 { streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
michael@0 327 #else
michael@0 328 #define ARCFOUR_NEXT_WORD() \
michael@0 329 { streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
michael@0 330 #endif
michael@0 331 #else
michael@0 332 /* 32-bit wordsize */
michael@0 333 #ifdef IS_LITTLE_ENDIAN
michael@0 334 #define ARCFOUR_NEXT_WORD() \
michael@0 335 { streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
michael@0 336 #else
michael@0 337 #define ARCFOUR_NEXT_WORD() \
michael@0 338 { streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
michael@0 339 #endif
michael@0 340 #endif
michael@0 341
michael@0 342 #ifdef IS_LITTLE_ENDIAN
michael@0 343 #define RSH <<
michael@0 344 #define LSH >>
michael@0 345 #else
michael@0 346 #define RSH >>
michael@0 347 #define LSH <<
michael@0 348 #endif
michael@0 349
michael@0 350 #ifdef IS_LITTLE_ENDIAN
michael@0 351 #define LEFTMOST_BYTE_SHIFT 0
michael@0 352 #define NEXT_BYTE_SHIFT(shift) shift + 8
michael@0 353 #else
michael@0 354 #define LEFTMOST_BYTE_SHIFT 8*(WORDSIZE - 1)
michael@0 355 #define NEXT_BYTE_SHIFT(shift) shift - 8
michael@0 356 #endif
michael@0 357
michael@0 358 #ifdef CONVERT_TO_WORDS
michael@0 359 static SECStatus
michael@0 360 rc4_wordconv(RC4Context *cx, unsigned char *output,
michael@0 361 unsigned int *outputLen, unsigned int maxOutputLen,
michael@0 362 const unsigned char *input, unsigned int inputLen)
michael@0 363 {
michael@0 364 PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t));
michael@0 365 unsigned int inOffset = (PRUword)input % WORDSIZE;
michael@0 366 unsigned int outOffset = (PRUword)output % WORDSIZE;
michael@0 367 register WORD streamWord;
michael@0 368 register const WORD *pInWord;
michael@0 369 register WORD *pOutWord;
michael@0 370 register WORD inWord, nextInWord;
michael@0 371 PRUint8 t;
michael@0 372 register Stype tmpSi, tmpSj;
michael@0 373 register PRUint8 tmpi = cx->i;
michael@0 374 register PRUint8 tmpj = cx->j;
michael@0 375 unsigned int bufShift, invBufShift;
michael@0 376 unsigned int i;
michael@0 377 const unsigned char *finalIn;
michael@0 378 unsigned char *finalOut;
michael@0 379
michael@0 380 PORT_Assert(maxOutputLen >= inputLen);
michael@0 381 if (maxOutputLen < inputLen) {
michael@0 382 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 383 return SECFailure;
michael@0 384 }
michael@0 385 if (inputLen < 2*WORDSIZE) {
michael@0 386 /* Ignore word conversion, do byte-at-a-time */
michael@0 387 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
michael@0 388 }
michael@0 389 *outputLen = inputLen;
michael@0 390 pInWord = (const WORD *)(input - inOffset);
michael@0 391 pOutWord = (WORD *)(output - outOffset);
michael@0 392 if (inOffset <= outOffset) {
michael@0 393 bufShift = 8*(outOffset - inOffset);
michael@0 394 invBufShift = 8*WORDSIZE - bufShift;
michael@0 395 } else {
michael@0 396 invBufShift = 8*(inOffset - outOffset);
michael@0 397 bufShift = 8*WORDSIZE - invBufShift;
michael@0 398 }
michael@0 399 /*****************************************************************/
michael@0 400 /* Step 1: */
michael@0 401 /* If the first output word is partial, consume the bytes in the */
michael@0 402 /* first partial output word by loading one or two words of */
michael@0 403 /* input and shifting them accordingly. Otherwise, just load */
michael@0 404 /* in the first word of input. At the end of this block, at */
michael@0 405 /* least one partial word of input should ALWAYS be loaded. */
michael@0 406 /*****************************************************************/
michael@0 407 if (outOffset) {
michael@0 408 unsigned int byteCount = WORDSIZE - outOffset;
michael@0 409 for (i = 0; i < byteCount; i++) {
michael@0 410 ARCFOUR_NEXT_BYTE();
michael@0 411 output[i] = cx->S[t] ^ input[i];
michael@0 412 }
michael@0 413 /* Consumed byteCount bytes of input */
michael@0 414 inputLen -= byteCount;
michael@0 415 pInWord++;
michael@0 416
michael@0 417 /* move to next word of output */
michael@0 418 pOutWord++;
michael@0 419
michael@0 420 /* If buffers are relatively misaligned, shift the bytes in inWord
michael@0 421 * to be aligned to the output buffer.
michael@0 422 */
michael@0 423 if (inOffset < outOffset) {
michael@0 424 /* The first input word (which may be partial) has more bytes
michael@0 425 * than needed. Copy the remainder to inWord.
michael@0 426 */
michael@0 427 unsigned int shift = LEFTMOST_BYTE_SHIFT;
michael@0 428 inWord = 0;
michael@0 429 for (i = 0; i < outOffset - inOffset; i++) {
michael@0 430 inWord |= (WORD)input[byteCount + i] << shift;
michael@0 431 shift = NEXT_BYTE_SHIFT(shift);
michael@0 432 }
michael@0 433 } else if (inOffset > outOffset) {
michael@0 434 /* Consumed some bytes in the second input word. Copy the
michael@0 435 * remainder to inWord.
michael@0 436 */
michael@0 437 inWord = *pInWord++;
michael@0 438 inWord = inWord LSH invBufShift;
michael@0 439 } else {
michael@0 440 inWord = 0;
michael@0 441 }
michael@0 442 } else {
michael@0 443 /* output is word-aligned */
michael@0 444 if (inOffset) {
michael@0 445 /* Input is not word-aligned. The first word load of input
michael@0 446 * will not produce a full word of input bytes, so one word
michael@0 447 * must be pre-loaded. The main loop below will load in the
michael@0 448 * next input word and shift some of its bytes into inWord
michael@0 449 * in order to create a full input word. Note that the main
michael@0 450 * loop must execute at least once because the input must
michael@0 451 * be at least two words.
michael@0 452 */
michael@0 453 unsigned int shift = LEFTMOST_BYTE_SHIFT;
michael@0 454 inWord = 0;
michael@0 455 for (i = 0; i < WORDSIZE - inOffset; i++) {
michael@0 456 inWord |= (WORD)input[i] << shift;
michael@0 457 shift = NEXT_BYTE_SHIFT(shift);
michael@0 458 }
michael@0 459 pInWord++;
michael@0 460 } else {
michael@0 461 /* Input is word-aligned. The first word load of input
michael@0 462 * will produce a full word of input bytes, so nothing
michael@0 463 * needs to be loaded here.
michael@0 464 */
michael@0 465 inWord = 0;
michael@0 466 }
michael@0 467 }
michael@0 468 /*****************************************************************/
michael@0 469 /* Step 2: main loop */
michael@0 470 /* At this point the output buffer is word-aligned. Any unused */
michael@0 471 /* bytes from above will be in inWord (shifted correctly). If */
michael@0 472 /* the input buffer is unaligned relative to the output buffer, */
michael@0 473 /* shifting has to be done. */
michael@0 474 /*****************************************************************/
michael@0 475 if (bufShift) {
michael@0 476 /* preloadedByteCount is the number of input bytes pre-loaded
michael@0 477 * in inWord.
michael@0 478 */
michael@0 479 unsigned int preloadedByteCount = bufShift/8;
michael@0 480 for (; inputLen >= preloadedByteCount + WORDSIZE;
michael@0 481 inputLen -= WORDSIZE) {
michael@0 482 nextInWord = *pInWord++;
michael@0 483 inWord |= nextInWord RSH bufShift;
michael@0 484 nextInWord = nextInWord LSH invBufShift;
michael@0 485 ARCFOUR_NEXT_WORD();
michael@0 486 *pOutWord++ = inWord ^ streamWord;
michael@0 487 inWord = nextInWord;
michael@0 488 }
michael@0 489 if (inputLen == 0) {
michael@0 490 /* Nothing left to do. */
michael@0 491 cx->i = tmpi;
michael@0 492 cx->j = tmpj;
michael@0 493 return SECSuccess;
michael@0 494 }
michael@0 495 finalIn = (const unsigned char *)pInWord - preloadedByteCount;
michael@0 496 } else {
michael@0 497 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
michael@0 498 inWord = *pInWord++;
michael@0 499 ARCFOUR_NEXT_WORD();
michael@0 500 *pOutWord++ = inWord ^ streamWord;
michael@0 501 }
michael@0 502 if (inputLen == 0) {
michael@0 503 /* Nothing left to do. */
michael@0 504 cx->i = tmpi;
michael@0 505 cx->j = tmpj;
michael@0 506 return SECSuccess;
michael@0 507 }
michael@0 508 finalIn = (const unsigned char *)pInWord;
michael@0 509 }
michael@0 510 /*****************************************************************/
michael@0 511 /* Step 3: */
michael@0 512 /* Do the remaining partial word of input one byte at a time. */
michael@0 513 /*****************************************************************/
michael@0 514 finalOut = (unsigned char *)pOutWord;
michael@0 515 for (i = 0; i < inputLen; i++) {
michael@0 516 ARCFOUR_NEXT_BYTE();
michael@0 517 finalOut[i] = cx->S[t] ^ finalIn[i];
michael@0 518 }
michael@0 519 cx->i = tmpi;
michael@0 520 cx->j = tmpj;
michael@0 521 return SECSuccess;
michael@0 522 }
michael@0 523 #endif
michael@0 524 #endif /* NSS_BEVAND_ARCFOUR */
michael@0 525
michael@0 526 SECStatus
michael@0 527 RC4_Encrypt(RC4Context *cx, unsigned char *output,
michael@0 528 unsigned int *outputLen, unsigned int maxOutputLen,
michael@0 529 const unsigned char *input, unsigned int inputLen)
michael@0 530 {
michael@0 531 PORT_Assert(maxOutputLen >= inputLen);
michael@0 532 if (maxOutputLen < inputLen) {
michael@0 533 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 534 return SECFailure;
michael@0 535 }
michael@0 536 #if defined(NSS_BEVAND_ARCFOUR)
michael@0 537 ARCFOUR(cx, inputLen, input, output);
michael@0 538 *outputLen = inputLen;
michael@0 539 return SECSuccess;
michael@0 540 #elif defined( CONVERT_TO_WORDS )
michael@0 541 /* Convert the byte-stream to a word-stream */
michael@0 542 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
michael@0 543 #else
michael@0 544 /* Operate on bytes, but unroll the main loop */
michael@0 545 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
michael@0 546 #endif
michael@0 547 }
michael@0 548
michael@0 549 SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
michael@0 550 unsigned int *outputLen, unsigned int maxOutputLen,
michael@0 551 const unsigned char *input, unsigned int inputLen)
michael@0 552 {
michael@0 553 PORT_Assert(maxOutputLen >= inputLen);
michael@0 554 if (maxOutputLen < inputLen) {
michael@0 555 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 556 return SECFailure;
michael@0 557 }
michael@0 558 /* decrypt and encrypt are same operation. */
michael@0 559 #if defined(NSS_BEVAND_ARCFOUR)
michael@0 560 ARCFOUR(cx, inputLen, input, output);
michael@0 561 *outputLen = inputLen;
michael@0 562 return SECSuccess;
michael@0 563 #elif defined( CONVERT_TO_WORDS )
michael@0 564 /* Convert the byte-stream to a word-stream */
michael@0 565 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
michael@0 566 #else
michael@0 567 /* Operate on bytes, but unroll the main loop */
michael@0 568 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
michael@0 569 #endif
michael@0 570 }
michael@0 571
michael@0 572 #undef CONVERT_TO_WORDS
michael@0 573 #undef USE_WORD

mercurial