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