1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/intel-gcm-wrap.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,253 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* Copyright(c) 2013, Intel Corp. */ 1.8 + 1.9 +/* Wrapper functions for Intel optimized implementation of AES-GCM */ 1.10 + 1.11 +#ifdef USE_HW_AES 1.12 + 1.13 +#ifdef FREEBL_NO_DEPEND 1.14 +#include "stubs.h" 1.15 +#endif 1.16 + 1.17 +#include "blapii.h" 1.18 +#include "blapit.h" 1.19 +#include "gcm.h" 1.20 +#include "ctr.h" 1.21 +#include "secerr.h" 1.22 +#include "prtypes.h" 1.23 +#include "pkcs11t.h" 1.24 + 1.25 +#include <limits.h> 1.26 + 1.27 +#include "intel-gcm.h" 1.28 +#include "rijndael.h" 1.29 + 1.30 +#include <emmintrin.h> 1.31 +#include <tmmintrin.h> 1.32 + 1.33 + 1.34 +struct intel_AES_GCMContextStr{ 1.35 + unsigned char Htbl[16*AES_BLOCK_SIZE]; 1.36 + unsigned char X0[AES_BLOCK_SIZE]; 1.37 + unsigned char T[AES_BLOCK_SIZE]; 1.38 + unsigned char CTR[AES_BLOCK_SIZE]; 1.39 + AESContext *aes_context; 1.40 + unsigned long tagBits; 1.41 + unsigned long Alen; 1.42 + unsigned long Mlen; 1.43 +}; 1.44 + 1.45 +intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context, 1.46 + freeblCipherFunc cipher, 1.47 + const unsigned char *params, 1.48 + unsigned int blocksize) 1.49 +{ 1.50 + intel_AES_GCMContext *gcm = NULL; 1.51 + AESContext *aes = (AESContext*)context; 1.52 + const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params; 1.53 + unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */ 1.54 + 1.55 + unsigned long IV_whole_len = gcmParams->ulIvLen & (~0xful); 1.56 + unsigned int IV_remainder_len = gcmParams->ulIvLen & 0xful; 1.57 + unsigned long AAD_whole_len = gcmParams->ulAADLen & (~0xful); 1.58 + unsigned int AAD_remainder_len = gcmParams->ulAADLen & 0xful; 1.59 + 1.60 + __m128i BSWAP_MASK = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); 1.61 + __m128i ONE = _mm_set_epi32(0,0,0,1); 1.62 + unsigned int j; 1.63 + SECStatus rv; 1.64 + 1.65 + if (blocksize != AES_BLOCK_SIZE) { 1.66 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.67 + return NULL; 1.68 + } 1.69 + gcm = PORT_ZNew(intel_AES_GCMContext); 1.70 + 1.71 + if (gcm == NULL) { 1.72 + return NULL; 1.73 + } 1.74 + 1.75 + /* initialize context fields */ 1.76 + gcm->aes_context = aes; 1.77 + gcm->tagBits = gcmParams->ulTagBits; 1.78 + gcm->Alen = 0; 1.79 + gcm->Mlen = 0; 1.80 + 1.81 + /* first prepare H and its derivatives for ghash */ 1.82 + intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); 1.83 + 1.84 + /* Initial TAG value is zero */ 1.85 + _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); 1.86 + _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); 1.87 + 1.88 + /* Init the counter */ 1.89 + if (gcmParams->ulIvLen == 12) { 1.90 + _mm_storeu_si128((__m128i*)gcm->CTR, 1.91 + _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0], 1.92 + ((unsigned int*)gcmParams->pIv)[1], 1.93 + ((unsigned int*)gcmParams->pIv)[2], 1.94 + 0x01000000)); 1.95 + } else { 1.96 + /* If IV size is not 96 bits, then the initial counter value is GHASH 1.97 + * of the IV */ 1.98 + intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); 1.99 + 1.100 + /* Partial block */ 1.101 + if (IV_remainder_len) { 1.102 + PORT_Memset(buff, 0, AES_BLOCK_SIZE); 1.103 + PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); 1.104 + intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); 1.105 + } 1.106 + 1.107 + intel_aes_gcmTAG( 1.108 + gcm->Htbl, 1.109 + gcm->T, 1.110 + gcmParams->ulIvLen, 1.111 + 0, 1.112 + gcm->X0, 1.113 + gcm->CTR); 1.114 + 1.115 + /* TAG should be zero again */ 1.116 + _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); 1.117 + } 1.118 + 1.119 + /* Encrypt the initial counter, will be used to encrypt the GHASH value, 1.120 + * in the end */ 1.121 + rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, 1.122 + AES_BLOCK_SIZE, AES_BLOCK_SIZE); 1.123 + if (rv != SECSuccess) { 1.124 + goto loser; 1.125 + } 1.126 + 1.127 + /* Promote the counter by 1 */ 1.128 + _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)); 1.129 + 1.130 + /* Now hash AAD - it would actually make sense to seperate the context 1.131 + * creation from the AAD, because that would allow to reuse the H, which 1.132 + * only changes when the AES key changes, and not every package, like the 1.133 + * IV and AAD */ 1.134 + intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); 1.135 + if (AAD_remainder_len) { 1.136 + PORT_Memset(buff, 0, AES_BLOCK_SIZE); 1.137 + PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); 1.138 + intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); 1.139 + } 1.140 + gcm->Alen += gcmParams->ulAADLen; 1.141 + return gcm; 1.142 + 1.143 +loser: 1.144 + if (gcm) { 1.145 + PORT_Free(gcm); 1.146 + } 1.147 + return NULL; 1.148 +} 1.149 + 1.150 +void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) 1.151 +{ 1.152 + if (freeit) { 1.153 + PORT_Free(gcm); 1.154 + } 1.155 +} 1.156 + 1.157 +SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, 1.158 + unsigned char *outbuf, 1.159 + unsigned int *outlen, unsigned int maxout, 1.160 + const unsigned char *inbuf, unsigned int inlen, 1.161 + unsigned int blocksize) 1.162 +{ 1.163 + unsigned int tagBytes; 1.164 + unsigned char T[AES_BLOCK_SIZE]; 1.165 + unsigned int j; 1.166 + 1.167 + tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 1.168 + if (UINT_MAX - inlen < tagBytes) { 1.169 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.170 + return SECFailure; 1.171 + } 1.172 + if (maxout < inlen + tagBytes) { 1.173 + *outlen = inlen + tagBytes; 1.174 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.175 + return SECFailure; 1.176 + } 1.177 + 1.178 + intel_aes_gcmENC( 1.179 + inbuf, 1.180 + outbuf, 1.181 + gcm, 1.182 + inlen); 1.183 + 1.184 + gcm->Mlen += inlen; 1.185 + 1.186 + intel_aes_gcmTAG( 1.187 + gcm->Htbl, 1.188 + gcm->T, 1.189 + gcm->Mlen, 1.190 + gcm->Alen, 1.191 + gcm->X0, 1.192 + T); 1.193 + 1.194 + *outlen = inlen + tagBytes; 1.195 + 1.196 + for (j = 0; j < tagBytes; j++) { 1.197 + outbuf[inlen + j] = T[j]; 1.198 + } 1.199 + return SECSuccess; 1.200 +} 1.201 + 1.202 +SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, 1.203 + unsigned char *outbuf, 1.204 + unsigned int *outlen, unsigned int maxout, 1.205 + const unsigned char *inbuf, unsigned int inlen, 1.206 + unsigned int blocksize) 1.207 +{ 1.208 + unsigned int tagBytes; 1.209 + unsigned char T[AES_BLOCK_SIZE]; 1.210 + const unsigned char *intag; 1.211 + 1.212 + tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 1.213 + 1.214 + /* get the authentication block */ 1.215 + if (inlen < tagBytes) { 1.216 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.217 + return SECFailure; 1.218 + } 1.219 + 1.220 + inlen -= tagBytes; 1.221 + intag = inbuf + inlen; 1.222 + 1.223 + if (maxout < inlen) { 1.224 + *outlen = inlen; 1.225 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.226 + return SECFailure; 1.227 + } 1.228 + 1.229 + intel_aes_gcmDEC( 1.230 + inbuf, 1.231 + outbuf, 1.232 + gcm, 1.233 + inlen); 1.234 + 1.235 + gcm->Mlen += inlen; 1.236 + intel_aes_gcmTAG( 1.237 + gcm->Htbl, 1.238 + gcm->T, 1.239 + gcm->Mlen, 1.240 + gcm->Alen, 1.241 + gcm->X0, 1.242 + T); 1.243 + 1.244 + if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { 1.245 + memset(outbuf, 0, inlen); 1.246 + *outlen = 0; 1.247 + /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ 1.248 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.249 + return SECFailure; 1.250 + } 1.251 + *outlen = inlen; 1.252 + 1.253 + return SECSuccess; 1.254 +} 1.255 + 1.256 +#endif