intel-gcm-wrap.c (14651B)
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 struct intel_AES_GCMContextStr { 31 unsigned char Htbl[16 * AES_BLOCK_SIZE]; 32 unsigned char X0[AES_BLOCK_SIZE]; 33 unsigned char T[AES_BLOCK_SIZE]; 34 unsigned char CTR[AES_BLOCK_SIZE]; 35 AESContext *aes_context; 36 unsigned long tagBits; 37 unsigned long Alen; 38 unsigned long Mlen; 39 freeblCipherFunc cipher; 40 PRBool ctr_context_init; 41 gcmIVContext gcm_iv; 42 }; 43 44 SECStatus intel_aes_gcmInitCounter(intel_AES_GCMContext *gcm, 45 const unsigned char *iv, 46 unsigned long ivLen, unsigned long tagBits, 47 const unsigned char *aad, unsigned long aadLen); 48 49 intel_AES_GCMContext * 50 intel_AES_GCM_CreateContext(void *context, 51 freeblCipherFunc cipher, 52 const unsigned char *params) 53 { 54 intel_AES_GCMContext *gcm = NULL; 55 AESContext *aes = (AESContext *)context; 56 const CK_NSS_GCM_PARAMS *gcmParams = (const CK_NSS_GCM_PARAMS *)params; 57 SECStatus rv; 58 59 gcm = PORT_ZNew(intel_AES_GCMContext); 60 if (gcm == NULL) { 61 return NULL; 62 } 63 64 /* initialize context fields */ 65 gcm->aes_context = aes; 66 gcm->cipher = cipher; 67 gcm->Alen = 0; 68 gcm->Mlen = 0; 69 gcm->ctr_context_init = PR_FALSE; 70 71 /* first prepare H and its derivatives for ghash */ 72 intel_aes_gcmINIT(gcm->Htbl, (unsigned char *)aes->k.expandedKey, aes->Nr); 73 74 gcm_InitIVContext(&gcm->gcm_iv); 75 76 /* if gcmParams is NULL, then we are creating an PKCS #11 MESSAGE 77 * style context, in which we initialize the key once, then do separate 78 * iv/aad's for each message. If we are doing that kind of operation, 79 * we've finished with init here. We'll init the Counter in each AEAD 80 * call */ 81 if (gcmParams == NULL) { 82 return gcm; 83 } 84 85 rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv, 86 gcmParams->ulIvLen, gcmParams->ulTagBits, 87 gcmParams->pAAD, gcmParams->ulAADLen); 88 if (rv != SECSuccess) { 89 PORT_Free(gcm); 90 return NULL; 91 } 92 gcm->ctr_context_init = PR_TRUE; 93 94 return gcm; 95 } 96 97 SECStatus 98 intel_aes_gcmInitCounter(intel_AES_GCMContext *gcm, 99 const unsigned char *iv, unsigned long ivLen, 100 unsigned long tagBits, 101 const unsigned char *aad, unsigned long aadLen) 102 { 103 unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */ 104 unsigned long IV_whole_len = ivLen & (~0xful); 105 unsigned int IV_remainder_len = ivLen & 0xful; 106 unsigned long AAD_whole_len = aadLen & (~0xful); 107 unsigned int AAD_remainder_len = aadLen & 0xful; 108 unsigned int j; 109 __m128i BSWAP_MASK = _mm_setr_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); 110 __m128i ONE = _mm_set_epi32(0, 0, 0, 1); 111 SECStatus rv; 112 113 if (ivLen == 0) { 114 PORT_SetError(SEC_ERROR_INVALID_ARGS); 115 return SECFailure; 116 } 117 118 if (tagBits != 128 && tagBits != 120 && tagBits != 112 && 119 tagBits != 104 && tagBits != 96 && tagBits != 64 && 120 tagBits != 32) { 121 PORT_SetError(SEC_ERROR_INVALID_ARGS); 122 return SECFailure; 123 } 124 gcm->tagBits = tagBits; 125 126 /* reset the aad and message length counters */ 127 gcm->Alen = 0; 128 gcm->Mlen = 0; 129 130 // Limit AADLen in accordance with SP800-38D 131 if (sizeof(AAD_whole_len) >= 8 && AAD_whole_len > (1ULL << 61) - 1) { 132 PORT_SetError(SEC_ERROR_INPUT_LEN); 133 return SECFailure; 134 } 135 /* Initial TAG value is zero */ 136 _mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128()); 137 _mm_storeu_si128((__m128i *)gcm->X0, _mm_setzero_si128()); 138 139 /* Init the counter */ 140 if (ivLen == 12) { 141 _mm_storeu_si128((__m128i *)gcm->CTR, 142 _mm_setr_epi32(((unsigned int *)iv)[0], 143 ((unsigned int *)iv)[1], 144 ((unsigned int *)iv)[2], 145 0x01000000)); 146 } else { 147 /* If IV size is not 96 bits, then the initial counter value is GHASH 148 * of the IV */ 149 intel_aes_gcmAAD(gcm->Htbl, (unsigned char *)iv, IV_whole_len, gcm->T); 150 151 /* Partial block */ 152 if (IV_remainder_len) { 153 PORT_Memset(buff, 0, AES_BLOCK_SIZE); 154 PORT_Memcpy(buff, iv + IV_whole_len, IV_remainder_len); 155 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); 156 } 157 158 intel_aes_gcmTAG( 159 gcm->Htbl, 160 gcm->T, 161 ivLen, 162 0, 163 gcm->X0, 164 gcm->CTR); 165 166 /* TAG should be zero again */ 167 _mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128()); 168 } 169 170 /* Encrypt the initial counter, will be used to encrypt the GHASH value, 171 * in the end */ 172 rv = (*gcm->cipher)(gcm->aes_context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR, 173 AES_BLOCK_SIZE, AES_BLOCK_SIZE); 174 if (rv != SECSuccess) { 175 return SECFailure; 176 } 177 178 /* Promote the counter by 1 */ 179 _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)); 180 181 /* Now hash AAD - it would actually make sense to seperate the context 182 * creation from the AAD, because that would allow to reuse the H, which 183 * only changes when the AES key changes, and not every package, like the 184 * IV and AAD */ 185 intel_aes_gcmAAD(gcm->Htbl, (unsigned char *)aad, AAD_whole_len, gcm->T); 186 if (AAD_remainder_len) { 187 PORT_Memset(buff, 0, AES_BLOCK_SIZE); 188 PORT_Memcpy(buff, aad + AAD_whole_len, AAD_remainder_len); 189 intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T); 190 } 191 gcm->Alen += aadLen; 192 return SECSuccess; 193 } 194 195 void 196 intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit) 197 { 198 PORT_SafeZero(gcm, sizeof(intel_AES_GCMContext)); 199 if (freeit) { 200 PORT_Free(gcm); 201 } 202 } 203 204 SECStatus 205 intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, 206 unsigned char *outbuf, 207 unsigned int *outlen, unsigned int maxout, 208 const unsigned char *inbuf, unsigned int inlen, 209 unsigned int blocksize) 210 { 211 unsigned int tagBytes; 212 unsigned char T[AES_BLOCK_SIZE]; 213 unsigned int j; 214 215 // GCM has a 16 octet block, with a 32-bit block counter 216 // Limit in accordance with SP800-38D 217 if (sizeof(inlen) > 4) { 218 unsigned long long inlen_ull = inlen; 219 if (inlen_ull >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) { 220 PORT_SetError(SEC_ERROR_INPUT_LEN); 221 return SECFailure; 222 } 223 } 224 225 if (!gcm->ctr_context_init) { 226 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 227 return SECFailure; 228 } 229 230 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 231 if (UINT_MAX - inlen < tagBytes) { 232 PORT_SetError(SEC_ERROR_INPUT_LEN); 233 return SECFailure; 234 } 235 if (maxout < inlen + tagBytes) { 236 *outlen = inlen + tagBytes; 237 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 238 return SECFailure; 239 } 240 241 intel_aes_gcmENC( 242 inbuf, 243 outbuf, 244 gcm, 245 inlen); 246 247 gcm->Mlen += inlen; 248 249 intel_aes_gcmTAG( 250 gcm->Htbl, 251 gcm->T, 252 gcm->Mlen, 253 gcm->Alen, 254 gcm->X0, 255 T); 256 257 *outlen = inlen + tagBytes; 258 259 for (j = 0; j < tagBytes; j++) { 260 outbuf[inlen + j] = T[j]; 261 } 262 return SECSuccess; 263 } 264 265 SECStatus 266 intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, 267 unsigned char *outbuf, 268 unsigned int *outlen, unsigned int maxout, 269 const unsigned char *inbuf, unsigned int inlen, 270 unsigned int blocksize) 271 { 272 unsigned int tagBytes; 273 unsigned char T[AES_BLOCK_SIZE]; 274 const unsigned char *intag; 275 276 if (!gcm->ctr_context_init) { 277 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 278 return SECFailure; 279 } 280 281 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 282 283 /* get the authentication block */ 284 if (inlen < tagBytes) { 285 PORT_SetError(SEC_ERROR_INPUT_LEN); 286 return SECFailure; 287 } 288 289 inlen -= tagBytes; 290 intag = inbuf + inlen; 291 292 // GCM has a 16 octet block, with a 32-bit block counter 293 // Limit in accordance with SP800-38D 294 if (sizeof(inlen) > 4) { 295 unsigned long long inlen_ull = inlen; 296 if (inlen_ull >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) { 297 PORT_SetError(SEC_ERROR_INPUT_LEN); 298 return SECFailure; 299 } 300 } 301 302 if (maxout < inlen) { 303 *outlen = inlen; 304 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 305 return SECFailure; 306 } 307 308 intel_aes_gcmDEC( 309 inbuf, 310 outbuf, 311 gcm, 312 inlen); 313 314 gcm->Mlen += inlen; 315 intel_aes_gcmTAG( 316 gcm->Htbl, 317 gcm->T, 318 gcm->Mlen, 319 gcm->Alen, 320 gcm->X0, 321 T); 322 323 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { 324 memset(outbuf, 0, inlen); 325 *outlen = 0; 326 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ 327 PORT_SetError(SEC_ERROR_BAD_DATA); 328 return SECFailure; 329 } 330 *outlen = inlen; 331 332 return SECSuccess; 333 } 334 335 SECStatus 336 intel_AES_GCM_EncryptAEAD(intel_AES_GCMContext *gcm, 337 unsigned char *outbuf, 338 unsigned int *outlen, unsigned int maxout, 339 const unsigned char *inbuf, unsigned int inlen, 340 void *params, unsigned int paramLen, 341 const unsigned char *aad, unsigned int aadLen, 342 unsigned int blocksize) 343 { 344 unsigned int tagBytes; 345 unsigned char T[AES_BLOCK_SIZE]; 346 const CK_GCM_MESSAGE_PARAMS *gcmParams = 347 (const CK_GCM_MESSAGE_PARAMS *)params; 348 SECStatus rv; 349 350 // GCM has a 16 octet block, with a 32-bit block counter 351 // Limit in accordance with SP800-38D 352 if (sizeof(inlen) > 4) { 353 unsigned long long inlen_ull = inlen; 354 if (inlen_ull >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) { 355 PORT_SetError(SEC_ERROR_INPUT_LEN); 356 return SECFailure; 357 } 358 } 359 /* paramLen comes all the way from the application layer, make sure 360 * it's correct */ 361 if (paramLen != sizeof(CK_GCM_MESSAGE_PARAMS)) { 362 PORT_SetError(SEC_ERROR_INVALID_ARGS); 363 return SECFailure; 364 } 365 366 /* if we were initialized with the C_EncryptInit, we shouldn't be in this 367 * function */ 368 if (gcm->ctr_context_init) { 369 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 370 return SECFailure; 371 } 372 373 if (maxout < inlen) { 374 *outlen = inlen; 375 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 376 return SECFailure; 377 } 378 379 rv = gcm_GenerateIV(&gcm->gcm_iv, gcmParams->pIv, gcmParams->ulIvLen, 380 gcmParams->ulIvFixedBits, gcmParams->ivGenerator); 381 if (rv != SECSuccess) { 382 return SECFailure; 383 } 384 385 rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv, gcmParams->ulIvLen, 386 gcmParams->ulTagBits, aad, aadLen); 387 if (rv != SECSuccess) { 388 return SECFailure; 389 } 390 391 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 392 393 intel_aes_gcmENC(inbuf, outbuf, gcm, inlen); 394 395 gcm->Mlen += inlen; 396 397 intel_aes_gcmTAG(gcm->Htbl, gcm->T, gcm->Mlen, gcm->Alen, gcm->X0, T); 398 399 *outlen = inlen; 400 PORT_Memcpy(gcmParams->pTag, T, tagBytes); 401 return SECSuccess; 402 } 403 404 SECStatus 405 intel_AES_GCM_DecryptAEAD(intel_AES_GCMContext *gcm, 406 unsigned char *outbuf, 407 unsigned int *outlen, unsigned int maxout, 408 const unsigned char *inbuf, unsigned int inlen, 409 void *params, unsigned int paramLen, 410 const unsigned char *aad, unsigned int aadLen, 411 unsigned int blocksize) 412 { 413 unsigned int tagBytes; 414 unsigned char T[AES_BLOCK_SIZE]; 415 const unsigned char *intag; 416 const CK_GCM_MESSAGE_PARAMS *gcmParams = 417 (const CK_GCM_MESSAGE_PARAMS *)params; 418 SECStatus rv; 419 420 /* paramLen comes all the way from the application layer, make sure 421 * it's correct */ 422 if (paramLen != sizeof(CK_GCM_MESSAGE_PARAMS)) { 423 PORT_SetError(SEC_ERROR_INVALID_ARGS); 424 return SECFailure; 425 } 426 /* if we were initialized with the C_DecryptInit, we shouldn't be in this 427 * function */ 428 if (gcm->ctr_context_init) { 429 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 430 return SECFailure; 431 } 432 433 // GCM has a 16 octet block, with a 32-bit block counter 434 // Limit in accordance with SP800-38D 435 if (sizeof(inlen) > 4) { 436 unsigned long long inlen_ull = inlen; 437 if (inlen_ull >= ((1ULL << 32) - 2) * AES_BLOCK_SIZE) { 438 PORT_SetError(SEC_ERROR_INPUT_LEN); 439 return SECFailure; 440 } 441 } 442 443 if (maxout < inlen) { 444 *outlen = inlen; 445 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 446 return SECFailure; 447 } 448 449 rv = intel_aes_gcmInitCounter(gcm, gcmParams->pIv, gcmParams->ulIvLen, 450 gcmParams->ulTagBits, aad, aadLen); 451 if (rv != SECSuccess) { 452 return SECFailure; 453 } 454 455 tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE; 456 intag = gcmParams->pTag; 457 PORT_Assert(tagBytes != 0); 458 459 intel_aes_gcmDEC(inbuf, outbuf, gcm, inlen); 460 461 gcm->Mlen += inlen; 462 intel_aes_gcmTAG(gcm->Htbl, gcm->T, gcm->Mlen, gcm->Alen, gcm->X0, T); 463 464 if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) { 465 memset(outbuf, 0, inlen); 466 *outlen = 0; 467 /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ 468 PORT_SetError(SEC_ERROR_BAD_DATA); 469 return SECFailure; 470 } 471 *outlen = inlen; 472 473 return SECSuccess; 474 } 475 #endif