tor-browser

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

blake2b.c (11739B)


      1 /*
      2 * blake2b.c - definitions for the blake2b hash function
      3 *
      4 * This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #ifdef FREEBL_NO_DEPEND
      9 #include "stubs.h"
     10 #endif
     11 
     12 #include "secerr.h"
     13 #include "blapi.h"
     14 #include "blake2b.h"
     15 #include "crypto_primitives.h"
     16 
     17 /**
     18 * This contains the BLAKE2b initialization vectors.
     19 */
     20 static const uint64_t iv[8] = {
     21    0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
     22    0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
     23    0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
     24 };
     25 
     26 /**
     27 * This contains the table of permutations for blake2b compression function.
     28 */
     29 static const uint8_t sigma[12][16] = {
     30    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
     31    { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
     32    { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
     33    { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
     34    { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
     35    { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
     36    { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
     37    { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
     38    { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
     39    { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
     40    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
     41    { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
     42 };
     43 
     44 /**
     45 * This function increments the blake2b ctx counter.
     46 */
     47 void
     48 blake2b_IncrementCounter(BLAKE2BContext* ctx, const uint64_t inc)
     49 {
     50    ctx->t[0] += inc;
     51    ctx->t[1] += ctx->t[0] < inc;
     52 }
     53 
     54 /**
     55 * This macro implements the blake2b mixing function which mixes two 8-byte
     56 * words from the message into the hash.
     57 */
     58 #define G(a, b, c, d, x, y) \
     59    a += b + x;             \
     60    d = ROTR64(d ^ a, 32);  \
     61    c += d;                 \
     62    b = ROTR64(b ^ c, 24);  \
     63    a += b + y;             \
     64    d = ROTR64(d ^ a, 16);  \
     65    c += d;                 \
     66    b = ROTR64(b ^ c, 63)
     67 
     68 #define ROUND(i)                                                   \
     69    G(v[0], v[4], v[8], v[12], m[sigma[i][0]], m[sigma[i][1]]);    \
     70    G(v[1], v[5], v[9], v[13], m[sigma[i][2]], m[sigma[i][3]]);    \
     71    G(v[2], v[6], v[10], v[14], m[sigma[i][4]], m[sigma[i][5]]);   \
     72    G(v[3], v[7], v[11], v[15], m[sigma[i][6]], m[sigma[i][7]]);   \
     73    G(v[0], v[5], v[10], v[15], m[sigma[i][8]], m[sigma[i][9]]);   \
     74    G(v[1], v[6], v[11], v[12], m[sigma[i][10]], m[sigma[i][11]]); \
     75    G(v[2], v[7], v[8], v[13], m[sigma[i][12]], m[sigma[i][13]]);  \
     76    G(v[3], v[4], v[9], v[14], m[sigma[i][14]], m[sigma[i][15]])
     77 
     78 /**
     79 * The blake2b compression function which takes a full 128-byte chunk of the
     80 * input message and mixes it into the ongoing ctx array, i.e., permute the
     81 * ctx while xoring in the block of data.
     82 */
     83 void
     84 blake2b_Compress(BLAKE2BContext* ctx, const uint8_t* block)
     85 {
     86    size_t i;
     87    uint64_t v[16], m[16];
     88 
     89    PORT_Memcpy(m, block, BLAKE2B_BLOCK_LENGTH);
     90 #if !defined(IS_LITTLE_ENDIAN)
     91    for (i = 0; i < 16; ++i) {
     92        m[i] = FREEBL_HTONLL(m[i]);
     93    }
     94 #endif
     95 
     96    PORT_Memcpy(v, ctx->h, 8 * 8);
     97    PORT_Memcpy(v + 8, iv, 8 * 8);
     98 
     99    v[12] ^= ctx->t[0];
    100    v[13] ^= ctx->t[1];
    101    v[14] ^= ctx->f;
    102 
    103    ROUND(0);
    104    ROUND(1);
    105    ROUND(2);
    106    ROUND(3);
    107    ROUND(4);
    108    ROUND(5);
    109    ROUND(6);
    110    ROUND(7);
    111    ROUND(8);
    112    ROUND(9);
    113    ROUND(10);
    114    ROUND(11);
    115 
    116    for (i = 0; i < 8; i++) {
    117        ctx->h[i] ^= v[i] ^ v[i + 8];
    118    }
    119 }
    120 
    121 /**
    122 * This function can be used for both keyed and unkeyed version.
    123 */
    124 BLAKE2BContext*
    125 BLAKE2B_NewContext()
    126 {
    127    return PORT_ZNew(BLAKE2BContext);
    128 }
    129 
    130 /**
    131 * Zero and free the context and can be used for both keyed and unkeyed version.
    132 */
    133 void
    134 BLAKE2B_DestroyContext(BLAKE2BContext* ctx, PRBool freeit)
    135 {
    136    PORT_Memset(ctx, 0, sizeof(*ctx));
    137    if (freeit) {
    138        PORT_Free(ctx);
    139    }
    140 }
    141 
    142 /**
    143 * This function initializes blake2b ctx and can be used for both keyed and
    144 * unkeyed version. It also checks ctx and sets error states.
    145 */
    146 static SECStatus
    147 blake2b_Begin(BLAKE2BContext* ctx, uint8_t outlen, const uint8_t* key,
    148              size_t keylen)
    149 {
    150    if (!ctx) {
    151        goto failure_noclean;
    152    }
    153    if (outlen == 0 || outlen > BLAKE2B512_LENGTH) {
    154        goto failure;
    155    }
    156    if (key && keylen > BLAKE2B_KEY_SIZE) {
    157        goto failure;
    158    }
    159    /* Note: key can be null if it's unkeyed. */
    160    if ((key == NULL && keylen > 0) || keylen > BLAKE2B_KEY_SIZE ||
    161        (key != NULL && keylen == 0)) {
    162        goto failure;
    163    }
    164 
    165    /* Mix key size(keylen) and desired hash length(outlen) into h0 */
    166    uint64_t param = outlen ^ (keylen << 8) ^ (1 << 16) ^ (1 << 24);
    167    PORT_Memcpy(ctx->h, iv, 8 * 8);
    168    ctx->h[0] ^= param;
    169    ctx->outlen = outlen;
    170 
    171    /* This updates the context for only the keyed version */
    172    if (keylen > 0 && keylen <= BLAKE2B_KEY_SIZE && key) {
    173        uint8_t block[BLAKE2B_BLOCK_LENGTH] = { 0 };
    174        PORT_Memcpy(block, key, keylen);
    175        BLAKE2B_Update(ctx, block, BLAKE2B_BLOCK_LENGTH);
    176        PORT_Memset(block, 0, BLAKE2B_BLOCK_LENGTH);
    177    }
    178 
    179    return SECSuccess;
    180 
    181 failure:
    182    PORT_Memset(ctx, 0, sizeof(*ctx));
    183 failure_noclean:
    184    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    185    return SECFailure;
    186 }
    187 
    188 SECStatus
    189 BLAKE2B_Begin(BLAKE2BContext* ctx)
    190 {
    191    return blake2b_Begin(ctx, BLAKE2B512_LENGTH, NULL, 0);
    192 }
    193 
    194 SECStatus
    195 BLAKE2B_MAC_Begin(BLAKE2BContext* ctx, const PRUint8* key, const size_t keylen)
    196 {
    197    PORT_Assert(key != NULL);
    198    if (!key) {
    199        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    200        return SECFailure;
    201    }
    202    return blake2b_Begin(ctx, BLAKE2B512_LENGTH, (const uint8_t*)key, keylen);
    203 }
    204 
    205 static void
    206 blake2b_IncrementCompress(BLAKE2BContext* ctx, size_t blockLength,
    207                          const unsigned char* input)
    208 {
    209    blake2b_IncrementCounter(ctx, blockLength);
    210    blake2b_Compress(ctx, input);
    211 }
    212 
    213 /**
    214 * This function updates blake2b ctx and can be used for both keyed and unkeyed
    215 * version.
    216 */
    217 SECStatus
    218 BLAKE2B_Update(BLAKE2BContext* ctx, const unsigned char* in,
    219               unsigned int inlen)
    220 {
    221    /* Nothing to do if there's nothing. */
    222    if (inlen == 0) {
    223        return SECSuccess;
    224    }
    225 
    226    if (!ctx || !in) {
    227        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    228        return SECFailure;
    229    }
    230 
    231    /* Is this a reused context? */
    232    if (ctx->f) {
    233        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    234        return SECFailure;
    235    }
    236 
    237    size_t left = ctx->buflen;
    238    PORT_Assert(left <= BLAKE2B_BLOCK_LENGTH);
    239    size_t fill = BLAKE2B_BLOCK_LENGTH - left;
    240 
    241    if (inlen > fill) {
    242        if (ctx->buflen) {
    243            /* There's some remaining data in ctx->buf that we have to prepend
    244             * to in. */
    245            PORT_Memcpy(ctx->buf + left, in, fill);
    246            ctx->buflen = 0;
    247            blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, ctx->buf);
    248            in += fill;
    249            inlen -= fill;
    250        }
    251        while (inlen > BLAKE2B_BLOCK_LENGTH) {
    252            blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, in);
    253            in += BLAKE2B_BLOCK_LENGTH;
    254            inlen -= BLAKE2B_BLOCK_LENGTH;
    255        }
    256    }
    257 
    258    /* Store the remaining data from in in ctx->buf to process later.
    259     * Note that ctx->buflen can be BLAKE2B_BLOCK_LENGTH. We can't process that
    260     * here because we have to update ctx->f before compressing the last block.
    261     */
    262    PORT_Assert(inlen <= BLAKE2B_BLOCK_LENGTH);
    263    PORT_Memcpy(ctx->buf + ctx->buflen, in, inlen);
    264    ctx->buflen += inlen;
    265 
    266    return SECSuccess;
    267 }
    268 
    269 /**
    270 * This function finalizes ctx, pads final block and stores hash.
    271 * It can be used for both keyed and unkeyed version.
    272 */
    273 SECStatus
    274 BLAKE2B_End(BLAKE2BContext* ctx, unsigned char* out,
    275            unsigned int* digestLen, size_t maxDigestLen)
    276 {
    277    size_t i;
    278    unsigned int outlen = PR_MIN(BLAKE2B512_LENGTH, maxDigestLen);
    279 
    280    /* Argument checks */
    281    if (!ctx || !out) {
    282        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    283        return SECFailure;
    284    }
    285 
    286    /* Sanity check against outlen in context. */
    287    if (ctx->outlen < outlen) {
    288        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    289        return SECFailure;
    290    }
    291 
    292    /* Is this a reused context? */
    293    if (ctx->f != 0) {
    294        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    295        return SECFailure;
    296    }
    297 
    298    /* Process the remaining data from ctx->buf (padded with 0). */
    299    blake2b_IncrementCounter(ctx, ctx->buflen);
    300    /* BLAKE2B_BLOCK_LENGTH - ctx->buflen can be 0. */
    301    PORT_Memset(ctx->buf + ctx->buflen, 0, BLAKE2B_BLOCK_LENGTH - ctx->buflen);
    302    ctx->f = UINT64_MAX;
    303    blake2b_Compress(ctx, ctx->buf);
    304 
    305    /* Write out the blake2b context(ctx). */
    306    for (i = 0; i < outlen; ++i) {
    307        out[i] = ctx->h[i / 8] >> ((i % 8) * 8);
    308    }
    309 
    310    if (digestLen) {
    311        *digestLen = outlen;
    312    }
    313 
    314    return SECSuccess;
    315 }
    316 
    317 SECStatus
    318 blake2b_HashBuf(uint8_t* output, const uint8_t* input, uint8_t outlen,
    319                size_t inlen, const uint8_t* key, size_t keylen)
    320 {
    321    SECStatus rv = SECFailure;
    322    BLAKE2BContext ctx = { { 0 } };
    323 
    324    if (inlen != 0) {
    325        PORT_Assert(input != NULL);
    326        if (input == NULL) {
    327            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    328            goto done;
    329        }
    330    }
    331 
    332    PORT_Assert(output != NULL);
    333    if (output == NULL) {
    334        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    335        goto done;
    336    }
    337 
    338    if (blake2b_Begin(&ctx, outlen, key, keylen) != SECSuccess) {
    339        goto done;
    340    }
    341 
    342    if (BLAKE2B_Update(&ctx, input, inlen) != SECSuccess) {
    343        goto done;
    344    }
    345 
    346    if (BLAKE2B_End(&ctx, output, NULL, outlen) != SECSuccess) {
    347        goto done;
    348    }
    349    rv = SECSuccess;
    350 
    351 done:
    352    PORT_Memset(&ctx, 0, sizeof ctx);
    353    return rv;
    354 }
    355 
    356 SECStatus
    357 BLAKE2B_Hash(unsigned char* dest, const char* src)
    358 {
    359    return blake2b_HashBuf(dest, (const unsigned char*)src, BLAKE2B512_LENGTH,
    360                           PORT_Strlen(src), NULL, 0);
    361 }
    362 
    363 SECStatus
    364 BLAKE2B_HashBuf(unsigned char* output, const unsigned char* input, PRUint32 inlen)
    365 {
    366    return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, NULL, 0);
    367 }
    368 
    369 SECStatus
    370 BLAKE2B_MAC_HashBuf(unsigned char* output, const unsigned char* input,
    371                    unsigned int inlen, const unsigned char* key,
    372                    unsigned int keylen)
    373 {
    374    PORT_Assert(key != NULL);
    375    if (!key && keylen <= BLAKE2B_KEY_SIZE) {
    376        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    377        return SECFailure;
    378    }
    379    return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, key, keylen);
    380 }
    381 
    382 unsigned int
    383 BLAKE2B_FlattenSize(BLAKE2BContext* ctx)
    384 {
    385    return sizeof(BLAKE2BContext);
    386 }
    387 
    388 SECStatus
    389 BLAKE2B_Flatten(BLAKE2BContext* ctx, unsigned char* space)
    390 {
    391    PORT_Assert(space != NULL);
    392    if (!space) {
    393        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    394        return SECFailure;
    395    }
    396    PORT_Memcpy(space, ctx, sizeof(BLAKE2BContext));
    397    return SECSuccess;
    398 }
    399 
    400 BLAKE2BContext*
    401 BLAKE2B_Resurrect(unsigned char* space, void* arg)
    402 {
    403    PORT_Assert(space != NULL);
    404    if (!space) {
    405        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    406        return NULL;
    407    }
    408    BLAKE2BContext* ctx = BLAKE2B_NewContext();
    409    if (ctx == NULL) {
    410        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    411        return NULL;
    412    }
    413 
    414    PORT_Memcpy(ctx, space, sizeof(BLAKE2BContext));
    415    return ctx;
    416 }
    417 
    418 void
    419 BLAKE2B_Clone(BLAKE2BContext* dest, BLAKE2BContext* src)
    420 {
    421    PORT_Assert(dest != NULL);
    422    PORT_Assert(src != NULL);
    423    if (!dest || !src) {
    424        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    425        return;
    426    }
    427    PORT_Memcpy(dest, src, sizeof(BLAKE2BContext));
    428 }