/src/nss-nspr/nss/lib/freebl/aeskeywrap.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394 |
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 <stddef.h> |
13 | | |
14 | | #include "prcpucfg.h" |
15 | | #if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG) |
16 | | #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0 |
17 | | #else |
18 | | #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1 |
19 | | #endif |
20 | | #include "prtypes.h" /* for PRUintXX */ |
21 | | #include "secport.h" /* for PORT_XXX */ |
22 | | #include "secerr.h" |
23 | | #include "blapi.h" /* for AES_ functions */ |
24 | | #include "rijndael.h" |
25 | | |
26 | | struct AESKeyWrapContextStr { |
27 | | AESContext aescx; |
28 | | unsigned char iv[AES_KEY_WRAP_IV_BYTES]; |
29 | | void *mem; /* Pointer to beginning of allocated memory. */ |
30 | | }; |
31 | | |
32 | | /******************************************/ |
33 | | /* |
34 | | ** AES key wrap algorithm, RFC 3394 |
35 | | */ |
36 | | |
37 | | AESKeyWrapContext * |
38 | | AESKeyWrap_AllocateContext(void) |
39 | 0 | { |
40 | | /* aligned_alloc is C11 so we have to do it the old way. */ |
41 | 0 | AESKeyWrapContext *ctx = PORT_ZAlloc(sizeof(AESKeyWrapContext) + 15); |
42 | 0 | if (ctx == NULL) { |
43 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
44 | 0 | return NULL; |
45 | 0 | } |
46 | 0 | ctx->mem = ctx; |
47 | 0 | return (AESKeyWrapContext *)(((uintptr_t)ctx + 15) & ~(uintptr_t)0x0F); |
48 | 0 | } |
49 | | |
50 | | SECStatus |
51 | | AESKeyWrap_InitContext(AESKeyWrapContext *cx, |
52 | | const unsigned char *key, |
53 | | unsigned int keylen, |
54 | | const unsigned char *iv, |
55 | | int x1, |
56 | | unsigned int encrypt, |
57 | | unsigned int x2) |
58 | 0 | { |
59 | 0 | SECStatus rv = SECFailure; |
60 | 0 | if (!cx) { |
61 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
62 | 0 | return SECFailure; |
63 | 0 | } |
64 | 0 | if (iv) { |
65 | 0 | memcpy(cx->iv, iv, sizeof cx->iv); |
66 | 0 | } else { |
67 | 0 | memset(cx->iv, 0xA6, sizeof cx->iv); |
68 | 0 | } |
69 | 0 | rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, |
70 | 0 | AES_BLOCK_SIZE); |
71 | 0 | return rv; |
72 | 0 | } |
73 | | |
74 | | /* |
75 | | ** Create a new AES context suitable for AES encryption/decryption. |
76 | | ** "key" raw key data |
77 | | ** "keylen" the number of bytes of key data (16, 24, or 32) |
78 | | */ |
79 | | extern AESKeyWrapContext * |
80 | | AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, |
81 | | int encrypt, unsigned int keylen) |
82 | 0 | { |
83 | 0 | SECStatus rv; |
84 | 0 | AESKeyWrapContext *cx = AESKeyWrap_AllocateContext(); |
85 | 0 | if (!cx) |
86 | 0 | return NULL; /* error is already set */ |
87 | 0 | rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0); |
88 | 0 | if (rv != SECSuccess) { |
89 | 0 | PORT_Free(cx->mem); |
90 | 0 | cx = NULL; /* error should already be set */ |
91 | 0 | } |
92 | 0 | return cx; |
93 | 0 | } |
94 | | |
95 | | /* |
96 | | ** Destroy a AES KeyWrap context. |
97 | | ** "cx" the context |
98 | | ** "freeit" if PR_TRUE then free the object as well as its sub-objects |
99 | | */ |
100 | | extern void |
101 | | AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit) |
102 | 0 | { |
103 | 0 | if (cx) { |
104 | 0 | AES_DestroyContext(&cx->aescx, PR_FALSE); |
105 | | /* memset(cx, 0, sizeof *cx); */ |
106 | 0 | if (freeit) { |
107 | 0 | PORT_Free(cx->mem); |
108 | 0 | } |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS |
113 | | |
114 | | /* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian |
115 | | ** (Most significant byte first) in memory. The only ALU operations done |
116 | | ** on them are increment, decrement, and XOR. So, on little-endian CPUs, |
117 | | ** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations |
118 | | ** are simulated in the following code. This is thought to be faster and |
119 | | ** simpler than trying to convert the data to little-endian and back. |
120 | | */ |
121 | | |
122 | | /* A and T point to two 64-bit values stored most signficant byte first |
123 | | ** (big endian). This function increments the 64-bit value T, and then |
124 | | ** XORs it with A, changing A. |
125 | | */ |
126 | | static void |
127 | | increment_and_xor(unsigned char *A, unsigned char *T) |
128 | 0 | { |
129 | 0 | if (!++T[7]) |
130 | 0 | if (!++T[6]) |
131 | 0 | if (!++T[5]) |
132 | 0 | if (!++T[4]) |
133 | 0 | if (!++T[3]) |
134 | 0 | if (!++T[2]) |
135 | 0 | if (!++T[1]) |
136 | 0 | ++T[0]; |
137 | |
|
138 | 0 | A[0] ^= T[0]; |
139 | 0 | A[1] ^= T[1]; |
140 | 0 | A[2] ^= T[2]; |
141 | 0 | A[3] ^= T[3]; |
142 | 0 | A[4] ^= T[4]; |
143 | 0 | A[5] ^= T[5]; |
144 | 0 | A[6] ^= T[6]; |
145 | 0 | A[7] ^= T[7]; |
146 | 0 | } |
147 | | |
148 | | /* A and T point to two 64-bit values stored most signficant byte first |
149 | | ** (big endian). This function XORs T with A, giving a new A, then |
150 | | ** decrements the 64-bit value T. |
151 | | */ |
152 | | static void |
153 | | xor_and_decrement(PRUint64 *A, PRUint64 *T) |
154 | 0 | { |
155 | 0 | unsigned char *TP = (unsigned char *)T; |
156 | 0 | const PRUint64 mask = 0xFF; |
157 | 0 | *A = ((*A & mask << 56) ^ (*T & mask << 56)) | |
158 | 0 | ((*A & mask << 48) ^ (*T & mask << 48)) | |
159 | 0 | ((*A & mask << 40) ^ (*T & mask << 40)) | |
160 | 0 | ((*A & mask << 32) ^ (*T & mask << 32)) | |
161 | 0 | ((*A & mask << 24) ^ (*T & mask << 23)) | |
162 | 0 | ((*A & mask << 16) ^ (*T & mask << 16)) | |
163 | 0 | ((*A & mask << 8) ^ (*T & mask << 8)) | |
164 | 0 | ((*A & mask) ^ (*T & mask)); |
165 | |
|
166 | 0 | if (!TP[7]--) |
167 | 0 | if (!TP[6]--) |
168 | 0 | if (!TP[5]--) |
169 | 0 | if (!TP[4]--) |
170 | 0 | if (!TP[3]--) |
171 | 0 | if (!TP[2]--) |
172 | 0 | if (!TP[1]--) |
173 | 0 | TP[0]--; |
174 | 0 | } |
175 | | |
176 | | /* Given an unsigned long t (in host byte order), store this value as a |
177 | | ** 64-bit big-endian value (MSB first) in *pt. |
178 | | */ |
179 | | static void |
180 | | set_t(unsigned char *pt, unsigned long t) |
181 | 0 | { |
182 | 0 | pt[7] = (unsigned char)t; |
183 | 0 | t >>= 8; |
184 | 0 | pt[6] = (unsigned char)t; |
185 | 0 | t >>= 8; |
186 | 0 | pt[5] = (unsigned char)t; |
187 | 0 | t >>= 8; |
188 | 0 | pt[4] = (unsigned char)t; |
189 | 0 | t >>= 8; |
190 | 0 | pt[3] = (unsigned char)t; |
191 | 0 | t >>= 8; |
192 | 0 | pt[2] = (unsigned char)t; |
193 | 0 | t >>= 8; |
194 | 0 | pt[1] = (unsigned char)t; |
195 | 0 | t >>= 8; |
196 | 0 | pt[0] = (unsigned char)t; |
197 | 0 | } |
198 | | |
199 | | #endif |
200 | | |
201 | | static void |
202 | | encode_PRUint32_BE(unsigned char *data, PRUint32 val) |
203 | 0 | { |
204 | 0 | size_t i; |
205 | 0 | for (i = 0; i < sizeof(PRUint32); i++) { |
206 | 0 | data[i] = PORT_GET_BYTE_BE(val, i, sizeof(PRUint32)); |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | static PRUint32 |
211 | | decode_PRUint32_BE(unsigned char *data) |
212 | 0 | { |
213 | 0 | PRUint32 val = 0; |
214 | 0 | size_t i; |
215 | |
|
216 | 0 | for (i = 0; i < sizeof(PRUint32); i++) { |
217 | 0 | val = (val << PR_BITS_PER_BYTE) | data[i]; |
218 | 0 | } |
219 | 0 | return val; |
220 | 0 | } |
221 | | |
222 | | /* |
223 | | ** Perform AES key wrap W function. |
224 | | ** "cx" the context |
225 | | ** "iv" the iv is concatenated to the plain text for for executing the function |
226 | | ** "output" the output buffer to store the encrypted data. |
227 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
228 | | ** after some data is stored in output. |
229 | | ** "maxOutputLen" the maximum amount of data that can ever be |
230 | | ** stored in "output" |
231 | | ** "input" the input data |
232 | | ** "inputLen" the amount of input data |
233 | | */ |
234 | | extern SECStatus |
235 | | AESKeyWrap_W(AESKeyWrapContext *cx, unsigned char *iv, unsigned char *output, |
236 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
237 | | const unsigned char *input, unsigned int inputLen) |
238 | 0 | { |
239 | 0 | PRUint64 *R = NULL; |
240 | 0 | unsigned int nBlocks; |
241 | 0 | unsigned int i, j; |
242 | 0 | unsigned int aesLen = AES_BLOCK_SIZE; |
243 | 0 | unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE; |
244 | 0 | SECStatus s = SECFailure; |
245 | | /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ |
246 | 0 | PRUint64 t; |
247 | 0 | PRUint64 B[2]; |
248 | |
|
249 | 0 | #define A B[0] |
250 | | |
251 | | /* Check args */ |
252 | 0 | if (inputLen < 2 * AES_KEY_WRAP_BLOCK_SIZE || |
253 | 0 | 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { |
254 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
255 | 0 | return s; |
256 | 0 | } |
257 | | #ifdef maybe |
258 | | if (!output && pOutputLen) { /* caller is asking for output size */ |
259 | | *pOutputLen = outLen; |
260 | | return SECSuccess; |
261 | | } |
262 | | #endif |
263 | 0 | if (maxOutputLen < outLen) { |
264 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
265 | 0 | return s; |
266 | 0 | } |
267 | 0 | if (cx == NULL || output == NULL || input == NULL) { |
268 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
269 | 0 | return s; |
270 | 0 | } |
271 | 0 | nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; |
272 | 0 | R = PORT_NewArray(PRUint64, nBlocks + 1); |
273 | 0 | if (!R) |
274 | 0 | return s; /* error is already set. */ |
275 | | /* |
276 | | ** 1) Initialize variables. |
277 | | */ |
278 | 0 | memcpy(&A, iv, AES_KEY_WRAP_IV_BYTES); |
279 | 0 | memcpy(&R[1], input, inputLen); |
280 | | #if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
281 | | t = 0; |
282 | | #else |
283 | 0 | memset(&t, 0, sizeof t); |
284 | 0 | #endif |
285 | | /* |
286 | | ** 2) Calculate intermediate values. |
287 | | */ |
288 | 0 | for (j = 0; j < 6; ++j) { |
289 | 0 | for (i = 1; i <= nBlocks; ++i) { |
290 | 0 | B[1] = R[i]; |
291 | 0 | s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, |
292 | 0 | sizeof B, (unsigned char *)B, sizeof B); |
293 | 0 | if (s != SECSuccess) |
294 | 0 | break; |
295 | 0 | R[i] = B[1]; |
296 | | /* here, increment t and XOR A with t (in big endian order); */ |
297 | | #if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
298 | | A ^= ++t; |
299 | | #else |
300 | 0 | increment_and_xor((unsigned char *)&A, (unsigned char *)&t); |
301 | 0 | #endif |
302 | 0 | } |
303 | 0 | } |
304 | | /* |
305 | | ** 3) Output the results. |
306 | | */ |
307 | 0 | if (s == SECSuccess) { |
308 | 0 | R[0] = A; |
309 | 0 | memcpy(output, &R[0], outLen); |
310 | 0 | if (pOutputLen) |
311 | 0 | *pOutputLen = outLen; |
312 | 0 | } else if (pOutputLen) { |
313 | 0 | *pOutputLen = 0; |
314 | 0 | } |
315 | 0 | PORT_ZFree(R, outLen); |
316 | 0 | return s; |
317 | 0 | } |
318 | | #undef A |
319 | | |
320 | | /* |
321 | | ** Perform AES key wrap W^-1 function. |
322 | | ** "cx" the context |
323 | | ** "iv" the input IV to verify against. If NULL, then skip verification. |
324 | | ** "ivOut" the output buffer to store the IV (optional). |
325 | | ** "output" the output buffer to store the decrypted data. |
326 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
327 | | ** after some data is stored in output. |
328 | | ** "maxOutputLen" the maximum amount of data that can ever be |
329 | | ** stored in "output" |
330 | | ** "input" the input data |
331 | | ** "inputLen" the amount of input data |
332 | | */ |
333 | | extern SECStatus |
334 | | AESKeyWrap_Winv(AESKeyWrapContext *cx, unsigned char *iv, |
335 | | unsigned char *ivOut, unsigned char *output, |
336 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
337 | | const unsigned char *input, unsigned int inputLen) |
338 | 0 | { |
339 | 0 | PRUint64 *R = NULL; |
340 | 0 | unsigned int nBlocks; |
341 | 0 | unsigned int i, j; |
342 | 0 | unsigned int aesLen = AES_BLOCK_SIZE; |
343 | 0 | unsigned int outLen; |
344 | 0 | SECStatus s = SECFailure; |
345 | | /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ |
346 | 0 | PRUint64 t; |
347 | 0 | PRUint64 B[2]; |
348 | | |
349 | | /* Check args */ |
350 | 0 | if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || |
351 | 0 | 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { |
352 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
353 | 0 | return s; |
354 | 0 | } |
355 | 0 | outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE; |
356 | | #ifdef maybe |
357 | | if (!output && pOutputLen) { /* caller is asking for output size */ |
358 | | *pOutputLen = outLen; |
359 | | return SECSuccess; |
360 | | } |
361 | | #endif |
362 | 0 | if (maxOutputLen < outLen) { |
363 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
364 | 0 | return s; |
365 | 0 | } |
366 | 0 | if (cx == NULL || output == NULL || input == NULL) { |
367 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
368 | 0 | return s; |
369 | 0 | } |
370 | 0 | nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; |
371 | 0 | R = PORT_NewArray(PRUint64, nBlocks); |
372 | 0 | if (!R) |
373 | 0 | return s; /* error is already set. */ |
374 | 0 | nBlocks--; |
375 | | /* |
376 | | ** 1) Initialize variables. |
377 | | */ |
378 | 0 | memcpy(&R[0], input, inputLen); |
379 | 0 | B[0] = R[0]; |
380 | | #if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
381 | | t = 6UL * nBlocks; |
382 | | #else |
383 | 0 | set_t((unsigned char *)&t, 6UL * nBlocks); |
384 | 0 | #endif |
385 | | /* |
386 | | ** 2) Calculate intermediate values. |
387 | | */ |
388 | 0 | for (j = 0; j < 6; ++j) { |
389 | 0 | for (i = nBlocks; i; --i) { |
390 | | /* here, XOR A with t (in big endian order) and decrement t; */ |
391 | | #if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
392 | | B[0] ^= t--; |
393 | | #else |
394 | 0 | xor_and_decrement(&B[0], &t); |
395 | 0 | #endif |
396 | 0 | B[1] = R[i]; |
397 | 0 | s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, |
398 | 0 | sizeof B, (unsigned char *)B, sizeof B); |
399 | 0 | if (s != SECSuccess) |
400 | 0 | break; |
401 | 0 | R[i] = B[1]; |
402 | 0 | } |
403 | 0 | } |
404 | | /* |
405 | | ** 3) Output the results. |
406 | | */ |
407 | 0 | if (s == SECSuccess) { |
408 | 0 | int bad = (iv) && memcmp(&B[0], iv, AES_KEY_WRAP_IV_BYTES); |
409 | 0 | if (!bad) { |
410 | 0 | memcpy(output, &R[1], outLen); |
411 | 0 | if (pOutputLen) |
412 | 0 | *pOutputLen = outLen; |
413 | 0 | if (ivOut) { |
414 | 0 | memcpy(ivOut, &B[0], AES_KEY_WRAP_IV_BYTES); |
415 | 0 | } |
416 | 0 | } else { |
417 | 0 | s = SECFailure; |
418 | 0 | PORT_SetError(SEC_ERROR_BAD_DATA); |
419 | 0 | if (pOutputLen) |
420 | 0 | *pOutputLen = 0; |
421 | 0 | } |
422 | 0 | } else if (pOutputLen) { |
423 | 0 | *pOutputLen = 0; |
424 | 0 | } |
425 | 0 | PORT_ZFree(R, inputLen); |
426 | 0 | return s; |
427 | 0 | } |
428 | | #undef A |
429 | | |
430 | | /* |
431 | | ** Perform AES key wrap. |
432 | | ** "cx" the context |
433 | | ** "output" the output buffer to store the encrypted data. |
434 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
435 | | ** after some data is stored in output. |
436 | | ** "maxOutputLen" the maximum amount of data that can ever be |
437 | | ** stored in "output" |
438 | | ** "input" the input data |
439 | | ** "inputLen" the amount of input data |
440 | | */ |
441 | | extern SECStatus |
442 | | AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, |
443 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
444 | | const unsigned char *input, unsigned int inputLen) |
445 | 0 | { |
446 | 0 | return AESKeyWrap_W(cx, cx->iv, output, pOutputLen, maxOutputLen, |
447 | 0 | input, inputLen); |
448 | 0 | } |
449 | | |
450 | | /* |
451 | | ** Perform AES key unwrap. |
452 | | ** "cx" the context |
453 | | ** "output" the output buffer to store the decrypted data. |
454 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
455 | | ** after some data is stored in output. |
456 | | ** "maxOutputLen" the maximum amount of data that can ever be |
457 | | ** stored in "output" |
458 | | ** "input" the input data |
459 | | ** "inputLen" the amount of input data |
460 | | */ |
461 | | extern SECStatus |
462 | | AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output, |
463 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
464 | | const unsigned char *input, unsigned int inputLen) |
465 | 0 | { |
466 | 0 | return AESKeyWrap_Winv(cx, cx->iv, NULL, output, pOutputLen, maxOutputLen, |
467 | 0 | input, inputLen); |
468 | 0 | } |
469 | | |
470 | 0 | #define BLOCK_PAD_POWER2(x, bs) (((bs) - ((x) & ((bs)-1))) & ((bs)-1)) |
471 | 0 | #define AES_KEY_WRAP_ICV2 0xa6, 0x59, 0x59, 0xa6 |
472 | | #define AES_KEY_WRAP_ICV2_INT32 0xa65959a6 |
473 | 0 | #define AES_KEY_WRAP_ICV2_LEN 4 |
474 | | |
475 | | /* |
476 | | ** Perform AES key wrap with padding. |
477 | | ** "cx" the context |
478 | | ** "output" the output buffer to store the encrypted data. |
479 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
480 | | ** after some data is stored in output. |
481 | | ** "maxOutputLen" the maximum amount of data that can ever be |
482 | | ** stored in "output" |
483 | | ** "input" the input data |
484 | | ** "inputLen" the amount of input data |
485 | | */ |
486 | | extern SECStatus |
487 | | AESKeyWrap_EncryptKWP(AESKeyWrapContext *cx, unsigned char *output, |
488 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
489 | | const unsigned char *input, unsigned int inputLen) |
490 | 0 | { |
491 | 0 | unsigned int padLen = BLOCK_PAD_POWER2(inputLen, AES_KEY_WRAP_BLOCK_SIZE); |
492 | 0 | unsigned int paddedInputLen = inputLen + padLen; |
493 | 0 | unsigned int outLen = paddedInputLen + AES_KEY_WRAP_BLOCK_SIZE; |
494 | 0 | unsigned char iv[AES_BLOCK_SIZE] = { AES_KEY_WRAP_ICV2 }; |
495 | 0 | unsigned char *newBuf; |
496 | 0 | SECStatus rv; |
497 | |
|
498 | 0 | *pOutputLen = outLen; |
499 | 0 | if (maxOutputLen < outLen) { |
500 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
501 | 0 | return SECFailure; |
502 | 0 | } |
503 | 0 | PORT_Assert((AES_KEY_WRAP_ICV2_LEN + sizeof(PRUint32)) == AES_KEY_WRAP_BLOCK_SIZE); |
504 | 0 | encode_PRUint32_BE(iv + AES_KEY_WRAP_ICV2_LEN, inputLen); |
505 | | |
506 | | /* If we can fit in an AES Block, just do and AES Encrypt, |
507 | | * iv is big enough to handle this on the stack, so no need to allocate |
508 | | */ |
509 | 0 | if (outLen == AES_BLOCK_SIZE) { |
510 | 0 | PORT_Assert(inputLen <= AES_KEY_WRAP_BLOCK_SIZE); |
511 | 0 | PORT_Memset(iv + AES_KEY_WRAP_BLOCK_SIZE, 0, AES_KEY_WRAP_BLOCK_SIZE); |
512 | 0 | PORT_Memcpy(iv + AES_KEY_WRAP_BLOCK_SIZE, input, inputLen); |
513 | 0 | rv = AES_Encrypt(&cx->aescx, output, pOutputLen, maxOutputLen, iv, |
514 | 0 | outLen); |
515 | 0 | PORT_Memset(iv, 0, sizeof(iv)); |
516 | 0 | return rv; |
517 | 0 | } |
518 | | |
519 | | /* add padding to our input block */ |
520 | 0 | newBuf = PORT_ZAlloc(paddedInputLen); |
521 | 0 | if (newBuf == NULL) { |
522 | 0 | return SECFailure; |
523 | 0 | } |
524 | 0 | PORT_Memcpy(newBuf, input, inputLen); |
525 | |
|
526 | 0 | rv = AESKeyWrap_W(cx, iv, output, pOutputLen, maxOutputLen, |
527 | 0 | newBuf, paddedInputLen); |
528 | 0 | PORT_ZFree(newBuf, paddedInputLen); |
529 | | /* a little overkill, we only need to clear out the length, but this |
530 | | * is easier to verify we got it all */ |
531 | 0 | PORT_Memset(iv, 0, sizeof(iv)); |
532 | 0 | return rv; |
533 | 0 | } |
534 | | |
535 | | /* |
536 | | ** Perform AES key unwrap with padding. |
537 | | ** "cx" the context |
538 | | ** "output" the output buffer to store the decrypted data. |
539 | | ** "pOutputLen" how much data is stored in "output". Set by the routine |
540 | | ** after some data is stored in output. |
541 | | ** "maxOutputLen" the maximum amount of data that can ever be |
542 | | ** stored in "output" |
543 | | ** "input" the input data |
544 | | ** "inputLen" the amount of input data |
545 | | */ |
546 | | extern SECStatus |
547 | | AESKeyWrap_DecryptKWP(AESKeyWrapContext *cx, unsigned char *output, |
548 | | unsigned int *pOutputLen, unsigned int maxOutputLen, |
549 | | const unsigned char *input, unsigned int inputLen) |
550 | 0 | { |
551 | 0 | unsigned int padLen; |
552 | 0 | unsigned int padLen2; |
553 | 0 | unsigned int outLen; |
554 | 0 | unsigned int paddedLen; |
555 | 0 | unsigned int good; |
556 | 0 | unsigned char *newBuf = NULL; |
557 | 0 | unsigned char *allocBuf = NULL; |
558 | 0 | int i; |
559 | 0 | unsigned char iv[AES_BLOCK_SIZE]; |
560 | 0 | PRUint32 magic; |
561 | 0 | SECStatus rv = SECFailure; |
562 | |
|
563 | 0 | paddedLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE; |
564 | | /* unwrap the padded result */ |
565 | 0 | if (inputLen == AES_BLOCK_SIZE) { |
566 | 0 | rv = AES_Decrypt(&cx->aescx, iv, &outLen, inputLen, input, inputLen); |
567 | 0 | newBuf = &iv[AES_KEY_WRAP_BLOCK_SIZE]; |
568 | 0 | outLen -= AES_KEY_WRAP_BLOCK_SIZE; |
569 | 0 | } else { |
570 | | /* if the caller supplied enough space to hold the unpadded buffer, |
571 | | * we can unwrap directly into that unpadded buffer. Otherwise |
572 | | * we allocate a buffer that can hold the padding, and we'll copy |
573 | | * the result in a later step */ |
574 | 0 | newBuf = output; |
575 | 0 | if (maxOutputLen < paddedLen) { |
576 | 0 | allocBuf = newBuf = PORT_Alloc(paddedLen); |
577 | 0 | if (!allocBuf) { |
578 | 0 | return SECFailure; |
579 | 0 | } |
580 | 0 | } |
581 | | /* We pass NULL for the first IV argument because we don't know |
582 | | * what the IV has since in includes the length, so we don't have |
583 | | * Winv verify it. We pass iv in the second argument to get the |
584 | | * iv, which we verify below before we return anything */ |
585 | 0 | rv = AESKeyWrap_Winv(cx, NULL, iv, newBuf, &outLen, |
586 | 0 | paddedLen, input, inputLen); |
587 | 0 | } |
588 | 0 | if (rv != SECSuccess) { |
589 | 0 | goto loser; |
590 | 0 | } |
591 | 0 | rv = SECFailure; |
592 | 0 | if (outLen != paddedLen) { |
593 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
594 | 0 | goto loser; |
595 | 0 | } |
596 | | |
597 | | /* we verify the result in a constant time manner */ |
598 | | /* verify ICV magic */ |
599 | 0 | magic = decode_PRUint32_BE(iv); |
600 | 0 | good = PORT_CT_EQ(magic, AES_KEY_WRAP_ICV2_INT32); |
601 | | /* fetch and verify plain text length */ |
602 | 0 | outLen = decode_PRUint32_BE(iv + AES_KEY_WRAP_ICV2_LEN); |
603 | 0 | good &= PORT_CT_LE(outLen, paddedLen); |
604 | | /* now verify the padding */ |
605 | 0 | padLen = paddedLen - outLen; |
606 | 0 | padLen2 = BLOCK_PAD_POWER2(outLen, AES_KEY_WRAP_BLOCK_SIZE); |
607 | 0 | good &= PORT_CT_EQ(padLen, padLen2); |
608 | 0 | for (i = 0; i < AES_KEY_WRAP_BLOCK_SIZE; i++) { |
609 | 0 | unsigned int doTest = PORT_CT_GT(padLen, i); |
610 | 0 | unsigned int result = PORT_CT_ZERO(newBuf[paddedLen - i - 1]); |
611 | 0 | good &= PORT_CT_SEL(doTest, result, PORT_CT_TRUE); |
612 | 0 | } |
613 | | |
614 | | /* now if anything was wrong, fail. At this point we will leak timing |
615 | | * information, but we also 'leak' the error code as well. */ |
616 | 0 | if (!good) { |
617 | 0 | PORT_SetError(SEC_ERROR_BAD_DATA); |
618 | 0 | goto loser; |
619 | 0 | } |
620 | | |
621 | | /* now copy out the result */ |
622 | 0 | *pOutputLen = outLen; |
623 | 0 | if (maxOutputLen < outLen) { |
624 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
625 | 0 | goto loser; |
626 | 0 | } |
627 | 0 | if (output != newBuf) { |
628 | 0 | PORT_Memcpy(output, newBuf, outLen); |
629 | 0 | } |
630 | 0 | rv = SECSuccess; |
631 | 0 | loser: |
632 | | /* if we failed, make sure we don't return any data to the user */ |
633 | 0 | if ((rv != SECSuccess) && (output == newBuf)) { |
634 | 0 | PORT_Memset(newBuf, 0, paddedLen); |
635 | 0 | } |
636 | | /* clear out CSP sensitive data from the heap and stack */ |
637 | 0 | if (allocBuf) { |
638 | 0 | PORT_ZFree(allocBuf, paddedLen); |
639 | 0 | } |
640 | 0 | PORT_Memset(iv, 0, sizeof(iv)); |
641 | 0 | return rv; |
642 | 0 | } |