/src/nss-nspr/nss/lib/freebl/arcfour.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #define ARCFOUR_STATE_SIZE 256 |
47 | | |
48 | | #define MASK1BYTE (WORD)(0xff) |
49 | | |
50 | | #define SWAP(a, b) \ |
51 | 0 | tmp = a; \ |
52 | 0 | a = b; \ |
53 | 0 | 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 | 0 | { |
111 | 0 | return PORT_ZNew(RC4Context); |
112 | 0 | } |
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 | 0 | { |
119 | 0 | unsigned int i; |
120 | 0 | PRUint8 j, tmp; |
121 | 0 | PRUint8 K[256]; |
122 | 0 | PRUint8 *L; |
123 | | |
124 | | /* verify the key length. */ |
125 | 0 | PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); |
126 | 0 | if (len == 0 || len >= ARCFOUR_STATE_SIZE) { |
127 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
128 | 0 | return SECFailure; |
129 | 0 | } |
130 | 0 | if (cx == NULL) { |
131 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
132 | 0 | return SECFailure; |
133 | 0 | } |
134 | | /* Initialize the state using array indices. */ |
135 | 0 | memcpy(cx->S, Kinit, sizeof cx->S); |
136 | | /* Fill in K repeatedly with values from key. */ |
137 | 0 | L = K; |
138 | 0 | for (i = sizeof K; i > len; i -= len) { |
139 | 0 | memcpy(L, key, len); |
140 | 0 | L += len; |
141 | 0 | } |
142 | 0 | memcpy(L, key, i); |
143 | | /* Stir the state of the generator. At this point it is assumed |
144 | | * that the key is the size of the state buffer. If this is not |
145 | | * the case, the key bytes are repeated to fill the buffer. |
146 | | */ |
147 | 0 | j = 0; |
148 | 0 | #define ARCFOUR_STATE_STIR(ii) \ |
149 | 0 | j = j + cx->S[ii] + K[ii]; \ |
150 | 0 | SWAP(cx->S[ii], cx->S[j]); |
151 | 0 | for (i = 0; i < ARCFOUR_STATE_SIZE; i++) { |
152 | 0 | ARCFOUR_STATE_STIR(i); |
153 | 0 | } |
154 | 0 | cx->i = 0; |
155 | 0 | cx->j = 0; |
156 | 0 | return SECSuccess; |
157 | 0 | } |
158 | | |
159 | | /* |
160 | | * Initialize a new generator. |
161 | | */ |
162 | | RC4Context * |
163 | | RC4_CreateContext(const unsigned char *key, int len) |
164 | 0 | { |
165 | 0 | RC4Context *cx = RC4_AllocateContext(); |
166 | 0 | if (cx) { |
167 | 0 | SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0); |
168 | 0 | if (rv != SECSuccess) { |
169 | 0 | PORT_ZFree(cx, sizeof(*cx)); |
170 | 0 | cx = NULL; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | return cx; |
174 | 0 | } |
175 | | |
176 | | void |
177 | | RC4_DestroyContext(RC4Context *cx, PRBool freeit) |
178 | 0 | { |
179 | 0 | if (freeit) |
180 | 0 | PORT_ZFree(cx, sizeof(*cx)); |
181 | 0 | } |
182 | | |
183 | | #if defined(NSS_BEVAND_ARCFOUR) |
184 | | extern void ARCFOUR(RC4Context *cx, WORD inputLen, |
185 | | const unsigned char *input, unsigned char *output); |
186 | | #else |
187 | | /* |
188 | | * Generate the next byte in the stream. |
189 | | */ |
190 | | #define ARCFOUR_NEXT_BYTE() \ |
191 | | tmpSi = cx->S[++tmpi]; \ |
192 | | tmpj += tmpSi; \ |
193 | | tmpSj = cx->S[tmpj]; \ |
194 | | cx->S[tmpi] = tmpSj; \ |
195 | | cx->S[tmpj] = tmpSi; \ |
196 | | t = tmpSi + tmpSj; |
197 | | |
198 | | #ifdef CONVERT_TO_WORDS |
199 | | /* |
200 | | * Straight ARCFOUR op. No optimization. |
201 | | */ |
202 | | static SECStatus |
203 | | rc4_no_opt(RC4Context *cx, unsigned char *output, |
204 | | unsigned int *outputLen, unsigned int maxOutputLen, |
205 | | const unsigned char *input, unsigned int inputLen) |
206 | | { |
207 | | PRUint8 t; |
208 | | Stype tmpSi, tmpSj; |
209 | | register PRUint8 tmpi = cx->i; |
210 | | register PRUint8 tmpj = cx->j; |
211 | | unsigned int index; |
212 | | PORT_Assert(maxOutputLen >= inputLen); |
213 | | if (maxOutputLen < inputLen) { |
214 | | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
215 | | return SECFailure; |
216 | | } |
217 | | for (index = 0; index < inputLen; index++) { |
218 | | /* Generate next byte from stream. */ |
219 | | ARCFOUR_NEXT_BYTE(); |
220 | | /* output = next stream byte XOR next input byte */ |
221 | | output[index] = cx->S[t] ^ input[index]; |
222 | | } |
223 | | *outputLen = inputLen; |
224 | | cx->i = tmpi; |
225 | | cx->j = tmpj; |
226 | | return SECSuccess; |
227 | | } |
228 | | |
229 | | #else |
230 | | /* !CONVERT_TO_WORDS */ |
231 | | |
232 | | /* |
233 | | * Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces. |
234 | | */ |
235 | | static SECStatus |
236 | | rc4_unrolled(RC4Context *cx, unsigned char *output, |
237 | | unsigned int *outputLen, unsigned int maxOutputLen, |
238 | | const unsigned char *input, unsigned int inputLen) |
239 | | { |
240 | | PRUint8 t; |
241 | | Stype tmpSi, tmpSj; |
242 | | register PRUint8 tmpi = cx->i; |
243 | | register PRUint8 tmpj = cx->j; |
244 | | int index; |
245 | | PORT_Assert(maxOutputLen >= inputLen); |
246 | | if (maxOutputLen < inputLen) { |
247 | | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
248 | | return SECFailure; |
249 | | } |
250 | | for (index = inputLen / 8; index-- > 0; input += 8, output += 8) { |
251 | | ARCFOUR_NEXT_BYTE(); |
252 | | output[0] = cx->S[t] ^ input[0]; |
253 | | ARCFOUR_NEXT_BYTE(); |
254 | | output[1] = cx->S[t] ^ input[1]; |
255 | | ARCFOUR_NEXT_BYTE(); |
256 | | output[2] = cx->S[t] ^ input[2]; |
257 | | ARCFOUR_NEXT_BYTE(); |
258 | | output[3] = cx->S[t] ^ input[3]; |
259 | | ARCFOUR_NEXT_BYTE(); |
260 | | output[4] = cx->S[t] ^ input[4]; |
261 | | ARCFOUR_NEXT_BYTE(); |
262 | | output[5] = cx->S[t] ^ input[5]; |
263 | | ARCFOUR_NEXT_BYTE(); |
264 | | output[6] = cx->S[t] ^ input[6]; |
265 | | ARCFOUR_NEXT_BYTE(); |
266 | | output[7] = cx->S[t] ^ input[7]; |
267 | | } |
268 | | index = inputLen % 8; |
269 | | if (index) { |
270 | | input += index; |
271 | | output += index; |
272 | | switch (index) { |
273 | | case 7: |
274 | | ARCFOUR_NEXT_BYTE(); |
275 | | output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */ |
276 | | case 6: |
277 | | ARCFOUR_NEXT_BYTE(); |
278 | | output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */ |
279 | | case 5: |
280 | | ARCFOUR_NEXT_BYTE(); |
281 | | output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */ |
282 | | case 4: |
283 | | ARCFOUR_NEXT_BYTE(); |
284 | | output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */ |
285 | | case 3: |
286 | | ARCFOUR_NEXT_BYTE(); |
287 | | output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */ |
288 | | case 2: |
289 | | ARCFOUR_NEXT_BYTE(); |
290 | | output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */ |
291 | | case 1: |
292 | | ARCFOUR_NEXT_BYTE(); |
293 | | output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */ |
294 | | default: |
295 | | /* FALLTHRU */ |
296 | | ; /* hp-ux build breaks without this */ |
297 | | } |
298 | | } |
299 | | cx->i = tmpi; |
300 | | cx->j = tmpj; |
301 | | *outputLen = inputLen; |
302 | | return SECSuccess; |
303 | | } |
304 | | #endif |
305 | | |
306 | | #ifdef IS_LITTLE_ENDIAN |
307 | | #define ARCFOUR_NEXT4BYTES_L(n) \ |
308 | | ARCFOUR_NEXT_BYTE(); \ |
309 | | streamWord |= (WORD)cx->S[t] << (n); \ |
310 | | ARCFOUR_NEXT_BYTE(); \ |
311 | | streamWord |= (WORD)cx->S[t] << (n + 8); \ |
312 | | ARCFOUR_NEXT_BYTE(); \ |
313 | | streamWord |= (WORD)cx->S[t] << (n + 16); \ |
314 | | ARCFOUR_NEXT_BYTE(); \ |
315 | | streamWord |= (WORD)cx->S[t] << (n + 24); |
316 | | #else |
317 | | #define ARCFOUR_NEXT4BYTES_B(n) \ |
318 | | ARCFOUR_NEXT_BYTE(); \ |
319 | | streamWord |= (WORD)cx->S[t] << (n + 24); \ |
320 | | ARCFOUR_NEXT_BYTE(); \ |
321 | | streamWord |= (WORD)cx->S[t] << (n + 16); \ |
322 | | ARCFOUR_NEXT_BYTE(); \ |
323 | | streamWord |= (WORD)cx->S[t] << (n + 8); \ |
324 | | ARCFOUR_NEXT_BYTE(); \ |
325 | | streamWord |= (WORD)cx->S[t] << (n); |
326 | | #endif |
327 | | |
328 | | #if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64) |
329 | | /* 64-bit wordsize */ |
330 | | #ifdef IS_LITTLE_ENDIAN |
331 | | #define ARCFOUR_NEXT_WORD() \ |
332 | | { \ |
333 | | streamWord = 0; \ |
334 | | ARCFOUR_NEXT4BYTES_L(0); \ |
335 | | ARCFOUR_NEXT4BYTES_L(32); \ |
336 | | } |
337 | | #else |
338 | | #define ARCFOUR_NEXT_WORD() \ |
339 | | { \ |
340 | | streamWord = 0; \ |
341 | | ARCFOUR_NEXT4BYTES_B(32); \ |
342 | | ARCFOUR_NEXT4BYTES_B(0); \ |
343 | | } |
344 | | #endif |
345 | | #else |
346 | | /* 32-bit wordsize */ |
347 | | #ifdef IS_LITTLE_ENDIAN |
348 | | #define ARCFOUR_NEXT_WORD() \ |
349 | | { \ |
350 | | streamWord = 0; \ |
351 | | ARCFOUR_NEXT4BYTES_L(0); \ |
352 | | } |
353 | | #else |
354 | | #define ARCFOUR_NEXT_WORD() \ |
355 | | { \ |
356 | | streamWord = 0; \ |
357 | | ARCFOUR_NEXT4BYTES_B(0); \ |
358 | | } |
359 | | #endif |
360 | | #endif |
361 | | |
362 | | #ifdef IS_LITTLE_ENDIAN |
363 | | #define RSH << |
364 | | #define LSH >> |
365 | | #else |
366 | | #define RSH >> |
367 | | #define LSH << |
368 | | #endif |
369 | | |
370 | | #ifdef IS_LITTLE_ENDIAN |
371 | | #define LEFTMOST_BYTE_SHIFT 0 |
372 | | #define NEXT_BYTE_SHIFT(shift) shift + 8 |
373 | | #else |
374 | | #define LEFTMOST_BYTE_SHIFT 8 * (WORDSIZE - 1) |
375 | | #define NEXT_BYTE_SHIFT(shift) shift - 8 |
376 | | #endif |
377 | | |
378 | | #ifdef CONVERT_TO_WORDS |
379 | | static SECStatus |
380 | | rc4_wordconv(RC4Context *cx, unsigned char *output, |
381 | | unsigned int *outputLen, unsigned int maxOutputLen, |
382 | | const unsigned char *input, unsigned int inputLen) |
383 | | { |
384 | | PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t)); |
385 | | unsigned int inOffset = (PRUword)input % WORDSIZE; |
386 | | unsigned int outOffset = (PRUword)output % WORDSIZE; |
387 | | register WORD streamWord; |
388 | | register const WORD *pInWord; |
389 | | register WORD *pOutWord; |
390 | | register WORD inWord, nextInWord; |
391 | | PRUint8 t; |
392 | | register Stype tmpSi, tmpSj; |
393 | | register PRUint8 tmpi = cx->i; |
394 | | register PRUint8 tmpj = cx->j; |
395 | | unsigned int bufShift, invBufShift; |
396 | | unsigned int i; |
397 | | const unsigned char *finalIn; |
398 | | unsigned char *finalOut; |
399 | | |
400 | | PORT_Assert(maxOutputLen >= inputLen); |
401 | | if (maxOutputLen < inputLen) { |
402 | | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
403 | | return SECFailure; |
404 | | } |
405 | | if (inputLen < 2 * WORDSIZE) { |
406 | | /* Ignore word conversion, do byte-at-a-time */ |
407 | | return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen); |
408 | | } |
409 | | *outputLen = inputLen; |
410 | | pInWord = (const WORD *)(input - inOffset); |
411 | | pOutWord = (WORD *)(output - outOffset); |
412 | | if (inOffset <= outOffset) { |
413 | | bufShift = 8 * (outOffset - inOffset); |
414 | | invBufShift = 8 * WORDSIZE - bufShift; |
415 | | } else { |
416 | | invBufShift = 8 * (inOffset - outOffset); |
417 | | bufShift = 8 * WORDSIZE - invBufShift; |
418 | | } |
419 | | /*****************************************************************/ |
420 | | /* Step 1: */ |
421 | | /* If the first output word is partial, consume the bytes in the */ |
422 | | /* first partial output word by loading one or two words of */ |
423 | | /* input and shifting them accordingly. Otherwise, just load */ |
424 | | /* in the first word of input. At the end of this block, at */ |
425 | | /* least one partial word of input should ALWAYS be loaded. */ |
426 | | /*****************************************************************/ |
427 | | if (outOffset) { |
428 | | unsigned int byteCount = WORDSIZE - outOffset; |
429 | | for (i = 0; i < byteCount; i++) { |
430 | | ARCFOUR_NEXT_BYTE(); |
431 | | output[i] = cx->S[t] ^ input[i]; |
432 | | } |
433 | | /* Consumed byteCount bytes of input */ |
434 | | inputLen -= byteCount; |
435 | | pInWord++; |
436 | | |
437 | | /* move to next word of output */ |
438 | | pOutWord++; |
439 | | |
440 | | /* If buffers are relatively misaligned, shift the bytes in inWord |
441 | | * to be aligned to the output buffer. |
442 | | */ |
443 | | if (inOffset < outOffset) { |
444 | | /* The first input word (which may be partial) has more bytes |
445 | | * than needed. Copy the remainder to inWord. |
446 | | */ |
447 | | unsigned int shift = LEFTMOST_BYTE_SHIFT; |
448 | | inWord = 0; |
449 | | for (i = 0; i < outOffset - inOffset; i++) { |
450 | | inWord |= (WORD)input[byteCount + i] << shift; |
451 | | shift = NEXT_BYTE_SHIFT(shift); |
452 | | } |
453 | | } else if (inOffset > outOffset) { |
454 | | /* Consumed some bytes in the second input word. Copy the |
455 | | * remainder to inWord. |
456 | | */ |
457 | | inWord = *pInWord++; |
458 | | inWord = inWord LSH invBufShift; |
459 | | } else { |
460 | | inWord = 0; |
461 | | } |
462 | | } else { |
463 | | /* output is word-aligned */ |
464 | | if (inOffset) { |
465 | | /* Input is not word-aligned. The first word load of input |
466 | | * will not produce a full word of input bytes, so one word |
467 | | * must be pre-loaded. The main loop below will load in the |
468 | | * next input word and shift some of its bytes into inWord |
469 | | * in order to create a full input word. Note that the main |
470 | | * loop must execute at least once because the input must |
471 | | * be at least two words. |
472 | | */ |
473 | | unsigned int shift = LEFTMOST_BYTE_SHIFT; |
474 | | inWord = 0; |
475 | | for (i = 0; i < WORDSIZE - inOffset; i++) { |
476 | | inWord |= (WORD)input[i] << shift; |
477 | | shift = NEXT_BYTE_SHIFT(shift); |
478 | | } |
479 | | pInWord++; |
480 | | } else { |
481 | | /* Input is word-aligned. The first word load of input |
482 | | * will produce a full word of input bytes, so nothing |
483 | | * needs to be loaded here. |
484 | | */ |
485 | | inWord = 0; |
486 | | } |
487 | | } |
488 | | /*****************************************************************/ |
489 | | /* Step 2: main loop */ |
490 | | /* At this point the output buffer is word-aligned. Any unused */ |
491 | | /* bytes from above will be in inWord (shifted correctly). If */ |
492 | | /* the input buffer is unaligned relative to the output buffer, */ |
493 | | /* shifting has to be done. */ |
494 | | /*****************************************************************/ |
495 | | if (bufShift) { |
496 | | /* preloadedByteCount is the number of input bytes pre-loaded |
497 | | * in inWord. |
498 | | */ |
499 | | unsigned int preloadedByteCount = bufShift / 8; |
500 | | for (; inputLen >= preloadedByteCount + WORDSIZE; |
501 | | inputLen -= WORDSIZE) { |
502 | | nextInWord = *pInWord++; |
503 | | inWord |= nextInWord RSH bufShift; |
504 | | nextInWord = nextInWord LSH invBufShift; |
505 | | ARCFOUR_NEXT_WORD(); |
506 | | *pOutWord++ = inWord ^ streamWord; |
507 | | inWord = nextInWord; |
508 | | } |
509 | | if (inputLen == 0) { |
510 | | /* Nothing left to do. */ |
511 | | cx->i = tmpi; |
512 | | cx->j = tmpj; |
513 | | return SECSuccess; |
514 | | } |
515 | | finalIn = (const unsigned char *)pInWord - preloadedByteCount; |
516 | | } else { |
517 | | for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { |
518 | | inWord = *pInWord++; |
519 | | ARCFOUR_NEXT_WORD(); |
520 | | *pOutWord++ = inWord ^ streamWord; |
521 | | } |
522 | | if (inputLen == 0) { |
523 | | /* Nothing left to do. */ |
524 | | cx->i = tmpi; |
525 | | cx->j = tmpj; |
526 | | return SECSuccess; |
527 | | } |
528 | | finalIn = (const unsigned char *)pInWord; |
529 | | } |
530 | | /*****************************************************************/ |
531 | | /* Step 3: */ |
532 | | /* Do the remaining partial word of input one byte at a time. */ |
533 | | /*****************************************************************/ |
534 | | finalOut = (unsigned char *)pOutWord; |
535 | | for (i = 0; i < inputLen; i++) { |
536 | | ARCFOUR_NEXT_BYTE(); |
537 | | finalOut[i] = cx->S[t] ^ finalIn[i]; |
538 | | } |
539 | | cx->i = tmpi; |
540 | | cx->j = tmpj; |
541 | | return SECSuccess; |
542 | | } |
543 | | #endif |
544 | | #endif /* NSS_BEVAND_ARCFOUR */ |
545 | | |
546 | | SECStatus |
547 | | RC4_Encrypt(RC4Context *cx, unsigned char *output, |
548 | | unsigned int *outputLen, unsigned int maxOutputLen, |
549 | | const unsigned char *input, unsigned int inputLen) |
550 | 0 | { |
551 | 0 | PORT_Assert(maxOutputLen >= inputLen); |
552 | 0 | if (maxOutputLen < inputLen) { |
553 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
554 | 0 | return SECFailure; |
555 | 0 | } |
556 | 0 | #if defined(NSS_BEVAND_ARCFOUR) |
557 | 0 | ARCFOUR(cx, inputLen, input, output); |
558 | 0 | *outputLen = inputLen; |
559 | 0 | return SECSuccess; |
560 | | #elif defined(CONVERT_TO_WORDS) |
561 | | /* Convert the byte-stream to a word-stream */ |
562 | | return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen); |
563 | | #else |
564 | | /* Operate on bytes, but unroll the main loop */ |
565 | | return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen); |
566 | | #endif |
567 | 0 | } |
568 | | |
569 | | SECStatus |
570 | | RC4_Decrypt(RC4Context *cx, unsigned char *output, |
571 | | unsigned int *outputLen, unsigned int maxOutputLen, |
572 | | const unsigned char *input, unsigned int inputLen) |
573 | 0 | { |
574 | 0 | PORT_Assert(maxOutputLen >= inputLen); |
575 | 0 | if (maxOutputLen < inputLen) { |
576 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
577 | 0 | return SECFailure; |
578 | 0 | } |
579 | | /* decrypt and encrypt are same operation. */ |
580 | 0 | #if defined(NSS_BEVAND_ARCFOUR) |
581 | 0 | ARCFOUR(cx, inputLen, input, output); |
582 | 0 | *outputLen = inputLen; |
583 | 0 | return SECSuccess; |
584 | | #elif defined(CONVERT_TO_WORDS) |
585 | | /* Convert the byte-stream to a word-stream */ |
586 | | return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen); |
587 | | #else |
588 | | /* Operate on bytes, but unroll the main loop */ |
589 | | return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen); |
590 | | #endif |
591 | 0 | } |
592 | | |
593 | | #undef CONVERT_TO_WORDS |
594 | | #undef USE_WORD |