Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(740)

Side by Side Diff: mozilla/security/nss/lib/freebl/aeskeywrap.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/lib/dev/nssdevt.h ('k') | mozilla/security/nss/lib/freebl/alg2268.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/dev/nssdevt.h ('k') | mozilla/security/nss/lib/freebl/alg2268.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698