OLD | NEW |
---|---|
1 /* arcfour.c - the arc four algorithm. | 1 /* arcfour.c - the arc four algorithm. |
2 * | 2 * |
3 * This Source Code Form is subject to the terms of the Mozilla Public | 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 | 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/. */ | 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | 6 |
7 /* See NOTES ON UMRs, Unititialized Memory Reads, below. */ | |
8 | |
9 #ifdef FREEBL_NO_DEPEND | 7 #ifdef FREEBL_NO_DEPEND |
10 #include "stubs.h" | 8 #include "stubs.h" |
11 #endif | 9 #endif |
12 | 10 |
13 #include "prerr.h" | 11 #include "prerr.h" |
14 #include "secerr.h" | 12 #include "secerr.h" |
15 | 13 |
16 #include "prtypes.h" | 14 #include "prtypes.h" |
17 #include "blapi.h" | 15 #include "blapi.h" |
18 | 16 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 RC4_AllocateContext(void) | 110 RC4_AllocateContext(void) |
113 { | 111 { |
114 return PORT_ZNew(RC4Context); | 112 return PORT_ZNew(RC4Context); |
115 } | 113 } |
116 | 114 |
117 SECStatus | 115 SECStatus |
118 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, | 116 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, |
119 const unsigned char * unused1, int unused2, | 117 const unsigned char * unused1, int unused2, |
120 unsigned int unused3, unsigned int unused4) | 118 unsigned int unused3, unsigned int unused4) |
121 { | 119 { |
122 » int i; | 120 » unsigned int i; |
123 PRUint8 j, tmp; | 121 PRUint8 j, tmp; |
124 PRUint8 K[256]; | 122 PRUint8 K[256]; |
125 PRUint8 *L; | 123 PRUint8 *L; |
126 | 124 |
127 /* verify the key length. */ | 125 /* verify the key length. */ |
128 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); | 126 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); |
129 if (len == 0 || len >= ARCFOUR_STATE_SIZE) { | 127 if (len == 0 || len >= ARCFOUR_STATE_SIZE) { |
130 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 128 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
131 return SECFailure; | 129 return SECFailure; |
132 } | 130 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
343 | 341 |
344 #ifdef IS_LITTLE_ENDIAN | 342 #ifdef IS_LITTLE_ENDIAN |
345 #define RSH << | 343 #define RSH << |
346 #define LSH >> | 344 #define LSH >> |
347 #else | 345 #else |
348 #define RSH >> | 346 #define RSH >> |
349 #define LSH << | 347 #define LSH << |
350 #endif | 348 #endif |
351 | 349 |
352 #ifdef CONVERT_TO_WORDS | 350 #ifdef CONVERT_TO_WORDS |
353 /* NOTE about UMRs, Uninitialized Memory Reads. | |
354 * | |
355 * This code reads all input data a WORD at a time, rather than byte at | |
356 * a time, and writes all output data a WORD at a time. Shifting and | |
357 * masking is used to remove unwanted data and realign bytes when | |
358 * needed. The first and last words of output are read, modified, and | |
359 * written when needed to preserve any unchanged bytes. This is a huge | |
360 * win on machines with high memory latency. | |
361 * | |
362 * However, when the input and output buffers do not begin and end on WORD | |
363 * boundaries, and the WORDS in memory that contain the first and last | |
364 * bytes of those buffers contain uninitialized data, then this code will | |
365 * read those uninitialized bytes, causing a UMR error to be reported by | |
366 * some tools. | |
367 * | |
368 * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed". | |
369 * | |
370 * All the words read and written contain at least one byte that is | |
371 * part of the input data or output data. No words are read or written | |
372 * that do not contain data that is part of the buffer. Therefore, | |
373 * these UMRs cannot cause page faults or other problems unless the | |
374 * buffers have been assigned to improper addresses that would cause | |
375 * page faults with or without UMRs. | |
376 */ | |
377 static SECStatus | 351 static SECStatus |
378 rc4_wordconv(RC4Context *cx, unsigned char *output, | 352 rc4_wordconv(RC4Context *cx, unsigned char *output, |
379 unsigned int *outputLen, unsigned int maxOutputLen, | 353 unsigned int *outputLen, unsigned int maxOutputLen, |
380 const unsigned char *input, unsigned int inputLen) | 354 const unsigned char *input, unsigned int inputLen) |
381 { | 355 { |
382 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE; | 356 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE; |
383 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE; | 357 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE; |
384 » register WORD streamWord, mask; | 358 » register WORD streamWord; |
wtc
2013/02/08 17:15:55
|mask| is used to mask off the unwanted bytes in t
| |
385 » register WORD *pInWord, *pOutWord; | 359 » const register WORD *pInWord; |
wtc
2013/02/08 17:15:55
Here I want to make |pInWord| a const pointer.
| |
360 » register WORD *pOutWord; | |
386 register WORD inWord, nextInWord; | 361 register WORD inWord, nextInWord; |
wtc
2013/02/08 17:46:43
Visual C++ does not allow me to take the address o
| |
387 PRUint8 t; | 362 PRUint8 t; |
388 register Stype tmpSi, tmpSj; | 363 register Stype tmpSi, tmpSj; |
389 register PRUint8 tmpi = cx->i; | 364 register PRUint8 tmpi = cx->i; |
390 register PRUint8 tmpj = cx->j; | 365 register PRUint8 tmpj = cx->j; |
391 unsigned int byteCount; | 366 unsigned int byteCount; |
392 unsigned int bufShift, invBufShift; | 367 unsigned int bufShift, invBufShift; |
393 int i; | 368 int i; |
369 const unsigned char *finalIn; | |
370 unsigned char *finalOut; | |
394 | 371 |
395 PORT_Assert(maxOutputLen >= inputLen); | 372 PORT_Assert(maxOutputLen >= inputLen); |
396 if (maxOutputLen < inputLen) { | 373 if (maxOutputLen < inputLen) { |
397 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 374 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
398 return SECFailure; | 375 return SECFailure; |
399 } | 376 } |
400 if (inputLen < 2*WORDSIZE) { | 377 if (inputLen < 2*WORDSIZE) { |
401 /* Ignore word conversion, do byte-at-a-time */ | 378 /* Ignore word conversion, do byte-at-a-time */ |
402 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen); | 379 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen); |
403 } | 380 } |
404 *outputLen = inputLen; | 381 *outputLen = inputLen; |
405 » pInWord = (WORD *)(input - inOffset); | 382 » pInWord = (const WORD *)(input - inOffset); |
383 » pOutWord = (WORD *)(output - outOffset); | |
406 if (inOffset < outOffset) { | 384 if (inOffset < outOffset) { |
407 bufShift = 8*(outOffset - inOffset); | 385 bufShift = 8*(outOffset - inOffset); |
408 invBufShift = 8*WORDSIZE - bufShift; | 386 invBufShift = 8*WORDSIZE - bufShift; |
409 } else { | 387 } else { |
410 invBufShift = 8*(inOffset - outOffset); | 388 invBufShift = 8*(inOffset - outOffset); |
411 bufShift = 8*WORDSIZE - invBufShift; | 389 bufShift = 8*WORDSIZE - invBufShift; |
412 } | 390 } |
413 /*****************************************************************/ | 391 /*****************************************************************/ |
414 /* Step 1: */ | 392 /* Step 1: */ |
wtc
2013/02/08 17:15:55
Step 1 is a complete rewrite. Therefore, do not re
| |
415 /* If the first output word is partial, consume the bytes in the */ | 393 /* If the first output word is partial, consume the bytes in the */ |
416 /* first partial output word by loading one or two words of */ | 394 /* first partial output word by loading one or two words of */ |
417 /* input and shifting them accordingly. Otherwise, just load */ | 395 /* input and shifting them accordingly. Otherwise, just load */ |
418 /* in the first word of input. At the end of this block, at */ | 396 /* in the first word of input. At the end of this block, at */ |
419 /* least one partial word of input should ALWAYS be loaded. */ | 397 /* least one partial word of input should ALWAYS be loaded. */ |
420 /*****************************************************************/ | 398 /*****************************************************************/ |
421 if (outOffset) { | 399 if (outOffset) { |
422 /* Generate input and stream words aligned relative to the | |
423 * partial output buffer. | |
424 */ | |
425 byteCount = WORDSIZE - outOffset; | 400 byteCount = WORDSIZE - outOffset; |
426 » » pOutWord = (WORD *)(output - outOffset); | 401 » » for (i = 0; i < byteCount; i++) { |
427 » » mask = streamWord = 0; | |
428 #ifdef IS_LITTLE_ENDIAN | |
429 » » for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) { | |
430 #else | |
431 » » for (i = byteCount - 1; i >= 0; --i) { | |
432 #endif | |
433 ARCFOUR_NEXT_BYTE(); | 402 ARCFOUR_NEXT_BYTE(); |
434 » » » streamWord |= (WORD)(cx->S[t]) << 8*i; | 403 » » » output[i] = cx->S[t] ^ input[i]; |
435 » » » mask |= MASK1BYTE << 8*i; | 404 » » } |
436 » » } /* } */ | 405 » » /* Consumed byteCount bytes of input */ |
437 » » inWord = *pInWord++; /* UMR? see comments above. */ | 406 » » inputLen -= byteCount; |
407 » » pInWord++; | |
408 | |
409 » » /* move to next word of output */ | |
410 » » pOutWord++; | |
411 | |
438 /* If buffers are relatively misaligned, shift the bytes in inWo rd | 412 /* If buffers are relatively misaligned, shift the bytes in inWo rd |
439 * to be aligned to the output buffer. | 413 * to be aligned to the output buffer. |
440 */ | 414 */ |
441 nextInWord = 0; | |
442 if (inOffset < outOffset) { | 415 if (inOffset < outOffset) { |
443 » » » /* Have more bytes than needed, shift remainder into nex tInWord */ | 416 » » » /* The first input word (which may be partial) has more bytes |
444 » » » nextInWord = inWord LSH 8*(inOffset + byteCount); | 417 » » » * than needed. Copy the remainder to inWord. |
445 » » » inWord = inWord RSH bufShift; | 418 » » » */ |
419 » » » inWord = 0; | |
420 » » » memcpy(&inWord, &input[byteCount], outOffset - inOffset) ; | |
446 } else if (inOffset > outOffset) { | 421 } else if (inOffset > outOffset) { |
447 » » » /* Didn't get enough bytes from current input word, load another | 422 » » » /* Consumed some bytes in the second input word. Copy t he |
448 » » » * word and then shift remainder into nextInWord. | 423 » » » * remainder to inWord. |
449 */ | 424 */ |
450 » » » nextInWord = *pInWord++; | 425 » » » inWord = *pInWord++; |
451 » » » inWord = (inWord LSH invBufShift) | | 426 » » » inWord = inWord LSH invBufShift; |
452 » » » (nextInWord RSH bufShift); | |
453 » » » nextInWord = nextInWord LSH invBufShift; | |
454 } | 427 } |
455 /* Store output of first partial word */ | |
456 *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask) ; | |
457 /* UMR? See comments above. */ | |
458 | |
459 /* Consumed byteCount bytes of input */ | |
460 inputLen -= byteCount; | |
461 /* move to next word of output */ | |
462 pOutWord++; | |
463 /* inWord has been consumed, but there may be bytes in nextInWor d */ | |
464 inWord = nextInWord; | |
465 } else { | 428 } else { |
466 /* output is word-aligned */ | 429 /* output is word-aligned */ |
467 pOutWord = (WORD *)output; | |
468 if (inOffset) { | 430 if (inOffset) { |
469 /* Input is not word-aligned. The first word load of in put | 431 /* Input is not word-aligned. The first word load of in put |
470 * will not produce a full word of input bytes, so one w ord | 432 * will not produce a full word of input bytes, so one w ord |
471 * must be pre-loaded. The main loop below will load in the | 433 * must be pre-loaded. The main loop below will load in the |
472 * next input word and shift some of its bytes into inWo rd | 434 * next input word and shift some of its bytes into inWo rd |
473 * in order to create a full input word. Note that the main | 435 * in order to create a full input word. Note that the main |
474 * loop must execute at least once because the input mus t | 436 * loop must execute at least once because the input mus t |
475 * be at least two words. | 437 * be at least two words. |
476 */ | 438 */ |
477 » » » inWord = *pInWord++; /* UMR? see comments above. */ | 439 » » » inWord = 0; |
478 » » » inWord = inWord LSH invBufShift; | 440 » » » memcpy(&inWord, &input[0], WORDSIZE - inOffset); |
441 » » » pInWord++; | |
479 } else { | 442 } else { |
480 /* Input is word-aligned. The first word load of input | 443 /* Input is word-aligned. The first word load of input |
481 * will produce a full word of input bytes, so nothing | 444 * will produce a full word of input bytes, so nothing |
482 * needs to be loaded here. | 445 * needs to be loaded here. |
483 */ | 446 */ |
484 inWord = 0; | 447 inWord = 0; |
485 } | 448 } |
486 } | 449 } |
487 /* Output buffer is aligned, inOffset is now measured relative to | 450 /* Output buffer is aligned, inOffset is now measured relative to |
488 * outOffset (and not a word boundary). | 451 * outOffset (and not a word boundary). |
489 */ | 452 */ |
490 inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE; | 453 inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE; |
491 /*****************************************************************/ | 454 /*****************************************************************/ |
492 /* Step 2: main loop */ | 455 /* Step 2: main loop */ |
wtc
2013/02/08 17:15:55
Step 2 is unchanged, except that at the end we nee
| |
493 /* At this point the output buffer is word-aligned. Any unused */ | 456 /* At this point the output buffer is word-aligned. Any unused */ |
494 /* bytes from above will be in inWord (shifted correctly). If */ | 457 /* bytes from above will be in inWord (shifted correctly). If */ |
495 /* the input buffer is unaligned relative to the output buffer, */ | 458 /* the input buffer is unaligned relative to the output buffer, */ |
496 /* shifting has to be done. */ | 459 /* shifting has to be done. */ |
497 /*****************************************************************/ | 460 /*****************************************************************/ |
498 if (inOffset) { | 461 if (inOffset) { |
499 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { | 462 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { |
500 nextInWord = *pInWord++; | 463 nextInWord = *pInWord++; |
501 inWord |= nextInWord RSH bufShift; | 464 inWord |= nextInWord RSH bufShift; |
502 nextInWord = nextInWord LSH invBufShift; | 465 nextInWord = nextInWord LSH invBufShift; |
503 ARCFOUR_NEXT_WORD(); | 466 ARCFOUR_NEXT_WORD(); |
504 *pOutWord++ = inWord ^ streamWord; | 467 *pOutWord++ = inWord ^ streamWord; |
505 inWord = nextInWord; | 468 inWord = nextInWord; |
506 } | 469 } |
507 if (inputLen == 0) { | 470 if (inputLen == 0) { |
508 /* Nothing left to do. */ | 471 /* Nothing left to do. */ |
509 cx->i = tmpi; | 472 cx->i = tmpi; |
510 cx->j = tmpj; | 473 cx->j = tmpj; |
511 return SECSuccess; | 474 return SECSuccess; |
512 } | 475 } |
513 » » /* If the amount of remaining input is greater than the amount | 476 » » finalIn = (const unsigned char *)pInWord - WORDSIZE + inOffset; |
514 » » * bytes pulled from the current input word, need to do another | |
515 » » * word load. What's left in inWord will be consumed in step 3. | |
516 » » */ | |
517 » » if (inputLen > WORDSIZE - inOffset) | |
518 » » » inWord |= *pInWord RSH bufShift; /* UMR? See above. */ | |
519 } else { | 477 } else { |
520 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { | 478 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { |
521 inWord = *pInWord++; | 479 inWord = *pInWord++; |
522 ARCFOUR_NEXT_WORD(); | 480 ARCFOUR_NEXT_WORD(); |
523 *pOutWord++ = inWord ^ streamWord; | 481 *pOutWord++ = inWord ^ streamWord; |
524 } | 482 } |
525 if (inputLen == 0) { | 483 if (inputLen == 0) { |
526 /* Nothing left to do. */ | 484 /* Nothing left to do. */ |
527 cx->i = tmpi; | 485 cx->i = tmpi; |
528 cx->j = tmpj; | 486 cx->j = tmpj; |
529 return SECSuccess; | 487 return SECSuccess; |
530 } else { | |
531 /* A partial input word remains at the tail. Load it. | |
532 * The relevant bytes will be consumed in step 3. | |
533 */ | |
534 inWord = *pInWord; /* UMR? See comments above */ | |
535 } | 488 } |
489 finalIn = (const unsigned char *)pInWord; | |
536 } | 490 } |
537 /*****************************************************************/ | 491 /*****************************************************************/ |
538 /* Step 3: */ | 492 /* Step 3: */ |
wtc
2013/02/08 17:15:55
Step 3 is a complete rewrite, but is simple.
| |
539 » /* A partial word of input remains, and it is already loaded */ | 493 » /* Do the remaining partial word of input one byte at a time. */ |
540 » /* into nextInWord. Shift appropriately and consume the bytes */ | |
541 » /* used in the partial word. */ | |
542 /*****************************************************************/ | 494 /*****************************************************************/ |
543 » mask = streamWord = 0; | 495 » finalOut = (unsigned char *)pOutWord; |
544 #ifdef IS_LITTLE_ENDIAN | 496 » for (i = 0; i < inputLen; i++) { |
545 » for (i = 0; i < inputLen; ++i) { | |
546 #else | |
547 » for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) { | |
548 #endif | |
549 ARCFOUR_NEXT_BYTE(); | 497 ARCFOUR_NEXT_BYTE(); |
550 » » streamWord |= (WORD)(cx->S[t]) << 8*i; | 498 » » finalout[i] = cx->S[t] ^ finalIn[i]; |
551 » » mask |= MASK1BYTE << 8*i; | 499 » } |
552 » } /* } */ | |
553 » /* UMR? See comments above. */ | |
554 » *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask); | |
555 cx->i = tmpi; | 500 cx->i = tmpi; |
556 cx->j = tmpj; | 501 cx->j = tmpj; |
557 return SECSuccess; | 502 return SECSuccess; |
558 } | 503 } |
559 #endif | 504 #endif |
560 #endif /* NSS_BEVAND_ARCFOUR */ | 505 #endif /* NSS_BEVAND_ARCFOUR */ |
561 | 506 |
562 SECStatus | 507 SECStatus |
563 RC4_Encrypt(RC4Context *cx, unsigned char *output, | 508 RC4_Encrypt(RC4Context *cx, unsigned char *output, |
564 unsigned int *outputLen, unsigned int maxOutputLen, | 509 unsigned int *outputLen, unsigned int maxOutputLen, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 /* Convert the byte-stream to a word-stream */ | 545 /* Convert the byte-stream to a word-stream */ |
601 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen ); | 546 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen ); |
602 #else | 547 #else |
603 /* Operate on bytes, but unroll the main loop */ | 548 /* Operate on bytes, but unroll the main loop */ |
604 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen ); | 549 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen ); |
605 #endif | 550 #endif |
606 } | 551 } |
607 | 552 |
608 #undef CONVERT_TO_WORDS | 553 #undef CONVERT_TO_WORDS |
609 #undef USE_WORD | 554 #undef USE_WORD |
OLD | NEW |