security/nss/lib/freebl/aeskeywrap.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     8 #ifdef FREEBL_NO_DEPEND
     9 #include "stubs.h"
    10 #endif
    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"
    24 struct AESKeyWrapContextStr {
    25      unsigned char iv[AES_KEY_WRAP_IV_BYTES];
    26      AESContext    aescx;
    27 };
    29 /******************************************/
    30 /*
    31 ** AES key wrap algorithm, RFC 3394
    32 */
    34 AESKeyWrapContext * 
    35 AESKeyWrap_AllocateContext(void)
    36 {
    37     AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext);
    38     return cx;
    39 }
    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 }
    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 }
    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 }
   102 #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
   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 */
   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];
   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 }
   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];
   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]--;
   163 }
   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 }
   181 #endif
   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];
   209 #define A B[0]
   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
   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];
   305 #define A B[0]
   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

mercurial