tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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