OLD | NEW |
(Empty) | |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 4 /* Copyright(c) 2013, Intel Corp. */ |
| 5 |
| 6 /* Wrapper functions for Intel optimized implementation of AES-GCM */ |
| 7 |
| 8 #ifdef USE_HW_AES |
| 9 |
| 10 #ifdef FREEBL_NO_DEPEND |
| 11 #include "stubs.h" |
| 12 #endif |
| 13 |
| 14 #include "blapii.h" |
| 15 #include "blapit.h" |
| 16 #include "gcm.h" |
| 17 #include "ctr.h" |
| 18 #include "secerr.h" |
| 19 #include "prtypes.h" |
| 20 #include "pkcs11t.h" |
| 21 |
| 22 #include <limits.h> |
| 23 |
| 24 #include "intel-gcm.h" |
| 25 #include "rijndael.h" |
| 26 |
| 27 #include <emmintrin.h> |
| 28 #include <tmmintrin.h> |
| 29 |
| 30 |
| 31 struct intel_AES_GCMContextStr{ |
| 32 unsigned char Htbl[16*AES_BLOCK_SIZE]; |
| 33 unsigned char X0[AES_BLOCK_SIZE]; |
| 34 unsigned char T[AES_BLOCK_SIZE]; |
| 35 unsigned char CTR[AES_BLOCK_SIZE]; |
| 36 AESContext *aes_context; |
| 37 unsigned long tagBits; |
| 38 unsigned long Alen; |
| 39 unsigned long Mlen; |
| 40 }; |
| 41 |
| 42 intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context, |
| 43 freeblCipherFunc cipher, |
| 44 const unsigned char *params, |
| 45 unsigned int blocksize) |
| 46 { |
| 47 intel_AES_GCMContext *gcm = NULL; |
| 48 AESContext *aes = (AESContext*)context; |
| 49 const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params; |
| 50 unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */ |
| 51 |
| 52 int IV_whole_len = gcmParams->ulIvLen&(~0xf); |
| 53 int IV_remainder_len = gcmParams->ulIvLen&0xf; |
| 54 int AAD_whole_len = gcmParams->ulAADLen&(~0xf); |
| 55 int AAD_remainder_len = gcmParams->ulAADLen&0xf; |
| 56 |
| 57 __m128i BSWAP_MASK = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); |
| 58 __m128i ONE = _mm_set_epi32(0,0,0,1); |
| 59 unsigned int j; |
| 60 SECStatus rv; |
| 61 |
| 62 if (blocksize != AES_BLOCK_SIZE) { |
| 63 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 64 return NULL; |
| 65 } |
| 66 gcm = PORT_ZNew(intel_AES_GCMContext); |
| 67 |
| 68 if (gcm == NULL) { |
| 69 return NULL; |
| 70 } |
| 71 /* initialize context fields */ |
| 72 gcm->aes_context = aes; |
| 73 gcm->tagBits = gcmParams->ulTagBits; |
| 74 gcm->Alen = 0; |
| 75 gcm->Mlen = 0; |
| 76 /* first prepare H and its derivatives for ghash */ |
| 77 intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); |
| 78 /* Initial TAG value is zero*/ |
| 79 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); |
| 80 _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); |
| 81 /* Init the counter */ |
| 82 if(gcmParams->ulIvLen == 12) { |
| 83 _mm_storeu_si128((__m128i*)gcm->CTR, _mm_setr_epi32(((unsigned int*)gcmP
arams->pIv)[0], ((unsigned int*)gcmParams->pIv)[1], ((unsigned int*)gcmParams->p
Iv)[2], 0x01000000)); |
| 84 } else { |
| 85 /* If IV size is not 96 bits, then the initial counter value is GHASH of
the IV */ |
| 86 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); |
| 87 /* Partial block */ |
| 88 if(IV_remainder_len) { |
| 89 PORT_Memset(buff, 0, AES_BLOCK_SIZE); |
| 90 PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); |
| 91 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); |
| 92 } |
| 93 |
| 94 intel_aes_gcmTAG |
| 95 ( |
| 96 gcm->Htbl, |
| 97 gcm->T, |
| 98 gcmParams->ulIvLen, |
| 99 0, |
| 100 gcm->X0, |
| 101 gcm->CTR |
| 102 ); |
| 103 /* TAG should be zero again */ |
| 104 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); |
| 105 } |
| 106 /* Encrypt the initial counter, will be used to encrypt the GHASH value, in
the end */ |
| 107 rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, AES_BLOCK_SIZ
E, AES_BLOCK_SIZE); |
| 108 if (rv != SECSuccess) { |
| 109 goto loser; |
| 110 } |
| 111 /* Promote the counter by 1 */ |
| 112 _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)); |
| 113 |
| 114 /* Now hash AAD - it would actually make sense to seperate the context creat
ion from the AAD, |
| 115 * because that would allow to reuse the H, which only changes when the AES
key changes, |
| 116 * and not every package, like the IV and AAD */ |
| 117 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); |
| 118 if(AAD_remainder_len) { |
| 119 PORT_Memset(buff, 0, AES_BLOCK_SIZE); |
| 120 PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); |
| 121 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); |
| 122 } |
| 123 gcm->Alen += gcmParams->ulAADLen; |
| 124 return gcm; |
| 125 |
| 126 loser: |
| 127 if (gcm) { |
| 128 PORT_Free(gcm); |
| 129 } |
| 130 return NULL; |
| 131 } |
| 132 |
| 133 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) |
| 134 { |
| 135 if (freeit) { |
| 136 PORT_Free(gcm); |
| 137 } |
| 138 } |
| 139 |
| 140 SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, |
| 141 unsigned char *outbuf, |
| 142 unsigned int *outlen, unsigned int maxout, |
| 143 const unsigned char *inbuf, unsigned int inlen, |
| 144 unsigned int blocksize) |
| 145 { |
| 146 unsigned int tagBytes; |
| 147 unsigned char T[AES_BLOCK_SIZE]; |
| 148 int j; |
| 149 |
| 150 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; |
| 151 if (UINT_MAX - inlen < tagBytes) { |
| 152 PORT_SetError(SEC_ERROR_INPUT_LEN); |
| 153 return SECFailure; |
| 154 } |
| 155 if (maxout < inlen + tagBytes) { |
| 156 *outlen = inlen + tagBytes; |
| 157 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| 158 return SECFailure; |
| 159 } |
| 160 |
| 161 intel_aes_gcmENC( |
| 162 inbuf, |
| 163 outbuf, |
| 164 gcm, |
| 165 inlen); |
| 166 |
| 167 gcm->Mlen += inlen; |
| 168 |
| 169 intel_aes_gcmTAG( |
| 170 gcm->Htbl, |
| 171 gcm->T, |
| 172 gcm->Mlen, |
| 173 gcm->Alen, |
| 174 gcm->X0, |
| 175 T); |
| 176 |
| 177 *outlen = inlen + tagBytes; |
| 178 |
| 179 for(j=0; j<tagBytes; j++) |
| 180 { |
| 181 outbuf[inlen+j] = T[j]; |
| 182 } |
| 183 return SECSuccess; |
| 184 } |
| 185 |
| 186 SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, |
| 187 unsigned char *outbuf, |
| 188 unsigned int *outlen, unsigned int maxout, |
| 189 const unsigned char *inbuf, unsigned int inlen, |
| 190 unsigned int blocksize) |
| 191 { |
| 192 unsigned int tagBytes; |
| 193 unsigned char T[AES_BLOCK_SIZE]; |
| 194 const unsigned char *intag; |
| 195 |
| 196 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE-1)) / PR_BITS_PER_BYTE; |
| 197 |
| 198 /* get the authentication block */ |
| 199 if (inlen < tagBytes) { |
| 200 PORT_SetError(SEC_ERROR_INPUT_LEN); |
| 201 return SECFailure; |
| 202 } |
| 203 |
| 204 inlen -= tagBytes; |
| 205 intag = inbuf + inlen; |
| 206 |
| 207 if (maxout < inlen) { |
| 208 *outlen = inlen; |
| 209 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| 210 return SECFailure; |
| 211 } |
| 212 |
| 213 intel_aes_gcmDEC( |
| 214 inbuf, |
| 215 outbuf, |
| 216 gcm, |
| 217 inlen); |
| 218 |
| 219 gcm->Mlen += inlen; |
| 220 intel_aes_gcmTAG( |
| 221 gcm->Htbl, |
| 222 gcm->T, |
| 223 gcm->Mlen, |
| 224 gcm->Alen, |
| 225 gcm->X0, |
| 226 T); |
| 227 |
| 228 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { |
| 229 memset(outbuf, 0, inlen); |
| 230 *outlen = 0; |
| 231 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ |
| 232 PORT_SetError(SEC_ERROR_BAD_DATA); |
| 233 return SECFailure; |
| 234 } |
| 235 *outlen = inlen; |
| 236 |
| 237 return SECSuccess; |
| 238 } |
| 239 |
| 240 #endif |
OLD | NEW |