OLD | NEW |
| (Empty) |
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 /* $Id: aeskeywrap.c,v 1.6 2012/04/25 14:49:43 gerv%gerv.net Exp $ */ | |
8 | |
9 /* $Id: aeskeywrap.c,v 1.6 2012/04/25 14:49:43 gerv%gerv.net Exp $ */ | |
10 | |
11 #ifdef FREEBL_NO_DEPEND | |
12 #include "stubs.h" | |
13 #endif | |
14 | |
15 #include "prcpucfg.h" | |
16 #if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG) | |
17 #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0 | |
18 #else | |
19 #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1 | |
20 #endif | |
21 #include "prtypes.h" /* for PRUintXX */ | |
22 #include "secport.h" /* for PORT_XXX */ | |
23 #include "secerr.h" | |
24 #include "blapi.h" /* for AES_ functions */ | |
25 #include "rijndael.h" | |
26 | |
27 struct AESKeyWrapContextStr { | |
28 unsigned char iv[AES_KEY_WRAP_IV_BYTES]; | |
29 AESContext aescx; | |
30 }; | |
31 | |
32 /******************************************/ | |
33 /* | |
34 ** AES key wrap algorithm, RFC 3394 | |
35 */ | |
36 | |
37 AESKeyWrapContext * | |
38 AESKeyWrap_AllocateContext(void) | |
39 { | |
40 AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext); | |
41 return cx; | |
42 } | |
43 | |
44 SECStatus | |
45 AESKeyWrap_InitContext(AESKeyWrapContext *cx, | |
46 const unsigned char *key, | |
47 unsigned int keylen, | |
48 const unsigned char *iv, | |
49 int x1, | |
50 unsigned int encrypt, | |
51 unsigned int x2) | |
52 { | |
53 SECStatus rv = SECFailure; | |
54 if (!cx) { | |
55 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
56 return SECFailure; | |
57 } | |
58 if (iv) { | |
59 memcpy(cx->iv, iv, sizeof cx->iv); | |
60 } else { | |
61 memset(cx->iv, 0xA6, sizeof cx->iv); | |
62 } | |
63 rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, | |
64 AES_BLOCK_SIZE); | |
65 return rv; | |
66 } | |
67 | |
68 /* | |
69 ** Create a new AES context suitable for AES encryption/decryption. | |
70 ** "key" raw key data | |
71 ** "keylen" the number of bytes of key data (16, 24, or 32) | |
72 */ | |
73 extern AESKeyWrapContext * | |
74 AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, | |
75 int encrypt, unsigned int keylen) | |
76 { | |
77 SECStatus rv; | |
78 AESKeyWrapContext * cx = AESKeyWrap_AllocateContext(); | |
79 if (!cx) | |
80 return NULL; /* error is already set */ | |
81 rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0); | |
82 if (rv != SECSuccess) { | |
83 PORT_Free(cx); | |
84 cx = NULL; /* error should already be set */ | |
85 } | |
86 return cx; | |
87 } | |
88 | |
89 /* | |
90 ** Destroy a AES KeyWrap context. | |
91 ** "cx" the context | |
92 ** "freeit" if PR_TRUE then free the object as well as its sub-objects | |
93 */ | |
94 extern void | |
95 AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit) | |
96 { | |
97 if (cx) { | |
98 AES_DestroyContext(&cx->aescx, PR_FALSE); | |
99 /* memset(cx, 0, sizeof *cx); */ | |
100 if (freeit) | |
101 PORT_Free(cx); | |
102 } | |
103 } | |
104 | |
105 #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS | |
106 | |
107 /* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian | |
108 ** (Most significant byte first) in memory. The only ALU operations done | |
109 ** on them are increment, decrement, and XOR. So, on little-endian CPUs, | |
110 ** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations | |
111 ** are simulated in the following code. This is thought to be faster and | |
112 ** simpler than trying to convert the data to little-endian and back. | |
113 */ | |
114 | |
115 /* A and T point to two 64-bit values stored most signficant byte first | |
116 ** (big endian). This function increments the 64-bit value T, and then | |
117 ** XORs it with A, changing A. | |
118 */ | |
119 static void | |
120 increment_and_xor(unsigned char *A, unsigned char *T) | |
121 { | |
122 if (!++T[7]) | |
123 if (!++T[6]) | |
124 if (!++T[5]) | |
125 if (!++T[4]) | |
126 if (!++T[3]) | |
127 if (!++T[2]) | |
128 if (!++T[1]) | |
129 ++T[0]; | |
130 | |
131 A[0] ^= T[0]; | |
132 A[1] ^= T[1]; | |
133 A[2] ^= T[2]; | |
134 A[3] ^= T[3]; | |
135 A[4] ^= T[4]; | |
136 A[5] ^= T[5]; | |
137 A[6] ^= T[6]; | |
138 A[7] ^= T[7]; | |
139 } | |
140 | |
141 /* A and T point to two 64-bit values stored most signficant byte first | |
142 ** (big endian). This function XORs T with A, giving a new A, then | |
143 ** decrements the 64-bit value T. | |
144 */ | |
145 static void | |
146 xor_and_decrement(unsigned char *A, unsigned char *T) | |
147 { | |
148 A[0] ^= T[0]; | |
149 A[1] ^= T[1]; | |
150 A[2] ^= T[2]; | |
151 A[3] ^= T[3]; | |
152 A[4] ^= T[4]; | |
153 A[5] ^= T[5]; | |
154 A[6] ^= T[6]; | |
155 A[7] ^= T[7]; | |
156 | |
157 if (!T[7]--) | |
158 if (!T[6]--) | |
159 if (!T[5]--) | |
160 if (!T[4]--) | |
161 if (!T[3]--) | |
162 if (!T[2]--) | |
163 if (!T[1]--) | |
164 T[0]--; | |
165 | |
166 } | |
167 | |
168 /* Given an unsigned long t (in host byte order), store this value as a | |
169 ** 64-bit big-endian value (MSB first) in *pt. | |
170 */ | |
171 static void | |
172 set_t(unsigned char *pt, unsigned long t) | |
173 { | |
174 pt[7] = (unsigned char)t; t >>= 8; | |
175 pt[6] = (unsigned char)t; t >>= 8; | |
176 pt[5] = (unsigned char)t; t >>= 8; | |
177 pt[4] = (unsigned char)t; t >>= 8; | |
178 pt[3] = (unsigned char)t; t >>= 8; | |
179 pt[2] = (unsigned char)t; t >>= 8; | |
180 pt[1] = (unsigned char)t; t >>= 8; | |
181 pt[0] = (unsigned char)t; | |
182 } | |
183 | |
184 #endif | |
185 | |
186 /* | |
187 ** Perform AES key wrap. | |
188 ** "cx" the context | |
189 ** "output" the output buffer to store the encrypted data. | |
190 ** "outputLen" how much data is stored in "output". Set by the routine | |
191 ** after some data is stored in output. | |
192 ** "maxOutputLen" the maximum amount of data that can ever be | |
193 ** stored in "output" | |
194 ** "input" the input data | |
195 ** "inputLen" the amount of input data | |
196 */ | |
197 extern SECStatus | |
198 AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, | |
199 unsigned int *pOutputLen, unsigned int maxOutputLen, | |
200 const unsigned char *input, unsigned int inputLen) | |
201 { | |
202 PRUint64 * R = NULL; | |
203 unsigned int nBlocks; | |
204 unsigned int i, j; | |
205 unsigned int aesLen = AES_BLOCK_SIZE; | |
206 unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE; | |
207 SECStatus s = SECFailure; | |
208 /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ | |
209 PRUint64 t; | |
210 PRUint64 B[2]; | |
211 | |
212 #define A B[0] | |
213 | |
214 /* Check args */ | |
215 if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { | |
216 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
217 return s; | |
218 } | |
219 #ifdef maybe | |
220 if (!output && pOutputLen) { /* caller is asking for output size */ | |
221 *pOutputLen = outLen; | |
222 return SECSuccess; | |
223 } | |
224 #endif | |
225 if (maxOutputLen < outLen) { | |
226 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
227 return s; | |
228 } | |
229 if (cx == NULL || output == NULL || input == NULL) { | |
230 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
231 return s; | |
232 } | |
233 nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; | |
234 R = PORT_NewArray(PRUint64, nBlocks + 1); | |
235 if (!R) | |
236 return s; /* error is already set. */ | |
237 /* | |
238 ** 1) Initialize variables. | |
239 */ | |
240 memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); | |
241 memcpy(&R[1], input, inputLen); | |
242 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS | |
243 t = 0; | |
244 #else | |
245 memset(&t, 0, sizeof t); | |
246 #endif | |
247 /* | |
248 ** 2) Calculate intermediate values. | |
249 */ | |
250 for (j = 0; j < 6; ++j) { | |
251 for (i = 1; i <= nBlocks; ++i) { | |
252 B[1] = R[i]; | |
253 s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, | |
254 sizeof B, (unsigned char *)B, sizeof B); | |
255 if (s != SECSuccess) | |
256 break; | |
257 R[i] = B[1]; | |
258 /* here, increment t and XOR A with t (in big endian order); */ | |
259 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS | |
260 A ^= ++t; | |
261 #else | |
262 increment_and_xor((unsigned char *)&A, (unsigned char *)&t); | |
263 #endif | |
264 } | |
265 } | |
266 /* | |
267 ** 3) Output the results. | |
268 */ | |
269 if (s == SECSuccess) { | |
270 R[0] = A; | |
271 memcpy(output, &R[0], outLen); | |
272 if (pOutputLen) | |
273 *pOutputLen = outLen; | |
274 } else if (pOutputLen) { | |
275 *pOutputLen = 0; | |
276 } | |
277 PORT_ZFree(R, outLen); | |
278 return s; | |
279 } | |
280 #undef A | |
281 | |
282 /* | |
283 ** Perform AES key unwrap. | |
284 ** "cx" the context | |
285 ** "output" the output buffer to store the decrypted data. | |
286 ** "outputLen" how much data is stored in "output". Set by the routine | |
287 ** after some data is stored in output. | |
288 ** "maxOutputLen" the maximum amount of data that can ever be | |
289 ** stored in "output" | |
290 ** "input" the input data | |
291 ** "inputLen" the amount of input data | |
292 */ | |
293 extern SECStatus | |
294 AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output, | |
295 unsigned int *pOutputLen, unsigned int maxOutputLen, | |
296 const unsigned char *input, unsigned int inputLen) | |
297 { | |
298 PRUint64 * R = NULL; | |
299 unsigned int nBlocks; | |
300 unsigned int i, j; | |
301 unsigned int aesLen = AES_BLOCK_SIZE; | |
302 unsigned int outLen; | |
303 SECStatus s = SECFailure; | |
304 /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ | |
305 PRUint64 t; | |
306 PRUint64 B[2]; | |
307 | |
308 #define A B[0] | |
309 | |
310 /* Check args */ | |
311 if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || | |
312 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { | |
313 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
314 return s; | |
315 } | |
316 outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE; | |
317 #ifdef maybe | |
318 if (!output && pOutputLen) { /* caller is asking for output size */ | |
319 *pOutputLen = outLen; | |
320 return SECSuccess; | |
321 } | |
322 #endif | |
323 if (maxOutputLen < outLen) { | |
324 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
325 return s; | |
326 } | |
327 if (cx == NULL || output == NULL || input == NULL) { | |
328 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
329 return s; | |
330 } | |
331 nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; | |
332 R = PORT_NewArray(PRUint64, nBlocks); | |
333 if (!R) | |
334 return s; /* error is already set. */ | |
335 nBlocks--; | |
336 /* | |
337 ** 1) Initialize variables. | |
338 */ | |
339 memcpy(&R[0], input, inputLen); | |
340 A = R[0]; | |
341 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS | |
342 t = 6UL * nBlocks; | |
343 #else | |
344 set_t((unsigned char *)&t, 6UL * nBlocks); | |
345 #endif | |
346 /* | |
347 ** 2) Calculate intermediate values. | |
348 */ | |
349 for (j = 0; j < 6; ++j) { | |
350 for (i = nBlocks; i; --i) { | |
351 /* here, XOR A with t (in big endian order) and decrement t; */ | |
352 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS | |
353 A ^= t--; | |
354 #else | |
355 xor_and_decrement((unsigned char *)&A, (unsigned char *)&t); | |
356 #endif | |
357 B[1] = R[i]; | |
358 s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, | |
359 sizeof B, (unsigned char *)B, sizeof B); | |
360 if (s != SECSuccess) | |
361 break; | |
362 R[i] = B[1]; | |
363 } | |
364 } | |
365 /* | |
366 ** 3) Output the results. | |
367 */ | |
368 if (s == SECSuccess) { | |
369 int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); | |
370 if (!bad) { | |
371 memcpy(output, &R[1], outLen); | |
372 if (pOutputLen) | |
373 *pOutputLen = outLen; | |
374 } else { | |
375 PORT_SetError(SEC_ERROR_BAD_DATA); | |
376 if (pOutputLen) | |
377 *pOutputLen = 0; | |
378 } | |
379 } else if (pOutputLen) { | |
380 *pOutputLen = 0; | |
381 } | |
382 PORT_ZFree(R, inputLen); | |
383 return s; | |
384 } | |
385 #undef A | |
OLD | NEW |