diff nss/lib/freebl/aeskeywrap.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/freebl/aeskeywrap.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,383 @@
+/*
+ * 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/. */
+
+#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 {
+	    s = SECFailure;
+	    PORT_SetError(SEC_ERROR_BAD_DATA);
+	    if (pOutputLen) 
+		*pOutputLen = 0;
+    	}
+    } else if (pOutputLen) {
+    	*pOutputLen = 0;
+    }
+    PORT_ZFree(R, inputLen);
+    return s;
+}
+#undef A
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)