Index: mozilla/security/nss/lib/freebl/aeskeywrap.c |
=================================================================== |
--- mozilla/security/nss/lib/freebl/aeskeywrap.c (revision 191424) |
+++ mozilla/security/nss/lib/freebl/aeskeywrap.c (working copy) |
@@ -1,385 +0,0 @@ |
-/* |
- * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394 |
- * |
- * This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
-/* $Id: aeskeywrap.c,v 1.6 2012/04/25 14:49:43 gerv%gerv.net Exp $ */ |
- |
-/* $Id: aeskeywrap.c,v 1.6 2012/04/25 14:49:43 gerv%gerv.net Exp $ */ |
- |
-#ifdef FREEBL_NO_DEPEND |
-#include "stubs.h" |
-#endif |
- |
-#include "prcpucfg.h" |
-#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG) |
-#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0 |
-#else |
-#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1 |
-#endif |
-#include "prtypes.h" /* for PRUintXX */ |
-#include "secport.h" /* for PORT_XXX */ |
-#include "secerr.h" |
-#include "blapi.h" /* for AES_ functions */ |
-#include "rijndael.h" |
- |
-struct AESKeyWrapContextStr { |
- unsigned char iv[AES_KEY_WRAP_IV_BYTES]; |
- AESContext aescx; |
-}; |
- |
-/******************************************/ |
-/* |
-** AES key wrap algorithm, RFC 3394 |
-*/ |
- |
-AESKeyWrapContext * |
-AESKeyWrap_AllocateContext(void) |
-{ |
- 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 rv = SECFailure; |
- if (!cx) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- if (iv) { |
- memcpy(cx->iv, iv, sizeof cx->iv); |
- } else { |
- memset(cx->iv, 0xA6, sizeof cx->iv); |
- } |
- 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) |
-*/ |
-extern AESKeyWrapContext * |
-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 */ |
- rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0); |
- if (rv != SECSuccess) { |
- PORT_Free(cx); |
- 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 |
-*/ |
-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); |
- } |
-} |
- |
-#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS |
- |
-/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian |
-** (Most significant byte first) in memory. The only ALU operations done |
-** on them are increment, decrement, and XOR. So, on little-endian CPUs, |
-** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations |
-** are simulated in the following code. This is thought to be faster and |
-** simpler than trying to convert the data to little-endian and back. |
-*/ |
- |
-/* 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]; |
- |
- 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]; |
-} |
- |
-/* 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 |
-** decrements the 64-bit value T. |
-*/ |
-static void |
-xor_and_decrement(unsigned char *A, unsigned char *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]--; |
- |
-} |
- |
-/* Given an unsigned long t (in host byte order), store this value as a |
-** 64-bit big-endian value (MSB first) in *pt. |
-*/ |
-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[0] = (unsigned char)t; |
-} |
- |
-#endif |
- |
-/* |
-** 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 |
-*/ |
-extern SECStatus |
-AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, |
- 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; |
- /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ |
- 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; |
- } |
-#ifdef maybe |
- 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; |
- } |
- if (cx == NULL || output == NULL || input == NULL) { |
- 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. */ |
- /* |
- ** 1) Initialize variables. |
- */ |
- memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); |
- memcpy(&R[1], input, inputLen); |
-#if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
- t = 0; |
-#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); */ |
-#if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
- A ^= ++t; |
-#else |
- 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; |
- } else if (pOutputLen) { |
- *pOutputLen = 0; |
- } |
- PORT_ZFree(R, outLen); |
- return s; |
-} |
-#undef A |
- |
-/* |
-** 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 |
-*/ |
-extern SECStatus |
-AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output, |
- 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; |
- /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ |
- PRUint64 t; |
- PRUint64 B[2]; |
- |
-#define A B[0] |
- |
- /* Check args */ |
- if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || |
- 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { |
- 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; |
- } |
-#endif |
- if (maxOutputLen < outLen) { |
- PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
- return s; |
- } |
- if (cx == NULL || output == NULL || input == NULL) { |
- 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. */ |
- nBlocks--; |
- /* |
- ** 1) Initialize variables. |
- */ |
- memcpy(&R[0], input, inputLen); |
- A = 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; */ |
-#if BIG_ENDIAN_WITH_64_BIT_REGISTERS |
- A ^= t--; |
-#else |
- xor_and_decrement((unsigned char *)&A, (unsigned char *)&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]; |
- } |
- } |
- /* |
- ** 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 { |
- PORT_SetError(SEC_ERROR_BAD_DATA); |
- if (pOutputLen) |
- *pOutputLen = 0; |
- } |
- } else if (pOutputLen) { |
- *pOutputLen = 0; |
- } |
- PORT_ZFree(R, inputLen); |
- return s; |
-} |
-#undef A |