PageRenderTime 37ms CodeModel.GetById 14ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/security/nss/lib/freebl/aeskeywrap.c

http://github.com/zpao/v8monkey
C | 417 lines | 274 code | 24 blank | 119 comment | 70 complexity | 6fcaf84bc1b743ed1193d9c43418942f MD5 | raw file
  1/*
  2 * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
  3 *
  4 * ***** BEGIN LICENSE BLOCK *****
  5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6 *
  7 * The contents of this file are subject to the Mozilla Public License Version
  8 * 1.1 (the "License"); you may not use this file except in compliance with
  9 * the License. You may obtain a copy of the License at
 10 * http://www.mozilla.org/MPL/
 11 *
 12 * Software distributed under the License is distributed on an "AS IS" basis,
 13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 14 * for the specific language governing rights and limitations under the
 15 * License.
 16 *
 17 * The Original Code is the Netscape security libraries.
 18 *
 19 * The Initial Developer of the Original Code is
 20 * Netscape Communications Corporation.
 21 * Portions created by the Initial Developer are Copyright (C) 2002
 22 * the Initial Developer. All Rights Reserved.
 23 *
 24 * Contributor(s):
 25 *
 26 * Alternatively, the contents of this file may be used under the terms of
 27 * either the GNU General Public License Version 2 or later (the "GPL"), or
 28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 29 * in which case the provisions of the GPL or the LGPL are applicable instead
 30 * of those above. If you wish to allow use of your version of this file only
 31 * under the terms of either the GPL or the LGPL, and not to allow others to
 32 * use your version of this file under the terms of the MPL, indicate your
 33 * decision by deleting the provisions above and replace them with the notice
 34 * and other provisions required by the GPL or the LGPL. If you do not delete
 35 * the provisions above, a recipient may use your version of this file under
 36 * the terms of any one of the MPL, the GPL or the LGPL.
 37 *
 38 * ***** END LICENSE BLOCK ***** */
 39/* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
 40
 41/* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
 42
 43#ifdef FREEBL_NO_DEPEND
 44#include "stubs.h"
 45#endif
 46
 47#include "prcpucfg.h"
 48#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
 49#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
 50#else
 51#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
 52#endif
 53#include "prtypes.h"	/* for PRUintXX */
 54#include "secport.h"	/* for PORT_XXX */
 55#include "secerr.h"
 56#include "blapi.h"	/* for AES_ functions */
 57#include "rijndael.h"
 58
 59struct AESKeyWrapContextStr {
 60     unsigned char iv[AES_KEY_WRAP_IV_BYTES];
 61     AESContext    aescx;
 62};
 63
 64/******************************************/
 65/*
 66** AES key wrap algorithm, RFC 3394
 67*/
 68
 69AESKeyWrapContext * 
 70AESKeyWrap_AllocateContext(void)
 71{
 72    AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext);
 73    return cx;
 74}
 75
 76SECStatus  
 77AESKeyWrap_InitContext(AESKeyWrapContext *cx, 
 78		       const unsigned char *key, 
 79		       unsigned int keylen,
 80		       const unsigned char *iv, 
 81		       int x1,
 82		       unsigned int encrypt,
 83		       unsigned int x2)
 84{
 85    SECStatus rv = SECFailure;
 86    if (!cx) {
 87	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 88    	return SECFailure;
 89    }
 90    if (iv) {
 91    	memcpy(cx->iv, iv, sizeof cx->iv);
 92    } else {
 93	memset(cx->iv, 0xA6, sizeof cx->iv);
 94    }
 95    rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, 
 96                                  AES_BLOCK_SIZE);
 97    return rv;
 98}
 99
100/*
101** Create a new AES context suitable for AES encryption/decryption.
102** 	"key" raw key data
103** 	"keylen" the number of bytes of key data (16, 24, or 32)
104*/
105extern AESKeyWrapContext *
106AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, 
107                         int encrypt, unsigned int keylen)
108{
109    SECStatus rv;
110    AESKeyWrapContext * cx = AESKeyWrap_AllocateContext();
111    if (!cx) 
112    	return NULL;	/* error is already set */
113    rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
114    if (rv != SECSuccess) {
115        PORT_Free(cx);
116	cx = NULL; 	/* error should already be set */
117    }
118    return cx;
119}
120
121/*
122** Destroy a AES KeyWrap context.
123**	"cx" the context
124**	"freeit" if PR_TRUE then free the object as well as its sub-objects
125*/
126extern void 
127AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
128{
129    if (cx) {
130	AES_DestroyContext(&cx->aescx, PR_FALSE);
131/*	memset(cx, 0, sizeof *cx); */
132	if (freeit)
133	    PORT_Free(cx);
134    }
135}
136
137#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
138
139/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
140** (Most significant byte first) in memory.  The only ALU operations done
141** on them are increment, decrement, and XOR.  So, on little-endian CPUs,
142** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
143** are simulated in the following code.  This is thought to be faster and
144** simpler than trying to convert the data to little-endian and back.
145*/
146
147/* A and T point to two 64-bit values stored most signficant byte first
148** (big endian).  This function increments the 64-bit value T, and then
149** XORs it with A, changing A.
150*/ 
151static void
152increment_and_xor(unsigned char *A, unsigned char *T)
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    A[0] ^= T[0];
164    A[1] ^= T[1];
165    A[2] ^= T[2];
166    A[3] ^= T[3];
167    A[4] ^= T[4];
168    A[5] ^= T[5];
169    A[6] ^= T[6];
170    A[7] ^= T[7];
171}
172
173/* A and T point to two 64-bit values stored most signficant byte first
174** (big endian).  This function XORs T with A, giving a new A, then 
175** decrements the 64-bit value T.
176*/ 
177static void
178xor_and_decrement(unsigned char *A, unsigned char *T)
179{
180    A[0] ^= T[0];
181    A[1] ^= T[1];
182    A[2] ^= T[2];
183    A[3] ^= T[3];
184    A[4] ^= T[4];
185    A[5] ^= T[5];
186    A[6] ^= T[6];
187    A[7] ^= T[7];
188
189    if (!T[7]--)
190        if (!T[6]--)
191	    if (!T[5]--)
192		if (!T[4]--)
193		    if (!T[3]--)
194			if (!T[2]--)
195			    if (!T[1]--)
196				 T[0]--;
197
198}
199
200/* Given an unsigned long t (in host byte order), store this value as a
201** 64-bit big-endian value (MSB first) in *pt.
202*/
203static void
204set_t(unsigned char *pt, unsigned long t)
205{
206    pt[7] = (unsigned char)t; t >>= 8;
207    pt[6] = (unsigned char)t; t >>= 8;
208    pt[5] = (unsigned char)t; t >>= 8;
209    pt[4] = (unsigned char)t; t >>= 8;
210    pt[3] = (unsigned char)t; t >>= 8;
211    pt[2] = (unsigned char)t; t >>= 8;
212    pt[1] = (unsigned char)t; t >>= 8;
213    pt[0] = (unsigned char)t;
214}
215
216#endif
217
218/*
219** Perform AES key wrap.
220**	"cx" the context
221**	"output" the output buffer to store the encrypted data.
222**	"outputLen" how much data is stored in "output". Set by the routine
223**	   after some data is stored in output.
224**	"maxOutputLen" the maximum amount of data that can ever be
225**	   stored in "output"
226**	"input" the input data
227**	"inputLen" the amount of input data
228*/
229extern SECStatus 
230AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
231            unsigned int *pOutputLen, unsigned int maxOutputLen,
232            const unsigned char *input, unsigned int inputLen)
233{
234    PRUint64 *     R          = NULL;
235    unsigned int   nBlocks;
236    unsigned int   i, j;
237    unsigned int   aesLen     = AES_BLOCK_SIZE;
238    unsigned int   outLen     = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
239    SECStatus      s          = SECFailure;
240    /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
241    PRUint64       t;
242    PRUint64       B[2];
243
244#define A B[0]
245
246    /* Check args */
247    if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
248	PORT_SetError(SEC_ERROR_INPUT_LEN);
249	return s;
250    }
251#ifdef maybe
252    if (!output && pOutputLen) {	/* caller is asking for output size */
253    	*pOutputLen = outLen;
254	return SECSuccess;
255    }
256#endif
257    if (maxOutputLen < outLen) {
258	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
259	return s;
260    }
261    if (cx == NULL || output == NULL || input == NULL) {
262	PORT_SetError(SEC_ERROR_INVALID_ARGS);
263	return s;
264    }
265    nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
266    R = PORT_NewArray(PRUint64, nBlocks + 1);
267    if (!R)
268    	return s;	/* error is already set. */
269    /* 
270    ** 1) Initialize variables.
271    */
272    memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
273    memcpy(&R[1], input, inputLen);
274#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
275    t = 0;
276#else
277    memset(&t, 0, sizeof t);
278#endif
279    /* 
280    ** 2) Calculate intermediate values.
281    */
282    for (j = 0; j < 6; ++j) {
283    	for (i = 1; i <= nBlocks; ++i) {
284	    B[1] = R[i];
285	    s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, 
286	                    sizeof B,  (unsigned char *)B, sizeof B);
287	    if (s != SECSuccess) 
288	        break;
289	    R[i] = B[1];
290	    /* here, increment t and XOR A with t (in big endian order); */
291#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
292   	    A ^= ++t; 
293#else
294	    increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
295#endif
296	}
297    }
298    /* 
299    ** 3) Output the results.
300    */
301    if (s == SECSuccess) {
302    	R[0] =  A;
303	memcpy(output, &R[0], outLen);
304	if (pOutputLen)
305	    *pOutputLen = outLen;
306    } else if (pOutputLen) {
307    	*pOutputLen = 0;
308    }
309    PORT_ZFree(R, outLen);
310    return s;
311}
312#undef A
313
314/*
315** Perform AES key unwrap.
316**	"cx" the context
317**	"output" the output buffer to store the decrypted data.
318**	"outputLen" how much data is stored in "output". Set by the routine
319**	   after some data is stored in output.
320**	"maxOutputLen" the maximum amount of data that can ever be
321**	   stored in "output"
322**	"input" the input data
323**	"inputLen" the amount of input data
324*/
325extern SECStatus 
326AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
327            unsigned int *pOutputLen, unsigned int maxOutputLen,
328            const unsigned char *input, unsigned int inputLen)
329{
330    PRUint64 *     R          = NULL;
331    unsigned int   nBlocks;
332    unsigned int   i, j;
333    unsigned int   aesLen     = AES_BLOCK_SIZE;
334    unsigned int   outLen;
335    SECStatus      s          = SECFailure;
336    /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
337    PRUint64       t;
338    PRUint64       B[2];
339
340#define A B[0]
341
342    /* Check args */
343    if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || 
344        0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
345	PORT_SetError(SEC_ERROR_INPUT_LEN);
346	return s;
347    }
348    outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
349#ifdef maybe
350    if (!output && pOutputLen) {	/* caller is asking for output size */
351    	*pOutputLen = outLen;
352	return SECSuccess;
353    }
354#endif
355    if (maxOutputLen < outLen) {
356	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
357	return s;
358    }
359    if (cx == NULL || output == NULL || input == NULL) {
360	PORT_SetError(SEC_ERROR_INVALID_ARGS);
361	return s;
362    }
363    nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
364    R = PORT_NewArray(PRUint64, nBlocks);
365    if (!R)
366    	return s;	/* error is already set. */
367    nBlocks--;
368    /* 
369    ** 1) Initialize variables.
370    */
371    memcpy(&R[0], input, inputLen);
372    A = R[0];
373#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
374    t = 6UL * nBlocks;
375#else
376    set_t((unsigned char *)&t, 6UL * nBlocks);
377#endif
378    /* 
379    ** 2) Calculate intermediate values.
380    */
381    for (j = 0; j < 6; ++j) {
382    	for (i = nBlocks; i; --i) {
383	    /* here, XOR A with t (in big endian order) and decrement t; */
384#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
385   	    A ^= t--; 
386#else
387	    xor_and_decrement((unsigned char *)&A, (unsigned char *)&t);
388#endif
389	    B[1] = R[i];
390	    s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, 
391	                    sizeof B,  (unsigned char *)B, sizeof B);
392	    if (s != SECSuccess) 
393	        break;
394	    R[i] = B[1];
395	}
396    }
397    /* 
398    ** 3) Output the results.
399    */
400    if (s == SECSuccess) {
401	int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
402	if (!bad) {
403	    memcpy(output, &R[1], outLen);
404	    if (pOutputLen)
405		*pOutputLen = outLen;
406	} else {
407	    PORT_SetError(SEC_ERROR_BAD_DATA);
408	    if (pOutputLen) 
409		*pOutputLen = 0;
410    	}
411    } else if (pOutputLen) {
412    	*pOutputLen = 0;
413    }
414    PORT_ZFree(R, inputLen);
415    return s;
416}
417#undef A