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