tor-browser

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

ppc-gcm-wrap.c (13457B)


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