/src/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 | if (len == 0 || len >= ARCFOUR_STATE_SIZE) { |
126 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
127 | 0 | return SECFailure; |
128 | 0 | } |
129 | 0 | if (cx == NULL) { |
130 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
131 | 0 | return SECFailure; |
132 | 0 | } |
133 | | /* Initialize the state using array indices. */ |
134 | 0 | memcpy(cx->S, Kinit, sizeof cx->S); |
135 | | /* Fill in K repeatedly with values from key. */ |
136 | 0 | L = K; |
137 | 0 | for (i = sizeof K; i > len; i -= len) { |
138 | 0 | memcpy(L, key, len); |
139 | 0 | L += len; |
140 | 0 | } |
141 | 0 | 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 | 0 | j = 0; |
147 | 0 | #define ARCFOUR_STATE_STIR(ii) \ |
148 | 0 | j = j + cx->S[ii] + K[ii]; \ |
149 | 0 | SWAP(cx->S[ii], cx->S[j]); |
150 | 0 | for (i = 0; i < ARCFOUR_STATE_SIZE; i++) { |
151 | 0 | ARCFOUR_STATE_STIR(i); |
152 | 0 | } |
153 | 0 | cx->i = 0; |
154 | 0 | cx->j = 0; |
155 | 0 | return SECSuccess; |
156 | 0 | } |
157 | | |
158 | | /* |
159 | | * Initialize a new generator. |
160 | | */ |
161 | | RC4Context * |
162 | | RC4_CreateContext(const unsigned char *key, int len) |
163 | 0 | { |
164 | 0 | RC4Context *cx = RC4_AllocateContext(); |
165 | 0 | if (cx) { |
166 | 0 | SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0); |
167 | 0 | if (rv != SECSuccess) { |
168 | 0 | PORT_ZFree(cx, sizeof(*cx)); |
169 | 0 | cx = NULL; |
170 | 0 | } |
171 | 0 | } |
172 | 0 | return cx; |
173 | 0 | } |
174 | | |
175 | | void |
176 | | RC4_DestroyContext(RC4Context *cx, PRBool freeit) |
177 | 0 | { |
178 | 0 | if (freeit) |
179 | 0 | PORT_ZFree(cx, sizeof(*cx)); |
180 | 0 | } |
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 | 0 | { |
550 | 0 | PORT_Assert(maxOutputLen >= inputLen); |
551 | 0 | if (maxOutputLen < inputLen) { |
552 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
553 | 0 | return SECFailure; |
554 | 0 | } |
555 | 0 | #if defined(NSS_BEVAND_ARCFOUR) |
556 | 0 | ARCFOUR(cx, inputLen, input, output); |
557 | 0 | *outputLen = inputLen; |
558 | 0 | 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 | 0 | } |
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 | 0 | { |
573 | 0 | PORT_Assert(maxOutputLen >= inputLen); |
574 | 0 | if (maxOutputLen < inputLen) { |
575 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
576 | 0 | return SECFailure; |
577 | 0 | } |
578 | | /* decrypt and encrypt are same operation. */ |
579 | 0 | #if defined(NSS_BEVAND_ARCFOUR) |
580 | 0 | ARCFOUR(cx, inputLen, input, output); |
581 | 0 | *outputLen = inputLen; |
582 | 0 | 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 | 0 | } |
591 | | |
592 | | #undef CONVERT_TO_WORDS |
593 | | #undef USE_WORD |