blob: 0cd2ebed35488a0d9edd55230114aaf014e8c91a [file] [log] [blame]
/* 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 Requested entropy returned
// FALSE Entropy Failure
BOOL
DRBG_GetEntropy(
UINT32 requiredEntropy, // IN: requested number of bytes of full
// entropy
BYTE *entropy // OUT: buffer to return collected entropy
)
{
#ifndef 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));
}
#ifndef 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()
// 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.
void
EncryptDRBG(
BYTE *dOut,
UINT32 dOutBytes,
DRBG_KEY_SCHEDULE *keySchedule,
DRBG_IV *iv,
UINT32 *lastValue // Points to the last output value
)
{
#ifdef 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])
)
FAIL(FATAL_ERROR_DRBG);
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
}
//*** 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.
//
void
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)
FAIL(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
}
//*** 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 reseed succeeded
// FALSE 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;
BYTE *pSeed = (BYTE *)&seed;
pAssert((drbgState != NULL) && (drbgState->magic == DRBG_MAGIC));
if(providedEntropy == NULL)
{
if(!DRBG_GetEntropy(sizeof(DRBG_SEED), pSeed))
return FALSE;
providedEntropy = &seed;
}
if(additionalData != NULL)
{
BYTE *in1 = (BYTE *)providedEntropy; // This might be seed
BYTE *in2 = (BYTE *)additionalData;
int i;
// XOR the provided data with the seed
for(i = sizeof(DRBG_SEED); i > 0; i--)
*pSeed++ = *in1++ ^ *in2++;
}
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
// FALSE test failed
// TRUE test OK
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 defined DRBG_DEBUG_PRINT && defined DEBUG
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 defined DRBG_DEBUG_PRINT && defined DEBUG
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 defined DRBG_DEBUG_PRINT && defined DEBUG
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. Other functions are only
// visible to programs in the LtcCryptoEngine.
//*** 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 S failure of the entropy generator
LIB_EXPORT TPM_RC
CryptRandomStir(
INT32 additionalDataSize,
BYTE *additionalData
)
{
DRBG_SEED tmpBuf;
DRBG_SEED dfResult;
//
#if defined USE_DEBUG_RNG && 1
// 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.
NOT_REFERENCED(dfResult);
if(additionalDataSize < 0)
additionalDataSize = 0;
else if(additionalDataSize > sizeof(tmpBuf))
additionalDataSize = sizeof(tmpBuf);
else
memset(&tmpBuf.bytes[additionalDataSize], 0, sizeof(tmpBuf) - additionalDataSize);
memcpy(tmpBuf.bytes, additionalData, additionalDataSize);
memcpy(drbgDefault.seed.bytes, tmpBuf.bytes, sizeof(drbgDefault.seed.bytes));
#else
// 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));
#endif
drbgDefault.reseedCounter = 1;
return TPM_RC_SUCCESS;
}
//*** CryptRandomGenerate()
// Generate a 'randomSize' number or random bytes.
LIB_EXPORT UINT16
CryptRandomGenerate(
INT32 randomSize,
BYTE *buffer
)
{
if(randomSize > UINT16_MAX)
randomSize = UINT16_MAX;
return DRBG_Generate((RAND_STATE *)&drbgDefault, buffer, (UINT16)randomSize);
}
//**** DRBG_InstantiateSeededKdf()
// Function used to instantiate a KDF-based RNG. This is used for derivations
LIB_EXPORT BOOL
DRBG_InstantiateSeededKdf(
KDF_STATE *state, // IN: 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
)
{
state->magic = KDF_MAGIC;
state->seed = seed;
state->hash = hashAlg;
state->kdf = kdf;
state->label = label;
state->context = context;
state->counter = 1;
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.
LIB_EXPORT BOOL
DRBG_InstantiateSeeded(
DRBG_STATE *drbgState, // IN: 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())
FAIL(FATAL_ERROR_SELF_TEST);
// 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 TRUE;
}
//**** CryptRandStartup()
// This function is called when TPM_Startup is executed.
//
LIB_EXPORT BOOL
CryptRandStartup(
void
)
{
#ifndef _DRBG_STATE_SAVE
// If not saved in NV, re-instantiate on each startup
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)
DRBG_Reseed(&go.drbgState, NULL, NULL);
else
DRBG_Instantiate(&go.drbgState, 0, NULL);
#endif
return TRUE;
}
//**** CryptRandInit()
// This function is called when _TPM_Init is being processed
LIB_EXPORT BOOL
CryptRandInit(
void
)
{
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
// TRUE without generating any bits or updating the reseed counter.
// This function returns 0 if a reseed is required. Otherwise, it returns the
// number of bytes produced which could be less than the number requested if the
// request is too large.
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 the caller used a KDF state, generate a sequence from the KDF
if(state->kdf.magic == KDF_MAGIC)
{
KDF_STATE *kdf = (KDF_STATE *)state;
UINT32 count = (UINT32)kdf->counter;
if((randomSize != 0) && (random != NULL))
CryptKDFa(kdf->hash, kdf->seed, kdf->label, kdf->context, NULL,
randomSize * 8, random, &count, 0);
kdf->counter = count;
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.
FAIL(FATAL_ERROR_INTERNAL);
}
// 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(FATAL_ERROR_INTERNAL);
// 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
{
FAIL(FATAL_ERROR_INTERNAL);
}
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 instantiation succeeded
// FALSE 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
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;
}
//*** CryptRandMinMax()
// This function generates a value that as not larger than (2^'max') - 1
// and no smaller than 2^('min' - 1). For example, if 'max' == 4 and 'min' == 2, then
// the number will be between 0x0010 and 0x1111 inclusively. If 'max' == 4 and
// 'min' == 4 then the number will be between 0x1000 and 0x1111.
LIB_EXPORT NUMBYTES
CryptRandMinMax(
BYTE *out,
UINT32 max,
UINT32 min,
RAND_STATE *rand
)
{
BN_VAR(bn, LARGEST_NUMBER_BITS);
NUMBYTES size = (NUMBYTES)BITS_TO_BYTES(max);
pAssert(max <= LARGEST_NUMBER_BITS);
do
{
BnGetRandomBits(bn, max, rand);
} while(BnSizeInBits(bn) < min);
BnToBytes(bn, out, &size);
return size;
}