// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014

//#define __TPM_RNG_FOR_DEBUG__
//
//
//          Introduction
//
//     This file contains the interface to the OpenSSL() random number functions.
//
//          Includes
//
#include "OsslCryptoEngine.h"
int         s_entropyFailure;
//
//
//          Functions
//
//          _cpri__RngStartup()
//
//     This function is called to initialize the random number generator. It collects entropy from the platform to
//     seed the OpenSSL() random number generator.
//
LIB_EXPORT BOOL
_cpri__RngStartup(void)
{
     UINT32           entropySize;
     BYTE             entropy[MAX_RNG_ENTROPY_SIZE];
     INT32            returnedSize = 0;
     // Initialize the entropy source
     s_entropyFailure = FALSE;
     _plat__GetEntropy(NULL, 0);
     // Collect entropy until we have enough
     for(entropySize = 0;
         entropySize < MAX_RNG_ENTROPY_SIZE && returnedSize >= 0;
         entropySize += returnedSize)
     {
         returnedSize = _plat__GetEntropy(&entropy[entropySize],
                                             MAX_RNG_ENTROPY_SIZE - entropySize);
     }
     // Got some entropy on the last call and did not get an error
     if(returnedSize > 0)
     {
         // Seed OpenSSL with entropy
         RAND_seed(entropy, entropySize);
     }
     else
     {
         s_entropyFailure = TRUE;
     }
     return s_entropyFailure == FALSE;
}
//
//
//          _cpri__DrbgGetPutState()
//
//     This function is used to set the state of the RNG (direction == PUT_STATE) or to recover the state of the
//     RNG (direction == GET_STATE).
//
//
//
//     NOTE:           This not currently supported on OpenSSL() version.
//
LIB_EXPORT CRYPT_RESULT
_cpri__DrbgGetPutState(
    GET_PUT              direction,
    int                  bufferSize,
    BYTE                *buffer
    )
{
    UNREFERENCED_PARAMETER(direction);
    UNREFERENCED_PARAMETER(bufferSize);
    UNREFERENCED_PARAMETER(buffer);
    return CRYPT_SUCCESS;                 // Function is not implemented
}
//
//
//          _cpri__StirRandom()
//
//     This function is called to add external entropy to the OpenSSL() random number generator.
//
LIB_EXPORT CRYPT_RESULT
_cpri__StirRandom(
    INT32                entropySize,
    BYTE                *entropy
    )
{
    if (entropySize >= 0)
    {
        RAND_add((const void *)entropy, (int) entropySize, 0.0);
    }
    return CRYPT_SUCCESS;
}
//
//
//          _cpri__GenerateRandom()
//
//     This function is called to get a string of random bytes from the OpenSSL() random number generator. The
//     return value is the number of bytes placed in the buffer. If the number of bytes returned is not equal to the
//     number of bytes requested (randomSize) it is indicative of a failure of the OpenSSL() random number
//     generator and is probably fatal.
//
LIB_EXPORT UINT16
_cpri__GenerateRandom(
    INT32                randomSize,
    BYTE                *buffer
    )
{
    //
    // We don't do negative sizes or ones that are too large
    if (randomSize < 0 || randomSize > UINT16_MAX)
        return 0;
    // RAND_bytes uses 1 for success and we use 0
    if(RAND_bytes(buffer, randomSize) == 1)
        return (UINT16)randomSize;
    else
        return 0;
}
//
//
//
//          _cpri__GenerateSeededRandom()
//
//     This funciton is used to generate a pseudo-random number from some seed values This funciton returns
//     the same result each time it is called with the same parameters
//
LIB_EXPORT UINT16
_cpri__GenerateSeededRandom(
   INT32               randomSize,      //   IN: the size of the request
   BYTE               *random,          //   OUT: receives the data
   TPM_ALG_ID          hashAlg,         //   IN: used by KDF version but not here
   TPM2B              *seed,            //   IN: the seed value
   const char         *label,           //   IN: a label string (optional)
   TPM2B              *partyU,          //   IN: other data (oprtional)
   TPM2B              *partyV           //   IN: still more (optional)
   )
{
   return (_cpri__KDFa(hashAlg, seed, label, partyU, partyV,
                       randomSize * 8, random, NULL, FALSE));
}