|
1 /* |
|
2 * alg2268.c - implementation of the algorithm in RFC 2268 |
|
3 * |
|
4 * This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #ifdef FREEBL_NO_DEPEND |
|
9 #include "stubs.h" |
|
10 #endif |
|
11 |
|
12 #include "blapi.h" |
|
13 #include "secerr.h" |
|
14 #ifdef XP_UNIX_XXX |
|
15 #include <stddef.h> /* for ptrdiff_t */ |
|
16 #endif |
|
17 |
|
18 /* |
|
19 ** RC2 symmetric block cypher |
|
20 */ |
|
21 |
|
22 typedef SECStatus (rc2Func)(RC2Context *cx, unsigned char *output, |
|
23 const unsigned char *input, unsigned int inputLen); |
|
24 |
|
25 /* forward declarations */ |
|
26 static rc2Func rc2_EncryptECB; |
|
27 static rc2Func rc2_DecryptECB; |
|
28 static rc2Func rc2_EncryptCBC; |
|
29 static rc2Func rc2_DecryptCBC; |
|
30 |
|
31 typedef union { |
|
32 PRUint32 l[2]; |
|
33 PRUint16 s[4]; |
|
34 PRUint8 b[8]; |
|
35 } RC2Block; |
|
36 |
|
37 struct RC2ContextStr { |
|
38 union { |
|
39 PRUint8 Kb[128]; |
|
40 PRUint16 Kw[64]; |
|
41 } u; |
|
42 RC2Block iv; |
|
43 rc2Func *enc; |
|
44 rc2Func *dec; |
|
45 }; |
|
46 |
|
47 #define B u.Kb |
|
48 #define K u.Kw |
|
49 #define BYTESWAP(x) ((x) << 8 | (x) >> 8) |
|
50 #define SWAPK(i) cx->K[i] = (tmpS = cx->K[i], BYTESWAP(tmpS)) |
|
51 #define RC2_BLOCK_SIZE 8 |
|
52 |
|
53 #define LOAD_HARD(R) \ |
|
54 R[0] = (PRUint16)input[1] << 8 | input[0]; \ |
|
55 R[1] = (PRUint16)input[3] << 8 | input[2]; \ |
|
56 R[2] = (PRUint16)input[5] << 8 | input[4]; \ |
|
57 R[3] = (PRUint16)input[7] << 8 | input[6]; |
|
58 #define LOAD_EASY(R) \ |
|
59 R[0] = ((PRUint16 *)input)[0]; \ |
|
60 R[1] = ((PRUint16 *)input)[1]; \ |
|
61 R[2] = ((PRUint16 *)input)[2]; \ |
|
62 R[3] = ((PRUint16 *)input)[3]; |
|
63 #define STORE_HARD(R) \ |
|
64 output[0] = (PRUint8)(R[0]); output[1] = (PRUint8)(R[0] >> 8); \ |
|
65 output[2] = (PRUint8)(R[1]); output[3] = (PRUint8)(R[1] >> 8); \ |
|
66 output[4] = (PRUint8)(R[2]); output[5] = (PRUint8)(R[2] >> 8); \ |
|
67 output[6] = (PRUint8)(R[3]); output[7] = (PRUint8)(R[3] >> 8); |
|
68 #define STORE_EASY(R) \ |
|
69 ((PRUint16 *)output)[0] = R[0]; \ |
|
70 ((PRUint16 *)output)[1] = R[1]; \ |
|
71 ((PRUint16 *)output)[2] = R[2]; \ |
|
72 ((PRUint16 *)output)[3] = R[3]; |
|
73 |
|
74 #if defined (NSS_X86_OR_X64) |
|
75 #define LOAD(R) LOAD_EASY(R) |
|
76 #define STORE(R) STORE_EASY(R) |
|
77 #elif !defined(IS_LITTLE_ENDIAN) |
|
78 #define LOAD(R) LOAD_HARD(R) |
|
79 #define STORE(R) STORE_HARD(R) |
|
80 #else |
|
81 #define LOAD(R) if ((ptrdiff_t)input & 1) { LOAD_HARD(R) } else { LOAD_EASY(R) } |
|
82 #define STORE(R) if ((ptrdiff_t)input & 1) { STORE_HARD(R) } else { STORE_EASY(R) } |
|
83 #endif |
|
84 |
|
85 static const PRUint8 S[256] = { |
|
86 0331,0170,0371,0304,0031,0335,0265,0355,0050,0351,0375,0171,0112,0240,0330,0235, |
|
87 0306,0176,0067,0203,0053,0166,0123,0216,0142,0114,0144,0210,0104,0213,0373,0242, |
|
88 0027,0232,0131,0365,0207,0263,0117,0023,0141,0105,0155,0215,0011,0201,0175,0062, |
|
89 0275,0217,0100,0353,0206,0267,0173,0013,0360,0225,0041,0042,0134,0153,0116,0202, |
|
90 0124,0326,0145,0223,0316,0140,0262,0034,0163,0126,0300,0024,0247,0214,0361,0334, |
|
91 0022,0165,0312,0037,0073,0276,0344,0321,0102,0075,0324,0060,0243,0074,0266,0046, |
|
92 0157,0277,0016,0332,0106,0151,0007,0127,0047,0362,0035,0233,0274,0224,0103,0003, |
|
93 0370,0021,0307,0366,0220,0357,0076,0347,0006,0303,0325,0057,0310,0146,0036,0327, |
|
94 0010,0350,0352,0336,0200,0122,0356,0367,0204,0252,0162,0254,0065,0115,0152,0052, |
|
95 0226,0032,0322,0161,0132,0025,0111,0164,0113,0237,0320,0136,0004,0030,0244,0354, |
|
96 0302,0340,0101,0156,0017,0121,0313,0314,0044,0221,0257,0120,0241,0364,0160,0071, |
|
97 0231,0174,0072,0205,0043,0270,0264,0172,0374,0002,0066,0133,0045,0125,0227,0061, |
|
98 0055,0135,0372,0230,0343,0212,0222,0256,0005,0337,0051,0020,0147,0154,0272,0311, |
|
99 0323,0000,0346,0317,0341,0236,0250,0054,0143,0026,0001,0077,0130,0342,0211,0251, |
|
100 0015,0070,0064,0033,0253,0063,0377,0260,0273,0110,0014,0137,0271,0261,0315,0056, |
|
101 0305,0363,0333,0107,0345,0245,0234,0167,0012,0246,0040,0150,0376,0177,0301,0255 |
|
102 }; |
|
103 |
|
104 RC2Context * RC2_AllocateContext(void) |
|
105 { |
|
106 return PORT_ZNew(RC2Context); |
|
107 } |
|
108 SECStatus |
|
109 RC2_InitContext(RC2Context *cx, const unsigned char *key, unsigned int len, |
|
110 const unsigned char *input, int mode, unsigned int efLen8, |
|
111 unsigned int unused) |
|
112 { |
|
113 PRUint8 *L,*L2; |
|
114 int i; |
|
115 #if !defined(IS_LITTLE_ENDIAN) |
|
116 PRUint16 tmpS; |
|
117 #endif |
|
118 PRUint8 tmpB; |
|
119 |
|
120 if (!key || !cx || !len || len > (sizeof cx->B) || |
|
121 efLen8 > (sizeof cx->B)) { |
|
122 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
123 return SECFailure; |
|
124 } |
|
125 if (mode == NSS_RC2) { |
|
126 /* groovy */ |
|
127 } else if (mode == NSS_RC2_CBC) { |
|
128 if (!input) { |
|
129 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
130 return SECFailure; |
|
131 } |
|
132 } else { |
|
133 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
134 return SECFailure; |
|
135 } |
|
136 |
|
137 if (mode == NSS_RC2_CBC) { |
|
138 cx->enc = & rc2_EncryptCBC; |
|
139 cx->dec = & rc2_DecryptCBC; |
|
140 LOAD(cx->iv.s); |
|
141 } else { |
|
142 cx->enc = & rc2_EncryptECB; |
|
143 cx->dec = & rc2_DecryptECB; |
|
144 } |
|
145 |
|
146 /* Step 0. Copy key into table. */ |
|
147 memcpy(cx->B, key, len); |
|
148 |
|
149 /* Step 1. Compute all values to the right of the key. */ |
|
150 L2 = cx->B; |
|
151 L = L2 + len; |
|
152 tmpB = L[-1]; |
|
153 for (i = (sizeof cx->B) - len; i > 0; --i) { |
|
154 *L++ = tmpB = S[ (PRUint8)(tmpB + *L2++) ]; |
|
155 } |
|
156 |
|
157 /* step 2. Adjust left most byte of effective key. */ |
|
158 i = (sizeof cx->B) - efLen8; |
|
159 L = cx->B + i; |
|
160 *L = tmpB = S[*L]; /* mask is always 0xff */ |
|
161 |
|
162 /* step 3. Recompute all values to the left of effective key. */ |
|
163 L2 = --L + efLen8; |
|
164 while(L >= cx->B) { |
|
165 *L-- = tmpB = S[ tmpB ^ *L2-- ]; |
|
166 } |
|
167 |
|
168 #if !defined(IS_LITTLE_ENDIAN) |
|
169 for (i = 63; i >= 0; --i) { |
|
170 SWAPK(i); /* candidate for unrolling */ |
|
171 } |
|
172 #endif |
|
173 return SECSuccess; |
|
174 } |
|
175 |
|
176 /* |
|
177 ** Create a new RC2 context suitable for RC2 encryption/decryption. |
|
178 ** "key" raw key data |
|
179 ** "len" the number of bytes of key data |
|
180 ** "iv" is the CBC initialization vector (if mode is NSS_RC2_CBC) |
|
181 ** "mode" one of NSS_RC2 or NSS_RC2_CBC |
|
182 ** "effectiveKeyLen" in bytes, not bits. |
|
183 ** |
|
184 ** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block |
|
185 ** chaining" mode. |
|
186 */ |
|
187 RC2Context * |
|
188 RC2_CreateContext(const unsigned char *key, unsigned int len, |
|
189 const unsigned char *iv, int mode, unsigned efLen8) |
|
190 { |
|
191 RC2Context *cx = PORT_ZNew(RC2Context); |
|
192 if (cx) { |
|
193 SECStatus rv = RC2_InitContext(cx, key, len, iv, mode, efLen8, 0); |
|
194 if (rv != SECSuccess) { |
|
195 RC2_DestroyContext(cx, PR_TRUE); |
|
196 cx = NULL; |
|
197 } |
|
198 } |
|
199 return cx; |
|
200 } |
|
201 |
|
202 /* |
|
203 ** Destroy an RC2 encryption/decryption context. |
|
204 ** "cx" the context |
|
205 ** "freeit" if PR_TRUE then free the object as well as its sub-objects |
|
206 */ |
|
207 void |
|
208 RC2_DestroyContext(RC2Context *cx, PRBool freeit) |
|
209 { |
|
210 if (cx) { |
|
211 memset(cx, 0, sizeof *cx); |
|
212 if (freeit) { |
|
213 PORT_Free(cx); |
|
214 } |
|
215 } |
|
216 } |
|
217 |
|
218 #define ROL(x,k) (x << k | x >> (16-k)) |
|
219 #define MIX(j) \ |
|
220 R0 = R0 + cx->K[ 4*j+0] + (R3 & R2) + (~R3 & R1); R0 = ROL(R0,1);\ |
|
221 R1 = R1 + cx->K[ 4*j+1] + (R0 & R3) + (~R0 & R2); R1 = ROL(R1,2);\ |
|
222 R2 = R2 + cx->K[ 4*j+2] + (R1 & R0) + (~R1 & R3); R2 = ROL(R2,3);\ |
|
223 R3 = R3 + cx->K[ 4*j+3] + (R2 & R1) + (~R2 & R0); R3 = ROL(R3,5) |
|
224 #define MASH \ |
|
225 R0 = R0 + cx->K[R3 & 63];\ |
|
226 R1 = R1 + cx->K[R0 & 63];\ |
|
227 R2 = R2 + cx->K[R1 & 63];\ |
|
228 R3 = R3 + cx->K[R2 & 63] |
|
229 |
|
230 /* Encrypt one block */ |
|
231 static void |
|
232 rc2_Encrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input) |
|
233 { |
|
234 register PRUint16 R0, R1, R2, R3; |
|
235 |
|
236 /* step 1. Initialize input. */ |
|
237 R0 = input->s[0]; |
|
238 R1 = input->s[1]; |
|
239 R2 = input->s[2]; |
|
240 R3 = input->s[3]; |
|
241 |
|
242 /* step 2. Expand Key (already done, in context) */ |
|
243 /* step 3. j = 0 */ |
|
244 /* step 4. Perform 5 mixing rounds. */ |
|
245 |
|
246 MIX(0); |
|
247 MIX(1); |
|
248 MIX(2); |
|
249 MIX(3); |
|
250 MIX(4); |
|
251 |
|
252 /* step 5. Perform 1 mashing round. */ |
|
253 MASH; |
|
254 |
|
255 /* step 6. Perform 6 mixing rounds. */ |
|
256 |
|
257 MIX(5); |
|
258 MIX(6); |
|
259 MIX(7); |
|
260 MIX(8); |
|
261 MIX(9); |
|
262 MIX(10); |
|
263 |
|
264 /* step 7. Perform 1 mashing round. */ |
|
265 MASH; |
|
266 |
|
267 /* step 8. Perform 5 mixing rounds. */ |
|
268 |
|
269 MIX(11); |
|
270 MIX(12); |
|
271 MIX(13); |
|
272 MIX(14); |
|
273 MIX(15); |
|
274 |
|
275 /* output results */ |
|
276 output->s[0] = R0; |
|
277 output->s[1] = R1; |
|
278 output->s[2] = R2; |
|
279 output->s[3] = R3; |
|
280 } |
|
281 |
|
282 #define ROR(x,k) (x >> k | x << (16-k)) |
|
283 #define R_MIX(j) \ |
|
284 R3 = ROR(R3,5); R3 = R3 - cx->K[ 4*j+3] - (R2 & R1) - (~R2 & R0); \ |
|
285 R2 = ROR(R2,3); R2 = R2 - cx->K[ 4*j+2] - (R1 & R0) - (~R1 & R3); \ |
|
286 R1 = ROR(R1,2); R1 = R1 - cx->K[ 4*j+1] - (R0 & R3) - (~R0 & R2); \ |
|
287 R0 = ROR(R0,1); R0 = R0 - cx->K[ 4*j+0] - (R3 & R2) - (~R3 & R1) |
|
288 #define R_MASH \ |
|
289 R3 = R3 - cx->K[R2 & 63];\ |
|
290 R2 = R2 - cx->K[R1 & 63];\ |
|
291 R1 = R1 - cx->K[R0 & 63];\ |
|
292 R0 = R0 - cx->K[R3 & 63] |
|
293 |
|
294 /* Encrypt one block */ |
|
295 static void |
|
296 rc2_Decrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input) |
|
297 { |
|
298 register PRUint16 R0, R1, R2, R3; |
|
299 |
|
300 /* step 1. Initialize input. */ |
|
301 R0 = input->s[0]; |
|
302 R1 = input->s[1]; |
|
303 R2 = input->s[2]; |
|
304 R3 = input->s[3]; |
|
305 |
|
306 /* step 2. Expand Key (already done, in context) */ |
|
307 /* step 3. j = 63 */ |
|
308 /* step 4. Perform 5 r_mixing rounds. */ |
|
309 R_MIX(15); |
|
310 R_MIX(14); |
|
311 R_MIX(13); |
|
312 R_MIX(12); |
|
313 R_MIX(11); |
|
314 |
|
315 /* step 5. Perform 1 r_mashing round. */ |
|
316 R_MASH; |
|
317 |
|
318 /* step 6. Perform 6 r_mixing rounds. */ |
|
319 R_MIX(10); |
|
320 R_MIX(9); |
|
321 R_MIX(8); |
|
322 R_MIX(7); |
|
323 R_MIX(6); |
|
324 R_MIX(5); |
|
325 |
|
326 /* step 7. Perform 1 r_mashing round. */ |
|
327 R_MASH; |
|
328 |
|
329 /* step 8. Perform 5 r_mixing rounds. */ |
|
330 R_MIX(4); |
|
331 R_MIX(3); |
|
332 R_MIX(2); |
|
333 R_MIX(1); |
|
334 R_MIX(0); |
|
335 |
|
336 /* output results */ |
|
337 output->s[0] = R0; |
|
338 output->s[1] = R1; |
|
339 output->s[2] = R2; |
|
340 output->s[3] = R3; |
|
341 } |
|
342 |
|
343 static SECStatus |
|
344 rc2_EncryptECB(RC2Context *cx, unsigned char *output, |
|
345 const unsigned char *input, unsigned int inputLen) |
|
346 { |
|
347 RC2Block iBlock; |
|
348 |
|
349 while (inputLen > 0) { |
|
350 LOAD(iBlock.s) |
|
351 rc2_Encrypt1Block(cx, &iBlock, &iBlock); |
|
352 STORE(iBlock.s) |
|
353 output += RC2_BLOCK_SIZE; |
|
354 input += RC2_BLOCK_SIZE; |
|
355 inputLen -= RC2_BLOCK_SIZE; |
|
356 } |
|
357 return SECSuccess; |
|
358 } |
|
359 |
|
360 static SECStatus |
|
361 rc2_DecryptECB(RC2Context *cx, unsigned char *output, |
|
362 const unsigned char *input, unsigned int inputLen) |
|
363 { |
|
364 RC2Block iBlock; |
|
365 |
|
366 while (inputLen > 0) { |
|
367 LOAD(iBlock.s) |
|
368 rc2_Decrypt1Block(cx, &iBlock, &iBlock); |
|
369 STORE(iBlock.s) |
|
370 output += RC2_BLOCK_SIZE; |
|
371 input += RC2_BLOCK_SIZE; |
|
372 inputLen -= RC2_BLOCK_SIZE; |
|
373 } |
|
374 return SECSuccess; |
|
375 } |
|
376 |
|
377 static SECStatus |
|
378 rc2_EncryptCBC(RC2Context *cx, unsigned char *output, |
|
379 const unsigned char *input, unsigned int inputLen) |
|
380 { |
|
381 RC2Block iBlock; |
|
382 |
|
383 while (inputLen > 0) { |
|
384 |
|
385 LOAD(iBlock.s) |
|
386 iBlock.l[0] ^= cx->iv.l[0]; |
|
387 iBlock.l[1] ^= cx->iv.l[1]; |
|
388 rc2_Encrypt1Block(cx, &iBlock, &iBlock); |
|
389 cx->iv = iBlock; |
|
390 STORE(iBlock.s) |
|
391 output += RC2_BLOCK_SIZE; |
|
392 input += RC2_BLOCK_SIZE; |
|
393 inputLen -= RC2_BLOCK_SIZE; |
|
394 } |
|
395 return SECSuccess; |
|
396 } |
|
397 |
|
398 static SECStatus |
|
399 rc2_DecryptCBC(RC2Context *cx, unsigned char *output, |
|
400 const unsigned char *input, unsigned int inputLen) |
|
401 { |
|
402 RC2Block iBlock; |
|
403 RC2Block oBlock; |
|
404 |
|
405 while (inputLen > 0) { |
|
406 LOAD(iBlock.s) |
|
407 rc2_Decrypt1Block(cx, &oBlock, &iBlock); |
|
408 oBlock.l[0] ^= cx->iv.l[0]; |
|
409 oBlock.l[1] ^= cx->iv.l[1]; |
|
410 cx->iv = iBlock; |
|
411 STORE(oBlock.s) |
|
412 output += RC2_BLOCK_SIZE; |
|
413 input += RC2_BLOCK_SIZE; |
|
414 inputLen -= RC2_BLOCK_SIZE; |
|
415 } |
|
416 return SECSuccess; |
|
417 } |
|
418 |
|
419 |
|
420 /* |
|
421 ** Perform RC2 encryption. |
|
422 ** "cx" the context |
|
423 ** "output" the output buffer to store the encrypted data. |
|
424 ** "outputLen" how much data is stored in "output". Set by the routine |
|
425 ** after some data is stored in output. |
|
426 ** "maxOutputLen" the maximum amount of data that can ever be |
|
427 ** stored in "output" |
|
428 ** "input" the input data |
|
429 ** "inputLen" the amount of input data |
|
430 */ |
|
431 SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output, |
|
432 unsigned int *outputLen, unsigned int maxOutputLen, |
|
433 const unsigned char *input, unsigned int inputLen) |
|
434 { |
|
435 SECStatus rv = SECSuccess; |
|
436 if (inputLen) { |
|
437 if (inputLen % RC2_BLOCK_SIZE) { |
|
438 PORT_SetError(SEC_ERROR_INPUT_LEN); |
|
439 return SECFailure; |
|
440 } |
|
441 if (maxOutputLen < inputLen) { |
|
442 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
|
443 return SECFailure; |
|
444 } |
|
445 rv = (*cx->enc)(cx, output, input, inputLen); |
|
446 } |
|
447 if (rv == SECSuccess) { |
|
448 *outputLen = inputLen; |
|
449 } |
|
450 return rv; |
|
451 } |
|
452 |
|
453 /* |
|
454 ** Perform RC2 decryption. |
|
455 ** "cx" the context |
|
456 ** "output" the output buffer to store the decrypted data. |
|
457 ** "outputLen" how much data is stored in "output". Set by the routine |
|
458 ** after some data is stored in output. |
|
459 ** "maxOutputLen" the maximum amount of data that can ever be |
|
460 ** stored in "output" |
|
461 ** "input" the input data |
|
462 ** "inputLen" the amount of input data |
|
463 */ |
|
464 SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output, |
|
465 unsigned int *outputLen, unsigned int maxOutputLen, |
|
466 const unsigned char *input, unsigned int inputLen) |
|
467 { |
|
468 SECStatus rv = SECSuccess; |
|
469 if (inputLen) { |
|
470 if (inputLen % RC2_BLOCK_SIZE) { |
|
471 PORT_SetError(SEC_ERROR_INPUT_LEN); |
|
472 return SECFailure; |
|
473 } |
|
474 if (maxOutputLen < inputLen) { |
|
475 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
|
476 return SECFailure; |
|
477 } |
|
478 rv = (*cx->dec)(cx, output, input, inputLen); |
|
479 } |
|
480 if (rv == SECSuccess) { |
|
481 *outputLen = inputLen; |
|
482 } |
|
483 return rv; |
|
484 } |
|
485 |