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