Blame crypto/fips/fips_drbg_ctr.c

Packit c4476c
/* fips/rand/fips_drbg_ctr.c */
Packit c4476c
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
Packit c4476c
 * project.
Packit c4476c
 */
Packit c4476c
/* ====================================================================
Packit c4476c
 * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
Packit c4476c
 *
Packit c4476c
 * Redistribution and use in source and binary forms, with or without
Packit c4476c
 * modification, are permitted provided that the following conditions
Packit c4476c
 * are met:
Packit c4476c
 *
Packit c4476c
 * 1. Redistributions of source code must retain the above copyright
Packit c4476c
 *    notice, this list of conditions and the following disclaimer. 
Packit c4476c
 *
Packit c4476c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit c4476c
 *    notice, this list of conditions and the following disclaimer in
Packit c4476c
 *    the documentation and/or other materials provided with the
Packit c4476c
 *    distribution.
Packit c4476c
 *
Packit c4476c
 * 3. All advertising materials mentioning features or use of this
Packit c4476c
 *    software must display the following acknowledgment:
Packit c4476c
 *    "This product includes software developed by the OpenSSL Project
Packit c4476c
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
Packit c4476c
 *
Packit c4476c
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
Packit c4476c
 *    endorse or promote products derived from this software without
Packit c4476c
 *    prior written permission. For written permission, please contact
Packit c4476c
 *    licensing@OpenSSL.org.
Packit c4476c
 *
Packit c4476c
 * 5. Products derived from this software may not be called "OpenSSL"
Packit c4476c
 *    nor may "OpenSSL" appear in their names without prior written
Packit c4476c
 *    permission of the OpenSSL Project.
Packit c4476c
 *
Packit c4476c
 * 6. Redistributions of any form whatsoever must retain the following
Packit c4476c
 *    acknowledgment:
Packit c4476c
 *    "This product includes software developed by the OpenSSL Project
Packit c4476c
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
Packit c4476c
 *
Packit c4476c
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
Packit c4476c
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit c4476c
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
Packit c4476c
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
Packit c4476c
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit c4476c
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit c4476c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit c4476c
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit c4476c
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit c4476c
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit c4476c
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit c4476c
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit c4476c
 * ====================================================================
Packit c4476c
 */
Packit c4476c
Packit c4476c
#include <stdlib.h>
Packit c4476c
#include <string.h>
Packit c4476c
#include <openssl/crypto.h>
Packit c4476c
#include <openssl/fips.h>
Packit c4476c
#include <openssl/fips_rand.h>
Packit c4476c
#include "fips_rand_lcl.h"
Packit c4476c
Packit c4476c
static void inc_128(DRBG_CTR_CTX * cctx)
Packit c4476c
{
Packit c4476c
    int i;
Packit c4476c
    unsigned char c;
Packit c4476c
    unsigned char *p = cctx->V + 15;
Packit c4476c
    for (i = 0; i < 16; i++) {
Packit c4476c
        c = *p;
Packit c4476c
        c++;
Packit c4476c
        *p = c;
Packit c4476c
        if (c)
Packit c4476c
            return;
Packit c4476c
        p--;
Packit c4476c
    }
Packit c4476c
}
Packit c4476c
Packit c4476c
static void ctr_XOR(DRBG_CTR_CTX * cctx, const unsigned char *in,
Packit c4476c
                    size_t inlen)
Packit c4476c
{
Packit c4476c
    size_t i, n;
Packit c4476c
    /* Any zero padding will have no effect on the result as we
Packit c4476c
     * are XORing. So just process however much input we have.
Packit c4476c
     */
Packit c4476c
Packit c4476c
    if (!in || !inlen)
Packit c4476c
        return;
Packit c4476c
Packit c4476c
    if (inlen < cctx->keylen)
Packit c4476c
        n = inlen;
Packit c4476c
    else
Packit c4476c
        n = cctx->keylen;
Packit c4476c
Packit c4476c
    for (i = 0; i < n; i++)
Packit c4476c
        cctx->K[i] ^= in[i];
Packit c4476c
    if (inlen <= cctx->keylen)
Packit c4476c
        return;
Packit c4476c
Packit c4476c
    n = inlen - cctx->keylen;
Packit c4476c
    /* Should never happen */
Packit c4476c
    if (n > 16)
Packit c4476c
        n = 16;
Packit c4476c
    for (i = 0; i < 16; i++)
Packit c4476c
        cctx->V[i] ^= in[i + cctx->keylen];
Packit c4476c
}
Packit c4476c
Packit c4476c
/* Process a complete block using BCC algorithm of SPP 800-90 10.4.3 */
Packit c4476c
Packit c4476c
static void ctr_BCC_block(DRBG_CTR_CTX * cctx, unsigned char *out,
Packit c4476c
                          const unsigned char *in)
Packit c4476c
{
Packit c4476c
    int i;
Packit c4476c
    for (i = 0; i < 16; i++)
Packit c4476c
        out[i] ^= in[i];
Packit c4476c
    AES_encrypt(out, out, &cctx->df_ks);
Packit c4476c
#if 0
Packit c4476c
    fprintf(stderr, "BCC in+out\n");
Packit c4476c
    BIO_dump_fp(stderr, in, 16);
Packit c4476c
    BIO_dump_fp(stderr, out, 16);
Packit c4476c
#endif
Packit c4476c
}
Packit c4476c
Packit c4476c
/* Handle several BCC operations for as much data as we need for K and X */
Packit c4476c
static void ctr_BCC_blocks(DRBG_CTR_CTX * cctx, const unsigned char *in)
Packit c4476c
{
Packit c4476c
    ctr_BCC_block(cctx, cctx->KX, in);
Packit c4476c
    ctr_BCC_block(cctx, cctx->KX + 16, in);
Packit c4476c
    if (cctx->keylen != 16)
Packit c4476c
        ctr_BCC_block(cctx, cctx->KX + 32, in);
Packit c4476c
}
Packit c4476c
Packit c4476c
/* Initialise BCC blocks: these have the value 0,1,2 in leftmost positions:
Packit c4476c
 * see 10.4.2 stage 7.
Packit c4476c
 */
Packit c4476c
static void ctr_BCC_init(DRBG_CTR_CTX * cctx)
Packit c4476c
{
Packit c4476c
    memset(cctx->KX, 0, 48);
Packit c4476c
    memset(cctx->bltmp, 0, 16);
Packit c4476c
    ctr_BCC_block(cctx, cctx->KX, cctx->bltmp);
Packit c4476c
    cctx->bltmp[3] = 1;
Packit c4476c
    ctr_BCC_block(cctx, cctx->KX + 16, cctx->bltmp);
Packit c4476c
    if (cctx->keylen != 16) {
Packit c4476c
        cctx->bltmp[3] = 2;
Packit c4476c
        ctr_BCC_block(cctx, cctx->KX + 32, cctx->bltmp);
Packit c4476c
    }
Packit c4476c
}
Packit c4476c
Packit c4476c
/* Process several blocks into BCC algorithm, some possibly partial */
Packit c4476c
static void ctr_BCC_update(DRBG_CTR_CTX * cctx,
Packit c4476c
                           const unsigned char *in, size_t inlen)
Packit c4476c
{
Packit c4476c
    if (!in || !inlen)
Packit c4476c
        return;
Packit c4476c
    /* If we have partial block handle it first */
Packit c4476c
    if (cctx->bltmp_pos) {
Packit c4476c
        size_t left = 16 - cctx->bltmp_pos;
Packit c4476c
        /* If we now have a complete block process it */
Packit c4476c
        if (inlen >= left) {
Packit c4476c
            memcpy(cctx->bltmp + cctx->bltmp_pos, in, left);
Packit c4476c
            ctr_BCC_blocks(cctx, cctx->bltmp);
Packit c4476c
            cctx->bltmp_pos = 0;
Packit c4476c
            inlen -= left;
Packit c4476c
            in += left;
Packit c4476c
        }
Packit c4476c
    }
Packit c4476c
    /* Process zero or more complete blocks */
Packit c4476c
    while (inlen >= 16) {
Packit c4476c
        ctr_BCC_blocks(cctx, in);
Packit c4476c
        in += 16;
Packit c4476c
        inlen -= 16;
Packit c4476c
    }
Packit c4476c
    /* Copy any remaining partial block to the temporary buffer */
Packit c4476c
    if (inlen > 0) {
Packit c4476c
        memcpy(cctx->bltmp + cctx->bltmp_pos, in, inlen);
Packit c4476c
        cctx->bltmp_pos += inlen;
Packit c4476c
    }
Packit c4476c
}
Packit c4476c
Packit c4476c
static void ctr_BCC_final(DRBG_CTR_CTX * cctx)
Packit c4476c
{
Packit c4476c
    if (cctx->bltmp_pos) {
Packit c4476c
        memset(cctx->bltmp + cctx->bltmp_pos, 0, 16 - cctx->bltmp_pos);
Packit c4476c
        ctr_BCC_blocks(cctx, cctx->bltmp);
Packit c4476c
    }
Packit c4476c
}
Packit c4476c
Packit c4476c
static void ctr_df(DRBG_CTR_CTX * cctx,
Packit c4476c
                   const unsigned char *in1, size_t in1len,
Packit c4476c
                   const unsigned char *in2, size_t in2len,
Packit c4476c
                   const unsigned char *in3, size_t in3len)
Packit c4476c
{
Packit c4476c
    size_t inlen;
Packit c4476c
    unsigned char *p = cctx->bltmp;
Packit c4476c
    static unsigned char c80 = 0x80;
Packit c4476c
Packit c4476c
    ctr_BCC_init(cctx);
Packit c4476c
    if (!in1)
Packit c4476c
        in1len = 0;
Packit c4476c
    if (!in2)
Packit c4476c
        in2len = 0;
Packit c4476c
    if (!in3)
Packit c4476c
        in3len = 0;
Packit c4476c
    inlen = in1len + in2len + in3len;
Packit c4476c
    /* Initialise L||N in temporary block */
Packit c4476c
    *p++ = (inlen >> 24) & 0xff;
Packit c4476c
    *p++ = (inlen >> 16) & 0xff;
Packit c4476c
    *p++ = (inlen >> 8) & 0xff;
Packit c4476c
    *p++ = inlen & 0xff;
Packit c4476c
    /* NB keylen is at most 32 bytes */
Packit c4476c
    *p++ = 0;
Packit c4476c
    *p++ = 0;
Packit c4476c
    *p++ = 0;
Packit c4476c
    *p = (unsigned char)((cctx->keylen + 16) & 0xff);
Packit c4476c
    cctx->bltmp_pos = 8;
Packit c4476c
    ctr_BCC_update(cctx, in1, in1len);
Packit c4476c
    ctr_BCC_update(cctx, in2, in2len);
Packit c4476c
    ctr_BCC_update(cctx, in3, in3len);
Packit c4476c
    ctr_BCC_update(cctx, &c80, 1);
Packit c4476c
    ctr_BCC_final(cctx);
Packit c4476c
    /* Set up key K */
Packit c4476c
    AES_set_encrypt_key(cctx->KX, cctx->keylen * 8, &cctx->df_kxks);
Packit c4476c
    /* X follows key K */
Packit c4476c
    AES_encrypt(cctx->KX + cctx->keylen, cctx->KX, &cctx->df_kxks);
Packit c4476c
    AES_encrypt(cctx->KX, cctx->KX + 16, &cctx->df_kxks);
Packit c4476c
    if (cctx->keylen != 16)
Packit c4476c
        AES_encrypt(cctx->KX + 16, cctx->KX + 32, &cctx->df_kxks);
Packit c4476c
#if 0
Packit c4476c
    fprintf(stderr, "Output of ctr_df:\n");
Packit c4476c
    BIO_dump_fp(stderr, cctx->KX, cctx->keylen + 16);
Packit c4476c
#endif
Packit c4476c
}
Packit c4476c
Packit c4476c
/* NB the no-df  Update in SP800-90 specifies a constant input length
Packit c4476c
 * of seedlen, however other uses of this algorithm pad the input with
Packit c4476c
 * zeroes if necessary and have up to two parameters XORed together,
Packit c4476c
 * handle both cases in this function instead.
Packit c4476c
 */
Packit c4476c
Packit c4476c
static void ctr_Update(DRBG_CTX *dctx,
Packit c4476c
                       const unsigned char *in1, size_t in1len,
Packit c4476c
                       const unsigned char *in2, size_t in2len,
Packit c4476c
                       const unsigned char *nonce, size_t noncelen)
Packit c4476c
{
Packit c4476c
    DRBG_CTR_CTX *cctx = &dctx->d.ctr;
Packit c4476c
    /* ks is already setup for correct key */
Packit c4476c
    inc_128(cctx);
Packit c4476c
    AES_encrypt(cctx->V, cctx->K, &cctx->ks);
Packit c4476c
    /* If keylen longer than 128 bits need extra encrypt */
Packit c4476c
    if (cctx->keylen != 16) {
Packit c4476c
        inc_128(cctx);
Packit c4476c
        AES_encrypt(cctx->V, cctx->K + 16, &cctx->ks);
Packit c4476c
    }
Packit c4476c
    inc_128(cctx);
Packit c4476c
    AES_encrypt(cctx->V, cctx->V, &cctx->ks);
Packit c4476c
    /* If 192 bit key part of V is on end of K */
Packit c4476c
    if (cctx->keylen == 24) {
Packit c4476c
        memcpy(cctx->V + 8, cctx->V, 8);
Packit c4476c
        memcpy(cctx->V, cctx->K + 24, 8);
Packit c4476c
    }
Packit c4476c
Packit c4476c
    if (dctx->xflags & DRBG_FLAG_CTR_USE_DF) {
Packit c4476c
        /* If no input reuse existing derived value */
Packit c4476c
        if (in1 || nonce || in2)
Packit c4476c
            ctr_df(cctx, in1, in1len, nonce, noncelen, in2, in2len);
Packit c4476c
        /* If this a reuse input in1len != 0 */
Packit c4476c
        if (in1len)
Packit c4476c
            ctr_XOR(cctx, cctx->KX, dctx->seedlen);
Packit c4476c
    } else {
Packit c4476c
        ctr_XOR(cctx, in1, in1len);
Packit c4476c
        ctr_XOR(cctx, in2, in2len);
Packit c4476c
    }
Packit c4476c
Packit c4476c
    AES_set_encrypt_key(cctx->K, dctx->strength, &cctx->ks);
Packit c4476c
#if 0
Packit c4476c
    fprintf(stderr, "K+V after update is:\n");
Packit c4476c
    BIO_dump_fp(stderr, cctx->K, cctx->keylen);
Packit c4476c
    BIO_dump_fp(stderr, cctx->V, 16);
Packit c4476c
#endif
Packit c4476c
}
Packit c4476c
Packit c4476c
static int drbg_ctr_instantiate(DRBG_CTX *dctx,
Packit c4476c
                                const unsigned char *ent, size_t entlen,
Packit c4476c
                                const unsigned char *nonce, size_t noncelen,
Packit c4476c
                                const unsigned char *pers, size_t perslen)
Packit c4476c
{
Packit c4476c
    DRBG_CTR_CTX *cctx = &dctx->d.ctr;
Packit c4476c
    memset(cctx->K, 0, sizeof(cctx->K));
Packit c4476c
    memset(cctx->V, 0, sizeof(cctx->V));
Packit c4476c
    AES_set_encrypt_key(cctx->K, dctx->strength, &cctx->ks);
Packit c4476c
    ctr_Update(dctx, ent, entlen, pers, perslen, nonce, noncelen);
Packit c4476c
    return 1;
Packit c4476c
}
Packit c4476c
Packit c4476c
static int drbg_ctr_reseed(DRBG_CTX *dctx,
Packit c4476c
                           const unsigned char *ent, size_t entlen,
Packit c4476c
                           const unsigned char *adin, size_t adinlen)
Packit c4476c
{
Packit c4476c
    ctr_Update(dctx, ent, entlen, adin, adinlen, NULL, 0);
Packit c4476c
    return 1;
Packit c4476c
}
Packit c4476c
Packit c4476c
static int drbg_ctr_generate(DRBG_CTX *dctx,
Packit c4476c
                             unsigned char *out, size_t outlen,
Packit c4476c
                             const unsigned char *adin, size_t adinlen)
Packit c4476c
{
Packit c4476c
    DRBG_CTR_CTX *cctx = &dctx->d.ctr;
Packit c4476c
    if (adin && adinlen) {
Packit c4476c
        ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0);
Packit c4476c
        /* This means we reuse derived value */
Packit c4476c
        if (dctx->xflags & DRBG_FLAG_CTR_USE_DF) {
Packit c4476c
            adin = NULL;
Packit c4476c
            adinlen = 1;
Packit c4476c
        }
Packit c4476c
    } else
Packit c4476c
        adinlen = 0;
Packit c4476c
Packit c4476c
    for (;;) {
Packit c4476c
        inc_128(cctx);
Packit c4476c
        if (outlen < 16) {
Packit c4476c
            /* Use K as temp space as it will be updated */
Packit c4476c
            AES_encrypt(cctx->V, cctx->K, &cctx->ks);
Packit c4476c
            memcpy(out, cctx->K, outlen);
Packit c4476c
            break;
Packit c4476c
        }
Packit c4476c
        AES_encrypt(cctx->V, out, &cctx->ks);
Packit c4476c
        out += 16;
Packit c4476c
        outlen -= 16;
Packit c4476c
        if (outlen == 0)
Packit c4476c
            break;
Packit c4476c
    }
Packit c4476c
Packit c4476c
    ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0);
Packit c4476c
Packit c4476c
    return 1;
Packit c4476c
Packit c4476c
}
Packit c4476c
Packit c4476c
static int drbg_ctr_uninstantiate(DRBG_CTX *dctx)
Packit c4476c
{
Packit c4476c
    memset(&dctx->d.ctr, 0, sizeof(DRBG_CTR_CTX));
Packit c4476c
    return 1;
Packit c4476c
}
Packit c4476c
Packit c4476c
int fips_drbg_ctr_init(DRBG_CTX *dctx)
Packit c4476c
{
Packit c4476c
    DRBG_CTR_CTX *cctx = &dctx->d.ctr;
Packit c4476c
Packit c4476c
    size_t keylen;
Packit c4476c
Packit c4476c
    switch (dctx->type) {
Packit c4476c
    case NID_aes_128_ctr:
Packit c4476c
        keylen = 16;
Packit c4476c
        break;
Packit c4476c
Packit c4476c
    case NID_aes_192_ctr:
Packit c4476c
        keylen = 24;
Packit c4476c
        break;
Packit c4476c
Packit c4476c
    case NID_aes_256_ctr:
Packit c4476c
        keylen = 32;
Packit c4476c
        break;
Packit c4476c
Packit c4476c
    default:
Packit c4476c
        return -2;
Packit c4476c
    }
Packit c4476c
Packit c4476c
    dctx->instantiate = drbg_ctr_instantiate;
Packit c4476c
    dctx->reseed = drbg_ctr_reseed;
Packit c4476c
    dctx->generate = drbg_ctr_generate;
Packit c4476c
    dctx->uninstantiate = drbg_ctr_uninstantiate;
Packit c4476c
Packit c4476c
    cctx->keylen = keylen;
Packit c4476c
    dctx->strength = keylen * 8;
Packit c4476c
    dctx->blocklength = 16;
Packit c4476c
    dctx->seedlen = keylen + 16;
Packit c4476c
Packit c4476c
    if (dctx->xflags & DRBG_FLAG_CTR_USE_DF) {
Packit c4476c
        /* df initialisation */
Packit c4476c
        static unsigned char df_key[32] = {
Packit c4476c
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Packit c4476c
            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
Packit c4476c
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
Packit c4476c
            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
Packit c4476c
        };
Packit c4476c
        /* Set key schedule for df_key */
Packit c4476c
        AES_set_encrypt_key(df_key, dctx->strength, &cctx->df_ks);
Packit c4476c
Packit c4476c
        dctx->min_entropy = cctx->keylen;
Packit c4476c
        dctx->max_entropy = DRBG_MAX_LENGTH;
Packit c4476c
        dctx->min_nonce = dctx->min_entropy / 2;
Packit c4476c
        dctx->max_nonce = DRBG_MAX_LENGTH;
Packit c4476c
        dctx->max_pers = DRBG_MAX_LENGTH;
Packit c4476c
        dctx->max_adin = DRBG_MAX_LENGTH;
Packit c4476c
    } else {
Packit c4476c
        dctx->min_entropy = dctx->seedlen;
Packit c4476c
        dctx->max_entropy = dctx->seedlen;
Packit c4476c
        /* Nonce not used */
Packit c4476c
        dctx->min_nonce = 0;
Packit c4476c
        dctx->max_nonce = 0;
Packit c4476c
        dctx->max_pers = dctx->seedlen;
Packit c4476c
        dctx->max_adin = dctx->seedlen;
Packit c4476c
    }
Packit c4476c
Packit c4476c
    dctx->max_request = 1 << 16;
Packit c4476c
    dctx->reseed_interval = 1 << 24;
Packit c4476c
Packit c4476c
    return 1;
Packit c4476c
}