diff options
Diffstat (limited to 'nss/lib/freebl/aeskeywrap.c')
-rw-r--r-- | nss/lib/freebl/aeskeywrap.c | 358 |
1 files changed, 182 insertions, 176 deletions
diff --git a/nss/lib/freebl/aeskeywrap.c b/nss/lib/freebl/aeskeywrap.c index c1c95b3..79ff8a8 100644 --- a/nss/lib/freebl/aeskeywrap.c +++ b/nss/lib/freebl/aeskeywrap.c @@ -15,15 +15,15 @@ #else #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1 #endif -#include "prtypes.h" /* for PRUintXX */ -#include "secport.h" /* for PORT_XXX */ +#include "prtypes.h" /* for PRUintXX */ +#include "secport.h" /* for PORT_XXX */ #include "secerr.h" -#include "blapi.h" /* for AES_ functions */ +#include "blapi.h" /* for AES_ functions */ #include "rijndael.h" struct AESKeyWrapContextStr { - unsigned char iv[AES_KEY_WRAP_IV_BYTES]; - AESContext aescx; + unsigned char iv[AES_KEY_WRAP_IV_BYTES]; + AESContext aescx; }; /******************************************/ @@ -31,71 +31,71 @@ struct AESKeyWrapContextStr { ** AES key wrap algorithm, RFC 3394 */ -AESKeyWrapContext * +AESKeyWrapContext * AESKeyWrap_AllocateContext(void) { - AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext); + AESKeyWrapContext *cx = PORT_New(AESKeyWrapContext); return cx; } -SECStatus -AESKeyWrap_InitContext(AESKeyWrapContext *cx, - const unsigned char *key, - unsigned int keylen, - const unsigned char *iv, - int x1, - unsigned int encrypt, - unsigned int x2) +SECStatus +AESKeyWrap_InitContext(AESKeyWrapContext *cx, + const unsigned char *key, + unsigned int keylen, + const unsigned char *iv, + int x1, + unsigned int encrypt, + unsigned int x2) { SECStatus rv = SECFailure; if (!cx) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; } if (iv) { - memcpy(cx->iv, iv, sizeof cx->iv); + memcpy(cx->iv, iv, sizeof cx->iv); } else { - memset(cx->iv, 0xA6, sizeof cx->iv); + memset(cx->iv, 0xA6, sizeof cx->iv); } - rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, - AES_BLOCK_SIZE); + rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt, + AES_BLOCK_SIZE); return rv; } /* ** Create a new AES context suitable for AES encryption/decryption. -** "key" raw key data -** "keylen" the number of bytes of key data (16, 24, or 32) +** "key" raw key data +** "keylen" the number of bytes of key data (16, 24, or 32) */ extern AESKeyWrapContext * -AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, +AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv, int encrypt, unsigned int keylen) { SECStatus rv; - AESKeyWrapContext * cx = AESKeyWrap_AllocateContext(); - if (!cx) - return NULL; /* error is already set */ + AESKeyWrapContext *cx = AESKeyWrap_AllocateContext(); + if (!cx) + return NULL; /* error is already set */ rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0); if (rv != SECSuccess) { PORT_Free(cx); - cx = NULL; /* error should already be set */ + cx = NULL; /* error should already be set */ } return cx; } /* ** Destroy a AES KeyWrap context. -** "cx" the context -** "freeit" if PR_TRUE then free the object as well as its sub-objects +** "cx" the context +** "freeit" if PR_TRUE then free the object as well as its sub-objects */ -extern void +extern void AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit) { if (cx) { - AES_DestroyContext(&cx->aescx, PR_FALSE); -/* memset(cx, 0, sizeof *cx); */ - if (freeit) - PORT_Free(cx); + AES_DestroyContext(&cx->aescx, PR_FALSE); + /* memset(cx, 0, sizeof *cx); */ + if (freeit) + PORT_Free(cx); } } @@ -112,18 +112,18 @@ AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit) /* A and T point to two 64-bit values stored most signficant byte first ** (big endian). This function increments the 64-bit value T, and then ** XORs it with A, changing A. -*/ +*/ static void increment_and_xor(unsigned char *A, unsigned char *T) { if (!++T[7]) if (!++T[6]) - if (!++T[5]) - if (!++T[4]) - if (!++T[3]) - if (!++T[2]) - if (!++T[1]) - ++T[0]; + if (!++T[5]) + if (!++T[4]) + if (!++T[3]) + if (!++T[2]) + if (!++T[1]) + ++T[0]; A[0] ^= T[0]; A[1] ^= T[1]; @@ -136,30 +136,31 @@ increment_and_xor(unsigned char *A, unsigned char *T) } /* A and T point to two 64-bit values stored most signficant byte first -** (big endian). This function XORs T with A, giving a new A, then +** (big endian). This function XORs T with A, giving a new A, then ** decrements the 64-bit value T. -*/ +*/ static void -xor_and_decrement(unsigned char *A, unsigned char *T) +xor_and_decrement(PRUint64 *A, PRUint64 *T) { - A[0] ^= T[0]; - A[1] ^= T[1]; - A[2] ^= T[2]; - A[3] ^= T[3]; - A[4] ^= T[4]; - A[5] ^= T[5]; - A[6] ^= T[6]; - A[7] ^= T[7]; - - if (!T[7]--) - if (!T[6]--) - if (!T[5]--) - if (!T[4]--) - if (!T[3]--) - if (!T[2]--) - if (!T[1]--) - T[0]--; + unsigned char *TP = (unsigned char *)T; + const PRUint64 mask = 0xFF; + *A = ((*A & mask << 56) ^ (*T & mask << 56)) | + ((*A & mask << 48) ^ (*T & mask << 48)) | + ((*A & mask << 40) ^ (*T & mask << 40)) | + ((*A & mask << 32) ^ (*T & mask << 32)) | + ((*A & mask << 24) ^ (*T & mask << 23)) | + ((*A & mask << 16) ^ (*T & mask << 16)) | + ((*A & mask << 8) ^ (*T & mask << 8)) | + ((*A & mask) ^ (*T & mask)); + if (!TP[7]--) + if (!TP[6]--) + if (!TP[5]--) + if (!TP[4]--) + if (!TP[3]--) + if (!TP[2]--) + if (!TP[1]--) + TP[0]--; } /* Given an unsigned long t (in host byte order), store this value as a @@ -168,13 +169,20 @@ xor_and_decrement(unsigned char *A, unsigned char *T) static void set_t(unsigned char *pt, unsigned long t) { - pt[7] = (unsigned char)t; t >>= 8; - pt[6] = (unsigned char)t; t >>= 8; - pt[5] = (unsigned char)t; t >>= 8; - pt[4] = (unsigned char)t; t >>= 8; - pt[3] = (unsigned char)t; t >>= 8; - pt[2] = (unsigned char)t; t >>= 8; - pt[1] = (unsigned char)t; t >>= 8; + pt[7] = (unsigned char)t; + t >>= 8; + pt[6] = (unsigned char)t; + t >>= 8; + pt[5] = (unsigned char)t; + t >>= 8; + pt[4] = (unsigned char)t; + t >>= 8; + pt[3] = (unsigned char)t; + t >>= 8; + pt[2] = (unsigned char)t; + t >>= 8; + pt[1] = (unsigned char)t; + t >>= 8; pt[0] = (unsigned char)t; } @@ -182,56 +190,56 @@ set_t(unsigned char *pt, unsigned long t) /* ** Perform AES key wrap. -** "cx" the context -** "output" the output buffer to store the encrypted data. -** "outputLen" how much data is stored in "output". Set by the routine -** after some data is stored in output. -** "maxOutputLen" the maximum amount of data that can ever be -** stored in "output" -** "input" the input data -** "inputLen" the amount of input data +** "cx" the context +** "output" the output buffer to store the encrypted data. +** "outputLen" how much data is stored in "output". Set by the routine +** after some data is stored in output. +** "maxOutputLen" the maximum amount of data that can ever be +** stored in "output" +** "input" the input data +** "inputLen" the amount of input data */ -extern SECStatus +extern SECStatus AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, - unsigned int *pOutputLen, unsigned int maxOutputLen, - const unsigned char *input, unsigned int inputLen) + unsigned int *pOutputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) { - PRUint64 * R = NULL; - unsigned int nBlocks; - unsigned int i, j; - unsigned int aesLen = AES_BLOCK_SIZE; - unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE; - SECStatus s = SECFailure; + PRUint64 *R = NULL; + unsigned int nBlocks; + unsigned int i, j; + unsigned int aesLen = AES_BLOCK_SIZE; + unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE; + SECStatus s = SECFailure; /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ - PRUint64 t; - PRUint64 B[2]; + PRUint64 t; + PRUint64 B[2]; #define A B[0] /* Check args */ if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return s; + PORT_SetError(SEC_ERROR_INPUT_LEN); + return s; } #ifdef maybe - if (!output && pOutputLen) { /* caller is asking for output size */ - *pOutputLen = outLen; - return SECSuccess; + if (!output && pOutputLen) { /* caller is asking for output size */ + *pOutputLen = outLen; + return SECSuccess; } #endif if (maxOutputLen < outLen) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return s; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return s; } if (cx == NULL || output == NULL || input == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return s; + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return s; } nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; R = PORT_NewArray(PRUint64, nBlocks + 1); if (!R) - return s; /* error is already set. */ - /* + return s; /* error is already set. */ + /* ** 1) Initialize variables. */ memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); @@ -241,35 +249,35 @@ AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, #else memset(&t, 0, sizeof t); #endif - /* + /* ** 2) Calculate intermediate values. */ for (j = 0; j < 6; ++j) { - for (i = 1; i <= nBlocks; ++i) { - B[1] = R[i]; - s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, - sizeof B, (unsigned char *)B, sizeof B); - if (s != SECSuccess) - break; - R[i] = B[1]; - /* here, increment t and XOR A with t (in big endian order); */ + for (i = 1; i <= nBlocks; ++i) { + B[1] = R[i]; + s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, + sizeof B, (unsigned char *)B, sizeof B); + if (s != SECSuccess) + break; + R[i] = B[1]; +/* here, increment t and XOR A with t (in big endian order); */ #if BIG_ENDIAN_WITH_64_BIT_REGISTERS - A ^= ++t; + A ^= ++t; #else - increment_and_xor((unsigned char *)&A, (unsigned char *)&t); + increment_and_xor((unsigned char *)&A, (unsigned char *)&t); #endif - } + } } - /* + /* ** 3) Output the results. */ if (s == SECSuccess) { - R[0] = A; - memcpy(output, &R[0], outLen); - if (pOutputLen) - *pOutputLen = outLen; + R[0] = A; + memcpy(output, &R[0], outLen); + if (pOutputLen) + *pOutputLen = outLen; } else if (pOutputLen) { - *pOutputLen = 0; + *pOutputLen = 0; } PORT_ZFree(R, outLen); return s; @@ -278,104 +286,102 @@ AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, /* ** Perform AES key unwrap. -** "cx" the context -** "output" the output buffer to store the decrypted data. -** "outputLen" how much data is stored in "output". Set by the routine -** after some data is stored in output. -** "maxOutputLen" the maximum amount of data that can ever be -** stored in "output" -** "input" the input data -** "inputLen" the amount of input data +** "cx" the context +** "output" the output buffer to store the decrypted data. +** "outputLen" how much data is stored in "output". Set by the routine +** after some data is stored in output. +** "maxOutputLen" the maximum amount of data that can ever be +** stored in "output" +** "input" the input data +** "inputLen" the amount of input data */ -extern SECStatus +extern SECStatus AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output, - unsigned int *pOutputLen, unsigned int maxOutputLen, - const unsigned char *input, unsigned int inputLen) + unsigned int *pOutputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen) { - PRUint64 * R = NULL; - unsigned int nBlocks; - unsigned int i, j; - unsigned int aesLen = AES_BLOCK_SIZE; - unsigned int outLen; - SECStatus s = SECFailure; + PRUint64 *R = NULL; + unsigned int nBlocks; + unsigned int i, j; + unsigned int aesLen = AES_BLOCK_SIZE; + unsigned int outLen; + SECStatus s = SECFailure; /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ - PRUint64 t; - PRUint64 B[2]; - -#define A B[0] + PRUint64 t; + PRUint64 B[2]; /* Check args */ - if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || + if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return s; + PORT_SetError(SEC_ERROR_INPUT_LEN); + return s; } outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE; #ifdef maybe - if (!output && pOutputLen) { /* caller is asking for output size */ - *pOutputLen = outLen; - return SECSuccess; + if (!output && pOutputLen) { /* caller is asking for output size */ + *pOutputLen = outLen; + return SECSuccess; } #endif if (maxOutputLen < outLen) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return s; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return s; } if (cx == NULL || output == NULL || input == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return s; + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return s; } nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; R = PORT_NewArray(PRUint64, nBlocks); if (!R) - return s; /* error is already set. */ + return s; /* error is already set. */ nBlocks--; - /* + /* ** 1) Initialize variables. */ memcpy(&R[0], input, inputLen); - A = R[0]; + B[0] = R[0]; #if BIG_ENDIAN_WITH_64_BIT_REGISTERS t = 6UL * nBlocks; #else set_t((unsigned char *)&t, 6UL * nBlocks); #endif - /* + /* ** 2) Calculate intermediate values. */ for (j = 0; j < 6; ++j) { - for (i = nBlocks; i; --i) { - /* here, XOR A with t (in big endian order) and decrement t; */ + for (i = nBlocks; i; --i) { +/* here, XOR A with t (in big endian order) and decrement t; */ #if BIG_ENDIAN_WITH_64_BIT_REGISTERS - A ^= t--; + B[0] ^= t--; #else - xor_and_decrement((unsigned char *)&A, (unsigned char *)&t); + xor_and_decrement(&B[0], &t); #endif - B[1] = R[i]; - s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, - sizeof B, (unsigned char *)B, sizeof B); - if (s != SECSuccess) - break; - R[i] = B[1]; - } + B[1] = R[i]; + s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, + sizeof B, (unsigned char *)B, sizeof B); + if (s != SECSuccess) + break; + R[i] = B[1]; + } } - /* + /* ** 3) Output the results. */ if (s == SECSuccess) { - int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); - if (!bad) { - memcpy(output, &R[1], outLen); - if (pOutputLen) - *pOutputLen = outLen; - } else { - s = SECFailure; - PORT_SetError(SEC_ERROR_BAD_DATA); - if (pOutputLen) - *pOutputLen = 0; - } + int bad = memcmp(&B[0], cx->iv, AES_KEY_WRAP_IV_BYTES); + if (!bad) { + memcpy(output, &R[1], outLen); + if (pOutputLen) + *pOutputLen = outLen; + } else { + s = SECFailure; + PORT_SetError(SEC_ERROR_BAD_DATA); + if (pOutputLen) + *pOutputLen = 0; + } } else if (pOutputLen) { - *pOutputLen = 0; + *pOutputLen = 0; } PORT_ZFree(R, inputLen); return s; |