Commit bbb02a5b authored by Mingtao Yang's avatar Mingtao Yang Committed by Andy Polyakov
Browse files

modes/ocb128.c: Reset nonce-dependent variables on setiv



Upon a call to CRYPTO_ocb128_setiv, either directly on an OCB_CTX or
indirectly with EVP_CTRL_AEAD_SET_IVLEN, reset the nonce-dependent
variables in the OCB_CTX.

Reviewed-by: default avatarAndy Polyakov <appro@openssl.org>
Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
Reviewed-by: default avatarPaul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/6420)
parent 10f27971
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -178,12 +178,13 @@ struct ocb128_context {
    OCB_BLOCK l_dollar;
    OCB_BLOCK *l;
    /* Must be reset for each session */
    struct {
        u64 blocks_hashed;
        u64 blocks_processed;
    OCB_BLOCK tag;
        OCB_BLOCK offset_aad;
        OCB_BLOCK sum;
        OCB_BLOCK offset;
        OCB_BLOCK checksum;
    } sess;
};
#endif                          /* OPENSSL_NO_OCB */
+61 −60
Original line number Diff line number Diff line
@@ -239,6 +239,9 @@ int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,
        return -1;
    }

    /* Reset nonce-dependent variables */
    memset(&ctx->sess, 0, sizeof(ctx->sess));

    /* Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N */
    nonce[0] = ((taglen * 8) % 128) << 1;
    memset(nonce + 1, 0, 15);
@@ -259,10 +262,10 @@ int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,

    /* Offset_0 = Stretch[1+bottom..128+bottom] */
    shift = bottom % 8;
    ocb_block_lshift(stretch + (bottom / 8), shift, ctx->offset.c);
    ocb_block_lshift(stretch + (bottom / 8), shift, ctx->sess.offset.c);
    mask = 0xff;
    mask <<= 8 - shift;
    ctx->offset.c[15] |=
    ctx->sess.offset.c[15] |=
        (*(stretch + (bottom / 8) + 16) & mask) >> (8 - shift);

    return 1;
@@ -281,25 +284,25 @@ int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,

    /* Calculate the number of blocks of AAD provided now, and so far */
    num_blocks = len / 16;
    all_num_blocks = num_blocks + ctx->blocks_hashed;
    all_num_blocks = num_blocks + ctx->sess.blocks_hashed;

    /* Loop through all full blocks of AAD */
    for (i = ctx->blocks_hashed + 1; i <= all_num_blocks; i++) {
    for (i = ctx->sess.blocks_hashed + 1; i <= all_num_blocks; i++) {
        OCB_BLOCK *lookup;

        /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
        lookup = ocb_lookup_l(ctx, ocb_ntz(i));
        if (lookup == NULL)
            return 0;
        ocb_block16_xor(&ctx->offset_aad, lookup, &ctx->offset_aad);
        ocb_block16_xor(&ctx->sess.offset_aad, lookup, &ctx->sess.offset_aad);

        memcpy(tmp.c, aad, 16);
        aad += 16;

        /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */
        ocb_block16_xor(&ctx->offset_aad, &tmp, &tmp);
        ocb_block16_xor(&ctx->sess.offset_aad, &tmp, &tmp);
        ctx->encrypt(tmp.c, tmp.c, ctx->keyenc);
        ocb_block16_xor(&tmp, &ctx->sum, &ctx->sum);
        ocb_block16_xor(&tmp, &ctx->sess.sum, &ctx->sess.sum);
    }

    /*
@@ -310,20 +313,21 @@ int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,

    if (last_len > 0) {
        /* Offset_* = Offset_m xor L_* */
        ocb_block16_xor(&ctx->offset_aad, &ctx->l_star, &ctx->offset_aad);
        ocb_block16_xor(&ctx->sess.offset_aad, &ctx->l_star,
                        &ctx->sess.offset_aad);

        /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */
        memset(tmp.c, 0, 16);
        memcpy(tmp.c, aad, last_len);
        tmp.c[last_len] = 0x80;
        ocb_block16_xor(&ctx->offset_aad, &tmp, &tmp);
        ocb_block16_xor(&ctx->sess.offset_aad, &tmp, &tmp);

        /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */
        ctx->encrypt(tmp.c, tmp.c, ctx->keyenc);
        ocb_block16_xor(&tmp, &ctx->sum, &ctx->sum);
        ocb_block16_xor(&tmp, &ctx->sess.sum, &ctx->sess.sum);
    }

    ctx->blocks_hashed = all_num_blocks;
    ctx->sess.blocks_hashed = all_num_blocks;

    return 1;
}
@@ -344,7 +348,7 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
     * so far
     */
    num_blocks = len / 16;
    all_num_blocks = num_blocks + ctx->blocks_processed;
    all_num_blocks = num_blocks + ctx->sess.blocks_processed;

    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
        && ctx->stream != NULL) {
@@ -360,11 +364,11 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
            return 0;

        ctx->stream(in, out, num_blocks, ctx->keyenc,
                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
                    (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                    (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
    } else {
        /* Loop through all full blocks to be encrypted */
        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
        for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) {
            OCB_BLOCK *lookup;
            OCB_BLOCK tmp;

@@ -372,18 +376,18 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
            lookup = ocb_lookup_l(ctx, ocb_ntz(i));
            if (lookup == NULL)
                return 0;
            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
            ocb_block16_xor(&ctx->sess.offset, lookup, &ctx->sess.offset);

            memcpy(tmp.c, in, 16);
            in += 16;

            /* Checksum_i = Checksum_{i-1} xor P_i */
            ocb_block16_xor(&tmp, &ctx->checksum, &ctx->checksum);
            ocb_block16_xor(&tmp, &ctx->sess.checksum, &ctx->sess.checksum);

            /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */
            ocb_block16_xor(&ctx->offset, &tmp, &tmp);
            ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp);
            ctx->encrypt(tmp.c, tmp.c, ctx->keyenc);
            ocb_block16_xor(&ctx->offset, &tmp, &tmp);
            ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp);

            memcpy(out, tmp.c, 16);
            out += 16;
@@ -400,10 +404,10 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
        OCB_BLOCK pad;

        /* Offset_* = Offset_m xor L_* */
        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
        ocb_block16_xor(&ctx->sess.offset, &ctx->l_star, &ctx->sess.offset);

        /* Pad = ENCIPHER(K, Offset_*) */
        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
        ctx->encrypt(ctx->sess.offset.c, pad.c, ctx->keyenc);

        /* C_* = P_* xor Pad[1..bitlen(P_*)] */
        ocb_block_xor(in, pad.c, last_len, out);
@@ -412,10 +416,10 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
        memset(pad.c, 0, 16);           /* borrow pad */
        memcpy(pad.c, in, last_len);
        pad.c[last_len] = 0x80;
        ocb_block16_xor(&pad, &ctx->checksum, &ctx->checksum);
        ocb_block16_xor(&pad, &ctx->sess.checksum, &ctx->sess.checksum);
    }

    ctx->blocks_processed = all_num_blocks;
    ctx->sess.blocks_processed = all_num_blocks;

    return 1;
}
@@ -436,7 +440,7 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
     * so far
     */
    num_blocks = len / 16;
    all_num_blocks = num_blocks + ctx->blocks_processed;
    all_num_blocks = num_blocks + ctx->sess.blocks_processed;

    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
        && ctx->stream != NULL) {
@@ -452,30 +456,30 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
            return 0;

        ctx->stream(in, out, num_blocks, ctx->keydec,
                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
                    (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                    (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
    } else {
        OCB_BLOCK tmp;

        /* Loop through all full blocks to be decrypted */
        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
        for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) {

            /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
            OCB_BLOCK *lookup = ocb_lookup_l(ctx, ocb_ntz(i));
            if (lookup == NULL)
                return 0;
            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
            ocb_block16_xor(&ctx->sess.offset, lookup, &ctx->sess.offset);

            memcpy(tmp.c, in, 16);
            in += 16;

            /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */
            ocb_block16_xor(&ctx->offset, &tmp, &tmp);
            ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp);
            ctx->decrypt(tmp.c, tmp.c, ctx->keydec);
            ocb_block16_xor(&ctx->offset, &tmp, &tmp);
            ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp);

            /* Checksum_i = Checksum_{i-1} xor P_i */
            ocb_block16_xor(&tmp, &ctx->checksum, &ctx->checksum);
            ocb_block16_xor(&tmp, &ctx->sess.checksum, &ctx->sess.checksum);

            memcpy(out, tmp.c, 16);
            out += 16;
@@ -492,10 +496,10 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
        OCB_BLOCK pad;

        /* Offset_* = Offset_m xor L_* */
        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
        ocb_block16_xor(&ctx->sess.offset, &ctx->l_star, &ctx->sess.offset);

        /* Pad = ENCIPHER(K, Offset_*) */
        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
        ctx->encrypt(ctx->sess.offset.c, pad.c, ctx->keyenc);

        /* P_* = C_* xor Pad[1..bitlen(C_*)] */
        ocb_block_xor(in, pad.c, last_len, out);
@@ -504,39 +508,46 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
        memset(pad.c, 0, 16);           /* borrow pad */
        memcpy(pad.c, out, last_len);
        pad.c[last_len] = 0x80;
        ocb_block16_xor(&pad, &ctx->checksum, &ctx->checksum);
        ocb_block16_xor(&pad, &ctx->sess.checksum, &ctx->sess.checksum);
    }

    ctx->blocks_processed = all_num_blocks;
    ctx->sess.blocks_processed = all_num_blocks;

    return 1;
}

/*
 * Calculate the tag and verify it against the supplied tag
 */
int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
                         size_t len)
static int ocb_finish(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len,
                      int write)
{
    OCB_BLOCK tmp;

    if (len > 16 || len < 1) {
        return -1;
    }

    /*
     * Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A)
     */
    ocb_block16_xor(&ctx->checksum, &ctx->offset, &tmp);
    ocb_block16_xor(&ctx->sess.checksum, &ctx->sess.offset, &tmp);
    ocb_block16_xor(&ctx->l_dollar, &tmp, &tmp);
    ctx->encrypt(tmp.c, tmp.c, ctx->keyenc);
    ocb_block16_xor(&tmp, &ctx->sum, &ctx->tag);
    ocb_block16_xor(&tmp, &ctx->sess.sum, &tmp);

    if (len > 16 || len < 1) {
        return -1;
    if (write) {
        memcpy(tag, &tmp, len);
        return 1;
    } else {
        return CRYPTO_memcmp(&tmp, tag, len);
    }
}

    /* Compare the tag if we've been given one */
    if (tag)
        return CRYPTO_memcmp(&ctx->tag, tag, len);
    else
        return -1;
/*
 * Calculate the tag and verify it against the supplied tag
 */
int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
                         size_t len)
{
    return ocb_finish(ctx, (unsigned char*)tag, len, 0);
}

/*
@@ -544,17 +555,7 @@ int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
 */
int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len)
{
    if (len > 16 || len < 1) {
        return -1;
    }

    /* Calculate the tag */
    CRYPTO_ocb128_finish(ctx, NULL, 0);

    /* Copy the tag into the supplied buffer */
    memcpy(tag, ctx->tag.c, len);

    return 1;
    return ocb_finish(ctx, tag, len, 1);
}

/*