Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/freebl/aeskeywrap.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 |