Mercurial > trustbridge > nss-cmake-static
diff nss/lib/freebl/intel-gcm-wrap.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/intel-gcm-wrap.c Mon Jul 28 10:47:06 2014 +0200 @@ -0,0 +1,240 @@ +/* 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/. */ +/* Copyright(c) 2013, Intel Corp. */ + +/* Wrapper functions for Intel optimized implementation of AES-GCM */ + +#ifdef USE_HW_AES + +#ifdef FREEBL_NO_DEPEND +#include "stubs.h" +#endif + +#include "blapii.h" +#include "blapit.h" +#include "gcm.h" +#include "ctr.h" +#include "secerr.h" +#include "prtypes.h" +#include "pkcs11t.h" + +#include <limits.h> + +#include "intel-gcm.h" +#include "rijndael.h" + +#include <emmintrin.h> +#include <tmmintrin.h> + + +struct intel_AES_GCMContextStr{ + unsigned char Htbl[16*AES_BLOCK_SIZE]; + unsigned char X0[AES_BLOCK_SIZE]; + unsigned char T[AES_BLOCK_SIZE]; + unsigned char CTR[AES_BLOCK_SIZE]; + AESContext *aes_context; + unsigned long tagBits; + unsigned long Alen; + unsigned long Mlen; +}; + +intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context, + freeblCipherFunc cipher, + const unsigned char *params, + unsigned int blocksize) +{ + intel_AES_GCMContext *gcm = NULL; + AESContext *aes = (AESContext*)context; + const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params; + unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */ + + int IV_whole_len = gcmParams->ulIvLen&(~0xf); + int IV_remainder_len = gcmParams->ulIvLen&0xf; + int AAD_whole_len = gcmParams->ulAADLen&(~0xf); + int AAD_remainder_len = gcmParams->ulAADLen&0xf; + + __m128i BSWAP_MASK = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); + __m128i ONE = _mm_set_epi32(0,0,0,1); + unsigned int j; + SECStatus rv; + + if (blocksize != AES_BLOCK_SIZE) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + gcm = PORT_ZNew(intel_AES_GCMContext); + + if (gcm == NULL) { + return NULL; + } + /* initialize context fields */ + gcm->aes_context = aes; + gcm->tagBits = gcmParams->ulTagBits; + gcm->Alen = 0; + gcm->Mlen = 0; + /* first prepare H and its derivatives for ghash */ + intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); + /* Initial TAG value is zero*/ + _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); + _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); + /* Init the counter */ + if(gcmParams->ulIvLen == 12) { + _mm_storeu_si128((__m128i*)gcm->CTR, _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0], ((unsigned int*)gcmParams->pIv)[1], ((unsigned int*)gcmParams->pIv)[2], 0x01000000)); + } else { + /* If IV size is not 96 bits, then the initial counter value is GHASH of the IV */ + intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); + /* Partial block */ + if(IV_remainder_len) { + PORT_Memset(buff, 0, AES_BLOCK_SIZE); + PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); + intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); + } + + intel_aes_gcmTAG + ( + gcm->Htbl, + gcm->T, + gcmParams->ulIvLen, + 0, + gcm->X0, + gcm->CTR + ); + /* TAG should be zero again */ + _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); + } + /* Encrypt the initial counter, will be used to encrypt the GHASH value, in the end */ + rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, AES_BLOCK_SIZE, AES_BLOCK_SIZE); + if (rv != SECSuccess) { + goto loser; + } + /* Promote the counter by 1 */ + _mm_storeu_si128((__m128i*)gcm->CTR, _mm_shuffle_epi8(_mm_add_epi32(ONE, _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)gcm->CTR), BSWAP_MASK)), BSWAP_MASK)); + +/* Now hash AAD - it would actually make sense to seperate the context creation from the AAD, + * because that would allow to reuse the H, which only changes when the AES key changes, + * and not every package, like the IV and AAD */ + intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); + if(AAD_remainder_len) { + PORT_Memset(buff, 0, AES_BLOCK_SIZE); + PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); + intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); + } + gcm->Alen += gcmParams->ulAADLen; + return gcm; + + loser: + if (gcm) { + PORT_Free(gcm); + } + return NULL; +} + +void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) +{ + if (freeit) { + PORT_Free(gcm); + } +} + +SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, + unsigned char *outbuf, + unsigned int *outlen, unsigned int maxout, + const unsigned char *inbuf, unsigned int inlen, + unsigned int blocksize) +{ + unsigned int tagBytes; + unsigned char T[AES_BLOCK_SIZE]; + int j; + + tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; + if (UINT_MAX - inlen < tagBytes) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + return SECFailure; + } + if (maxout < inlen + tagBytes) { + *outlen = inlen + tagBytes; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + + intel_aes_gcmENC( + inbuf, + outbuf, + gcm, + inlen); + + gcm->Mlen += inlen; + + intel_aes_gcmTAG( + gcm->Htbl, + gcm->T, + gcm->Mlen, + gcm->Alen, + gcm->X0, + T); + + *outlen = inlen + tagBytes; + + for(j=0; j<tagBytes; j++) + { + outbuf[inlen+j] = T[j]; + } + return SECSuccess; +} + +SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, + unsigned char *outbuf, + unsigned int *outlen, unsigned int maxout, + const unsigned char *inbuf, unsigned int inlen, + unsigned int blocksize) +{ + unsigned int tagBytes; + unsigned char T[AES_BLOCK_SIZE]; + const unsigned char *intag; + + tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; + + /* get the authentication block */ + if (inlen < tagBytes) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + return SECFailure; + } + + inlen -= tagBytes; + intag = inbuf + inlen; + + if (maxout < inlen) { + *outlen = inlen; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + + intel_aes_gcmDEC( + inbuf, + outbuf, + gcm, + inlen); + + gcm->Mlen += inlen; + intel_aes_gcmTAG( + gcm->Htbl, + gcm->T, + gcm->Mlen, + gcm->Alen, + gcm->X0, + T); + + if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { + memset(outbuf, 0, inlen); + *outlen = 0; + /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + *outlen = inlen; + + return SECSuccess; +} + +#endif