tor-browser

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

cmac.c (9962B)


      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 
      9 #include "rijndael.h"
     10 #include "blapi.h"
     11 #include "cmac.h"
     12 #include "secerr.h"
     13 #include "nspr.h"
     14 
     15 struct CMACContextStr {
     16    /* Information about the block cipher to use internally. The cipher should
     17     * be placed in ECB mode so that we can use it to directly encrypt blocks.
     18     *
     19     *
     20     * To add a new cipher, add an entry to CMACCipher, update CMAC_Init,
     21     * cmac_Encrypt, and CMAC_Destroy methods to handle the new cipher, and
     22     * add a new Context pointer to the cipher union with the correct type. */
     23    CMACCipher cipherType;
     24    union {
     25        AESContext *aes;
     26    } cipher;
     27    unsigned int blockSize;
     28 
     29    /* Internal keys which are conditionally used by the algorithm. Derived
     30     * from encrypting the NULL block. We leave the storing of (and the
     31     * cleanup of) the CMAC key to the underlying block cipher. */
     32    unsigned char k1[MAX_BLOCK_SIZE];
     33    unsigned char k2[MAX_BLOCK_SIZE];
     34 
     35    /* When Update is called with data which isn't a multiple of the block
     36     * size, we need a place to put it. HMAC handles this by passing it to
     37     * the underlying hash function right away; we can't do that as the
     38     * contract on the cipher object is different. */
     39    unsigned int partialIndex;
     40    unsigned char partialBlock[MAX_BLOCK_SIZE];
     41 
     42    /* Last encrypted block. This gets xor-ed with partialBlock prior to
     43     * encrypting it. NIST defines this to be the empty string to begin. */
     44    unsigned char lastBlock[MAX_BLOCK_SIZE];
     45 };
     46 
     47 static void
     48 cmac_ShiftLeftOne(unsigned char *out, const unsigned char *in, int length)
     49 {
     50    int i = 0;
     51    for (; i < length - 1; i++) {
     52        out[i] = in[i] << 1;
     53        out[i] |= in[i + 1] >> 7;
     54    }
     55    out[i] = in[i] << 1;
     56 }
     57 
     58 static SECStatus
     59 cmac_Encrypt(CMACContext *ctx, unsigned char *output,
     60             const unsigned char *input,
     61             unsigned int inputLen)
     62 {
     63    if (ctx->cipherType == CMAC_AES) {
     64        unsigned int tmpOutputLen;
     65        SECStatus rv = AES_Encrypt(ctx->cipher.aes, output, &tmpOutputLen,
     66                                   ctx->blockSize, input, inputLen);
     67 
     68        /* Assumption: AES_Encrypt (when in ECB mode) always returns an
     69         * output of length equal to blockSize (what was pass as the value
     70         * of the maxOutputLen parameter). */
     71        PORT_Assert(tmpOutputLen == ctx->blockSize);
     72        return rv;
     73    }
     74 
     75    return SECFailure;
     76 }
     77 
     78 /* NIST SP.800-38B, 6.1 Subkey Generation */
     79 static SECStatus
     80 cmac_GenerateSubkeys(CMACContext *ctx)
     81 {
     82    unsigned char null_block[MAX_BLOCK_SIZE] = { 0 };
     83    unsigned char L[MAX_BLOCK_SIZE];
     84    unsigned char v;
     85    unsigned char i;
     86 
     87    /* Step 1: L = AES(key, null_block) */
     88    if (cmac_Encrypt(ctx, L, null_block, ctx->blockSize) != SECSuccess) {
     89        return SECFailure;
     90    }
     91 
     92    /* In the following, some effort has been made to be constant time. Rather
     93     * than conditioning on the value of the MSB (of L or K1), we use the loop
     94     * to build a mask for the conditional constant. */
     95 
     96    /* Step 2: If MSB(L) = 0, K1 = L << 1. Else, K1 = (L << 1) ^ R_b. */
     97    cmac_ShiftLeftOne(ctx->k1, L, ctx->blockSize);
     98    v = L[0] >> 7;
     99    for (i = 1; i <= 7; i <<= 1) {
    100        v |= (v << i);
    101    }
    102    ctx->k1[ctx->blockSize - 1] ^= (0x87 & v);
    103 
    104    /* Step 3: If MSB(K1) = 0, K2 = K1 << 1. Else, K2 = (K1 <, 1) ^ R_b. */
    105    cmac_ShiftLeftOne(ctx->k2, ctx->k1, ctx->blockSize);
    106    v = ctx->k1[0] >> 7;
    107    for (i = 1; i <= 7; i <<= 1) {
    108        v |= (v << i);
    109    }
    110    ctx->k2[ctx->blockSize - 1] ^= (0x87 & v);
    111 
    112    /* Any intermediate value in the computation of the subkey shall be
    113     * secret. */
    114    PORT_Memset(null_block, 0, MAX_BLOCK_SIZE);
    115    PORT_Memset(L, 0, MAX_BLOCK_SIZE);
    116 
    117    /* Step 4: Return the values. */
    118    return SECSuccess;
    119 }
    120 
    121 /* NIST SP.800-38B, 6.2 MAC Generation step 6 */
    122 static SECStatus
    123 cmac_UpdateState(CMACContext *ctx)
    124 {
    125    if (ctx == NULL || ctx->partialIndex != ctx->blockSize) {
    126        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    127        return SECFailure;
    128    }
    129 
    130    /* Step 6: C_i = CIPHER(key, C_{i-1} ^ M_i)  for 1 <= i <= n, and
    131     *         C_0 is defined as the empty string. */
    132 
    133    for (unsigned int index = 0; index < ctx->blockSize; index++) {
    134        ctx->partialBlock[index] ^= ctx->lastBlock[index];
    135    }
    136 
    137    return cmac_Encrypt(ctx, ctx->lastBlock, ctx->partialBlock, ctx->blockSize);
    138 }
    139 
    140 SECStatus
    141 CMAC_Init(CMACContext *ctx, CMACCipher type,
    142          const unsigned char *key, unsigned int key_len)
    143 {
    144    if (ctx == NULL) {
    145        PORT_SetError(SEC_ERROR_NO_MEMORY);
    146        return SECFailure;
    147    }
    148 
    149    /* We only currently support AES-CMAC. */
    150    if (type != CMAC_AES) {
    151        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    152        return SECFailure;
    153    }
    154 
    155    PORT_Memset(ctx, 0, sizeof(*ctx));
    156 
    157    ctx->blockSize = AES_BLOCK_SIZE;
    158    ctx->cipherType = CMAC_AES;
    159    ctx->cipher.aes = AES_CreateContext(key, NULL, NSS_AES, 1, key_len,
    160                                        ctx->blockSize);
    161    if (ctx->cipher.aes == NULL) {
    162        return SECFailure;
    163    }
    164 
    165    return CMAC_Begin(ctx);
    166 }
    167 
    168 CMACContext *
    169 CMAC_Create(CMACCipher type, const unsigned char *key,
    170            unsigned int key_len)
    171 {
    172    CMACContext *result = PORT_New(CMACContext);
    173 
    174    if (CMAC_Init(result, type, key, key_len) != SECSuccess) {
    175        CMAC_Destroy(result, PR_TRUE);
    176        return NULL;
    177    }
    178 
    179    return result;
    180 }
    181 
    182 SECStatus
    183 CMAC_Begin(CMACContext *ctx)
    184 {
    185    if (ctx == NULL) {
    186        return SECFailure;
    187    }
    188 
    189    /* Ensure that our blockSize is less than the maximum. When this fails,
    190     * a cipher with a larger block size was added and MAX_BLOCK_SIZE needs
    191     * to be updated accordingly. */
    192    PORT_Assert(ctx->blockSize <= MAX_BLOCK_SIZE);
    193 
    194    if (cmac_GenerateSubkeys(ctx) != SECSuccess) {
    195        return SECFailure;
    196    }
    197 
    198    /* Set the index to write partial blocks at to zero. This saves us from
    199     * having to clear ctx->partialBlock. */
    200    ctx->partialIndex = 0;
    201 
    202    /* Step 5: Let C_0 = 0^b. */
    203    PORT_Memset(ctx->lastBlock, 0, ctx->blockSize);
    204 
    205    return SECSuccess;
    206 }
    207 
    208 /* NIST SP.800-38B, 6.2 MAC Generation */
    209 SECStatus
    210 CMAC_Update(CMACContext *ctx, const unsigned char *data,
    211            unsigned int data_len)
    212 {
    213    unsigned int data_index = 0;
    214    if (ctx == NULL) {
    215        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    216        return SECFailure;
    217    }
    218 
    219    if (data == NULL || data_len == 0) {
    220        return SECSuccess;
    221    }
    222 
    223    /* Copy as many bytes from data into ctx->partialBlock as we can, up to
    224     * the maximum of the remaining data and the remaining space in
    225     * ctx->partialBlock.
    226     *
    227     * Note that we swap the order (encrypt *then* copy) because the last
    228     * block is different from the rest. If we end on an even multiple of
    229     * the block size, we have to be able to XOR it with K1. But we won't know
    230     * that it is the last until CMAC_Finish is called (and by then, CMAC_Update
    231     * has already returned). */
    232    while (data_index < data_len) {
    233        if (ctx->partialIndex == ctx->blockSize) {
    234            if (cmac_UpdateState(ctx) != SECSuccess) {
    235                return SECFailure;
    236            }
    237 
    238            ctx->partialIndex = 0;
    239        }
    240 
    241        unsigned int copy_len = data_len - data_index;
    242        if (copy_len > (ctx->blockSize - ctx->partialIndex)) {
    243            copy_len = ctx->blockSize - ctx->partialIndex;
    244        }
    245 
    246        PORT_Memcpy(ctx->partialBlock + ctx->partialIndex, data + data_index, copy_len);
    247        data_index += copy_len;
    248        ctx->partialIndex += copy_len;
    249    }
    250 
    251    return SECSuccess;
    252 }
    253 
    254 /* NIST SP.800-38B, 6.2 MAC Generation */
    255 SECStatus
    256 CMAC_Finish(CMACContext *ctx, unsigned char *result,
    257            unsigned int *result_len,
    258            unsigned int max_result_len)
    259 {
    260    if (ctx == NULL || result == NULL || max_result_len == 0) {
    261        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    262        return SECFailure;
    263    }
    264 
    265    if (max_result_len > ctx->blockSize) {
    266        /* This is a weird situation. The PKCS #11 soft tokencode passes
    267         * sizeof(result) here, which is hard-coded as SFTK_MAX_MAC_LENGTH.
    268         * This later gets truncated to min(SFTK_MAX_MAC_LENGTH, requested). */
    269        max_result_len = ctx->blockSize;
    270    }
    271 
    272    /* Step 4: If M_n* is a complete block, M_n = K1 ^ M_n*. Else,
    273     * M_n = K2 ^ (M_n* || 10^j). */
    274    if (ctx->partialIndex == ctx->blockSize) {
    275        /* XOR in K1. */
    276        for (unsigned int index = 0; index < ctx->blockSize; index++) {
    277            ctx->partialBlock[index] ^= ctx->k1[index];
    278        }
    279    } else {
    280        /* Use 10* padding on the partial block. */
    281        ctx->partialBlock[ctx->partialIndex++] = 0x80;
    282        PORT_Memset(ctx->partialBlock + ctx->partialIndex, 0,
    283                    ctx->blockSize - ctx->partialIndex);
    284        ctx->partialIndex = ctx->blockSize;
    285 
    286        /* XOR in K2. */
    287        for (unsigned int index = 0; index < ctx->blockSize; index++) {
    288            ctx->partialBlock[index] ^= ctx->k2[index];
    289        }
    290    }
    291 
    292    /* Encrypt the block. */
    293    if (cmac_UpdateState(ctx) != SECSuccess) {
    294        return SECFailure;
    295    }
    296 
    297    /* Step 7 & 8: T = MSB_tlen(C_n); return T. */
    298    PORT_Memcpy(result, ctx->lastBlock, max_result_len);
    299    if (result_len != NULL) {
    300        *result_len = max_result_len;
    301    }
    302    return SECSuccess;
    303 }
    304 
    305 void
    306 CMAC_Destroy(CMACContext *ctx, PRBool free_it)
    307 {
    308    if (ctx == NULL) {
    309        return;
    310    }
    311 
    312    if (ctx->cipherType == CMAC_AES && ctx->cipher.aes != NULL) {
    313        AES_DestroyContext(ctx->cipher.aes, PR_TRUE);
    314    }
    315 
    316    /* Destroy everything in the context. This includes sensitive data in
    317     * K1, K2, and lastBlock. */
    318    PORT_Memset(ctx, 0, sizeof(*ctx));
    319 
    320    if (free_it == PR_TRUE) {
    321        PORT_Free(ctx);
    322    }
    323 }