tor-browser

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

ctr.c (8097B)


      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 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 #include "prtypes.h"
      9 #include "blapit.h"
     10 #include "blapii.h"
     11 #include "ctr.h"
     12 #include "pkcs11t.h"
     13 #include "secerr.h"
     14 
     15 #ifdef USE_HW_AES
     16 #ifdef NSS_X86_OR_X64
     17 #include "intel-aes.h"
     18 #endif
     19 #include "rijndael.h"
     20 #endif
     21 
     22 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
     23 #include <arm_neon.h>
     24 #endif
     25 
     26 SECStatus
     27 CTR_InitContext(CTRContext *ctr, void *context, freeblCipherFunc cipher,
     28                const unsigned char *param)
     29 {
     30    const CK_AES_CTR_PARAMS *ctrParams = (const CK_AES_CTR_PARAMS *)param;
     31 
     32    if (ctrParams->ulCounterBits == 0 ||
     33        ctrParams->ulCounterBits > AES_BLOCK_SIZE * PR_BITS_PER_BYTE) {
     34        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     35        return SECFailure;
     36    }
     37 
     38    /* Invariant: 0 < ctr->bufPtr <= AES_BLOCK_SIZE */
     39    ctr->checkWrap = PR_FALSE;
     40    ctr->bufPtr = AES_BLOCK_SIZE; /* no unused data in the buffer */
     41    ctr->cipher = cipher;
     42    ctr->context = context;
     43    ctr->counterBits = ctrParams->ulCounterBits;
     44    if (AES_BLOCK_SIZE > sizeof(ctr->counter) ||
     45        AES_BLOCK_SIZE > sizeof(ctrParams->cb)) {
     46        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     47        return SECFailure;
     48    }
     49    PORT_Memcpy(ctr->counter, ctrParams->cb, AES_BLOCK_SIZE);
     50    if (ctr->counterBits < 64) {
     51        PORT_Memcpy(ctr->counterFirst, ctr->counter, AES_BLOCK_SIZE);
     52        ctr->checkWrap = PR_TRUE;
     53    }
     54    return SECSuccess;
     55 }
     56 
     57 CTRContext *
     58 CTR_CreateContext(void *context, freeblCipherFunc cipher,
     59                  const unsigned char *param)
     60 {
     61    CTRContext *ctr;
     62    SECStatus rv;
     63 
     64    /* first fill in the Counter context */
     65    ctr = PORT_ZNew(CTRContext);
     66    if (ctr == NULL) {
     67        return NULL;
     68    }
     69    rv = CTR_InitContext(ctr, context, cipher, param);
     70    if (rv != SECSuccess) {
     71        CTR_DestroyContext(ctr, PR_TRUE);
     72        ctr = NULL;
     73    }
     74    return ctr;
     75 }
     76 
     77 void
     78 CTR_DestroyContext(CTRContext *ctr, PRBool freeit)
     79 {
     80    PORT_Memset(ctr, 0, sizeof(CTRContext));
     81    if (freeit) {
     82        PORT_Free(ctr);
     83    }
     84 }
     85 
     86 /*
     87 * Used by counter mode. Increment the counter block. Not all bits in the
     88 * counter block are part of the counter, counterBits tells how many bits
     89 * are part of the counter. The counter block is blocksize long. It's a
     90 * big endian value.
     91 *
     92 * XXX Does not handle counter rollover.
     93 */
     94 static void
     95 ctr_GetNextCtr(unsigned char *counter, unsigned int counterBits,
     96               unsigned int blocksize)
     97 {
     98    unsigned char *counterPtr = counter + blocksize - 1;
     99    unsigned char mask, count;
    100 
    101    PORT_Assert(counterBits <= blocksize * PR_BITS_PER_BYTE);
    102    while (counterBits >= PR_BITS_PER_BYTE) {
    103        if (++(*(counterPtr--))) {
    104            return;
    105        }
    106        counterBits -= PR_BITS_PER_BYTE;
    107    }
    108    if (counterBits == 0) {
    109        return;
    110    }
    111    /* increment the final partial byte */
    112    mask = (1 << counterBits) - 1;
    113    count = ++(*counterPtr) & mask;
    114    *counterPtr = ((*counterPtr) & ~mask) | count;
    115    return;
    116 }
    117 
    118 static void
    119 ctr_xor(unsigned char *target, const unsigned char *x,
    120        const unsigned char *y, unsigned int count)
    121 {
    122    unsigned int i;
    123 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
    124    while (count >= 16) {
    125        vst1q_u8(target, veorq_u8(vld1q_u8(x), vld1q_u8(y)));
    126        target += 16;
    127        x += 16;
    128        y += 16;
    129        count -= 16;
    130    }
    131 #endif
    132    for (i = 0; i < count; i++) {
    133        *target++ = *x++ ^ *y++;
    134    }
    135 }
    136 
    137 SECStatus
    138 CTR_Update(CTRContext *ctr, unsigned char *outbuf,
    139           unsigned int *outlen, unsigned int maxout,
    140           const unsigned char *inbuf, unsigned int inlen,
    141           unsigned int blocksize)
    142 {
    143    unsigned int tmp;
    144    SECStatus rv;
    145 
    146    // Limit block count to 2^counterBits - 2
    147    if (ctr->counterBits < (sizeof(unsigned int) * 8) &&
    148        inlen > ((1 << ctr->counterBits) - 2) * AES_BLOCK_SIZE) {
    149        PORT_SetError(SEC_ERROR_INPUT_LEN);
    150        return SECFailure;
    151    }
    152    if (maxout < inlen) {
    153        *outlen = inlen;
    154        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    155        return SECFailure;
    156    }
    157    *outlen = 0;
    158    if (ctr->bufPtr != blocksize) {
    159        unsigned int needed = PR_MIN(blocksize - ctr->bufPtr, inlen);
    160        ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
    161        ctr->bufPtr += needed;
    162        outbuf += needed;
    163        inbuf += needed;
    164        *outlen += needed;
    165        inlen -= needed;
    166        if (inlen == 0) {
    167            return SECSuccess;
    168        }
    169        PORT_Assert(ctr->bufPtr == blocksize);
    170    }
    171 
    172    while (inlen >= blocksize) {
    173        rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
    174                            ctr->counter, blocksize, blocksize);
    175        ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
    176        if (ctr->checkWrap) {
    177            if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) {
    178                PORT_SetError(SEC_ERROR_INVALID_ARGS);
    179                return SECFailure;
    180            }
    181        }
    182        if (rv != SECSuccess) {
    183            return SECFailure;
    184        }
    185        ctr_xor(outbuf, inbuf, ctr->buffer, blocksize);
    186        outbuf += blocksize;
    187        inbuf += blocksize;
    188        *outlen += blocksize;
    189        inlen -= blocksize;
    190    }
    191    if (inlen == 0) {
    192        return SECSuccess;
    193    }
    194    rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
    195                        ctr->counter, blocksize, blocksize);
    196    ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
    197    if (ctr->checkWrap) {
    198        if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) {
    199            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    200            return SECFailure;
    201        }
    202    }
    203    if (rv != SECSuccess) {
    204        return SECFailure;
    205    }
    206    ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
    207    ctr->bufPtr = inlen;
    208    *outlen += inlen;
    209    return SECSuccess;
    210 }
    211 
    212 #if defined(USE_HW_AES) && defined(_MSC_VER) && defined(NSS_X86_OR_X64)
    213 SECStatus
    214 CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
    215                  unsigned int *outlen, unsigned int maxout,
    216                  const unsigned char *inbuf, unsigned int inlen,
    217                  unsigned int blocksize)
    218 {
    219    unsigned int fullblocks;
    220    unsigned int tmp;
    221    SECStatus rv;
    222 
    223    // Limit block count to 2^counterBits - 2
    224    if (ctr->counterBits < (sizeof(unsigned int) * 8) &&
    225        inlen > ((1 << ctr->counterBits) - 2) * AES_BLOCK_SIZE) {
    226        PORT_SetError(SEC_ERROR_INPUT_LEN);
    227        return SECFailure;
    228    }
    229    if (maxout < inlen) {
    230        *outlen = inlen;
    231        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    232        return SECFailure;
    233    }
    234    *outlen = 0;
    235    if (ctr->bufPtr != blocksize) {
    236        unsigned int needed = PR_MIN(blocksize - ctr->bufPtr, inlen);
    237        ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
    238        ctr->bufPtr += needed;
    239        outbuf += needed;
    240        inbuf += needed;
    241        *outlen += needed;
    242        inlen -= needed;
    243        if (inlen == 0) {
    244            return SECSuccess;
    245        }
    246        PORT_Assert(ctr->bufPtr == blocksize);
    247    }
    248 
    249    if (inlen >= blocksize) {
    250        rv = intel_aes_ctr_worker(((AESContext *)(ctr->context))->Nr)(
    251            ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
    252        if (rv != SECSuccess) {
    253            return SECFailure;
    254        }
    255        fullblocks = (inlen / blocksize) * blocksize;
    256        *outlen += fullblocks;
    257        outbuf += fullblocks;
    258        inbuf += fullblocks;
    259        inlen -= fullblocks;
    260    }
    261 
    262    if (inlen == 0) {
    263        return SECSuccess;
    264    }
    265    rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
    266                        ctr->counter, blocksize, blocksize);
    267    ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
    268    if (rv != SECSuccess) {
    269        return SECFailure;
    270    }
    271    ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
    272    ctr->bufPtr = inlen;
    273    *outlen += inlen;
    274    return SECSuccess;
    275 }
    276 #endif