/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
//** Introduction
// This file implements a DRBG with a behavior according to SP800-90A using
// a block cypher. This is also compliant to ISO/IEC 18031:2011(E) C.3.2.
//
// A state structure is created for use by TPM.lib and functions
// within the CryptoEngine my use their own state structures when they need to have
// deterministic values.
//
// A debug mode is available that allows the random numbers generated for TPM.lib
// to be repeated during runs of the simulator. The switch for it is in
// TpmBuildSwitches.h. It is USE_DEBUG_RNG.
//
//
// This is the implementation layer of CTR DRGB mechanism as defined in SP800-90A
// and the functions are organized as closely as practical to the organization in
// SP800-90A. It is intended to be compiled as a separate module that is linked
// with a secure application so that both reside inside the same boundary
// [SP 800-90A 8.5]. The secure application in particular manages the accesses
// protected storage for the state of the DRBG instantiations, and supplies the
// implementation functions here with a valid pointer to the working state of the
// given instantiations (as a DRBG_STATE structure).
//
// This DRBG mechanism implementation does not support prediction resistance. Thus
// 'prediction_resistance_flag' is omitted from Instantiate_function(),
// Reseed_function(), Generate_function() argument lists [SP 800-90A 9.1, 9.2,
// 9.3], as well as from the working state data structure DRBG_STATE [SP 800-90A
// 9.1].
//
// This DRBG mechanism implementation always uses the highest security strength of
// available in the block ciphers. Thus 'requested_security_strength' parameter is
// omitted from Instantiate_function() and Generate_function() argument lists
// [SP 800-90A 9.1, 9.2, 9.3], as well as from the working state data structure
// DRBG_STATE [SP 800-90A 9.1].
//
// Internal functions (ones without Crypt prefix) expect validated arguments and
// therefore use assertions instead of runtime parameter checks and mostly return
// void instead of a status value.

#include "Tpm.h"

// Pull in the test vector definitions and define the space
#include    "PRNG_TestVectors.h"

const BYTE DRBG_NistTestVector_Entropy[] = {DRBG_TEST_INITIATE_ENTROPY};
const BYTE DRBG_NistTestVector_GeneratedInterm[] =
                                {DRBG_TEST_GENERATED_INTERM};

const BYTE DRBG_NistTestVector_EntropyReseed[] =
                                {DRBG_TEST_RESEED_ENTROPY};
const BYTE DRBG_NistTestVector_Generated[] = {DRBG_TEST_GENERATED};

//** Derivation Functions
//*** Description
// The functions in this section are used to reduce the personalization input values
// to make them usable as input for reseeding and instantiation. The overall
// behavior is intended to produce the same results as described in SP800-90A,
// section 10.4.2 "Derivation Function Using a Block Cipher Algorithm
// (Block_Cipher_df)." The code is broken into several subroutines to deal with the
// fact that the data used for personalization may come in several separate blocks
// such as a Template hash and a proof value and a primary seed.

//*** Derivation Function Defines and Structures

#define     DF_COUNT (DRBG_KEY_SIZE_WORDS / DRBG_IV_SIZE_WORDS + 1)
#if DRBG_KEY_SIZE_BITS != 128 && DRBG_KEY_SIZE_BITS != 256
#   error "CryptRand.c only written for AES with 128- or 256-bit keys."
#endif

typedef struct
{
    DRBG_KEY_SCHEDULE   keySchedule;
    DRBG_IV             iv[DF_COUNT];
    DRBG_IV             out1;
    DRBG_IV             buf;
    int                 contents;
} DF_STATE, *PDF_STATE;

//*** DfCompute()
// This function does the incremental update of the derivation function state. It
// encrypts the 'iv' value and XOR's the results into each of the blocks of the
// output. This is equivalent to processing all of input data for each output block.
static void
DfCompute(
    PDF_STATE        dfState
    )
{
    int              i;
    int              iv;
    crypt_uword_t   *pIv;
    crypt_uword_t    temp[DRBG_IV_SIZE_WORDS] = {0};
//
    for(iv = 0; iv < DF_COUNT; iv++)
    {
        pIv = (crypt_uword_t *)&dfState->iv[iv].words[0];
        for(i = 0; i < DRBG_IV_SIZE_WORDS; i++)
        {
            temp[i] ^= pIv[i] ^ dfState->buf.words[i];
        }
        DRBG_ENCRYPT(&dfState->keySchedule, &temp, pIv);
    }
    for(i = 0; i < DRBG_IV_SIZE_WORDS; i++)
        dfState->buf.words[i] = 0;
    dfState->contents = 0;
}

//*** DfStart()
// This initializes the output blocks with an encrypted counter value and
// initializes the key schedule.
static void
DfStart(
    PDF_STATE        dfState,
    uint32_t         inputLength
    )
{
    BYTE            init[8];
    int             i;
    UINT32          drbgSeedSize = sizeof(DRBG_SEED);

    const BYTE dfKey[DRBG_KEY_SIZE_BYTES] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    #if DRBG_KEY_SIZE_BYTES > 16
        ,0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
    #endif
    };
    memset(dfState, 0, sizeof(DF_STATE));
    DRBG_ENCRYPT_SETUP(&dfKey[0], DRBG_KEY_SIZE_BITS, &dfState->keySchedule);
    // Create the first chaining values
    for(i = 0; i < DF_COUNT; i++)
        ((BYTE *)&dfState->iv[i])[3] = (BYTE)i;
    DfCompute(dfState);
    // initialize the first 64 bits of the IV in a way that doesn't depend
    // on the size of the words used.
    UINT32_TO_BYTE_ARRAY(inputLength, init);
    UINT32_TO_BYTE_ARRAY(drbgSeedSize, &init[4]);
    memcpy(&dfState->iv[0], init, 8);
    dfState->contents = 4;
}

//*** DfUpdate()
// This updates the state with the input data. A byte at a time is moved into the
// state buffer until it is full and then that block is encrypted by DfCompute().
static void
DfUpdate(
    PDF_STATE        dfState,
    int              size,
    const BYTE      *data
    )
{
    while(size > 0)
    {
        int         toFill = DRBG_IV_SIZE_BYTES - dfState->contents;
        if(size < toFill)
            toFill = size;
        // Copy as many bytes as there are or until the state buffer is full
        memcpy(&dfState->buf.bytes[dfState->contents], data, toFill);
        // Reduce the size left by the amount copied
        size -= toFill;
        // Advance the data pointer by the amount copied
        data += toFill;
        // increase the buffer contents count by the amount copied
        dfState->contents += toFill;
        pAssert(dfState->contents <= DRBG_IV_SIZE_BYTES);
        // If we have a full buffer, do a computation pass.
        if(dfState->contents == DRBG_IV_SIZE_BYTES)
            DfCompute(dfState);
    }
}

//*** DfEnd()
// This function is called to get the result of the derivation function computation.
// If the buffer is not full, it is padded with zeros. The output buffer is
// structured to be the same as a DRBG_SEED value so that the function can return
// a pointer to the DRBG_SEED value in the DF_STATE structure.
static DRBG_SEED *
DfEnd(
    PDF_STATE        dfState
    )
{
    // Since DfCompute is always called when a buffer is full, there is always
    // space in the buffer for the terminator
    dfState->buf.bytes[dfState->contents++] = 0x80;
    // If the buffer is not full, pad with zeros
    while(dfState->contents < DRBG_IV_SIZE_BYTES)
        dfState->buf.bytes[dfState->contents++] = 0;
    // Do a final state update
    DfCompute(dfState);
    return (DRBG_SEED *)&dfState->iv;
}

//*** DfBuffer()
// Function to take an input buffer and do the derivation function to produce a
// DRBG_SEED value that can be used in DRBG_Reseed();
static DRBG_SEED *
DfBuffer(
    DRBG_SEED       *output,        // OUT: receives the result
    int              size,          // IN: size of the buffer to add
    BYTE            *buf            // IN: address of the buffer
    )
{
    DF_STATE        dfState;
    if(size == 0 || buf == NULL)
        return NULL;
    // Initialize the derivation function
    DfStart(&dfState, size);
    DfUpdate(&dfState, size, buf);
    DfEnd(&dfState);
    memcpy(output, &dfState.iv[0], sizeof(DRBG_SEED));
    return output;
}

//*** DRBG_GetEntropy()
// Even though this implementation never fails, it may get blocked
// indefinitely long in the call to get entropy from the platform
// (DRBG_GetEntropy32()).
// This function is only used during instantiation of the DRBG for
// manufacturing and on each start-up after an non-orderly shutdown.
//
//  Return Type: BOOL
//      TRUE(1)         requested entropy returned
//      FALSE(0)        entropy Failure
BOOL
DRBG_GetEntropy(
    UINT32           requiredEntropy,   // IN: requested number of bytes of full
                                        //     entropy
    BYTE            *entropy            // OUT: buffer to return collected entropy
    )
{
#if !USE_DEBUG_RNG

    UINT32       obtainedEntropy;
    INT32        returnedEntropy;

// If in debug mode, always use the self-test values for initialization
    if(IsSelfTest())
    {
#endif
        // If doing simulated DRBG, then check to see if the
        // entropyFailure condition is being tested
        if(!IsEntropyBad())
        {
            // In self-test, the caller should be asking for exactly the seed
            // size of entropy.
            pAssert(requiredEntropy == sizeof(DRBG_NistTestVector_Entropy));
            memcpy(entropy, DRBG_NistTestVector_Entropy,
                   sizeof(DRBG_NistTestVector_Entropy));
        }
#if !USE_DEBUG_RNG
    }
    else if(!IsEntropyBad())
    {
        // Collect entropy
        // Note: In debug mode, the only "entropy" value ever returned
        // is the value of the self-test vector.
        for(returnedEntropy = 1, obtainedEntropy = 0;
            obtainedEntropy < requiredEntropy && !IsEntropyBad();
            obtainedEntropy += returnedEntropy)
        {
            returnedEntropy = _plat__GetEntropy(&entropy[obtainedEntropy],
                                                requiredEntropy - obtainedEntropy);
            if(returnedEntropy <= 0)
                SetEntropyBad();
        }
    }
#endif
    return !IsEntropyBad();
}

//*** IncrementIv()
// This function increments the IV value by 1. It is used by EncryptDRBG().
void
IncrementIv(
    DRBG_IV         *iv
    )
{
    BYTE      *ivP = ((BYTE *)iv) + DRBG_IV_SIZE_BYTES;
    while((--ivP >= (BYTE *)iv) && ((*ivP = ((*ivP + 1) & 0xFF)) == 0));
}

//*** EncryptDRBG()
// This does the encryption operation for the DRBG. It will encrypt
// the input state counter (IV) using the state key. Into the output
// buffer for as many times as it takes to generate the required
// number of bytes.
static BOOL
EncryptDRBG(
    BYTE                *dOut,
    UINT32               dOutBytes,
    DRBG_KEY_SCHEDULE   *keySchedule,
    DRBG_IV             *iv,
    UINT32              *lastValue      // Points to the last output value
    )
{
#if FIPS_COMPLIANT
// For FIPS compliance, the DRBG has to do a continuous self-test to make sure that
// no two consecutive values are the same. This overhead is not incurred if the TPM
// is not required to be FIPS compliant
//
    UINT32           temp[DRBG_IV_SIZE_BYTES / sizeof(UINT32)];
    int              i;
    BYTE            *p;

    for(; dOutBytes > 0;)
    {
        // Increment the IV before each encryption (this is what makes this
        // different from normal counter-mode encryption
        IncrementIv(iv);
        DRBG_ENCRYPT(keySchedule, iv, temp);
// Expect a 16 byte block
#if DRBG_IV_SIZE_BITS != 128
#error  "Unsuppored IV size in DRBG"
#endif
        if((lastValue[0] == temp[0])
            && (lastValue[1] == temp[1])
            && (lastValue[2] == temp[2])
            && (lastValue[3] == temp[3])
            )
        {
            LOG_FAILURE(FATAL_ERROR_ENTROPY);
            return FALSE;
        }
        lastValue[0] = temp[0];
        lastValue[1] = temp[1];
        lastValue[2] = temp[2];
        lastValue[3] = temp[3];
        i = MIN(dOutBytes, DRBG_IV_SIZE_BYTES);
        dOutBytes -= i;
        for(p = (BYTE *)temp; i > 0; i--)
            *dOut++ = *p++;
    }
#else // version without continuous self-test
    NOT_REFERENCED(lastValue);
    for(; dOutBytes >= DRBG_IV_SIZE_BYTES;
    dOut = &dOut[DRBG_IV_SIZE_BYTES], dOutBytes -= DRBG_IV_SIZE_BYTES)
    {
        // Increment the IV
        IncrementIv(iv);
        DRBG_ENCRYPT(keySchedule, iv, dOut);
    }
    // If there is a partial, generate into a block-sized
    // temp buffer and copy to the output.
    if(dOutBytes != 0)
    {
        BYTE        temp[DRBG_IV_SIZE_BYTES];
        // Increment the IV
        IncrementIv(iv);
        DRBG_ENCRYPT(keySchedule, iv, temp);
        memcpy(dOut, temp, dOutBytes);
    }
#endif
    return TRUE;
}

//*** DRBG_Update()
// This function performs the state update function.
// According to SP800-90A, a temp value is created by doing CTR mode
// encryption of 'providedData' and replacing the key and IV with
// these values. The one difference is that, with counter mode, the
// IV is incremented after each block is encrypted and in this
// operation, the counter is incremented before each block is
// encrypted. This function implements an 'optimized' version
// of the algorithm in that it does the update of the drbgState->seed
// in place and then 'providedData' is XORed into drbgState->seed
// to complete the encryption of 'providedData'. This works because
// the IV is the last thing that gets encrypted.
//
static BOOL
DRBG_Update(
    DRBG_STATE          *drbgState,     // IN:OUT state to update
    DRBG_KEY_SCHEDULE   *keySchedule,   // IN: the key schedule (optional)
    DRBG_SEED           *providedData   // IN: additional data
    )
{
    UINT32               i;
    BYTE                *temp = (BYTE *)&drbgState->seed;
    DRBG_KEY            *key = pDRBG_KEY(&drbgState->seed);
    DRBG_IV             *iv = pDRBG_IV(&drbgState->seed);
    DRBG_KEY_SCHEDULE    localKeySchedule;
//
    pAssert(drbgState->magic == DRBG_MAGIC);

    // If an key schedule was not provided, make one
    if(keySchedule == NULL)
    {
        if(DRBG_ENCRYPT_SETUP((BYTE *)key,
            DRBG_KEY_SIZE_BITS, &localKeySchedule) != 0)
        {
            LOG_FAILURE(FATAL_ERROR_INTERNAL);
            return FALSE;
        }
        keySchedule = &localKeySchedule;
    }
    // Encrypt the temp value

    EncryptDRBG(temp, sizeof(DRBG_SEED), keySchedule, iv,
                drbgState->lastValue);
    if(providedData != NULL)
    {
        BYTE        *pP = (BYTE *)providedData;
        for(i = DRBG_SEED_SIZE_BYTES; i != 0; i--)
            *temp++ ^= *pP++;
    }
    // Since temp points to the input key and IV, we are done and
    // don't need to copy the resulting 'temp' to drbgState->seed
    return TRUE;
}

//*** DRBG_Reseed()
// This function is used when reseeding of the DRBG is required. If
// entropy is provided, it is used in lieu of using hardware entropy.
// Note: the provided entropy must be the required size.
//
//  Return Type: BOOL
//      TRUE(1)         reseed succeeded
//      FALSE(0)        reseed failed, probably due to the entropy generation
BOOL
DRBG_Reseed(
    DRBG_STATE          *drbgState,         // IN: the state to update
    DRBG_SEED           *providedEntropy,   // IN: entropy
    DRBG_SEED           *additionalData     // IN:
    )
{
    DRBG_SEED            seed;

    pAssert((drbgState != NULL) && (drbgState->magic == DRBG_MAGIC));

    if(providedEntropy == NULL)
    {
        providedEntropy = &seed;
        if(!DRBG_GetEntropy(sizeof(DRBG_SEED), (BYTE *)providedEntropy))
            return FALSE;
    }
    if(additionalData != NULL)
    {
        unsigned int          i;

        // XOR the provided data into the provided entropy
        for(i = 0; i < sizeof(DRBG_SEED); i++)
            ((BYTE *)providedEntropy)[i] ^= ((BYTE *)additionalData)[i];
    }
    DRBG_Update(drbgState, NULL, providedEntropy);

    drbgState->reseedCounter = 1;

    return TRUE;
}

//*** DRBG_SelfTest()
// This is run when the DRBG is instantiated and at startup.
//
//  Return Type: BOOL
//      TRUE(1)         test OK
//      FALSE(0)        test failed
BOOL
DRBG_SelfTest(
    void
    )
{
    BYTE             buf[sizeof(DRBG_NistTestVector_Generated)];
    DRBG_SEED        seed;
    UINT32           i;
    BYTE            *p;
    DRBG_STATE       testState;
//
    pAssert(!IsSelfTest());

    SetSelfTest();
    SetDrbgTested();
    // Do an instantiate
    if(!DRBG_Instantiate(&testState, 0, NULL))
        return FALSE;
#if DRBG_DEBUG_PRINT
    dbgDumpMemBlock(pDRBG_KEY(&testState), DRBG_KEY_SIZE_BYTES,
                    "Key after Instantiate");
    dbgDumpMemBlock(pDRBG_IV(&testState), DRBG_IV_SIZE_BYTES,
                    "Value after Instantiate");
#endif
    if(DRBG_Generate((RAND_STATE *)&testState, buf, sizeof(buf)) == 0)
        return FALSE;
#if DRBG_DEBUG_PRINT
    dbgDumpMemBlock(pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES,
                    "Key after 1st Generate");
    dbgDumpMemBlock(pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES,
                    "Value after 1st Generate");
#endif
    if(memcmp(buf, DRBG_NistTestVector_GeneratedInterm, sizeof(buf)) != 0)
        return FALSE;
    memcpy(seed.bytes, DRBG_NistTestVector_EntropyReseed, sizeof(seed));
    DRBG_Reseed(&testState, &seed, NULL);
#if DRBG_DEBUG_PRINT
    dbgDumpMemBlock((BYTE *)pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES,
                    "Key after 2nd Generate");
    dbgDumpMemBlock((BYTE *)pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES,
                    "Value after 2nd Generate");
    dbgDumpMemBlock(buf, sizeof(buf), "2nd Generated");
#endif
    if(DRBG_Generate((RAND_STATE *)&testState, buf, sizeof(buf)) == 0)
        return FALSE;
    if(memcmp(buf, DRBG_NistTestVector_Generated, sizeof(buf)) != 0)
        return FALSE;
    ClearSelfTest();

    DRBG_Uninstantiate(&testState);
    for(p = (BYTE *)&testState, i = 0; i < sizeof(DRBG_STATE); i++)
    {
        if(*p++)
            return FALSE;
    }
    // Simulate hardware failure to make sure that we get an error when
    // trying to instantiate
    SetEntropyBad();
    if(DRBG_Instantiate(&testState, 0, NULL))
       return FALSE;
    ClearEntropyBad();

    return TRUE;
}

//** Public Interface
//*** Description
// The functions in this section are the interface to the RNG. These
// are the functions that are used by TPM.lib.

//*** CryptRandomStir()
// This function is used to cause a reseed. A DRBG_SEED amount of entropy is
// collected from the hardware and then additional data is added.
//
//  Return Type: TPM_RC
//      TPM_RC_NO_RESULT        failure of the entropy generator
LIB_EXPORT TPM_RC
CryptRandomStir(
    UINT16           additionalDataSize,
    BYTE            *additionalData
    )
{
#if !USE_DEBUG_RNG
    DRBG_SEED        tmpBuf;
    DRBG_SEED        dfResult;
//
    // All reseed with outside data starts with a buffer full of entropy
    if(!DRBG_GetEntropy(sizeof(tmpBuf), (BYTE *)&tmpBuf))
        return TPM_RC_NO_RESULT;

    DRBG_Reseed(&drbgDefault, &tmpBuf,
                DfBuffer(&dfResult, additionalDataSize, additionalData));
    drbgDefault.reseedCounter = 1;

    return TPM_RC_SUCCESS;

#else
    // If doing debug, use the input data as the initial setting for the RNG state
    // so that the test can be reset at any time.
    // Note: If this is called with a data size of 0 or less, nothing happens. The
    // presumption is that, in a debug environment, the caller will have specific
    // values for initialization, so this check is just a simple way to prevent
    // inadvertent programming errors from screwing things up. This doesn't use an
    // pAssert() because the non-debug version of this function will accept these
    // parameters as meaning that there is no additionalData and only hardware
    // entropy is used.
    if((additionalDataSize > 0) && (additionalData != NULL))
    {
        memset(drbgDefault.seed.bytes, 0, sizeof(drbgDefault.seed.bytes));
        memcpy(drbgDefault.seed.bytes, additionalData,
               MIN(additionalDataSize, sizeof(drbgDefault.seed.bytes)));
    }
    drbgDefault.reseedCounter = 1;

    return TPM_RC_SUCCESS;
#endif
}

//*** CryptRandomGenerate()
// Generate a 'randomSize' number or random bytes.
LIB_EXPORT UINT16
CryptRandomGenerate(
    UINT16           randomSize,
    BYTE            *buffer
    )
{
    return DRBG_Generate((RAND_STATE *)&drbgDefault, buffer, randomSize);
}



//*** DRBG_InstantiateSeededKdf()
// This function is used to instantiate a KDF-based RNG. This is used for derivations.
// This function always returns TRUE.
LIB_EXPORT BOOL
DRBG_InstantiateSeededKdf(
    KDF_STATE       *state,         // OUT: buffer to hold the state
    TPM_ALG_ID       hashAlg,       // IN: hash algorithm
    TPM_ALG_ID       kdf,           // IN: the KDF to use
    TPM2B           *seed,          // IN: the seed to use
    const TPM2B     *label,         // IN: a label for the generation process.
    TPM2B           *context,       // IN: the context value
    UINT32           limit          // IN: Maximum number of bits from the KDF
    )
{
    state->magic = KDF_MAGIC;
    state->limit = limit;
    state->seed = seed;
    state->hash = hashAlg;
    state->kdf = kdf;
    state->label = label;
    state->context = context;
    state->digestSize = CryptHashGetDigestSize(hashAlg);
    state->counter = 0;
    state->residual.t.size = 0;
    return TRUE;
}

//*** DRBG_AdditionalData()
// Function to reseed the DRBG with additional entropy. This is normally called
// before computing the protection value of a primary key in the Endorsement
// hierarchy.
LIB_EXPORT void
DRBG_AdditionalData(
    DRBG_STATE      *drbgState,     // IN:OUT state to update
    TPM2B           *additionalData // IN: value to incorporate
    )
{
    DRBG_SEED        dfResult;
    if(drbgState->magic == DRBG_MAGIC)
    {
        DfBuffer(&dfResult, additionalData->size, additionalData->buffer);
        DRBG_Reseed(drbgState, &dfResult, NULL);
    }
}


//*** DRBG_InstantiateSeeded()
// This function is used to instantiate a random number generator from seed values.
// The nominal use of this generator is to create sequences of pseudo-random
// numbers from a seed value.
//
// Return Type: TPM_RC
//  TPM_RC_FAILURE      DRBG self-test failure
LIB_EXPORT TPM_RC
DRBG_InstantiateSeeded(
    DRBG_STATE      *drbgState,     // IN/OUT: buffer to hold the state
    const TPM2B     *seed,          // IN: the seed to use
    const TPM2B     *purpose,       // IN: a label for the generation process.
    const TPM2B     *name,          // IN: name of the object
    const TPM2B     *additional     // IN: additional data
    )
{
    DF_STATE         dfState;
    int              totalInputSize;
    // DRBG should have been tested, but...
    if(!IsDrbgTested() && !DRBG_SelfTest())
    {
        LOG_FAILURE(FATAL_ERROR_SELF_TEST);
        return TPM_RC_FAILURE;
    }
    // Initialize the DRBG state
    memset(drbgState, 0, sizeof(DRBG_STATE));
    drbgState->magic = DRBG_MAGIC;

    // Size all of the values
    totalInputSize = (seed != NULL) ? seed->size : 0;
    totalInputSize += (purpose != NULL) ? purpose->size : 0;
    totalInputSize += (name != NULL) ? name->size : 0;
    totalInputSize += (additional != NULL) ? additional->size : 0;

    // Initialize the derivation
    DfStart(&dfState, totalInputSize);

    // Run all the input strings through the derivation function
    if(seed != NULL)
        DfUpdate(&dfState, seed->size, seed->buffer);
    if(purpose != NULL)
        DfUpdate(&dfState, purpose->size, purpose->buffer);
    if(name != NULL)
        DfUpdate(&dfState, name->size, name->buffer);
    if(additional != NULL)
        DfUpdate(&dfState, additional->size, additional->buffer);

    // Used the derivation function output as the "entropy" input. This is not
    // how it is described in SP800-90A but this is the equivalent function
    DRBG_Reseed(((DRBG_STATE *)drbgState), DfEnd(&dfState), NULL);

    return TPM_RC_SUCCESS;
}

//*** CryptRandStartup()
// This function is called when TPM_Startup is executed. This function always returns
// TRUE.
LIB_EXPORT BOOL
CryptRandStartup(
    void
    )
{
#if ! _DRBG_STATE_SAVE
    // If not saved in NV, re-instantiate on each startup
    return DRBG_Instantiate(&drbgDefault, 0, NULL);
#else
    // If the running state is saved in NV, NV has to be loaded before it can
    // be updated
    if(go.drbgState.magic == DRBG_MAGIC)
        return DRBG_Reseed(&go.drbgState, NULL, NULL);
    else
        return DRBG_Instantiate(&go.drbgState, 0, NULL);
#endif
}

//*** CryptRandInit()
// This function is called when _TPM_Init is being processed.
//
//  Return Type: BOOL
//      TRUE(1)         success
//      FALSE(0)        failure
LIB_EXPORT BOOL
CryptRandInit(
    void
    )
{
#if !USE_DEBUG_RNG
    _plat__GetEntropy(NULL, 0);
#endif
    return DRBG_SelfTest();
}

//*** DRBG_Generate()
// This function generates a random sequence according SP800-90A.
// If 'random' is not NULL, then 'randomSize' bytes of random values are generated.
// If 'random' is NULL or 'randomSize' is zero, then the function returns
// zero without generating any bits or updating the reseed counter.
// This function returns the number of bytes produced which could be less than the
// number requested if the request is too large ("too large" is implementation
// dependent.)
LIB_EXPORT UINT16
DRBG_Generate(
    RAND_STATE      *state,
    BYTE            *random,        // OUT: buffer to receive the random values
    UINT16           randomSize     // IN: the number of bytes to generate
    )
{
    if(state == NULL)
        state = (RAND_STATE *)&drbgDefault;
    if(random == NULL)
        return 0;

    // If the caller used a KDF state, generate a sequence from the KDF not to
    // exceed the limit.
    if(state->kdf.magic == KDF_MAGIC)
    {
        KDF_STATE       *kdf = (KDF_STATE *)state;
        UINT32           counter = (UINT32)kdf->counter;
        INT32            bytesLeft = randomSize;
//
        // If the number of bytes to be returned would put the generator
        // over the limit, then return 0
        if((((kdf->counter * kdf->digestSize) + randomSize) * 8) > kdf->limit)
            return 0;
        // Process partial and full blocks until all requested bytes provided
        while(bytesLeft > 0)
        {
            // If there is any residual data in the buffer, copy it to the output
            // buffer
            if(kdf->residual.t.size > 0)
            {
                INT32      size;
//
                // Don't use more of the residual than will fit or more than are
                // available
                size = MIN(kdf->residual.t.size, bytesLeft);

                // Copy some or all of the residual to the output. The residual is
                // at the end of the buffer. The residual might be a full buffer.
                MemoryCopy(random,
                           &kdf->residual.t.buffer
                           [kdf->digestSize - kdf->residual.t.size], size);

                // Advance the buffer pointer
                random += size;

                // Reduce the number of bytes left to get
                bytesLeft -= size;

                // And reduce the residual size appropriately
                kdf->residual.t.size -= (UINT16)size;
            }
            else
            {
                UINT16           blocks = (UINT16)(bytesLeft / kdf->digestSize);
//
                // Get the number of required full blocks
                if(blocks > 0)
                {
                    UINT16      size = blocks * kdf->digestSize;
// Get some number of full blocks and put them in the return buffer
                    CryptKDFa(kdf->hash, kdf->seed, kdf->label, kdf->context, NULL,
                              kdf->limit, random, &counter, blocks);

                    // reduce the size remaining to be moved and advance the pointer
                    bytesLeft -= size;
                    random += size;
                }
                else
                {
                    // Fill the residual buffer with a full block and then loop to
                    // top to get part of it copied to the output.
                    kdf->residual.t.size = CryptKDFa(kdf->hash, kdf->seed,
                                                     kdf->label, kdf->context, NULL,
                                                     kdf->limit,
                                                     kdf->residual.t.buffer,
                                                     &counter, 1);
                }
            }
        }
        kdf->counter = counter;
        return randomSize;
    }
    else if(state->drbg.magic == DRBG_MAGIC)
    {
        DRBG_STATE          *drbgState = (DRBG_STATE *)state;
        DRBG_KEY_SCHEDULE    keySchedule;
        DRBG_SEED           *seed = &drbgState->seed;

        if(drbgState->reseedCounter >= CTR_DRBG_MAX_REQUESTS_PER_RESEED)
        {
            if(drbgState == &drbgDefault)
            {
                DRBG_Reseed(drbgState, NULL, NULL);
                if(IsEntropyBad() && !IsSelfTest())
                    return 0;
            }
            else
            {
                // If this is a PRNG then the only way to get
                // here is if the SW has run away.
                LOG_FAILURE(FATAL_ERROR_INTERNAL);
                return 0;
            }
        }
        // if the allowed number of bytes in a request is larger than the
        // less than the number of bytes that can be requested, then check
#if UINT16_MAX >=  CTR_DRBG_MAX_BYTES_PER_REQUEST
        if(randomSize > CTR_DRBG_MAX_BYTES_PER_REQUEST)
            randomSize = CTR_DRBG_MAX_BYTES_PER_REQUEST;
#endif
        // Create  encryption schedule
        if(DRBG_ENCRYPT_SETUP((BYTE *)pDRBG_KEY(seed),
                              DRBG_KEY_SIZE_BITS, &keySchedule) != 0)
        {
            LOG_FAILURE(FATAL_ERROR_INTERNAL);
            return 0;
        }
        // Generate the random data
        EncryptDRBG(random, randomSize, &keySchedule, pDRBG_IV(seed),
                    drbgState->lastValue);
        // Do a key update
        DRBG_Update(drbgState, &keySchedule, NULL);

        // Increment the reseed counter
        drbgState->reseedCounter += 1;
    }
    else
    {
        LOG_FAILURE(FATAL_ERROR_INTERNAL);
        return FALSE;
    }
    return randomSize;
}

//*** DRBG_Instantiate()
// This is CTR_DRBG_Instantiate_algorithm() from [SP 800-90A 10.2.1.3.1].
// This is called when a the TPM DRBG is to be instantiated. This is
// called to instantiate a DRBG used by the TPM for normal
// operations.
//
//  Return Type: BOOL
//      TRUE(1)         instantiation succeeded
//      FALSE(0)        instantiation failed
LIB_EXPORT BOOL
DRBG_Instantiate(
    DRBG_STATE      *drbgState,         // OUT: the instantiated value
    UINT16           pSize,             // IN: Size of personalization string
    BYTE            *personalization    // IN: The personalization string
    )
{
    DRBG_SEED        seed;
    DRBG_SEED        dfResult;
//
    pAssert((pSize == 0) || (pSize <= sizeof(seed)) || (personalization != NULL));
    // If the DRBG has not been tested, test when doing an instantiation. Since
    // Instantiation is called during self test, make sure we don't get stuck in a
    // loop.
    if(!IsDrbgTested() && !IsSelfTest() && !DRBG_SelfTest())
        return FALSE;
    // If doing a self test, DRBG_GetEntropy will return the NIST
    // test vector value.
    if(!DRBG_GetEntropy(sizeof(seed), (BYTE *)&seed))
        return FALSE;
    // set everything to zero
    memset(drbgState, 0, sizeof(DRBG_STATE));
    drbgState->magic = DRBG_MAGIC;

    // Steps 1, 2, 3, 6, 7 of SP 800-90A 10.2.1.3.1 are exactly what
    // reseeding does. So, do a reduction on the personalization value (if any)
    // and do a reseed.
    DRBG_Reseed(drbgState, &seed, DfBuffer(&dfResult, pSize, personalization));

    return TRUE;
}

//*** DRBG_Uninstantiate()
// This is Uninstantiate_function() from [SP 800-90A 9.4].
//
//  Return Type: TPM_RC
//      TPM_RC_VALUE        not a valid state
LIB_EXPORT TPM_RC
DRBG_Uninstantiate(
    DRBG_STATE      *drbgState      // IN/OUT: working state to erase
    )
{
    if((drbgState == NULL) || (drbgState->magic != DRBG_MAGIC))
        return TPM_RC_VALUE;
    memset(drbgState, 0, sizeof(DRBG_STATE));
    return TPM_RC_SUCCESS;
}
