/********************************************************************************/
/*										*/
/*		DRBG with a behavior according to SP800-90A			*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*										*/
/*  Licenses and Notices							*/
/*										*/
/*  1. Copyright Licenses:							*/
/*										*/
/*  - Trusted Computing Group (TCG) grants to the user of the source code in	*/
/*    this specification (the "Source Code") a worldwide, irrevocable, 		*/
/*    nonexclusive, royalty free, copyright license to reproduce, create 	*/
/*    derivative works, distribute, display and perform the Source Code and	*/
/*    derivative works thereof, and to grant others the rights granted herein.	*/
/*										*/
/*  - The TCG grants to the user of the other parts of the specification 	*/
/*    (other than the Source Code) the rights to reproduce, distribute, 	*/
/*    display, and perform the specification solely for the purpose of 		*/
/*    developing products based on such documents.				*/
/*										*/
/*  2. Source Code Distribution Conditions:					*/
/*										*/
/*  - Redistributions of Source Code must retain the above copyright licenses, 	*/
/*    this list of conditions and the following disclaimers.			*/
/*										*/
/*  - Redistributions in binary form must reproduce the above copyright 	*/
/*    licenses, this list of conditions	and the following disclaimers in the 	*/
/*    documentation and/or other materials provided with the distribution.	*/
/*										*/
/*  3. Disclaimers:								*/
/*										*/
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF	*/
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH	*/
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)	*/
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.		*/
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for 		*/
/*  information on specification licensing rights available through TCG 	*/
/*  membership agreements.							*/
/*										*/
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED 	*/
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR 	*/
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR 		*/
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY 		*/
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.		*/
/*										*/
/*  - Without limitation, TCG and its members and licensors disclaim all 	*/
/*    liability, including liability for infringement of any proprietary 	*/
/*    rights, relating to use of information in this specification and to the	*/
/*    implementation of this specification, and TCG disclaims all liability for	*/
/*    cost of procurement of substitute goods or services, lost profits, loss 	*/
/*    of use, loss of data or any incidental, consequential, direct, indirect, 	*/
/*    or special damages, whether under contract, tort, warranty or otherwise, 	*/
/*    arising in any way out of use or reliance upon this specification or any 	*/
/*    information herein.							*/
/*										*/
/*  (c) Copyright IBM Corp. and others, 2016 - 2023				*/
/*										*/
/********************************************************************************/

//** 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 tpmKeyScheduleAES DRBG_KEY_SCHEDULE;

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								// libtpms changed
if(RuntimeProfileRequiresAttributeFlags(&g_RuntimeProfile,			// libtpms added
					RUNTIME_ATTRIBUTE_DRBG_CONTINOUS_TEST))	// libtpms added
{
    // 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]))
		{
		    FAIL_BOOL(FATAL_ERROR_ENTROPY);
		}
	    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				// libtpms changed
} else {									// libtpms added
    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);
	}
}										// libtpms added
//#endif									// libtpms changed
    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;

    memset(&localKeySchedule, 0, sizeof(localKeySchedule)); /* libtpms added: coverity */
    //
    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)
		{
		    FAIL_BOOL(FATAL_ERROR_INTERNAL);
		}
	    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
					 SEED_COMPAT_LEVEL seedCompatLevel // IN: compatibility level; libtpms added					 )
					 )
{
    DF_STATE dfState;
    int      totalInputSize;
    // DRBG should have been tested, but...
    if(!IsDrbgTested() && !DRBG_SelfTest())
	{
	    FAIL_RC(FATAL_ERROR_SELF_TEST);
	}
    // Initialize the DRBG state
    memset(drbgState, 0, sizeof(DRBG_STATE));
    drbgState->magic = DRBG_MAGIC;
    drbgState->seedCompatLevel = seedCompatLevel; // libtpms added

    // 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();
}
// libtpms added begin
LIB_EXPORT SEED_COMPAT_LEVEL
DRBG_GetSeedCompatLevel(
               RAND_STATE     *state
	      )
{
    if(state == NULL)
        {
	    return SEED_COMPAT_LEVEL_LAST;
	}
    else if(state->drbg.magic == DRBG_MAGIC)
	{
	    DRBG_STATE          *drbgState = (DRBG_STATE *)state;

	    return drbgState->seedCompatLevel;
	}
    else
	{
	    return SEED_COMPAT_LEVEL_LAST;
	}
}
// libtpms added end

//*** 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;

	    memset(&keySchedule, 0, sizeof(keySchedule)); /* libtpms added: coverity */
	    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.
			    FAIL_IMMEDIATE(FATAL_ERROR_INTERNAL, 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)
		{
		    FAIL_IMMEDIATE(FATAL_ERROR_INTERNAL, 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
	{
	    // invalid DRBG state structure
	    FAIL_IMMEDIATE(FATAL_ERROR_INTERNAL, 0);
	}
    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;
}
