| 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 unsigned long IV_whole_len = gcmParams->ulIvLen & (~0xful); | |
| 53 unsigned int IV_remainder_len = gcmParams->ulIvLen & 0xful; | |
| 54 unsigned long AAD_whole_len = gcmParams->ulAADLen & (~0xful); | |
| 55 unsigned int AAD_remainder_len = gcmParams->ulAADLen & 0xful; | |
| 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 | |
| 72 /* initialize context fields */ | |
| 73 gcm->aes_context = aes; | |
| 74 gcm->tagBits = gcmParams->ulTagBits; | |
| 75 gcm->Alen = 0; | |
| 76 gcm->Mlen = 0; | |
| 77 | |
| 78 /* first prepare H and its derivatives for ghash */ | |
| 79 intel_aes_gcmINIT(gcm->Htbl, (unsigned char*)aes->expandedKey, aes->Nr); | |
| 80 | |
| 81 /* Initial TAG value is zero */ | |
| 82 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); | |
| 83 _mm_storeu_si128((__m128i*)gcm->X0, _mm_setzero_si128()); | |
| 84 | |
| 85 /* Init the counter */ | |
| 86 if (gcmParams->ulIvLen == 12) { | |
| 87 _mm_storeu_si128((__m128i*)gcm->CTR, | |
| 88 _mm_setr_epi32(((unsigned int*)gcmParams->pIv)[0], | |
| 89 ((unsigned int*)gcmParams->pIv)[1], | |
| 90 ((unsigned int*)gcmParams->pIv)[2], | |
| 91 0x01000000)); | |
| 92 } else { | |
| 93 /* If IV size is not 96 bits, then the initial counter value is GHASH | |
| 94 * of the IV */ | |
| 95 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T); | |
| 96 | |
| 97 /* Partial block */ | |
| 98 if (IV_remainder_len) { | |
| 99 PORT_Memset(buff, 0, AES_BLOCK_SIZE); | |
| 100 PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len); | |
| 101 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); | |
| 102 } | |
| 103 | |
| 104 intel_aes_gcmTAG( | |
| 105 gcm->Htbl, | |
| 106 gcm->T, | |
| 107 gcmParams->ulIvLen, | |
| 108 0, | |
| 109 gcm->X0, | |
| 110 gcm->CTR); | |
| 111 | |
| 112 /* TAG should be zero again */ | |
| 113 _mm_storeu_si128((__m128i*)gcm->T, _mm_setzero_si128()); | |
| 114 } | |
| 115 | |
| 116 /* Encrypt the initial counter, will be used to encrypt the GHASH value, | |
| 117 * in the end */ | |
| 118 rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, | |
| 119 AES_BLOCK_SIZE, AES_BLOCK_SIZE); | |
| 120 if (rv != SECSuccess) { | |
| 121 goto loser; | |
| 122 } | |
| 123 | |
| 124 /* Promote the counter by 1 */ | |
| 125 _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)); | |
| 126 | |
| 127 /* Now hash AAD - it would actually make sense to seperate the context | |
| 128 * creation from the AAD, because that would allow to reuse the H, which | |
| 129 * only changes when the AES key changes, and not every package, like the | |
| 130 * IV and AAD */ | |
| 131 intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T); | |
| 132 if (AAD_remainder_len) { | |
| 133 PORT_Memset(buff, 0, AES_BLOCK_SIZE); | |
| 134 PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len); | |
| 135 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); | |
| 136 } | |
| 137 gcm->Alen += gcmParams->ulAADLen; | |
| 138 return gcm; | |
| 139 | |
| 140 loser: | |
| 141 if (gcm) { | |
| 142 PORT_Free(gcm); | |
| 143 } | |
| 144 return NULL; | |
| 145 } | |
| 146 | |
| 147 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) | |
| 148 { | |
| 149 if (freeit) { | |
| 150 PORT_Free(gcm); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, | |
| 155 unsigned char *outbuf, | |
| 156 unsigned int *outlen, unsigned int maxout, | |
| 157 const unsigned char *inbuf, unsigned int inlen, | |
| 158 unsigned int blocksize) | |
| 159 { | |
| 160 unsigned int tagBytes; | |
| 161 unsigned char T[AES_BLOCK_SIZE]; | |
| 162 unsigned int j; | |
| 163 | |
| 164 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; | |
| 165 if (UINT_MAX - inlen < tagBytes) { | |
| 166 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 167 return SECFailure; | |
| 168 } | |
| 169 if (maxout < inlen + tagBytes) { | |
| 170 *outlen = inlen + tagBytes; | |
| 171 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 172 return SECFailure; | |
| 173 } | |
| 174 | |
| 175 intel_aes_gcmENC( | |
| 176 inbuf, | |
| 177 outbuf, | |
| 178 gcm, | |
| 179 inlen); | |
| 180 | |
| 181 gcm->Mlen += inlen; | |
| 182 | |
| 183 intel_aes_gcmTAG( | |
| 184 gcm->Htbl, | |
| 185 gcm->T, | |
| 186 gcm->Mlen, | |
| 187 gcm->Alen, | |
| 188 gcm->X0, | |
| 189 T); | |
| 190 | |
| 191 *outlen = inlen + tagBytes; | |
| 192 | |
| 193 for (j = 0; j < tagBytes; j++) { | |
| 194 outbuf[inlen + j] = T[j]; | |
| 195 } | |
| 196 return SECSuccess; | |
| 197 } | |
| 198 | |
| 199 SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, | |
| 200 unsigned char *outbuf, | |
| 201 unsigned int *outlen, unsigned int maxout, | |
| 202 const unsigned char *inbuf, unsigned int inlen, | |
| 203 unsigned int blocksize) | |
| 204 { | |
| 205 unsigned int tagBytes; | |
| 206 unsigned char T[AES_BLOCK_SIZE]; | |
| 207 const unsigned char *intag; | |
| 208 | |
| 209 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; | |
| 210 | |
| 211 /* get the authentication block */ | |
| 212 if (inlen < tagBytes) { | |
| 213 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 214 return SECFailure; | |
| 215 } | |
| 216 | |
| 217 inlen -= tagBytes; | |
| 218 intag = inbuf + inlen; | |
| 219 | |
| 220 if (maxout < inlen) { | |
| 221 *outlen = inlen; | |
| 222 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 223 return SECFailure; | |
| 224 } | |
| 225 | |
| 226 intel_aes_gcmDEC( | |
| 227 inbuf, | |
| 228 outbuf, | |
| 229 gcm, | |
| 230 inlen); | |
| 231 | |
| 232 gcm->Mlen += inlen; | |
| 233 intel_aes_gcmTAG( | |
| 234 gcm->Htbl, | |
| 235 gcm->T, | |
| 236 gcm->Mlen, | |
| 237 gcm->Alen, | |
| 238 gcm->X0, | |
| 239 T); | |
| 240 | |
| 241 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { | |
| 242 memset(outbuf, 0, inlen); | |
| 243 *outlen = 0; | |
| 244 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ | |
| 245 PORT_SetError(SEC_ERROR_BAD_DATA); | |
| 246 return SECFailure; | |
| 247 } | |
| 248 *outlen = inlen; | |
| 249 | |
| 250 return SECSuccess; | |
| 251 } | |
| 252 | |
| 253 #endif | |
| OLD | NEW |