C++程序  |  3713行  |  143.22 KB

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

#include        "TPM_Types.h"
#include        "CryptoEngine.h"        // types shared by CryptUtil and CryptoEngine.
                                       // Includes the function prototypes for the
                                       // CryptoEngine functions.
#include        "Global.h"
#include        "InternalRoutines.h"
#include        "MemoryLib_fp.h"
//#include        "CryptSelfTest_fp.h"
//
//
//     10.2.2     TranslateCryptErrors()
//
//     This function converts errors from the cryptographic library into TPM_RC_VALUES.
//
//     Error Returns                     Meaning
//
//     TPM_RC_VALUE                      CRYPT_FAIL
//     TPM_RC_NO_RESULT                  CRYPT_NO_RESULT
//     TPM_RC_SCHEME                     CRYPT_SCHEME
//     TPM_RC_VALUE                      CRYPT_PARAMETER
//     TPM_RC_SIZE                       CRYPT_UNDERFLOW
//     TPM_RC_ECC_POINT                  CRYPT_POINT
//     TPM_RC_CANCELLED                  CRYPT_CANCEL
//
static TPM_RC
TranslateCryptErrors (
      CRYPT_RESULT            retVal                 // IN: crypt error to evaluate
)
{
      switch (retVal)
      {
      case CRYPT_SUCCESS:
          return TPM_RC_SUCCESS;
      case CRYPT_FAIL:
          return TPM_RC_VALUE;
      case CRYPT_NO_RESULT:
          return TPM_RC_NO_RESULT;
      case CRYPT_SCHEME:
          return TPM_RC_SCHEME;
      case CRYPT_PARAMETER:
          return TPM_RC_VALUE;
      case CRYPT_UNDERFLOW:
          return TPM_RC_SIZE;
      case CRYPT_POINT:
          return TPM_RC_ECC_POINT;
      case CRYPT_CANCEL:
       return TPM_RC_CANCELED;
   default: // Other unknown warnings
       return TPM_RC_FAILURE;
   }
}
//
//
//     10.2.3     Random Number Generation Functions
//
#ifdef TPM_ALG_NULL //%
#ifdef _DRBG_STATE_SAVE //%
//
//
//     10.2.3.1    CryptDrbgGetPutState()
//
//     Read or write the current state from the DRBG in the cryptoEngine.
//
void
CryptDrbgGetPutState(
   GET_PUT              direction         // IN: Get from or put to DRBG
   )
{
   _cpri__DrbgGetPutState(direction,
                          sizeof(go.drbgState),
                          (BYTE *)&go.drbgState);
}
#else   //% 00
//%#define CryptDrbgGetPutState(ignored)            // If not doing state save, turn this
//%                                                  // into a null macro
#endif //%
//
//
//     10.2.3.2    CryptStirRandom()
//
//     Stir random entropy
//
void
CryptStirRandom(
   UINT32               entropySize,      // IN: size of entropy buffer
   BYTE                *buffer            // IN: entropy buffer
   )
{
   // RNG self testing code may be inserted here
   // Call crypto engine random number stirring function
   _cpri__StirRandom(entropySize, buffer);
   return;
}
//
//
//     10.2.3.3    CryptGenerateRandom()
//
//     This is the interface to _cpri__GenerateRandom().
//
UINT16
CryptGenerateRandom(
   UINT16               randomSize,       // IN: size of random number
   BYTE                *buffer            // OUT: buffer of random number
   )
{
   UINT16               result;
   pAssert(randomSize <= MAX_RSA_KEY_BYTES || randomSize <= PRIMARY_SEED_SIZE);
   if(randomSize == 0)
          return 0;
    // Call crypto engine random number generation
    result = _cpri__GenerateRandom(randomSize, buffer);
    if(result != randomSize)
        FAIL(FATAL_ERROR_INTERNAL);
   return result;
}
#endif //TPM_ALG_NULL //%
//
//
//      10.2.4     Hash/HMAC Functions
//
//      10.2.4.1    CryptGetContextAlg()
//
//      This function returns the hash algorithm associated with a hash context.
//
#ifdef TPM_ALG_KEYEDHASH                 //% 1
TPM_ALG_ID
CryptGetContextAlg(
    void                *state                // IN: the context to check
    )
{
    HASH_STATE *context = (HASH_STATE *)state;
    return _cpri__GetContextAlg(&context->state);
}
//
//
//      10.2.4.2    CryptStartHash()
//
//      This function starts a hash and return the size, in bytes, of the digest.
//
//      Return Value                      Meaning
//
//      >0                                the digest size of the algorithm
//      =0                                the hashAlg was TPM_ALG_NULL
//
UINT16
CryptStartHash(
    TPMI_ALG_HASH        hashAlg,             // IN: hash algorithm
    HASH_STATE          *hashState            // OUT: the state of hash stack. It will be used
                                              //     in hash update and completion
    )
{
    CRYPT_RESULT            retVal = 0;
    pAssert(hashState != NULL);
    TEST_HASH(hashAlg);
    hashState->type = HASH_STATE_EMPTY;
    // Call crypto engine start hash function
    if((retVal = _cpri__StartHash(hashAlg, FALSE, &hashState->state)) > 0)
        hashState->type = HASH_STATE_HASH;
    return retVal;
}
//
//
//
//      10.2.4.3    CryptStartHashSequence()
//
//      Start a hash stack for a sequence object and return the size, in bytes, of the digest. This call uses the
//      form of the hash state that requires context save and restored.
//
//      Return Value                    Meaning
//
//      >0                              the digest size of the algorithm
//      =0                              the hashAlg was TPM_ALG_NULL
//
UINT16
CryptStartHashSequence(
    TPMI_ALG_HASH       hashAlg,            // IN: hash algorithm
    HASH_STATE         *hashState           // OUT: the state of hash stack. It will be used
                                            //     in hash update and completion
    )
{
    CRYPT_RESULT      retVal = 0;
    pAssert(hashState != NULL);
    TEST_HASH(hashAlg);
    hashState->type = HASH_STATE_EMPTY;
    // Call crypto engine start hash function
    if((retVal = _cpri__StartHash(hashAlg, TRUE, &hashState->state)) > 0)
        hashState->type = HASH_STATE_HASH;
    return retVal;
}
//
//
//      10.2.4.4    CryptStartHMAC()
//
//      This function starts an HMAC sequence and returns the size of the digest that will be produced.
//      The caller must provide a block of memory in which the hash sequence state is kept. The caller should
//      not alter the contents of this buffer until the hash sequence is completed or abandoned.
//
//      Return Value                    Meaning
//
//      >0                              the digest size of the algorithm
//      =0                              the hashAlg was TPM_ALG_NULL
//
UINT16
CryptStartHMAC(
    TPMI_ALG_HASH       hashAlg,            //   IN: hash algorithm
    UINT16              keySize,            //   IN: the size of HMAC key in byte
    BYTE               *key,                //   IN: HMAC key
    HMAC_STATE         *hmacState           //   OUT: the state of HMAC stack. It will be used
                                            //       in HMAC update and completion
    )
{
    HASH_STATE         *hashState = (HASH_STATE *)hmacState;
    CRYPT_RESULT       retVal;
    // This has to come before the pAssert in case we             all calling this function
    // during testing. If so, the first instance will             have no arguments but the
    // hash algorithm. The call from the test routine             will have arguments. When
    // the second call is done, then we return to the             test dispatcher.
    TEST_HASH(hashAlg);
    pAssert(hashState != NULL);
    hashState->type = HASH_STATE_EMPTY;
    if((retVal =    _cpri__StartHMAC(hashAlg, FALSE, &hashState->state, keySize, key,
                                     &hmacState->hmacKey.b)) > 0)
          hashState->type = HASH_STATE_HMAC;
    return retVal;
}
//
//
//      10.2.4.5    CryptStartHMACSequence()
//
//      This function starts an HMAC sequence and returns the size of the digest that will be produced.
//      The caller must provide a block of memory in which the hash sequence state is kept. The caller should
//      not alter the contents of this buffer until the hash sequence is completed or abandoned.
//      This call is used to start a sequence HMAC that spans multiple TPM commands.
//
//      Return Value                      Meaning
//
//      >0                                the digest size of the algorithm
//      =0                                the hashAlg was TPM_ALG_NULL
//
UINT16
CryptStartHMACSequence(
    TPMI_ALG_HASH       hashAlg,              //   IN: hash algorithm
    UINT16              keySize,              //   IN: the size of HMAC key in byte
    BYTE               *key,                  //   IN: HMAC key
    HMAC_STATE         *hmacState             //   OUT: the state of HMAC stack. It will be used
                                              //       in HMAC update and completion
    )
{
    HASH_STATE         *hashState = (HASH_STATE *)hmacState;
    CRYPT_RESULT       retVal;
    TEST_HASH(hashAlg);
    hashState->type = HASH_STATE_EMPTY;
    if((retVal =    _cpri__StartHMAC(hashAlg, TRUE, &hashState->state,
                                     keySize, key, &hmacState->hmacKey.b)) > 0)
          hashState->type = HASH_STATE_HMAC;
    return retVal;
}
//
//
//      10.2.4.6    CryptStartHMAC2B()
//
//      This function starts an HMAC and returns the size of the digest that will be produced.
//      This function is provided to support the most common use of starting an HMAC with a TPM2B key.
//      The caller must provide a block of memory in which the hash sequence state is kept. The caller should
//      not alter the contents of this buffer until the hash sequence is completed or abandoned.
//
//
//
//
//      Return Value                    Meaning
//
//      >0                              the digest size of the algorithm
//      =0                              the hashAlg was TPM_ALG_NULL
//
LIB_EXPORT UINT16
CryptStartHMAC2B(
    TPMI_ALG_HASH       hashAlg,            // IN: hash algorithm
    TPM2B              *key,                // IN: HMAC key
    HMAC_STATE         *hmacState           // OUT: the state of HMAC stack. It will be used
                                            //     in HMAC update and completion
    )
{
    return CryptStartHMAC(hashAlg, key->size, key->buffer, hmacState);
}
//
//
//      10.2.4.7    CryptStartHMACSequence2B()
//
//      This function starts an HMAC sequence and returns the size of the digest that will be produced.
//      This function is provided to support the most common use of starting an HMAC with a TPM2B key.
//      The caller must provide a block of memory in which the hash sequence state is kept. The caller should
//      not alter the contents of this buffer until the hash sequence is completed or abandoned.
//
//      Return Value                    Meaning
//
//      >0                              the digest size of the algorithm
//      =0                              the hashAlg was TPM_ALG_NULL
//
UINT16
CryptStartHMACSequence2B(
    TPMI_ALG_HASH       hashAlg,            // IN: hash algorithm
    TPM2B              *key,                // IN: HMAC key
    HMAC_STATE         *hmacState           // OUT: the state of HMAC stack. It will be used
                                            //     in HMAC update and completion
    )
{
    return CryptStartHMACSequence(hashAlg, key->size, key->buffer, hmacState);
}
//
//
//      10.2.4.8    CryptUpdateDigest()
//
//      This function updates a digest (hash or HMAC) with an array of octets.
//      This function can be used for both HMAC and hash functions so the digestState is void so that either
//      state type can be passed.
//
LIB_EXPORT void
CryptUpdateDigest(
    void               *digestState,        // IN: the state of hash stack
    UINT32              dataSize,           // IN: the size of data
    BYTE               *data                // IN: data to be hashed
    )
{
    HASH_STATE         *hashState = (HASH_STATE *)digestState;
    pAssert(digestState != NULL);
    if(hashState->type != HASH_STATE_EMPTY && data != NULL && dataSize != 0)
    {
          // Call crypto engine update hash function
          _cpri__UpdateHash(&hashState->state, dataSize, data);
    }
    return;
}
//
//
//      10.2.4.9     CryptUpdateDigest2B()
//
//      This function updates a digest (hash or HMAC) with a TPM2B.
//      This function can be used for both HMAC and hash functions so the digestState is void so that either
//      state type can be passed.
//
LIB_EXPORT void
CryptUpdateDigest2B(
    void                *digestState,       // IN: the digest state
    TPM2B               *bIn                // IN: 2B containing the data
    )
{
    // Only compute the digest if a pointer to the 2B is provided.
    // In CryptUpdateDigest(), if size is zero or buffer is NULL, then no change
    // to the digest occurs. This function should not provide a buffer if bIn is
    // not provided.
    if(bIn != NULL)
        CryptUpdateDigest(digestState, bIn->size, bIn->buffer);
    return;
}
//
//
//      10.2.4.10 CryptUpdateDigestInt()
//
//      This function is used to include an integer value to a hash stack. The function marshals the integer into its
//      canonical form before calling CryptUpdateHash().
//
LIB_EXPORT void
CryptUpdateDigestInt(
    void                *state,             // IN: the state of hash stack
    UINT32               intSize,           // IN: the size of 'intValue' in byte
    void                *intValue           // IN: integer value to be hashed
    )
{
#if BIG_ENDIAN_TPM == YES
   pAssert(    intValue != NULL && (intSize == 1 || intSize == 2
           || intSize == 4 || intSize == 8));
   CryptUpdateHash(state, inSize, (BYTE *)intValue);
#else
    BYTE        marshalBuffer[8];
    // Point to the big end of an little-endian value
    BYTE        *p = &((BYTE *)intValue)[intSize - 1];
    // Point to the big end of an big-endian value
    BYTE        *q = marshalBuffer;
    pAssert(intValue != NULL);
    switch (intSize)
    {
    case 8:
        *q++ = *p--;
        *q++ = *p--;
        *q++ = *p--;
        *q++ = *p--;
    case 4:
        *q++ = *p--;
         *q++ = *p--;
     case 2:
         *q++ = *p--;
     case 1:
         *q = *p;
         // Call update the hash
         CryptUpdateDigest(state, intSize, marshalBuffer);
         break;
     default:
         FAIL(0);
     }
#endif
   return;
}
//
//
//      10.2.4.11 CryptCompleteHash()
//
//      This function completes a hash sequence and returns the digest.
//      This function can be called to complete either an HMAC or hash sequence. The state type determines if
//      the context type is a hash or HMAC. If an HMAC, then the call is forwarded to CryptCompleteHash().
//      If digestSize is smaller than the digest size of hash/HMAC algorithm, the most significant bytes of
//      required size will be returned
//
//      Return Value                     Meaning
//
//      >=0                              the number of bytes placed in digest
//
LIB_EXPORT UINT16
CryptCompleteHash(
     void               *state,             // IN: the state of hash stack
     UINT16              digestSize,        // IN: size of digest buffer
     BYTE               *digest             // OUT: hash digest
     )
{
     HASH_STATE         *hashState = (HASH_STATE *)state;              // local value
     // If the session type is HMAC, then could forward this to
     // the HMAC processing and not cause an error. However, if no
     // function calls this routine to forward it, then we can't get
     // test coverage. The decision is to assert if this is called with
     // the type == HMAC and fix anything that makes the wrong call.
     pAssert(hashState->type == HASH_STATE_HASH);
     // Set the state to empty so that it doesn't get used again
     hashState->type = HASH_STATE_EMPTY;
     // Call crypto engine complete hash function
     return     _cpri__CompleteHash(&hashState->state, digestSize, digest);
}
//
//
//      10.2.4.12 CryptCompleteHash2B()
//
//      This function is the same as CypteCompleteHash() but the digest is placed in a TPM2B. This is the most
//      common use and this is provided for specification clarity. 'digest.size' should be set to indicate the number
//      of bytes to place in the buffer
//
//
//
//
//      Return Value                      Meaning
//
//      >=0                               the number of bytes placed in 'digest.buffer'
//
LIB_EXPORT UINT16
CryptCompleteHash2B(
     void               *state,               // IN: the state of hash stack
     TPM2B              *digest               // IN: the size of the buffer Out: requested
                                              //     number of byte
     )
{
     UINT16                  retVal = 0;
     if(digest != NULL)
         retVal = CryptCompleteHash(state, digest->size, digest->buffer);
     return retVal;
}
//
//
//      10.2.4.13 CryptHashBlock()
//
//      Hash a block of data and return the results. If the digest is larger than retSize, it is truncated and with the
//      least significant octets dropped.
//
//      Return Value                      Meaning
//
//      >=0                               the number of bytes placed in ret
//
LIB_EXPORT UINT16
CryptHashBlock(
     TPM_ALG_ID          algId,               //   IN: the hash algorithm to use
     UINT16              blockSize,           //   IN: size of the data block
     BYTE               *block,               //   IN: address of the block to hash
     UINT16              retSize,             //   IN: size of the return buffer
     BYTE               *ret                  //   OUT: address of the buffer
     )
{
     TEST_HASH(algId);
     return _cpri__HashBlock(algId, blockSize, block, retSize, ret);
}
//
//
//      10.2.4.14 CryptCompleteHMAC()
//
//      This function completes a HMAC sequence and returns the digest. If digestSize is smaller than the digest
//      size of the HMAC algorithm, the most significant bytes of required size will be returned.
//
//      Return Value                      Meaning
//
//      >=0                               the number of bytes placed in digest
//
LIB_EXPORT UINT16
CryptCompleteHMAC(
     HMAC_STATE         *hmacState,           // IN: the state of HMAC stack
     UINT32              digestSize,          // IN: size of digest buffer
     BYTE               *digest               // OUT: HMAC digest
     )
{
     HASH_STATE         *hashState;
     pAssert(hmacState != NULL);
     hashState = &hmacState->hashState;
     pAssert(hashState->type == HASH_STATE_HMAC);
     hashState->type = HASH_STATE_EMPTY;
     return _cpri__CompleteHMAC(&hashState->state, &hmacState->hmacKey.b,
                                digestSize, digest);
}
//
//
//      10.2.4.15 CryptCompleteHMAC2B()
//
//      This function is the same as CryptCompleteHMAC() but the HMAC result is returned in a TPM2B which is
//      the most common use.
//
//      Return Value                     Meaning
//
//      >=0                              the number of bytes placed in digest
//
LIB_EXPORT UINT16
CryptCompleteHMAC2B(
     HMAC_STATE         *hmacState,           // IN: the state of HMAC stack
     TPM2B              *digest               // OUT: HMAC
     )
{
     UINT16               retVal = 0;
     if(digest != NULL)
         retVal = CryptCompleteHMAC(hmacState, digest->size, digest->buffer);
     return retVal;
}
//
//
//      10.2.4.16 CryptHashStateImportExport()
//
//      This function is used to prepare a hash state context for LIB_EXPORT or to import it into the internal
//      format. It is used by TPM2_ContextSave() and TPM2_ContextLoad() via SequenceDataImportExport().
//      This is just a pass-through function to the crypto library.
//
void
CryptHashStateImportExport(
     HASH_STATE         *internalFmt,         // IN: state to LIB_EXPORT
     HASH_STATE         *externalFmt,         // OUT: exported state
     IMPORT_EXPORT       direction
     )
{
     _cpri__ImportExportHashState(&internalFmt->state,
                                  (EXPORT_HASH_STATE *)&externalFmt->state,
                                  direction);
}
//
//
//      10.2.4.17 CryptGetHashDigestSize()
//
//      This function returns the digest size in bytes for a hash algorithm.
//
//      Return Value                     Meaning
//
//      0                                digest size for TPM_ALG_NULL
//      >0                               digest size
//
LIB_EXPORT UINT16
CryptGetHashDigestSize(
    TPM_ALG_ID           hashAlg              // IN: hash algorithm
    )
{
    return _cpri__GetDigestSize(hashAlg);
}
//
//
//      10.2.4.18 CryptGetHashBlockSize()
//
//      Get the digest size in byte of a hash algorithm.
//
//      Return Value                      Meaning
//
//      0                                 block size for TPM_ALG_NULL
//      >0                                block size
//
LIB_EXPORT UINT16
CryptGetHashBlockSize(
    TPM_ALG_ID           hash                 // IN: hash algorithm to look up
    )
{
    return _cpri__GetHashBlockSize(hash);
}
//
//
//      10.2.4.19 CryptGetHashAlgByIndex()
//
//      This function is used to iterate through the hashes. TPM_ALG_NULL is returned for all indexes that are
//      not valid hashes. If the TPM implements 3 hashes, then an index value of 0 will return the first
//      implemented hash and an index value of 2 will return the last implemented hash. All other index values
//      will return TPM_ALG_NULL.
//
//      Return Value                      Meaning
//
//      TPM_ALG_xxx()                     a hash algorithm
//      TPM_ALG_NULL                      this can be used as a stop value
//
LIB_EXPORT TPM_ALG_ID
CryptGetHashAlgByIndex(
    UINT32               index                // IN: the index
    )
{
    return _cpri__GetHashAlgByIndex(index);
}
//
//
//      10.2.4.20 CryptSignHMAC()
//
//      Sign a digest using an HMAC key. This an HMAC of a digest, not an HMAC of a message.
//
//      Error Returns                     Meaning
//
static TPM_RC
CryptSignHMAC(
    OBJECT                   *signKey,              //   IN: HMAC key sign the hash
    TPMT_SIG_SCHEME          *scheme,               //   IN: signing scheme
    TPM2B_DIGEST             *hashData,             //   IN: hash to be signed
    TPMT_SIGNATURE           *signature             //   OUT: signature
    )
{
//
   HMAC_STATE           hmacState;
   UINT32               digestSize;
   // HMAC algorithm self testing code may be inserted here
   digestSize = CryptStartHMAC2B(scheme->details.hmac.hashAlg,
                                 &signKey->sensitive.sensitive.bits.b,
                                 &hmacState);
   // The hash algorithm must be a valid one.
   pAssert(digestSize > 0);
   CryptUpdateDigest2B(&hmacState, &hashData->b);
   CryptCompleteHMAC(&hmacState, digestSize,
                     (BYTE *) &signature->signature.hmac.digest);
   // Set HMAC algorithm
   signature->signature.hmac.hashAlg = scheme->details.hmac.hashAlg;
   return TPM_RC_SUCCESS;
}
//
//
//      10.2.4.21 CryptHMACVerifySignature()
//
//      This function will verify a signature signed by a HMAC key.
//
//      Error Returns                   Meaning
//
//      TPM_RC_SIGNATURE                if invalid input or signature is not genuine
//
static TPM_RC
CryptHMACVerifySignature(
   OBJECT              *signKey,            // IN: HMAC key signed the hash
   TPM2B_DIGEST        *hashData,           // IN: digest being verified
   TPMT_SIGNATURE      *signature           // IN: signature to be verified
   )
{
   HMAC_STATE                hmacState;
   TPM2B_DIGEST              digestToCompare;
   digestToCompare.t.size = CryptStartHMAC2B(signature->signature.hmac.hashAlg,
                            &signKey->sensitive.sensitive.bits.b, &hmacState);
   CryptUpdateDigest2B(&hmacState, &hashData->b);
   CryptCompleteHMAC2B(&hmacState, &digestToCompare.b);
   // Compare digest
   if(MemoryEqual(digestToCompare.t.buffer,
                  (BYTE *) &signature->signature.hmac.digest,
                  digestToCompare.t.size))
       return TPM_RC_SUCCESS;
   else
       return TPM_RC_SIGNATURE;
}
//
//
//      10.2.4.22 CryptGenerateKeyedHash()
//
//      This function creates a keyedHash object.
//
//
//
//      Error Returns                     Meaning
//
//      TPM_RC_SIZE                       sensitive data size is larger than allowed for the scheme
//      TPM_RC_VALUE                      the publicArea nameAlg is invalid
//
static TPM_RC
CryptGenerateKeyedHash(
   TPMT_PUBLIC                    *publicArea,                //   IN/OUT: the public area template
                                                              //       for the new key.
   TPMS_SENSITIVE_CREATE          *sensitiveCreate,           //   IN: sensitive creation data
   TPMT_SENSITIVE                 *sensitive,                 //   OUT: sensitive area
   TPM_ALG_ID                      kdfHashAlg,                //   IN: algorithm for the KDF
   TPM2B_SEED                     *seed,                      //   IN: the seed
   TPM2B_NAME                     *name                       //   IN: name of the object
   )
{
   TPMT_KEYEDHASH_SCHEME          *scheme;
   TPM_ALG_ID                      hashAlg;
   UINT16                          hashBlockSize;
   // Check parameter values
   if(publicArea->nameAlg == TPM_ALG_NULL)
   {
       return TPM_RC_VALUE;
   }
   scheme = &publicArea->parameters.keyedHashDetail.scheme;
   pAssert(publicArea->type == TPM_ALG_KEYEDHASH);
   // Pick the limiting hash algorithm
   if(scheme->scheme == TPM_ALG_NULL)
       hashAlg = publicArea->nameAlg;
   else if(scheme->scheme == TPM_ALG_XOR)
       hashAlg = scheme->details.xor_.hashAlg;
   else
       hashAlg = scheme->details.hmac.hashAlg;
   hashBlockSize = CryptGetHashBlockSize(hashAlg);
   // if this is a signing or a decryption key, then then the limit
   // for the data size is the block size of the hash. This limit
   // is set because larger values have lower entropy because of the
   // HMAC function.
   if(publicArea->objectAttributes.sensitiveDataOrigin == CLEAR)
   {
       if(    (    publicArea->objectAttributes.decrypt
                || publicArea->objectAttributes.sign)
           && sensitiveCreate->data.t.size > hashBlockSize)
           return TPM_RC_SIZE;
   }
   else
   {
       // If the TPM is going to generate the data, then set the size to be the
       // size of the digest of the algorithm
       sensitive->sensitive.sym.t.size = CryptGetHashDigestSize(hashAlg);
       sensitiveCreate->data.t.size = 0;
   }
   // Fill in the sensitive area
   CryptGenerateNewSymmetric(sensitiveCreate, sensitive, kdfHashAlg,
                             seed, name);
   // Create unique area in public
   CryptComputeSymmetricUnique(publicArea->nameAlg,
                               sensitive, &publicArea->unique.sym);
   return TPM_RC_SUCCESS;
}
//
//
//      10.2.4.25 KDFa()
//
//      This function is used by functions outside of CryptUtil() to access _cpri_KDFa().
//
void
KDFa(
   TPM_ALG_ID           hash,              //   IN: hash algorithm used in HMAC
   TPM2B               *key,               //   IN: HMAC key
   const char          *label,             //   IN: a null-terminated label for KDF
   TPM2B               *contextU,          //   IN: context U
   TPM2B               *contextV,          //   IN: context V
   UINT32               sizeInBits,        //   IN: size of generated key in bit
   BYTE                *keyStream,         //   OUT: key buffer
   UINT32              *counterInOut       //   IN/OUT: caller may provide the iteration
                                           //       counter for incremental operations to
                                           //       avoid large intermediate buffers.
   )
{
   CryptKDFa(hash, key, label, contextU, contextV, sizeInBits,
             keyStream, counterInOut);
}
#endif //TPM_ALG_KEYEDHASH     //% 1
//
//
//      10.2.5     RSA Functions
//
//      10.2.5.1    BuildRSA()
//
//      Function to set the cryptographic elements of an RSA key into a structure to simplify the interface to
//      _cpri__ RSA function. This can/should be eliminated by building this structure into the object structure.
//
#ifdef TPM_ALG_RSA                 //% 2
static void
BuildRSA(
   OBJECT              *rsaKey,
   RSA_KEY             *key
   )
{
   key->exponent = rsaKey->publicArea.parameters.rsaDetail.exponent;
   if(key->exponent == 0)
       key->exponent = RSA_DEFAULT_PUBLIC_EXPONENT;
   key->publicKey = &rsaKey->publicArea.unique.rsa.b;
   if(rsaKey->attributes.publicOnly || rsaKey->privateExponent.t.size == 0)
       key->privateKey = NULL;
   else
       key->privateKey = &(rsaKey->privateExponent.b);
}
//
//
//      10.2.5.2    CryptTestKeyRSA()
//
//      This function provides the interface to _cpri__TestKeyRSA(). If both p and q are provided, n will be set to
//      p*q.
//      If only p is provided, q is computed by q = n/p. If n mod p != 0, TPM_RC_BINDING is returned.
//      The key is validated by checking that a d can be found such that e d mod ((p-1)*(q-1)) = 1. If d is found
//      that satisfies this requirement, it will be placed in d.
//      Page 286                                     TCG Published                                   Family "2.0"
//      October 30, 2014                     Copyright © TCG 2006-2014                  Level 00 Revision 01.16
//      Part 4: Supporting Routines                                                    Trusted Platform Module Library
//
//
//      Error Returns                   Meaning
//
//      TPM_RC_BINDING                  the public and private portions of the key are not matched
//
TPM_RC
CryptTestKeyRSA(
   TPM2B              *d,                   //   OUT: receives the private exponent
   UINT32              e,                   //   IN: public exponent
   TPM2B              *n,                   //   IN/OUT: public modulu
   TPM2B              *p,                   //   IN: a first prime
   TPM2B              *q                    //   IN: an optional second prime
   )
{
   CRYPT_RESULT       retVal;
   TEST(ALG_NULL_VALUE);
   pAssert(d != NULL && n != NULL && p != NULL);
   // Set the exponent
   if(e == 0)
       e = RSA_DEFAULT_PUBLIC_EXPONENT;
   // CRYPT_PARAMETER
   retVal =_cpri__TestKeyRSA(d, e, n, p, q);
   if(retVal == CRYPT_SUCCESS)
       return TPM_RC_SUCCESS;
   else
       return TPM_RC_BINDING; // convert CRYPT_PARAMETER
}
//
//
//      10.2.5.3   CryptGenerateKeyRSA()
//
//      This function is called to generate an RSA key from a provided seed. It calls _cpri__GenerateKeyRSA()
//      to perform the computations. The implementation is vendor specific.
//
//      Error Returns                   Meaning
//
//      TPM_RC_RANGE                    the exponent value is not supported
//      TPM_RC_CANCELLED                key generation has been canceled
//      TPM_RC_VALUE                    exponent is not prime or is less than 3; or could not find a prime using
//                                      the provided parameters
//
static TPM_RC
CryptGenerateKeyRSA(
   TPMT_PUBLIC               *publicArea,              //   IN/OUT: The public area template for
                                                       //        the new key. The public key
                                                       //        area will be replaced by the
                                                       //        product of two primes found by
                                                       //        this function
   TPMT_SENSITIVE            *sensitive,               //   OUT: the sensitive area will be
                                                       //        updated to contain the first
                                                       //        prime and the symmetric
                                                       //        encryption key
   TPM_ALG_ID                 hashAlg,                 //   IN: the hash algorithm for the KDF
   TPM2B_SEED                *seed,                    //   IN: Seed for the creation
   TPM2B_NAME                *name,                    //   IN: Object name
   UINT32                    *counter                  //   OUT: last iteration of the counter
)
{
   CRYPT_RESULT       retVal;
   UINT32             exponent = publicArea->parameters.rsaDetail.exponent;
   TEST_HASH(hashAlg);
   TEST(ALG_NULL_VALUE);
   // In this implementation, only the default exponent is allowed
   if(exponent != 0 && exponent != RSA_DEFAULT_PUBLIC_EXPONENT)
       return TPM_RC_RANGE;
   exponent = RSA_DEFAULT_PUBLIC_EXPONENT;
   *counter = 0;
   // _cpri_GenerateKeyRSA can return CRYPT_CANCEL or CRYPT_FAIL
   retVal = _cpri__GenerateKeyRSA(&publicArea->unique.rsa.b,
                                  &sensitive->sensitive.rsa.b,
                                  publicArea->parameters.rsaDetail.keyBits,
                                  exponent,
                                  hashAlg,
                                  &seed->b,
                                  "RSA key by vendor",
                                  &name->b,
                                  counter);
   // CRYPT_CANCEL -> TPM_RC_CANCELLED; CRYPT_FAIL -> TPM_RC_VALUE
   return TranslateCryptErrors(retVal);
}
//
//
//      10.2.5.4    CryptLoadPrivateRSA()
//
//      This function is called to generate the private exponent of an RSA key. It uses CryptTestKeyRSA().
//
//      Error Returns                     Meaning
//
//      TPM_RC_BINDING                    public and private parts of rsaKey are not matched
//
TPM_RC
CryptLoadPrivateRSA(
   OBJECT              *rsaKey               // IN: the RSA key object
   )
{
   TPM_RC               result;
   TPMT_PUBLIC         *publicArea = &rsaKey->publicArea;
   TPMT_SENSITIVE      *sensitive = &rsaKey->sensitive;
   // Load key by computing the private exponent
   // TPM_RC_BINDING
   result = CryptTestKeyRSA(&(rsaKey->privateExponent.b),
                            publicArea->parameters.rsaDetail.exponent,
                            &(publicArea->unique.rsa.b),
                            &(sensitive->sensitive.rsa.b),
                            NULL);
   if(result == TPM_RC_SUCCESS)
       rsaKey->attributes.privateExp = SET;
   return result;
}
//
//
//      10.2.5.5    CryptSelectRSAScheme()
//
//      This function is used by TPM2_RSA_Decrypt() and TPM2_RSA_Encrypt(). It sets up the rules to select a
//      scheme between input and object default. This function assume the RSA object is loaded. If a default
//      scheme is defined in object, the default scheme should be chosen, otherwise, the input scheme should
//      be chosen. In the case that both the object and scheme are not TPM_ALG_NULL, then if the schemes
//
//
//      are the same, the input scheme will be chosen. if the scheme are not compatible, a NULL pointer will be
//      returned.
//      The return pointer may point to a TPM_ALG_NULL scheme.
//
TPMT_RSA_DECRYPT*
CryptSelectRSAScheme(
   TPMI_DH_OBJECT             rsaHandle,         // IN: handle of sign key
   TPMT_RSA_DECRYPT          *scheme             // IN: a sign or decrypt scheme
   )
{
   OBJECT                    *rsaObject;
   TPMT_ASYM_SCHEME          *keyScheme;
   TPMT_RSA_DECRYPT          *retVal = NULL;
   // Get sign object pointer
   rsaObject = ObjectGet(rsaHandle);
   keyScheme = &rsaObject->publicArea.parameters.asymDetail.scheme;
   // if the default scheme of the object is TPM_ALG_NULL, then select the
   // input scheme
   if(keyScheme->scheme == TPM_ALG_NULL)
   {
       retVal = scheme;
   }
   // if the object scheme is not TPM_ALG_NULL and the input scheme is
   // TPM_ALG_NULL, then select the default scheme of the object.
   else if(scheme->scheme == TPM_ALG_NULL)
   {
       // if input scheme is NULL
       retVal = (TPMT_RSA_DECRYPT *)keyScheme;
   }
   // get here if both the object scheme and the input scheme are
   // not TPM_ALG_NULL. Need to insure that they are the same.
   // The hash algorithm match has to be verified for OAEP.
   // IMPLEMENTATION NOTE: This could cause problems if future versions have
   // schemes that have more values than just a hash algorithm. A new function
   // (IsSchemeSame()) might be needed then.
   else if (keyScheme->scheme == scheme->scheme
            && ((keyScheme->scheme != TPM_ALG_OAEP) ||
                (keyScheme->details.anySig.hashAlg == scheme->details.anySig.hashAlg)))
   {
       retVal = scheme;
   }
   // two different, incompatible schemes specified will return NULL
   return retVal;
}
//
//
//      10.2.5.6    CryptDecryptRSA()
//
//      This function is the interface to _cpri__DecryptRSA(). It handles the return codes from that function and
//      converts them from CRYPT_RESULT to TPM_RC values. The rsaKey parameter must reference an RSA
//      decryption key
//
//      Error Returns                   Meaning
//
//      TPM_RC_BINDING                  Public and private parts of the key are not cryptographically bound.
//      TPM_RC_SIZE                     Size of data to decrypt is not the same as the key size.
//      TPM_RC_VALUE                    Numeric value of the encrypted data is greater than the public
//                                      exponent, or output buffer is too small for the decrypted message.
//
TPM_RC
CryptDecryptRSA(
   UINT16                    *dataOutSize,       // OUT: size of plain text in byte
   BYTE                    *dataOut,        //   OUT: plain text
   OBJECT                  *rsaKey,         //   IN: internal RSA key
   TPMT_RSA_DECRYPT        *scheme,         //   IN: selects the padding scheme
   UINT16                   cipherInSize,   //   IN: size of cipher text in byte
   BYTE                    *cipherIn,       //   IN: cipher text
   const char              *label           //   IN: a label, when needed
   )
{
   RSA_KEY            key;
   CRYPT_RESULT       retVal = CRYPT_SUCCESS;
   UINT32             dSize;                   //   Place to put temporary value for the
                                               //   returned data size
   TPMI_ALG_HASH      hashAlg = TPM_ALG_NULL; //    hash algorithm in the selected
                                               //   padding scheme
   TPM_RC             result = TPM_RC_SUCCESS;
   // pointer checks
   pAssert(    (dataOutSize != NULL) && (dataOut != NULL)
           && (rsaKey != NULL) && (cipherIn != NULL));
   // The public type is a RSA decrypt key
   pAssert(    (rsaKey->publicArea.type == TPM_ALG_RSA
           && rsaKey->publicArea.objectAttributes.decrypt == SET));
   // Must have the private portion loaded. This check is made before this
   // function is called.
   pAssert(rsaKey->attributes.publicOnly == CLEAR);
   // decryption requires that the private modulus be present
   if(rsaKey->attributes.privateExp == CLEAR)
   {
        // Load key by computing the private exponent
        // CryptLoadPrivateRSA may return TPM_RC_BINDING
        result = CryptLoadPrivateRSA(rsaKey);
   }
   // the input buffer must be the size of the key
   if(result == TPM_RC_SUCCESS)
   {
       if(cipherInSize != rsaKey->publicArea.unique.rsa.t.size)
            result = TPM_RC_SIZE;
       else
       {
            BuildRSA(rsaKey, &key);
             // Initialize the dOutSize parameter
             dSize = *dataOutSize;
             // For OAEP scheme, initialize the hash algorithm for padding
             if(scheme->scheme == TPM_ALG_OAEP)
             {
                 hashAlg = scheme->details.oaep.hashAlg;
                 TEST_HASH(hashAlg);
             }
             // See if the padding mode needs to be tested
             TEST(scheme->scheme);
             // _cpri__DecryptRSA may return CRYPT_PARAMETER CRYPT_FAIL CRYPT_SCHEME
             retVal = _cpri__DecryptRSA(&dSize, dataOut, &key, scheme->scheme,
                                        cipherInSize, cipherIn, hashAlg, label);
             // Scheme must have been validated when the key was loaded/imported
             pAssert(retVal != CRYPT_SCHEME);
             // Set the return size
               pAssert(dSize <= UINT16_MAX);
               *dataOutSize = (UINT16)dSize;
               // CRYPT_PARAMETER -> TPM_RC_VALUE, CRYPT_FAIL -> TPM_RC_VALUE
               result = TranslateCryptErrors(retVal);
       }
   }
   return result;
}
//
//
//      10.2.5.7   CryptEncryptRSA()
//
//      This function provides the interface to _cpri__EncryptRSA(). The object referenced by rsaKey is required
//      to be an RSA decryption key.
//
//      Error Returns                   Meaning
//
//      TPM_RC_SCHEME                   scheme is not supported
//      TPM_RC_VALUE                    numeric value of dataIn is greater than the key modulus
//
TPM_RC
CryptEncryptRSA(
   UINT16                    *cipherOutSize,    //   OUT: size of cipher text in byte
   BYTE                      *cipherOut,        //   OUT: cipher text
   OBJECT                    *rsaKey,           //   IN: internal RSA key
   TPMT_RSA_DECRYPT          *scheme,           //   IN: selects the padding scheme
   UINT16                     dataInSize,       //   IN: size of plain text in byte
   BYTE                      *dataIn,           //   IN: plain text
   const char                *label             //   IN: an optional label
   )
{
   RSA_KEY                    key;
   CRYPT_RESULT               retVal;
   UINT32                     cOutSize;                         // Conversion variable
   TPMI_ALG_HASH              hashAlg = TPM_ALG_NULL;           // hash algorithm in selected
                                                                // padding scheme
   // must have a pointer to a key and some data to encrypt
   pAssert(rsaKey != NULL && dataIn != NULL);
   // The public type is a RSA decryption key
   pAssert(   rsaKey->publicArea.type == TPM_ALG_RSA
           && rsaKey->publicArea.objectAttributes.decrypt == SET);
   // If the cipher buffer must be provided and it must be large enough
   // for the result
   pAssert(   cipherOut != NULL
           && cipherOutSize != NULL
           && *cipherOutSize >= rsaKey->publicArea.unique.rsa.t.size);
   // Only need the public key and exponent for encryption
   BuildRSA(rsaKey, &key);
   // Copy the size to the conversion buffer
   cOutSize = *cipherOutSize;
   // For OAEP scheme, initialize the hash algorithm for padding
   if(scheme->scheme == TPM_ALG_OAEP)
   {
       hashAlg = scheme->details.oaep.hashAlg;
       TEST_HASH(hashAlg);
   }
   // This is a public key operation and does not require that the private key
   // be loaded. To verify this, need to do the full algorithm
   TEST(scheme->scheme);
   // Encrypt the data with the public exponent
   // _cpri__EncryptRSA may return CRYPT_PARAMETER or CRYPT_SCHEME
   retVal = _cpri__EncryptRSA(&cOutSize,cipherOut, &key, scheme->scheme,
                              dataInSize, dataIn, hashAlg, label);
   pAssert (cOutSize <= UINT16_MAX);
   *cipherOutSize = (UINT16)cOutSize;
   // CRYPT_PARAMETER -> TPM_RC_VALUE, CRYPT_SCHEME -> TPM_RC_SCHEME
   return TranslateCryptErrors(retVal);
}
//
//
//      10.2.5.8     CryptSignRSA()
//
//      This function is used to sign a digest with an RSA signing key.
//
//      Error Returns                     Meaning
//
//      TPM_RC_BINDING                    public and private part of signKey are not properly bound
//      TPM_RC_SCHEME                     scheme is not supported
//      TPM_RC_VALUE                      hashData is larger than the modulus of signKey, or the size of
//                                        hashData does not match hash algorithm in scheme
//
static TPM_RC
CryptSignRSA(
   OBJECT                   *signKey,              //   IN: RSA key signs the hash
   TPMT_SIG_SCHEME          *scheme,               //   IN: sign scheme
   TPM2B_DIGEST             *hashData,             //   IN: hash to be signed
   TPMT_SIGNATURE           *sig                   //   OUT: signature
   )
{
   UINT32                     signSize;
   RSA_KEY                    key;
   CRYPT_RESULT               retVal;
   TPM_RC                     result = TPM_RC_SUCCESS;
   pAssert(       (signKey != NULL) && (scheme != NULL)
                  && (hashData != NULL) && (sig != NULL));
   // assume that the key has private part loaded and that it is a signing key.
   pAssert(   (signKey->attributes.publicOnly == CLEAR)
           && (signKey->publicArea.objectAttributes.sign == SET));
   // check if the private exponent has been computed
   if(signKey->attributes.privateExp == CLEAR)
       // May return TPM_RC_BINDING
       result = CryptLoadPrivateRSA(signKey);
   if(result == TPM_RC_SUCCESS)
   {
       BuildRSA(signKey, &key);
          // Make sure that the hash is tested
          TEST_HASH(sig->signature.any.hashAlg);
          // Run a test of the RSA sign
          TEST(scheme->scheme);
          // _crypi__SignRSA can return CRYPT_SCHEME and CRYPT_PARAMETER
          retVal = _cpri__SignRSA(&signSize,
                                  sig->signature.rsassa.sig.t.buffer,
                                  &key,
                                  sig->sigAlg,
                                  sig->signature.any.hashAlg,
                                  hashData->t.size, hashData->t.buffer);
          pAssert(signSize <= UINT16_MAX);
          sig->signature.rsassa.sig.t.size = (UINT16)signSize;
          // CRYPT_SCHEME -> TPM_RC_SCHEME; CRYPT_PARAMTER -> TPM_RC_VALUE
          result = TranslateCryptErrors(retVal);
   }
   return result;
}
//
//
//      10.2.5.9    CryptRSAVerifySignature()
//
//      This function is used to verify signature signed by a RSA key.
//
//      Error Returns                   Meaning
//
//      TPM_RC_SIGNATURE                if signature is not genuine
//      TPM_RC_SCHEME                   signature scheme not supported
//
static TPM_RC
CryptRSAVerifySignature(
   OBJECT              *signKey,            // IN: RSA key signed the hash
   TPM2B_DIGEST        *digestData,         // IN: digest being signed
   TPMT_SIGNATURE      *sig                 // IN: signature to be verified
   )
{
   RSA_KEY                   key;
   CRYPT_RESULT              retVal;
   TPM_RC                    result;
   // Validate parameter assumptions
   pAssert((signKey != NULL) && (digestData != NULL) && (sig != NULL));
   TEST_HASH(sig->signature.any.hashAlg);
   TEST(sig->sigAlg);
   // This is a public-key-only operation
   BuildRSA(signKey, &key);
   // Call crypto engine to verify signature
   // _cpri_ValidateSignaturRSA may return CRYPT_FAIL or CRYPT_SCHEME
   retVal = _cpri__ValidateSignatureRSA(&key,
                                        sig->sigAlg,
                                        sig->signature.any.hashAlg,
                                        digestData->t.size,
                                        digestData->t.buffer,
                                        sig->signature.rsassa.sig.t.size,
                                        sig->signature.rsassa.sig.t.buffer,
                                        0);
   // _cpri__ValidateSignatureRSA can return CRYPT_SUCCESS, CRYPT_FAIL, or
   // CRYPT_SCHEME. Translate CRYPT_FAIL to TPM_RC_SIGNATURE
   if(retVal == CRYPT_FAIL)
       result = TPM_RC_SIGNATURE;
   else
       // CRYPT_SCHEME -> TPM_RC_SCHEME
       result = TranslateCryptErrors(retVal);
   return result;
}
//
#endif //TPM_ALG_RSA             //% 2
//
//
//      10.2.6     ECC Functions
//
//      10.2.6.1    CryptEccGetCurveDataPointer()
//
//      This function returns a pointer to an ECC_CURVE_VALUES structure that contains the parameters for
//      the key size and schemes for a given curve.
//
#ifdef TPM_ALG_ECC //% 3
static const ECC_CURVE    *
CryptEccGetCurveDataPointer(
    TPM_ECC_CURVE        curveID             // IN: id of the curve
    )
{
    return _cpri__EccGetParametersByCurveId(curveID);
}
//
//
//      10.2.6.2    CryptEccGetKeySizeInBits()
//
//      This function returns the size in bits of the key associated with a curve.
//
UINT16
CryptEccGetKeySizeInBits(
    TPM_ECC_CURVE        curveID             // IN: id of the curve
    )
{
    const ECC_CURVE               *curve = CryptEccGetCurveDataPointer(curveID);
    UINT16                         keySizeInBits = 0;
    if(curve != NULL)
        keySizeInBits = curve->keySizeBits;
    return keySizeInBits;
}
//
//
//      10.2.6.4    CryptEccGetParameter()
//
//      This function returns a pointer to an ECC curve parameter. The parameter is selected by a single
//      character designator from the set of {pnabxyh}.
//
LIB_EXPORT const TPM2B *
CryptEccGetParameter(
    char                 p,                  // IN: the parameter selector
    TPM_ECC_CURVE        curveId             // IN: the curve id
    )
{
    const ECC_CURVE          *curve = _cpri__EccGetParametersByCurveId(curveId);
    const TPM2B              *parameter = NULL;
    if(curve != NULL)
    {
          switch (p)
          {
          case 'p':
              parameter    = curve->curveData->p;
              break;
          case 'n':
              parameter    =   curve->curveData->n;
              break;
          case 'a':
              parameter    =   curve->curveData->a;
              break;
          case 'b':
              parameter    =   curve->curveData->b;
              break;
          case 'x':
              parameter    =   curve->curveData->x;
              break;
          case 'y':
              parameter    =   curve->curveData->y;
              break;
          case 'h':
              parameter    =   curve->curveData->h;
              break;
          default:
              break;
          }
    }
    return parameter;
}
//
//
//       10.2.6.5    CryptGetCurveSignScheme()
//
//       This function will return a pointer to the scheme of the curve.
//
const TPMT_ECC_SCHEME *
CryptGetCurveSignScheme(
    TPM_ECC_CURVE         curveId            // IN: The curve selector
    )
{
    const ECC_CURVE               *curve = _cpri__EccGetParametersByCurveId(curveId);
    const TPMT_ECC_SCHEME         *scheme = NULL;
    if(curve != NULL)
        scheme = &(curve->sign);
    return scheme;
}
//
//
//       10.2.6.6    CryptEccIsPointOnCurve()
//
//       This function will validate that an ECC point is on the curve of given curveID.
//
//       Return Value                     Meaning
//
//       TRUE                             if the point is on curve
//       FALSE                            if the point is not on curve
//
BOOL
CryptEccIsPointOnCurve(
    TPM_ECC_CURVE        curveID,            // IN: ECC curve ID
    TPMS_ECC_POINT      *Q                   // IN: ECC point
    )
{
   // Make sure that point multiply is working
   TEST(TPM_ALG_ECC);
   // Check point on curve logic by seeing if the test key is on the curve
   // Call crypto engine function to check if a ECC public point is on the
   // given curve
   if(_cpri__EccIsPointOnCurve(curveID, Q))
       return TRUE;
   else
       return FALSE;
}
//
//
//       10.2.6.7    CryptNewEccKey()
//
//       This function creates a random ECC key that is not derived from other parameters as is a Primary Key.
//
TPM_RC
CryptNewEccKey(
   TPM_ECC_CURVE                    curveID,               // IN: ECC curve
   TPMS_ECC_POINT                  *publicPoint,           // OUT: public point
   TPM2B_ECC_PARAMETER             *sensitive              // OUT: private area
   )
{
   TPM_RC               result = TPM_RC_SUCCESS;
   // _cpri__GetEphemeralECC may return CRYPT_PARAMETER
   if(_cpri__GetEphemeralEcc(publicPoint, sensitive, curveID) != CRYPT_SUCCESS)
       // Something is wrong with the key.
       result = TPM_RC_KEY;
   return result;
}
//
//
//       10.2.6.8    CryptEccPointMultiply()
//
//       This function is used to perform a point multiply R = [d]Q. If Q is not provided, the multiplication is
//       performed using the generator point of the curve.
//
//       Error Returns                     Meaning
//
//       TPM_RC_ECC_POINT                  invalid optional ECC point pIn
//       TPM_RC_NO_RESULT                  multiplication resulted in a point at infinity
//       TPM_RC_CANCELED                   if a self-test was done, it might have been aborted
//
TPM_RC
CryptEccPointMultiply(
   TPMS_ECC_POINT                  *pOut,                  //   OUT: output point
   TPM_ECC_CURVE                    curveId,               //   IN: curve selector
   TPM2B_ECC_PARAMETER             *dIn,                   //   IN: public scalar
   TPMS_ECC_POINT                  *pIn                    //   IN: optional point
   )
{
   TPM2B_ECC_PARAMETER             *n = NULL;
   CRYPT_RESULT                    retVal;
   pAssert(pOut != NULL && dIn != NULL);
   if(pIn != NULL)
   {
       n = dIn;
       dIn = NULL;
   }
   // Do a test of point multiply
   TEST(TPM_ALG_ECC);
   // _cpri__EccPointMultiply may return CRYPT_POINT or CRYPT_NO_RESULT
   retVal = _cpri__EccPointMultiply(pOut, curveId, dIn, pIn, n);
   // CRYPT_POINT->TPM_RC_ECC_POINT and CRYPT_NO_RESULT->TPM_RC_NO_RESULT
   return TranslateCryptErrors(retVal);
}
//
//
//       10.2.6.9    CryptGenerateKeyECC()
//
//       This function generates an ECC key from a seed value.
//       The method here may not work for objects that have an order (G) that with a different size than a private
//       key.
//
//       Error Returns                   Meaning
//
//       TPM_RC_VALUE                    hash algorithm is not supported
//
static TPM_RC
CryptGenerateKeyECC(
   TPMT_PUBLIC         *publicArea,        //   IN/OUT: The public area template for the new
                                           //       key.
   TPMT_SENSITIVE      *sensitive,         //   IN/OUT: the sensitive area
   TPM_ALG_ID           hashAlg,           //   IN: algorithm for the KDF
   TPM2B_SEED          *seed,              //   IN: the seed value
   TPM2B_NAME          *name,              //   IN: the name of the object
   UINT32              *counter            //   OUT: the iteration counter
   )
{
   CRYPT_RESULT              retVal;
   TEST_HASH(hashAlg);
   TEST(ALG_ECDSA_VALUE); // ECDSA is used to verify each key
   // The iteration counter has no meaning for ECC key generation. The parameter
   // will be overloaded for those implementations that have a requirement for
   // doing pair-wise consistency checks on signing keys. If the counter parameter
   // is 0 or NULL, then no consistency check is done. If it is other than 0, then
   // a consistency check is run. This modification allow this code to work with
   // the existing versions of the CrytpoEngine and with FIPS-compliant versions
   // as well.
   *counter = (UINT32)(publicArea->objectAttributes.sign == SET);
   // _cpri__GenerateKeyEcc only has one error return (CRYPT_PARAMETER) which means
   // that the hash algorithm is not supported. This should not be possible
   retVal = _cpri__GenerateKeyEcc(&publicArea->unique.ecc,
                                  &sensitive->sensitive.ecc,
                                  publicArea->parameters.eccDetail.curveID,
                                  hashAlg, &seed->b, "ECC key by vendor",
                                  &name->b, counter);
   // This will only be useful if _cpri__GenerateKeyEcc return CRYPT_CANCEL
   return TranslateCryptErrors(retVal);
}
//
//
//       10.2.6.10 CryptSignECC()
//
//       This function is used for ECC signing operations. If the signing scheme is a split scheme, and the signing
//       operation is successful, the commit value is retired.
//
//
//       Error Returns                     Meaning
//
//       TPM_RC_SCHEME                     unsupported scheme
//       TPM_RC_VALUE                      invalid commit status (in case of a split scheme) or failed to generate
//                                         r value.
//
static TPM_RC
CryptSignECC(
   OBJECT                   *signKey,                //   IN: ECC key to sign the hash
   TPMT_SIG_SCHEME          *scheme,                 //   IN: sign scheme
   TPM2B_DIGEST             *hashData,               //   IN: hash to be signed
   TPMT_SIGNATURE           *signature               //   OUT: signature
   )
{
   TPM2B_ECC_PARAMETER              r;
   TPM2B_ECC_PARAMETER             *pr = NULL;
   CRYPT_RESULT                     retVal;
   // Run a test of the ECC sign and verify if it has not already been run
   TEST_HASH(scheme->details.any.hashAlg);
   TEST(scheme->scheme);
   if(CryptIsSplitSign(scheme->scheme))
   {
       // When this code was written, the only split scheme was ECDAA
       // (which can also be used for U-Prove).
       if(!CryptGenerateR(&r,
                          &scheme->details.ecdaa.count,
                          signKey->publicArea.parameters.eccDetail.curveID,
                          &signKey->name))
           return TPM_RC_VALUE;
       pr = &r;
   }
   // Call crypto engine function to sign
   // _cpri__SignEcc may return CRYPT_SCHEME
   retVal = _cpri__SignEcc(&signature->signature.ecdsa.signatureR,
                           &signature->signature.ecdsa.signatureS,
                           scheme->scheme,
                           scheme->details.any.hashAlg,
                           signKey->publicArea.parameters.eccDetail.curveID,
                           &signKey->sensitive.sensitive.ecc,
                           &hashData->b,
                           pr
                           );
   if(CryptIsSplitSign(scheme->scheme) && retVal == CRYPT_SUCCESS)
       CryptEndCommit(scheme->details.ecdaa.count);
   // CRYPT_SCHEME->TPM_RC_SCHEME
   return TranslateCryptErrors(retVal);
}
//
//
//       10.2.6.11 CryptECCVerifySignature()
//
//       This function is used to verify a signature created with an ECC key.
//
//       Error Returns                     Meaning
//
//       TPM_RC_SIGNATURE                  if signature is not valid
//       TPM_RC_SCHEME                     the signing scheme or hashAlg is not supported
//
static TPM_RC
CryptECCVerifySignature(
   OBJECT              *signKey,               // IN: ECC key signed the hash
   TPM2B_DIGEST        *digestData,       // IN: digest being signed
   TPMT_SIGNATURE      *signature         // IN: signature to be verified
   )
{
   CRYPT_RESULT              retVal;
   TEST_HASH(signature->signature.any.hashAlg);
   TEST(signature->sigAlg);
   // This implementation uses the fact that all the defined ECC signing
   // schemes have the hash as the first parameter.
   // _cpriValidateSignatureEcc may return CRYPT_FAIL or CRYP_SCHEME
   retVal = _cpri__ValidateSignatureEcc(&signature->signature.ecdsa.signatureR,
                                  &signature->signature.ecdsa.signatureS,
                                  signature->sigAlg,
                                  signature->signature.any.hashAlg,
                                  signKey->publicArea.parameters.eccDetail.curveID,
                                  &signKey->publicArea.unique.ecc,
                                  &digestData->b);
   if(retVal == CRYPT_FAIL)
       return TPM_RC_SIGNATURE;
   // CRYPT_SCHEME->TPM_RC_SCHEME
   return TranslateCryptErrors(retVal);
}
//
//
//       10.2.6.12 CryptGenerateR()
//
//       This function computes the commit random value for a split signing scheme.
//       If c is NULL, it indicates that r is being generated for TPM2_Commit(). If c is not NULL, the TPM will
//       validate that the gr.commitArray bit associated with the input value of c is SET. If not, the TPM returns
//       FALSE and no r value is generated.
//
//       Return Value                    Meaning
//
//       TRUE                            r value computed
//       FALSE                           no r value computed
//
BOOL
CryptGenerateR(
   TPM2B_ECC_PARAMETER           *r,                 //   OUT: the generated random value
   UINT16                        *c,                 //   IN/OUT: count value.
   TPMI_ECC_CURVE                 curveID,           //   IN: the curve for the value
   TPM2B_NAME                    *name               //   IN: optional name of a key to
                                                     //       associate with 'r'
   )
{
   // This holds the marshaled g_commitCounter.
   TPM2B_TYPE(8B, 8);
   TPM2B_8B                cntr = {.b.size = 8};
   UINT32                   iterations;
   const TPM2B             *n;
   UINT64                   currentCount = gr.commitCounter;
   // This is just to suppress a compiler warning about a conditional expression
   // being a constant. This is because of the macro expansion of ryptKDFa
   TPMI_ALG_HASH            hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
   n = CryptEccGetParameter('n', curveID);
   pAssert(r != NULL && n != NULL);
   // If this is the commit phase, use the current value of the commit counter
   if(c != NULL)
//
   {
        UINT16      t1;
        // if the array bit is not set, can't use the value.
        if(!BitIsSet((*c & COMMIT_INDEX_MASK), gr.commitArray,
                     sizeof(gr.commitArray)))
            return FALSE;
        //   If it is the sign phase, figure out what the counter value was
        //   when the commitment was made.
        //
        //   When gr.commitArray has less than 64K bits, the extra
        //   bits of 'c' are used as a check to make sure that the
        //   signing operation is not using an out of range count value
        t1   = (UINT16)currentCount;
        // If the lower bits of c are greater or equal to the lower bits of t1
        // then the upper bits of t1 must be one more than the upper bits
        // of c
        if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK))
            // Since the counter is behind, reduce the current count
            currentCount = currentCount - (COMMIT_INDEX_MASK + 1);
        t1 = (UINT16)currentCount;
        if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK))
            return FALSE;
        // set the counter to the value that was
        // present when the commitment was made
        currentCount = (currentCount & 0xffffffffffff0000) | *c;
   }
   // Marshal the count value to a TPM2B buffer for the KDF
   cntr.t.size = sizeof(currentCount);
   UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer);
   //   Now can do the KDF to create the random value for the signing operation
   //   During the creation process, we may generate an r that does not meet the
   //   requirements of the random value.
   //   want to generate a new r.
   r->t.size = n->size;
   // Arbitrary upper limit on the number of times that we can look for
   // a suitable random value. The normally number of tries will be 1.
   for(iterations = 1; iterations < 1000000;)
   {
       BYTE    *pr = &r->b.buffer[0];
       int     i;
       CryptKDFa(hashAlg, &gr.commitNonce.b, "ECDAA Commit",
                 name, &cntr.b, n->size * 8, r->t.buffer, &iterations);
        // random value must be less than the prime
        if(CryptCompare(r->b.size, r->b.buffer, n->size, n->buffer) >= 0)
            continue;
        // in this implementation it is required that at least bit
        // in the upper half of the number be set
        for(i = n->size/2; i > 0; i--)
            if(*pr++ != 0)
                return TRUE;
   }
   return FALSE;
}
//
//
//
//       10.2.6.13 CryptCommit()
//
//       This function is called when the count value is committed. The gr.commitArray value associated with the
//       current count value is SET and g_commitCounter is incremented. The low-order 16 bits of old value of the
//       counter is returned.
//
UINT16
CryptCommit(
   void
   )
{
   UINT16      oldCount = (UINT16)gr.commitCounter;
   gr.commitCounter++;
   BitSet(oldCount & COMMIT_INDEX_MASK, gr.commitArray, sizeof(gr.commitArray));
   return oldCount;
}
//
//
//       10.2.6.14 CryptEndCommit()
//
//       This function is called when the signing operation using the committed value is completed. It clears the
//       gr.commitArray bit associated with the count value so that it can't be used again.
//
void
CryptEndCommit(
   UINT16               c                    // IN: the counter value of the commitment
   )
{
   BitClear((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray));
}
//
//
//       10.2.6.15 CryptCommitCompute()
//
//       This function performs the computations for the TPM2_Commit() command. This could be a macro.
//
//       Error Returns                   Meaning
//
//       TPM_RC_NO_RESULT                K, L, or E is the point at infinity
//       TPM_RC_CANCELLED                command was canceled
//
TPM_RC
CryptCommitCompute(
   TPMS_ECC_POINT                *K,                     //   OUT: [d]B
   TPMS_ECC_POINT                *L,                     //   OUT: [r]B
   TPMS_ECC_POINT                *E,                     //   OUT: [r]M
   TPM_ECC_CURVE                  curveID,               //   IN: The curve for the computation
   TPMS_ECC_POINT                *M,                     //   IN: M (P1)
   TPMS_ECC_POINT                *B,                     //   IN: B (x2, y2)
   TPM2B_ECC_PARAMETER           *d,                     //   IN: the private scalar
   TPM2B_ECC_PARAMETER           *r                      //   IN: the computed r value
   )
{
   TEST(ALG_ECDH_VALUE);
   // CRYPT_NO_RESULT->TPM_RC_NO_RESULT CRYPT_CANCEL->TPM_RC_CANCELLED
   return TranslateCryptErrors(
              _cpri__EccCommitCompute(K, L , E, curveID, M, B, d, r));
}
//
//
//
//       10.2.6.16 CryptEccGetParameters()
//
//       This function returns the ECC parameter details of the given curve
//
//       Return Value                      Meaning
//
//       TRUE                              Get parameters success
//       FALSE                             Unsupported ECC curve ID
//
BOOL
CryptEccGetParameters(
   TPM_ECC_CURVE                        curveId,            // IN: ECC curve ID
   TPMS_ALGORITHM_DETAIL_ECC           *parameters          // OUT: ECC parameter
   )
{
   const ECC_CURVE                     *curve = _cpri__EccGetParametersByCurveId(curveId);
   const ECC_CURVE_DATA                *data;
   BOOL                                 found = curve != NULL;
   if(found)
   {
        data = curve->curveData;
        parameters->curveID = curve->curveId;
        // Key size in bit
        parameters->keySize = curve->keySizeBits;
        // KDF
        parameters->kdf = curve->kdf;
        // Sign
        parameters->sign = curve->sign;
        // Copy p value
        MemoryCopy2B(&parameters->p.b, data->p, sizeof(parameters->p.t.buffer));
        // Copy a value
        MemoryCopy2B(&parameters->a.b, data->a, sizeof(parameters->a.t.buffer));
        // Copy b value
        MemoryCopy2B(&parameters->b.b, data->b, sizeof(parameters->b.t.buffer));
        // Copy Gx value
        MemoryCopy2B(&parameters->gX.b, data->x, sizeof(parameters->gX.t.buffer));
        // Copy Gy value
        MemoryCopy2B(&parameters->gY.b, data->y, sizeof(parameters->gY.t.buffer));
        // Copy n value
        MemoryCopy2B(&parameters->n.b, data->n, sizeof(parameters->n.t.buffer));
        // Copy h value
        MemoryCopy2B(&parameters->h.b, data->h, sizeof(parameters->h.t.buffer));
   }
   return found;
}
#if CC_ZGen_2Phase == YES
//
//       CryptEcc2PhaseKeyExchange() This is the interface to the key exchange function.
//
TPM_RC
CryptEcc2PhaseKeyExchange(
   TPMS_ECC_POINT                *outZ1,            //   OUT: the computed point
   TPMS_ECC_POINT                *outZ2,            //   OUT: optional second point
   TPM_ALG_ID                     scheme,           //   IN: the key exchange scheme
   TPM_ECC_CURVE                  curveId,          //   IN: the curve for the computation
   TPM2B_ECC_PARAMETER           *dsA,              //   IN: static private TPM key
   TPM2B_ECC_PARAMETER           *deA,              //   IN: ephemeral private TPM key
   TPMS_ECC_POINT                *QsB,              //   IN: static public party B key
   TPMS_ECC_POINT                *QeB               //   IN: ephemeral public party B key
   )
{
   return (TranslateCryptErrors(_cpri__C_2_2_KeyExchange(outZ1,
                                                         outZ2,
                                                         scheme,
                                                         curveId,
                                                         dsA,
                                                         deA,
                                                         QsB,
                                                         QeB)));
}
#endif // CC_ZGen_2Phase
#endif //TPM_ALG_ECC //% 3
//
//
//       10.2.6.17 CryptIsSchemeAnonymous()
//
//       This function is used to test a scheme to see if it is an anonymous scheme The only anonymous scheme
//       is ECDAA. ECDAA can be used to do things like U-Prove.
//
BOOL
CryptIsSchemeAnonymous(
   TPM_ALG_ID           scheme            // IN: the scheme algorithm to test
   )
{
#ifdef TPM_ALG_ECDAA
   return (scheme == TPM_ALG_ECDAA);
#else
   UNREFERENCED(scheme);
   return 0;
#endif
}
//
//
//       10.2.7     Symmetric Functions
//
//       10.2.7.1    ParmDecryptSym()
//
//       This function performs parameter decryption using symmetric block cipher.
//
void
ParmDecryptSym(
   TPM_ALG_ID          symAlg,            //   IN: the symmetric algorithm
   TPM_ALG_ID          hash,              //   IN: hash algorithm for KDFa
   UINT16              keySizeInBits,     //   IN: key key size in bit
   TPM2B              *key,               //   IN: KDF HMAC key
   TPM2B              *nonceCaller,       //   IN: nonce caller
   TPM2B              *nonceTpm,          //   IN: nonce TPM
   UINT32              dataSize,          //   IN: size of parameter buffer
   BYTE               *data               //   OUT: buffer to be decrypted
   )
{
   // KDF output buffer
   // It contains parameters for the CFB encryption
   // From MSB to LSB, they are the key and iv
   BYTE             symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
   // Symmetric key size in byte
   UINT16           keySize = (keySizeInBits + 7) / 8;
   TPM2B_IV         iv;
   iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits);
   // If there is decryption to do...
   if(iv.t.size > 0)
   {
       // Generate key and iv
       CryptKDFa(hash, key, "CFB", nonceCaller, nonceTpm,
                 keySizeInBits + (iv.t.size * 8), symParmString, NULL);
       MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size,
                  sizeof(iv.t.buffer));
          CryptSymmetricDecrypt(data, symAlg, keySizeInBits, TPM_ALG_CFB,
                                symParmString, &iv, dataSize, data);
   }
   return;
}
//
//
//       10.2.7.2     ParmEncryptSym()
//
//       This function performs parameter encryption using symmetric block cipher.
//
void
ParmEncryptSym(
   TPM_ALG_ID          symAlg,            //   IN: symmetric algorithm
   TPM_ALG_ID          hash,              //   IN: hash algorithm for KDFa
   UINT16              keySizeInBits,     //   IN: AES key size in bit
   TPM2B              *key,               //   IN: KDF HMAC key
   TPM2B              *nonceCaller,       //   IN: nonce caller
   TPM2B              *nonceTpm,          //   IN: nonce TPM
   UINT32              dataSize,          //   IN: size of parameter buffer
   BYTE               *data               //   OUT: buffer to be encrypted
   )
{
   // KDF output buffer
   // It contains parameters for the CFB encryption
   BYTE             symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
   // Symmetric key size in bytes
   UINT16           keySize = (keySizeInBits + 7) / 8;
   TPM2B_IV             iv;
   iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits);
   // See if there is any encryption to do
   if(iv.t.size > 0)
   {
       // Generate key and iv
       CryptKDFa(hash, key, "CFB", nonceTpm, nonceCaller,
                 keySizeInBits + (iv.t.size * 8), symParmString, NULL);
          MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size,
                     sizeof(iv.t.buffer));
          CryptSymmetricEncrypt(data, symAlg, keySizeInBits, TPM_ALG_CFB,
                                symParmString, &iv, dataSize, data);
   }
   return;
}
//
//
//
//       10.2.7.3     CryptGenerateNewSymmetric()
//
//       This function creates the sensitive symmetric values for an HMAC or symmetric key. If the sensitive area
//       is zero, then the sensitive creation key data is copied. If it is not zero, then the TPM will generate a
//       random value of the selected size.
//
void
CryptGenerateNewSymmetric(
   TPMS_SENSITIVE_CREATE        *sensitiveCreate,       //   IN: sensitive creation data
   TPMT_SENSITIVE               *sensitive,             //   OUT: sensitive area
   TPM_ALG_ID                    hashAlg,               //   IN: hash algorithm for the KDF
   TPM2B_SEED                   *seed,                  //   IN: seed used in creation
   TPM2B_NAME                   *name                   //   IN: name of the object
   )
{
   // This function is called to create a key and obfuscation value for a
   // symmetric key that can either be a block cipher or an XOR key. The buffer
   // in sensitive->sensitive will hold either. When we call the function
   // to copy the input value or generated value to the sensitive->sensitive
   // buffer we will need to have a size for the output buffer. This define
   // computes the maximum that it might need to be and uses that. It will always
   // be smaller than the largest value that will fit.
   #define MAX_SENSITIVE_SIZE                                                   \
       (MAX(sizeof(sensitive->sensitive.bits.t.buffer),                         \
           sizeof(sensitive->sensitive.sym.t.buffer)))
   // set the size of the obfuscation value
   sensitive->seedValue.t.size = CryptGetHashDigestSize(hashAlg);
   // If the input sensitive size is zero, then create both the sensitive data
   // and the obfuscation value
   if(sensitiveCreate->data.t.size == 0)
   {
       BYTE                     symValues[MAX(MAX_DIGEST_SIZE, MAX_SYM_KEY_BYTES)
                                          + MAX_DIGEST_SIZE];
       UINT16                  requestSize;
          // Set the size of the request to be the size of the key and the
          // obfuscation value
          requestSize =   sensitive->sensitive.sym.t.size
                        + sensitive->seedValue.t.size;
          pAssert(requestSize <= sizeof(symValues));
          requestSize = _cpri__GenerateSeededRandom(requestSize, symValues, hashAlg,
                                                    &seed->b,
                                                    "symmetric sensitive", &name->b,
                                                    NULL);
          pAssert(requestSize != 0);
          // Copy the new key
          MemoryCopy(sensitive->sensitive.sym.t.buffer,
                     symValues, sensitive->sensitive.sym.t.size,
                     MAX_SENSITIVE_SIZE);
          // copy the obfuscation value
          MemoryCopy(sensitive->seedValue.t.buffer,
                     &symValues[sensitive->sensitive.sym.t.size],
                     sensitive->seedValue.t.size,
                     sizeof(sensitive->seedValue.t.buffer));
   }
   else
   {
       // Copy input symmetric key to sensitive area as long as it will fit
       MemoryCopy2B(&sensitive->sensitive.sym.b, &sensitiveCreate->data.b,
                    MAX_SENSITIVE_SIZE);
          // Create the obfuscation value
          _cpri__GenerateSeededRandom(sensitive->seedValue.t.size,
                                      sensitive->seedValue.t.buffer,
                                      hashAlg, &seed->b,
                                      "symmetric obfuscation", &name->b, NULL);
   }
   return;
}
//
//
//       10.2.7.4    CryptGenerateKeySymmetric()
//
//       This function derives a symmetric cipher key from the provided seed.
//
//       Error Returns                     Meaning
//
//       TPM_RC_KEY_SIZE                   key size in the public area does not match the size in the sensitive
//                                         creation area
//       TPM_RC_VALUE                      the publicArea nameAlg is invalid
//
static TPM_RC
CryptGenerateKeySymmetric(
   TPMT_PUBLIC                    *publicArea,               //   IN/OUT: The public area template
                                                             //       for the new key.
   TPMS_SENSITIVE_CREATE          *sensitiveCreate,          //   IN: sensitive creation data
   TPMT_SENSITIVE                 *sensitive,                //   OUT: sensitive area
   TPM_ALG_ID                      hashAlg,                  //   IN: hash algorithm for the KDF
   TPM2B_SEED                     *seed,                     //   IN: seed used in creation
   TPM2B_NAME                     *name                      //   IN: name of the object
   )
{
   // Check parameter values
   if(publicArea->nameAlg == TPM_ALG_NULL)
   {
       return TPM_RC_VALUE;
   }
   // If this is not a new key, then the provided key data must be the right size
   if(publicArea->objectAttributes.sensitiveDataOrigin == CLEAR)
   {
       if(     (sensitiveCreate->data.t.size * 8)
           != publicArea->parameters.symDetail.sym.keyBits.sym)
           return TPM_RC_KEY_SIZE;
       // Make sure that the key size is OK.
       // This implementation only supports symmetric key sizes that are
       // multiples of 8
       if(publicArea->parameters.symDetail.sym.keyBits.sym % 8 != 0)
           return TPM_RC_KEY_SIZE;
   }
   else
   {
       // TPM is going to generate the key so set the size
       sensitive->sensitive.sym.t.size
           = publicArea->parameters.symDetail.sym.keyBits.sym / 8;
       sensitiveCreate->data.t.size = 0;
   }
   // Fill in the sensitive area
   CryptGenerateNewSymmetric(sensitiveCreate, sensitive, hashAlg,
                             seed, name);
   // Create unique area in public
   CryptComputeSymmetricUnique(publicArea->nameAlg,
                               sensitive, &publicArea->unique.sym);
   return TPM_RC_SUCCESS;
}
//
//
//
//       10.2.7.5     CryptXORObfuscation()
//
//       This function implements XOR obfuscation. It should not be called if the hash algorithm is not
//       implemented. The only return value from this function is TPM_RC_SUCCESS.
//
#ifdef TPM_ALG_KEYEDHASH //% 5
void
CryptXORObfuscation(
   TPM_ALG_ID             hash,                  //   IN: hash algorithm for KDF
   TPM2B                 *key,                   //   IN: KDF key
   TPM2B                 *contextU,              //   IN: contextU
   TPM2B                 *contextV,              //   IN: contextV
   UINT32                 dataSize,              //   IN: size of data buffer
   BYTE                  *data                   //   IN/OUT: data to be XORed in place
   )
{
   BYTE                   mask[MAX_DIGEST_SIZE]; // Allocate a digest sized buffer
   BYTE                  *pm;
   UINT32                 i;
   UINT32                 counter = 0;
   UINT16                 hLen = CryptGetHashDigestSize(hash);
   UINT32                 requestSize = dataSize * 8;
   INT32                  remainBytes = (INT32) dataSize;
   pAssert((key != NULL) && (data != NULL) && (hLen != 0));
   // Call KDFa to generate XOR mask
   for(; remainBytes > 0; remainBytes -= hLen)
   {
       // Make a call to KDFa to get next iteration
       CryptKDFaOnce(hash, key, "XOR", contextU, contextV,
                     requestSize, mask, &counter);
          // XOR next piece of the data
          pm = mask;
          for(i = hLen < remainBytes ? hLen : remainBytes; i > 0; i--)
              *data++ ^= *pm++;
   }
   return;
}
#endif //TPM_ALG_KEYED_HASH //%5
//
//
//       10.2.8     Initialization and shut down
//
//       10.2.8.1     CryptInitUnits()
//
//       This function is called when the TPM receives a _TPM_Init() indication. After function returns, the hash
//       algorithms should be available.
//
//       NOTE:           The hash algorithms do not have to be tested, they just need to be available. They have to be tested before the
//                       TPM can accept HMAC authorization or return any result that relies on a hash algorithm.
//
void
CryptInitUnits(
   void
   )
{
   // Initialize the vector of implemented algorithms
   AlgorithmGetImplementedVector(&g_implementedAlgorithms);
   // Indicate that all test are necessary
   CryptInitializeToTest();
//
   // Call crypto engine unit initialization
   // It is assumed that crypt engine initialization should always succeed.
   // Otherwise, TPM should go to failure mode.
   if(_cpri__InitCryptoUnits(&TpmFail) != CRYPT_SUCCESS)
       FAIL(FATAL_ERROR_INTERNAL);
   return;
}
//
//
//       10.2.8.2    CryptStopUnits()
//
//       This function is only used in a simulated environment. There should be no reason to shut down the
//       cryptography on an actual TPM other than loss of power. After receiving TPM2_Startup(), the TPM should
//       be able to accept commands until it loses power and, unless the TPM is in Failure Mode, the
//       cryptographic algorithms should be available.
//
void
CryptStopUnits(
   void
   )
{
   // Call crypto engine unit stopping
   _cpri__StopCryptoUnits();
   return;
}
//
//
//       10.2.8.3    CryptUtilStartup()
//
//       This function is called by TPM2_Startup() to initialize the functions in this crypto library and in the
//       provided CryptoEngine(). In this implementation, the only initialization required in this library is
//       initialization of the Commit nonce on TPM Reset.
//       This function returns false if some problem prevents the functions from starting correctly. The TPM should
//       go into failure mode.
//
BOOL
CryptUtilStartup(
   STARTUP_TYPE         type               // IN: the startup type
   )
{
   // Make sure that the crypto library functions are ready.
   // NOTE: need to initialize the crypto before loading
   // the RND state may trigger a self-test which
   // uses the
   if( !_cpri__Startup())
       return FALSE;
   // Initialize the state of the RNG.
   CryptDrbgGetPutState(PUT_STATE);
   if(type == SU_RESET)
   {
#ifdef TPM_ALG_ECC
       // Get a new random commit nonce
       gr.commitNonce.t.size = sizeof(gr.commitNonce.t.buffer);
       _cpri__GenerateRandom(gr.commitNonce.t.size, gr.commitNonce.t.buffer);
       // Reset the counter and commit array
       gr.commitCounter = 0;
       MemorySet(gr.commitArray, 0, sizeof(gr.commitArray));
#endif // TPM_ALG_ECC
   }
    // If the shutdown was orderly, then the values recovered from NV will
    // be OK to use. If the shutdown was not orderly, then a TPM Reset was required
    // and we would have initialized in the code above.
    return TRUE;
}
//
//
//       10.2.9     Algorithm-Independent Functions
//
//       10.2.9.1    Introduction
//
//       These functions are used generically when a function of a general type (e.g., symmetric encryption) is
//       required. The functions will modify the parameters as required to interface to the indicated algorithms.
//
//       10.2.9.2    CryptIsAsymAlgorithm()
//
//       This function indicates if an algorithm is an asymmetric algorithm.
//
//       Return Value                      Meaning
//
//       TRUE                              if it is an asymmetric algorithm
//       FALSE                             if it is not an asymmetric algorithm
//
BOOL
CryptIsAsymAlgorithm(
    TPM_ALG_ID           algID                // IN: algorithm ID
    )
{
   return (
#ifdef TPM_ALG_RSA
            algID == TPM_ALG_RSA
#endif
#if defined TPM_ALG_RSA && defined TPM_ALG_ECC
            ||
#endif
#ifdef TPM_ALG_ECC
            algID == TPM_ALG_ECC
#endif
          );
}
//
//
//       10.2.9.3    CryptGetSymmetricBlockSize()
//
//       This function returns the size in octets of the symmetric encryption block used by an algorithm and key
//       size combination.
//
INT16
CryptGetSymmetricBlockSize(
    TPMI_ALG_SYM         algorithm,           // IN: symmetric algorithm
    UINT16               keySize              // IN: key size in bit
    )
{
    return _cpri__GetSymmetricBlockSize(algorithm, keySize);
}
//
//
//
//       10.2.9.4    CryptSymmetricEncrypt()
//
//       This function does in-place encryption of a buffer using the indicated symmetric algorithm, key, IV, and
//       mode. If the symmetric algorithm and mode are not defined, the TPM will fail.
//
void
CryptSymmetricEncrypt(
   BYTE                    *encrypted,         //   OUT: the encrypted data
   TPM_ALG_ID               algorithm,         //   IN: algorithm for encryption
   UINT16                   keySizeInBits,     //   IN: key size in bit
   TPMI_ALG_SYM_MODE        mode,              //   IN: symmetric encryption mode
   BYTE                    *key,               //   IN: encryption key
   TPM2B_IV                *ivIn,              //   IN/OUT: Input IV and output chaining
                                               //       value for the next block
   UINT32                   dataSize,          //   IN: data size in byte
   BYTE                    *data               //   IN/OUT: data buffer
   )
{
   TPM2B_IV                 defaultIv = {};
   TPM2B_IV                *iv = (ivIn != NULL) ? ivIn : &defaultIv;
   TEST(algorithm);
   pAssert(encrypted != NULL && key != NULL);
   // this check can pass but the case below can fail. ALG_xx_VALUE values are
   // defined for all algorithms but the TPM_ALG_xx might not be.
   if(algorithm == ALG_AES_VALUE || algorithm == ALG_SM4_VALUE)
   {
       if(mode != TPM_ALG_ECB)
           defaultIv.t.size = 16;
       // A provided IV has to be the right size
       pAssert(mode == TPM_ALG_ECB || iv->t.size == 16);
   }
   switch(algorithm)
   {
#ifdef TPM_ALG_AES
       case TPM_ALG_AES:
       {
           switch (mode)
           {
               case TPM_ALG_CTR:
                   _cpri__AESEncryptCTR(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_OFB:
                   _cpri__AESEncryptOFB(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_CBC:
                   _cpri__AESEncryptCBC(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_CFB:
                   _cpri__AESEncryptCFB(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_ECB:
                   _cpri__AESEncryptECB(encrypted, keySizeInBits, key,
                                        dataSize, data);
                   break;
               default:
                   pAssert(0);
           }
          }
          break;
#endif
#ifdef TPM_ALG_SM4
       case TPM_ALG_SM4:
       {
           switch (mode)
           {
               case TPM_ALG_CTR:
                   _cpri__SM4EncryptCTR(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_OFB:
                   _cpri__SM4EncryptOFB(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
               case TPM_ALG_CBC:
                   _cpri__SM4EncryptCBC(encrypted, keySizeInBits, key,
                                        iv->t.buffer, dataSize, data);
                   break;
                   case TPM_ALG_CFB:
                       _cpri__SM4EncryptCFB(encrypted, keySizeInBits, key,
                                            iv->t.buffer, dataSize, data);
                       break;
                   case TPM_ALG_ECB:
                       _cpri__SM4EncryptECB(encrypted, keySizeInBits, key,
                                            dataSize, data);
                       break;
                   default:
                       pAssert(0);
              }
          }
          break;
#endif
          default:
              pAssert(FALSE);
              break;
   }
   return;
}
//
//
//       10.2.9.5    CryptSymmetricDecrypt()
//
//       This function does in-place decryption of a buffer using the indicated symmetric algorithm, key, IV, and
//       mode. If the symmetric algorithm and mode are not defined, the TPM will fail.
//
void
CryptSymmetricDecrypt(
   BYTE                      *decrypted,
   TPM_ALG_ID                 algorithm,       //   IN: algorithm for encryption
   UINT16                     keySizeInBits,   //   IN: key size in bit
   TPMI_ALG_SYM_MODE          mode,            //   IN: symmetric encryption mode
   BYTE                      *key,             //   IN: encryption key
   TPM2B_IV                  *ivIn,            //   IN/OUT: IV for next block
   UINT32                     dataSize,        //   IN: data size in byte
   BYTE                      *data             //   IN/OUT: data buffer
   )
{
   BYTE                      *iv = NULL;
   BYTE                       defaultIV[sizeof(TPMT_HA)];
   TEST(algorithm);
   if(
#ifdef TPM_ALG_AES
         algorithm == TPM_ALG_AES
#endif
#if defined TPM_ALG_AES && defined TPM_ALG_SM4
      ||
#endif
#ifdef TPM_ALG_SM4
         algorithm == TPM_ALG_SM4
#endif
     )
   {
       // Both SM4 and AES have block size of 128 bits
       // If the iv is not provided, create a default of 0
       if(ivIn == NULL)
       {
            // Initialize the default IV
            iv = defaultIV;
            MemorySet(defaultIV, 0, 16);
       }
       else
       {
            // A provided IV has to be the right size
            pAssert(mode == TPM_ALG_ECB || ivIn->t.size == 16);
            iv = &(ivIn->t.buffer[0]);
       }
   }
   switch(algorithm)
   {
#ifdef TPM_ALG_AES
   case TPM_ALG_AES:
   {
        switch (mode)
        {
            case TPM_ALG_CTR:
                _cpri__AESDecryptCTR(decrypted, keySizeInBits,   key, iv,
                                     dataSize, data);
                break;
            case TPM_ALG_OFB:
                _cpri__AESDecryptOFB(decrypted, keySizeInBits,   key, iv,
                                     dataSize, data);
                break;
            case TPM_ALG_CBC:
                _cpri__AESDecryptCBC(decrypted, keySizeInBits,   key, iv,
                                     dataSize, data);
                break;
            case TPM_ALG_CFB:
                _cpri__AESDecryptCFB(decrypted, keySizeInBits,   key, iv,
                                     dataSize, data);
                break;
            case TPM_ALG_ECB:
                _cpri__AESDecryptECB(decrypted, keySizeInBits,   key,
                                     dataSize, data);
                break;
            default:
                pAssert(0);
        }
        break;
   }
#endif //TPM_ALG_AES
#ifdef TPM_ALG_SM4
   case TPM_ALG_SM4 :
       switch (mode)
       {
           case TPM_ALG_CTR:
               _cpri__SM4DecryptCTR(decrypted, keySizeInBits,                       key, iv,
                                    dataSize, data);
               break;
           case TPM_ALG_OFB:
               _cpri__SM4DecryptOFB(decrypted, keySizeInBits,                       key, iv,
                                    dataSize, data);
               break;
           case TPM_ALG_CBC:
               _cpri__SM4DecryptCBC(decrypted, keySizeInBits,                       key, iv,
                                    dataSize, data);
               break;
           case TPM_ALG_CFB:
               _cpri__SM4DecryptCFB(decrypted, keySizeInBits,                       key, iv,
                                    dataSize, data);
               break;
           case TPM_ALG_ECB:
               _cpri__SM4DecryptECB(decrypted, keySizeInBits,                       key,
                                    dataSize, data);
               break;
           default:
               pAssert(0);
       }
       break;
#endif //TPM_ALG_SM4
   default:
       pAssert(FALSE);
       break;
   }
   return;
}
//
//
//       10.2.9.6    CryptSecretEncrypt()
//
//       This function creates a secret value and its associated secret structure using an asymmetric algorithm.
//       This function is used by TPM2_Rewrap() TPM2_MakeCredential(), and TPM2_Duplicate().
//
//       Error Returns                   Meaning
//
//       TPM_RC_ATTRIBUTES               keyHandle does not reference a valid decryption key
//       TPM_RC_KEY                      invalid ECC key (public point is not on the curve)
//       TPM_RC_SCHEME                   RSA key with an unsupported padding scheme
//       TPM_RC_VALUE                    numeric value of the data to be decrypted is greater than the RSA
//                                       key modulus
//
TPM_RC
CryptSecretEncrypt(
   TPMI_DH_OBJECT                 keyHandle,           //   IN: encryption key handle
   const char                    *label,               //   IN: a null-terminated string as L
   TPM2B_DATA                    *data,                //   OUT: secret value
   TPM2B_ENCRYPTED_SECRET        *secret               //   OUT: secret structure
   )
{
   TPM_RC          result = TPM_RC_SUCCESS;
   OBJECT         *encryptKey = ObjectGet(keyHandle);              // TPM key used for encrypt
   pAssert(data != NULL && secret != NULL);
   // The output secret value has the size of the digest produced by the nameAlg.
   data->t.size = CryptGetHashDigestSize(encryptKey->publicArea.nameAlg);
   pAssert(encryptKey->publicArea.objectAttributes.decrypt == SET);
   switch(encryptKey->publicArea.type)
   {
#ifdef TPM_ALG_RSA
       case TPM_ALG_RSA:
       {
           TPMT_RSA_DECRYPT            scheme;
             // Use OAEP scheme
             scheme.scheme = TPM_ALG_OAEP;
             scheme.details.oaep.hashAlg = encryptKey->publicArea.nameAlg;
             // Create secret data from RNG
             CryptGenerateRandom(data->t.size, data->t.buffer);
             // Encrypt the data by RSA OAEP into encrypted secret
             result = CryptEncryptRSA(&secret->t.size, secret->t.secret,
                                      encryptKey, &scheme,
                                      data->t.size, data->t.buffer, label);
       }
       break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       case TPM_ALG_ECC:
       {
           TPMS_ECC_POINT         eccPublic;
           TPM2B_ECC_PARAMETER    eccPrivate;
           TPMS_ECC_POINT         eccSecret;
           BYTE                   *buffer = secret->t.secret;
           INT32                  bufferSize = sizeof(TPMS_ECC_POINT);
             // Need to make sure that the public point of the key is on the
             // curve defined by the key.
             if(!_cpri__EccIsPointOnCurve(
                         encryptKey->publicArea.parameters.eccDetail.curveID,
                         &encryptKey->publicArea.unique.ecc))
                 result = TPM_RC_KEY;
             else
             {
                  // Call crypto engine to create an auxiliary ECC key
                  // We assume crypt engine initialization should always success.
                  // Otherwise, TPM should go to failure mode.
                  CryptNewEccKey(encryptKey->publicArea.parameters.eccDetail.curveID,
                                 &eccPublic, &eccPrivate);
                  // Marshal ECC public to secret structure. This will be used by the
                  // recipient to decrypt the secret with their private key.
                  secret->t.size = TPMS_ECC_POINT_Marshal(&eccPublic, &buffer, &bufferSize);
                  // Compute ECDH shared secret which is R = [d]Q where d is the
                  // private part of the ephemeral key and Q is the public part of a
                  // TPM key. TPM_RC_KEY error return from CryptComputeECDHSecret
                  // because the auxiliary ECC key is just created according to the
                  // parameters of input ECC encrypt key.
                  if(     CryptEccPointMultiply(&eccSecret,
                                  encryptKey->publicArea.parameters.eccDetail.curveID,
                                  &eccPrivate,
                                  &encryptKey->publicArea.unique.ecc)
                      != CRYPT_SUCCESS)
                       result = TPM_RC_KEY;
                  else
                      //     The secret value is computed from Z using KDFe as:
                      //     secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
                      //     Where:
                      //      HashID the nameAlg of the decrypt key
                      //      Z    the x coordinate (Px) of the product (P) of the point
                      //           (Q) of the secret and the private x coordinate (de,V)
                      //           of the decryption key
                      //      Use a null-terminated string containing "SECRET"
                      //      PartyUInfo the x coordinate of the point in the secret
                      //                   (Qe,U )
                      //      PartyVInfo the x coordinate of the public key (Qs,V )
                      //      bits     the number of bits in the digest of HashID
                      //     Retrieve seed from KDFe
                      CryptKDFe(encryptKey->publicArea.nameAlg, &eccSecret.x.b,
                                label, &eccPublic.x.b,
                                &encryptKey->publicArea.unique.ecc.x.b,
                                data->t.size * 8, data->t.buffer);
           }
       }
       break;
#endif //TPM_ALG_ECC
   default:
       FAIL(FATAL_ERROR_INTERNAL);
       break;
   }
   return result;
}
//
//
//       10.2.9.7   CryptSecretDecrypt()
//
//       Decrypt a secret value by asymmetric (or symmetric) algorithm This function is used for
//       ActivateCredential() and Import for asymmetric decryption, and StartAuthSession() for both asymmetric
//       and symmetric decryption process
//
//       Error Returns                    Meaning
//
//       TPM_RC_ATTRIBUTES                RSA key is not a decryption key
//       TPM_RC_BINDING                   Invalid RSA key (public and private parts are not cryptographically
//                                        bound.
//       TPM_RC_ECC_POINT                 ECC point in the secret is not on the curve
//       TPM_RC_INSUFFICIENT              failed to retrieve ECC point from the secret
//       TPM_RC_NO_RESULT                 multiplication resulted in ECC point at infinity
//       TPM_RC_SIZE                      data to decrypt is not of the same size as RSA key
//       TPM_RC_VALUE                     For RSA key, numeric value of the encrypted data is greater than the
//                                        modulus, or the recovered data is larger than the output buffer. For
//                                        keyedHash or symmetric key, the secret is larger than the size of the
//                                        digest produced by the name algorithm.
//       TPM_RC_FAILURE                   internal error
//
TPM_RC
CryptSecretDecrypt(
   TPM_HANDLE                      tpmKey,               // IN: decrypt key
   TPM2B_NONCE                    *nonceCaller,          // IN: nonceCaller. It is needed for
                                                         //     symmetric decryption. For
                                                   //     asymmetric decryption, this
                                                   //     parameter is NULL
   const char                    *label,           // IN: a null-terminated string as L
   TPM2B_ENCRYPTED_SECRET        *secret,          // IN: input secret
   TPM2B_DATA                    *data             // OUT: decrypted secret value
   )
{
   TPM_RC         result = TPM_RC_SUCCESS;
   OBJECT         *decryptKey = ObjectGet(tpmKey);          //TPM key used for decrypting
   // Decryption for secret
   switch(decryptKey->publicArea.type)
   {
#ifdef TPM_ALG_RSA
       case TPM_ALG_RSA:
       {
           TPMT_RSA_DECRYPT             scheme;
             // Use OAEP scheme
             scheme.scheme = TPM_ALG_OAEP;
             scheme.details.oaep.hashAlg = decryptKey->publicArea.nameAlg;
             // Set the output buffer capacity
             data->t.size = sizeof(data->t.buffer);
             // Decrypt seed by RSA OAEP
             result = CryptDecryptRSA(&data->t.size, data->t.buffer, decryptKey,
                                       &scheme,
                                       secret->t.size, secret->t.secret,label);
             if(    (result == TPM_RC_SUCCESS)
                 && (data->t.size
                      > CryptGetHashDigestSize(decryptKey->publicArea.nameAlg)))
                  result = TPM_RC_VALUE;
       }
       break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       case TPM_ALG_ECC:
       {
           TPMS_ECC_POINT            eccPublic;
           TPMS_ECC_POINT            eccSecret;
           BYTE                     *buffer = secret->t.secret;
           INT32                     size = secret->t.size;
             // Retrieve ECC point from secret buffer
             result = TPMS_ECC_POINT_Unmarshal(&eccPublic, &buffer, &size);
             if(result == TPM_RC_SUCCESS)
             {
                 result = CryptEccPointMultiply(&eccSecret,
                                decryptKey->publicArea.parameters.eccDetail.curveID,
                                &decryptKey->sensitive.sensitive.ecc,
                                &eccPublic);
                  if(result == TPM_RC_SUCCESS)
                  {
                      // Set the size of the "recovered" secret value to be the size
                      // of the digest produced by the nameAlg.
                      data->t.size =
                              CryptGetHashDigestSize(decryptKey->publicArea.nameAlg);
                      // The secret value is computed from Z using KDFe as:
                      // secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
                      // Where:
                      // HashID -- the nameAlg of the decrypt key
                      // Z -- the x coordinate (Px) of the product (P) of the point
                      //        (Q) of the secret and the private x coordinate (de,V)
                      //        of the decryption key
                      // Use -- a null-terminated string containing "SECRET"
                      // PartyUInfo -- the x coordinate of the point in the secret
                      //              (Qe,U )
                      // PartyVInfo -- the x coordinate of the public key (Qs,V )
                      // bits -- the number of bits in the digest of HashID
                      // Retrieve seed from KDFe
                      CryptKDFe(decryptKey->publicArea.nameAlg, &eccSecret.x.b, label,
                                &eccPublic.x.b,
                                &decryptKey->publicArea.unique.ecc.x.b,
                                data->t.size * 8, data->t.buffer);
                  }
              }
       }
       break;
#endif //TPM_ALG_ECC
        case TPM_ALG_KEYEDHASH:
            // The seed size can not be bigger than the digest size of nameAlg
            if(secret->t.size >
                    CryptGetHashDigestSize(decryptKey->publicArea.nameAlg))
                result = TPM_RC_VALUE;
            else
            {
                // Retrieve seed by XOR Obfuscation:
                //    seed = XOR(secret, hash, key, nonceCaller, nullNonce)
                //    where:
                //    secret the secret parameter from the TPM2_StartAuthHMAC
                //             command
                //             which contains the seed value
                //    hash     nameAlg of tpmKey
                //    key      the key or data value in the object referenced by
                //             entityHandle in the TPM2_StartAuthHMAC command
                //    nonceCaller the parameter from the TPM2_StartAuthHMAC command
                //    nullNonce    a zero-length nonce
                // XOR Obfuscation in place
                CryptXORObfuscation(decryptKey->publicArea.nameAlg,
                                     &decryptKey->sensitive.sensitive.bits.b,
                                     &nonceCaller->b, NULL,
                                     secret->t.size, secret->t.secret);
                // Copy decrypted seed
                MemoryCopy2B(&data->b, &secret->b, sizeof(data->t.buffer));
            }
            break;
        case TPM_ALG_SYMCIPHER:
            {
                TPM2B_IV                 iv = {};
                TPMT_SYM_DEF_OBJECT      *symDef;
                // The seed size can not be bigger than the digest size of nameAlg
                if(secret->t.size >
                         CryptGetHashDigestSize(decryptKey->publicArea.nameAlg))
                    result = TPM_RC_VALUE;
                else
                {
                    symDef = &decryptKey->publicArea.parameters.symDetail.sym;
                    iv.t.size = CryptGetSymmetricBlockSize(symDef->algorithm,
                                                             symDef->keyBits.sym);
                    pAssert(iv.t.size != 0);
                    if(nonceCaller->t.size >= iv.t.size)
                         MemoryCopy(iv.t.buffer, nonceCaller->t.buffer, iv.t.size,
                                     sizeof(iv.t.buffer));
                    else
                         MemoryCopy(iv.b.buffer, nonceCaller->t.buffer,
                                      nonceCaller->t.size, sizeof(iv.t.buffer));
                       // CFB decrypt in place, using nonceCaller as iv
                       CryptSymmetricDecrypt(secret->t.secret, symDef->algorithm,
                                          symDef->keyBits.sym, TPM_ALG_CFB,
                                          decryptKey->sensitive.sensitive.sym.t.buffer,
                                          &iv, secret->t.size, secret->t.secret);
                       // Copy decrypted seed
                       MemoryCopy2B(&data->b, &secret->b, sizeof(data->t.buffer));
                   }
              }
              break;
          default:
              pAssert(0);
              break;
   }
   return result;
}
//
//
//       10.2.9.8    CryptParameterEncryption()
//
//       This function does in-place encryption of a response parameter.
//
void
CryptParameterEncryption(
   TPM_HANDLE           handle,            // IN: encrypt session handle
   TPM2B               *nonceCaller,       // IN: nonce caller
   UINT16               leadingSizeInByte, // IN: the size of the leading size field in
                                           //     byte
   TPM2B_AUTH          *extraKey,          // IN: additional key material other than
                                           //     session auth
   BYTE                *buffer             // IN/OUT: parameter buffer to be encrypted
   )
{
   SESSION     *session = SessionGet(handle); // encrypt session
   TPM2B_TYPE(SYM_KEY, ( sizeof(extraKey->t.buffer)
                        + sizeof(session->sessionKey.t.buffer)));
   TPM2B_SYM_KEY        key;               // encryption key
   UINT32               cipherSize = 0;    // size of cipher text
   pAssert(session->sessionKey.t.size + extraKey->t.size <= sizeof(key.t.buffer));
   // Retrieve encrypted data size.
   if(leadingSizeInByte == 2)
   {
       // Extract the first two bytes as the size field as the data size
       // encrypt
       cipherSize = (UINT32)BYTE_ARRAY_TO_UINT16(buffer);
       // advance the buffer
       buffer = &buffer[2];
   }
#ifdef      TPM4B
   else if(leadingSizeInByte == 4)
   {
       // use the first four bytes to indicate the number of bytes to encrypt
       cipherSize = BYTE_ARRAY_TO_UINT32(buffer);
       //advance pointer
       buffer = &buffer[4];
   }
#endif
   else
   {
       pAssert(FALSE);
   }
//
   // Compute encryption key by concatenating sessionAuth with extra key
   MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
   MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer));
   if (session->symmetric.algorithm == TPM_ALG_XOR)
       // XOR parameter encryption formulation:
       //    XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder)
       CryptXORObfuscation(session->authHashAlg, &(key.b),
                                  &(session->nonceTPM.b),
                                  nonceCaller, cipherSize, buffer);
   else
       ParmEncryptSym(session->symmetric.algorithm, session->authHashAlg,
                             session->symmetric.keyBits.aes, &(key.b),
                             nonceCaller, &(session->nonceTPM.b),
                             cipherSize, buffer);
   return;
}
//
//
//       10.2.9.9   CryptParameterDecryption()
//
//       This function does in-place decryption of a command parameter.
//
//       Error Returns                  Meaning
//
//       TPM_RC_SIZE                    The number of bytes in the input buffer is less than the number of
//                                      bytes to be decrypted.
//
TPM_RC
CryptParameterDecryption(
   TPM_HANDLE          handle,                 //   IN: encrypted session handle
   TPM2B              *nonceCaller,            //   IN: nonce caller
   UINT32              bufferSize,             //   IN: size of parameter buffer
   UINT16              leadingSizeInByte,      //   IN: the size of the leading size field in
                                               //       byte
   TPM2B_AUTH         *extraKey,               //   IN: the authValue
   BYTE               *buffer                  //   IN/OUT: parameter buffer to be decrypted
   )
{
   SESSION         *session = SessionGet(handle); // encrypt session
   // The HMAC key is going to be the concatenation of the session key and any
   // additional key material (like the authValue). The size of both of these
   // is the size of the buffer which can contain a TPMT_HA.
   TPM2B_TYPE(HMAC_KEY, ( sizeof(extraKey->t.buffer)
                         + sizeof(session->sessionKey.t.buffer)));
   TPM2B_HMAC_KEY          key;            // decryption key
   UINT32                  cipherSize = 0; // size of cipher text
   pAssert(session->sessionKey.t.size + extraKey->t.size <= sizeof(key.t.buffer));
   // Retrieve encrypted data size.
   if(leadingSizeInByte == 2)
   {
       // The first two bytes of the buffer are the size of the
       // data to be decrypted
       cipherSize = (UINT32)BYTE_ARRAY_TO_UINT16(buffer);
       buffer = &buffer[2];    // advance the buffer
   }
#ifdef TPM4B
   else if(leadingSizeInByte == 4)
   {
       // the leading size is four bytes so get the four byte size field
       cipherSize = BYTE_ARRAY_TO_UINT32(buffer);
       buffer = &buffer[4];    //advance pointer
   }
#endif
   else
   {
       pAssert(FALSE);
   }
   if(cipherSize > bufferSize)
       return TPM_RC_SIZE;
   // Compute decryption key by concatenating sessionAuth with extra input key
   MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
   MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer));
   if(session->symmetric.algorithm == TPM_ALG_XOR)
       // XOR parameter decryption formulation:
       //    XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder)
       // Call XOR obfuscation function
       CryptXORObfuscation(session->authHashAlg, &key.b, nonceCaller,
                                  &(session->nonceTPM.b), cipherSize, buffer);
   else
       // Assume that it is one of the symmetric block ciphers.
       ParmDecryptSym(session->symmetric.algorithm, session->authHashAlg,
                             session->symmetric.keyBits.sym,
                             &key.b, nonceCaller, &session->nonceTPM.b,
                             cipherSize, buffer);
   return TPM_RC_SUCCESS;
}
//
//
//       10.2.9.10 CryptComputeSymmetricUnique()
//
//       This function computes the unique field in public area for symmetric objects.
//
void
CryptComputeSymmetricUnique(
   TPMI_ALG_HASH        nameAlg,           // IN: object name algorithm
   TPMT_SENSITIVE      *sensitive,         // IN: sensitive area
   TPM2B_DIGEST        *unique             // OUT: unique buffer
   )
{
   HASH_STATE     hashState;
   pAssert(sensitive != NULL && unique != NULL);
   // Compute the public value as the hash of sensitive.symkey || unique.buffer
   unique->t.size = CryptGetHashDigestSize(nameAlg);
   CryptStartHash(nameAlg, &hashState);
   // Add obfuscation value
   CryptUpdateDigest2B(&hashState, &sensitive->seedValue.b);
   // Add sensitive value
   CryptUpdateDigest2B(&hashState, &sensitive->sensitive.any.b);
   CryptCompleteHash2B(&hashState, &unique->b);
   return;
}
#if 0 //%
//
//
//
//       10.2.9.11 CryptComputeSymValue()
//
//       This function computes the seedValue field in asymmetric sensitive areas.
//
void
CryptComputeSymValue(
    TPM_HANDLE            parentHandle,      //   IN: parent handle of the object to be created
    TPMT_PUBLIC          *publicArea,        //   IN/OUT: the public area template
    TPMT_SENSITIVE       *sensitive,         //   IN: sensitive area
    TPM2B_SEED           *seed,              //   IN: the seed
    TPMI_ALG_HASH         hashAlg,           //   IN: hash algorithm for KDFa
    TPM2B_NAME           *name               //   IN: object name
    )
{
    TPM2B_AUTH       *proof = NULL;
    if(CryptIsAsymAlgorithm(publicArea->type))
    {
        // Generate seedValue only when an asymmetric key is a storage key
        if(publicArea->objectAttributes.decrypt == SET
                  && publicArea->objectAttributes.restricted == SET)
        {
             // If this is a primary object in the endorsement hierarchy, use
             // ehProof in the creation of the symmetric seed so that child
             // objects in the endorsement hierarchy are voided on TPM2_Clear()
             // or TPM2_ChangeEPS()
             if(    parentHandle == TPM_RH_ENDORSEMENT
                 && publicArea->objectAttributes.fixedTPM == SET)
                  proof = &gp.ehProof;
        }
        else
        {
             sensitive->seedValue.t.size = 0;
             return;
        }
    }
    // For all object types, the size of seedValue is the digest size of nameAlg
    sensitive->seedValue.t.size = CryptGetHashDigestSize(publicArea->nameAlg);
    // Compute seedValue using implementation-dependent method
    _cpri__GenerateSeededRandom(sensitive->seedValue.t.size,
                                sensitive->seedValue.t.buffer,
                                hashAlg,
                                &seed->b,
                                "seedValue",
                                &name->b,
                                (TPM2B *)proof);
    return;
}
#endif //%
//
//
//       10.2.9.12 CryptCreateObject()
//
//       This function creates an object. It:
//       a) fills in the created key in public and sensitive area;
//       b) creates a random number in sensitive area for symmetric keys; and
//       c) compute the unique id in public area for symmetric keys.
//
//
//
//
//       Error Returns                     Meaning
//
//       TPM_RC_KEY_SIZE                   key size in the public area does not match the size in the sensitive
//                                         creation area for a symmetric key
//       TPM_RC_RANGE                      for an RSA key, the exponent is not supported
//       TPM_RC_SIZE                       sensitive data size is larger than allowed for the scheme for a keyed
//                                         hash object
//       TPM_RC_VALUE                      exponent is not prime or could not find a prime using the provided
//                                         parameters for an RSA key; unsupported name algorithm for an ECC
//                                         key; unsupported name algorithm for symmetric algorithms
//
TPM_RC
CryptCreateObject(
   TPM_HANDLE                       parentHandle,            //   IN/OUT: indication of the seed
                                                             //       source
   TPMT_PUBLIC                    *publicArea,               //   IN/OUT: public area
   TPMS_SENSITIVE_CREATE          *sensitiveCreate,          //   IN: sensitive creation
   TPMT_SENSITIVE                 *sensitive                 //   OUT: sensitive area
   )
{
   // Next value is a placeholder for a random seed that is used in
   // key creation when the parent is not a primary seed. It has the same
   // size as the primary seed.
   TPM2B_SEED          localSeed;            // data to seed key creation if this
                                             // is not a primary seed
   TPM2B_SEED         *seed = NULL;
   TPM_RC              result = TPM_RC_SUCCESS;
   TPM2B_NAME          name;
   TPM_ALG_ID          hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
   OBJECT             *parent;
   UINT32              counter;
   // Set the sensitive type for the object
   sensitive->sensitiveType = publicArea->type;
   ObjectComputeName(publicArea, &name);
   // For all objects, copy the initial auth data
   sensitive->authValue = sensitiveCreate->userAuth;
   // If this is a permanent handle assume that it is a hierarchy
   if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
   {
       seed = HierarchyGetPrimarySeed(parentHandle);
   }
   else
   {
       // If not hierarchy handle, get parent
       parent = ObjectGet(parentHandle);
       hashAlg = parent->publicArea.nameAlg;
        // Use random value as seed for non-primary objects
        localSeed.t.size = PRIMARY_SEED_SIZE;
        CryptGenerateRandom(PRIMARY_SEED_SIZE, localSeed.t.buffer);
        seed = &localSeed;
   }
   switch(publicArea->type)
   {
#ifdef TPM_ALG_RSA
       // Create RSA key
   case TPM_ALG_RSA:
       result = CryptGenerateKeyRSA(publicArea, sensitive,
                                    hashAlg, seed, &name, &counter);
       break;
#endif // TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       // Create ECC key
   case TPM_ALG_ECC:
       result = CryptGenerateKeyECC(publicArea, sensitive,
                                        hashAlg, seed, &name, &counter);
       break;
#endif // TPM_ALG_ECC
       // Collect symmetric key information
   case TPM_ALG_SYMCIPHER:
       return CryptGenerateKeySymmetric(publicArea, sensitiveCreate,
                                        sensitive, hashAlg, seed, &name);
       break;
   case TPM_ALG_KEYEDHASH:
       return CryptGenerateKeyedHash(publicArea, sensitiveCreate,
                                     sensitive, hashAlg, seed, &name);
       break;
   default:
       pAssert(0);
       break;
   }
   if(result == TPM_RC_SUCCESS)
   {
       TPM2B_AUTH          *proof = NULL;
        if(publicArea->objectAttributes.decrypt == SET
                 && publicArea->objectAttributes.restricted == SET)
        {
            // If this is a primary object in the endorsement hierarchy, use
            // ehProof in the creation of the symmetric seed so that child
            // objects in the endorsement hierarchy are voided on TPM2_Clear()
            // or TPM2_ChangeEPS()
            if(    parentHandle == TPM_RH_ENDORSEMENT
                && publicArea->objectAttributes.fixedTPM == SET)
                 proof = &gp.ehProof;
              // For all object types, the size of seedValue is the digest size
              // of its nameAlg
              sensitive->seedValue.t.size
                  = CryptGetHashDigestSize(publicArea->nameAlg);
              // Compute seedValue using implementation-dependent method
              _cpri__GenerateSeededRandom(sensitive->seedValue.t.size,
                                          sensitive->seedValue.t.buffer,
                                          hashAlg,
                                          &seed->b,
                                          "seedValuea",
                                          &name.b,
                                          (TPM2B *)proof);
        }
        else
        {
              sensitive->seedValue.t.size = 0;
        }
   }
   return result;
}
//
//       10.2.9.13 CryptObjectIsPublicConsistent()
//
//       This function checks that the key sizes in the public area are consistent. For an asymmetric key, the size
//       of the public key must match the size indicated by the public->parameters.
//       Checks for the algorithm types matching the key type are handled by the unmarshaling operation.
//
//       Return Value                      Meaning
//
//       TRUE                              sizes are consistent
//       FALSE                             sizes are not consistent
//
BOOL
CryptObjectIsPublicConsistent(
   TPMT_PUBLIC         *publicArea           // IN: public area
   )
{
   BOOL                  OK = TRUE;
   switch (publicArea->type)
   {
#ifdef TPM_ALG_RSA
       case TPM_ALG_RSA:
           OK = CryptAreKeySizesConsistent(publicArea);
           break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       case TPM_ALG_ECC:
           {
               const ECC_CURVE                              *curveValue;
                  // Check that the public point is on the indicated curve.
                  OK = CryptEccIsPointOnCurve(
                                  publicArea->parameters.eccDetail.curveID,
                                  &publicArea->unique.ecc);
                  if(OK)
                  {
                      curveValue = CryptEccGetCurveDataPointer(
                                           publicArea->parameters.eccDetail.curveID);
                      pAssert(curveValue != NULL);
                       // The input ECC curve must be a supported curve
                       // IF a scheme is defined for the curve, then that scheme must
                       // be used.
                       OK =    (curveValue->sign.scheme == TPM_ALG_NULL
                            || (   publicArea->parameters.eccDetail.scheme.scheme
                                == curveValue->sign.scheme));
                       OK = OK && CryptAreKeySizesConsistent(publicArea);
               }
           }
           break;
#endif //TPM_ALG_ECC
        default:
            // Symmetric object common checks
            // There is noting to check with a symmetric key that is public only.
            // Also not sure that there is anything useful to be done with it
            // either.
            break;
   }
   return OK;
}
//
//
//
//       10.2.9.14 CryptObjectPublicPrivateMatch()
//
//       This function checks the cryptographic binding between the public and sensitive areas.
//
//       Error Returns                   Meaning
//
//       TPM_RC_TYPE                     the type of the public and private areas are not the same
//       TPM_RC_FAILURE                  crypto error
//       TPM_RC_BINDING                  the public and private areas are not cryptographically matched.
//
TPM_RC
CryptObjectPublicPrivateMatch(
   OBJECT              *object                // IN: the object to check
   )
{
   TPMT_PUBLIC               *publicArea;
   TPMT_SENSITIVE            *sensitive;
   TPM_RC                     result = TPM_RC_SUCCESS;
   BOOL                       isAsymmetric = FALSE;
   pAssert(object != NULL);
   publicArea = &object->publicArea;
   sensitive = &object->sensitive;
   if(publicArea->type != sensitive->sensitiveType)
       return TPM_RC_TYPE;
   switch(publicArea->type)
   {
#ifdef TPM_ALG_RSA
   case TPM_ALG_RSA:
       isAsymmetric = TRUE;
       // The public and private key sizes need to be consistent
       if(sensitive->sensitive.rsa.t.size != publicArea->unique.rsa.t.size/2)
            result = TPM_RC_BINDING;
       else
       // Load key by computing the private exponent
            result = CryptLoadPrivateRSA(object);
       break;
#endif
#ifdef TPM_ALG_ECC
       // This function is called from ObjectLoad() which has already checked to
       // see that the public point is on the curve so no need to repeat that
       // check.
   case TPM_ALG_ECC:
       isAsymmetric = TRUE;
       if(    publicArea->unique.ecc.x.t.size
                 != sensitive->sensitive.ecc.t.size)
            result = TPM_RC_BINDING;
       else if(publicArea->nameAlg != TPM_ALG_NULL)
       {
            TPMS_ECC_POINT           publicToCompare;
            // Compute ECC public key
            CryptEccPointMultiply(&publicToCompare,
                                   publicArea->parameters.eccDetail.curveID,
                                   &sensitive->sensitive.ecc, NULL);
            // Compare ECC public key
            if(    (!Memory2BEqual(&publicArea->unique.ecc.x.b,
                                   &publicToCompare.x.b))
                || (!Memory2BEqual(&publicArea->unique.ecc.y.b,
                                   &publicToCompare.y.b)))
                 result = TPM_RC_BINDING;
       }
       break;
//
#endif
   case TPM_ALG_KEYEDHASH:
       break;
   case TPM_ALG_SYMCIPHER:
       if(    (publicArea->parameters.symDetail.sym.keyBits.sym + 7)/8
           != sensitive->sensitive.sym.t.size)
            result = TPM_RC_BINDING;
       break;
   default:
       // The choice here is an assert or a return of a bad type for the object
       pAssert(0);
       break;
   }
   // For asymmetric keys, the algorithm for validating the linkage between
   // the public and private areas is algorithm dependent. For symmetric keys
   // the linkage is based on hashing the symKey and obfuscation values.
   if(   result == TPM_RC_SUCCESS && !isAsymmetric
      && publicArea->nameAlg != TPM_ALG_NULL)
   {
       TPM2B_DIGEST    uniqueToCompare;
        // Compute unique for symmetric key
        CryptComputeSymmetricUnique(publicArea->nameAlg, sensitive,
                                     &uniqueToCompare);
        // Compare unique
        if(!Memory2BEqual(&publicArea->unique.sym.b,
                          &uniqueToCompare.b))
            result = TPM_RC_BINDING;
   }
   return result;
}
//
//
//       10.2.9.15 CryptGetSignHashAlg()
//
//       Get the hash algorithm of signature from a TPMT_SIGNATURE structure. It assumes the signature is not
//       NULL This is a function for easy access
//
TPMI_ALG_HASH
CryptGetSignHashAlg(
   TPMT_SIGNATURE     *auth             // IN: signature
   )
{
   pAssert(auth->sigAlg != TPM_ALG_NULL);
   // Get authHash algorithm based on signing scheme
   switch(auth->sigAlg)
   {
#ifdef   TPM_ALG_RSA
        case TPM_ALG_RSASSA:
            return auth->signature.rsassa.hash;
        case TPM_ALG_RSAPSS:
            return auth->signature.rsapss.hash;
   #endif //TPM_ALG_RSA
   #ifdef TPM_ALG_ECC
       case TPM_ALG_ECDSA:
           return auth->signature.ecdsa.hash;
   #endif //TPM_ALG_ECC
            case TPM_ALG_HMAC:
                return auth->signature.hmac.hashAlg;
            default:
                return TPM_ALG_NULL;
    }
}
//
//
//       10.2.9.16 CryptIsSplitSign()
//
//       This function us used to determine if the signing operation is a split signing operation that required a
//       TPM2_Commit().
//
BOOL
CryptIsSplitSign(
    TPM_ALG_ID           scheme             // IN: the algorithm selector
    )
{
    if(   0
#    ifdef   TPM_ALG_ECDAA
       || scheme == TPM_ALG_ECDAA
#    endif   // TPM_ALG_ECDAA
        )
        return TRUE;
    return FALSE;
}
//
//
//       10.2.9.17 CryptIsSignScheme()
//
//       This function indicates if a scheme algorithm is a sign algorithm.
//
BOOL
CryptIsSignScheme(
    TPMI_ALG_ASYM_SCHEME           scheme
    )
{
    BOOL                isSignScheme = FALSE;
   switch(scheme)
   {
#ifdef TPM_ALG_RSA
       // If RSA is implemented, then both signing schemes are required
   case TPM_ALG_RSASSA:
   case TPM_ALG_RSAPSS:
       isSignScheme = TRUE;
       break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       // If ECC is implemented ECDSA is required
   case TPM_ALG_ECDSA:
#ifdef TPM_ALG_ECDAA
       // ECDAA is optional
   case TPM_ALG_ECDAA:
#endif
#ifdef   TPM_ALG_ECSCHNORR
       // Schnorr is also optional
   case TPM_ALG_ECSCHNORR:
#endif
#ifdef TPM_ALG_SM2
   case TPM_ALG_SM2:
#endif
       isSignScheme = TRUE;
       break;
#endif //TPM_ALG_ECC
   default:
       break;
   }
   return isSignScheme;
}
//
//
//       10.2.9.18 CryptIsDecryptScheme()
//
//       This function indicate if a scheme algorithm is a decrypt algorithm.
//
BOOL
CryptIsDecryptScheme(
    TPMI_ALG_ASYM_SCHEME           scheme
    )
{
    BOOL           isDecryptScheme = FALSE;
   switch(scheme)
   {
#ifdef TPM_ALG_RSA
       // If RSA is implemented, then both decrypt schemes are required
   case TPM_ALG_RSAES:
   case TPM_ALG_OAEP:
        isDecryptScheme = TRUE;
       break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       // If ECC is implemented ECDH is required
   case TPM_ALG_ECDH:
#ifdef TPM_ALG_SM2
   case TPM_ALG_SM2:
#endif
#ifdef TPM_ALG_ECMQV
   case TPM_ALG_ECMQV:
#endif
       isDecryptScheme = TRUE;
       break;
#endif //TPM_ALG_ECC
   default:
       break;
   }
   return isDecryptScheme;
}
//
//
//       10.2.9.19 CryptSelectSignScheme()
//
//       This function is used by the attestation and signing commands. It implements the rules for selecting the
//       signature scheme to use in signing. This function requires that the signing key either be TPM_RH_NULL
//       or be loaded.
//       If a default scheme is defined in object, the default scheme should be chosen, otherwise, the input
//       scheme should be chosen. In the case that both object and input scheme has a non-NULL scheme
//       algorithm, if the schemes are compatible, the input scheme will be chosen.
//
//
//
//
//       Error Returns                   Meaning
//
//       TPM_RC_KEY                      key referenced by signHandle is not a signing key
//       TPM_RC_SCHEME                   both scheme and key's default scheme are empty; or scheme is
//                                       empty while key's default scheme requires explicit input scheme (split
//                                       signing); or non-empty default key scheme differs from scheme
//
TPM_RC
CryptSelectSignScheme(
   TPMI_DH_OBJECT             signHandle,        // IN: handle of signing key
   TPMT_SIG_SCHEME           *scheme             // IN/OUT: signing scheme
   )
{
   OBJECT                    *signObject;
   TPMT_SIG_SCHEME           *objectScheme;
   TPMT_PUBLIC               *publicArea;
   TPM_RC                     result = TPM_RC_SUCCESS;
   // If the signHandle is TPM_RH_NULL, then the NULL scheme is used, regardless
   // of the setting of scheme
   if(signHandle == TPM_RH_NULL)
   {
       scheme->scheme = TPM_ALG_NULL;
       scheme->details.any.hashAlg = TPM_ALG_NULL;
   }
   else
   {
       // sign handle is not NULL so...
       // Get sign object pointer
       signObject = ObjectGet(signHandle);
       publicArea = &signObject->publicArea;
        // is this a signing key?
        if(!publicArea->objectAttributes.sign)
             result = TPM_RC_KEY;
        else
        {
             // "parms" defined to avoid long code lines.
             TPMU_PUBLIC_PARMS    *parms = &publicArea->parameters;
             if(CryptIsAsymAlgorithm(publicArea->type))
                 objectScheme = (TPMT_SIG_SCHEME *)&parms->asymDetail.scheme;
             else
                 objectScheme = (TPMT_SIG_SCHEME *)&parms->keyedHashDetail.scheme;
               // If the object doesn't have a default scheme, then use the
               // input scheme.
               if(objectScheme->scheme == TPM_ALG_NULL)
               {
                   // Input and default can't both be NULL
                   if(scheme->scheme == TPM_ALG_NULL)
                       result = TPM_RC_SCHEME;
                   // Assume that the scheme is compatible with the key. If not,
                   // we will generate an error in the signing operation.
               }
               else if(scheme->scheme == TPM_ALG_NULL)
               {
                   // input scheme is NULL so use default
                   // First, check to see if the default requires that the caller
                   // provided scheme data
                   if(CryptIsSplitSign(objectScheme->scheme))
                       result = TPM_RC_SCHEME;
                   else
                   {
                       scheme->scheme = objectScheme->scheme;
                       scheme->details.any.hashAlg
                                   = objectScheme->details.any.hashAlg;
                   }
               }
               else
               {
                   // Both input and object have scheme selectors
                   // If the scheme and the hash are not the same then...
                   if(    objectScheme->scheme != scheme->scheme
                       || (   objectScheme->details.any.hashAlg
                           != scheme->details.any.hashAlg))
                        result = TPM_RC_SCHEME;
               }
        }
   }
   return result;
}
//
//
//       10.2.9.20 CryptSign()
//
//       Sign a digest with asymmetric key or HMAC. This function is called by attestation commands and the
//       generic TPM2_Sign() command. This function checks the key scheme and digest size. It does not check
//       if the sign operation is allowed for restricted key. It should be checked before the function is called. The
//       function will assert if the key is not a signing key.
//
//       Error Returns                     Meaning
//
//       TPM_RC_SCHEME                     signScheme is not compatible with the signing key type
//       TPM_RC_VALUE                      digest value is greater than the modulus of signHandle or size of
//                                         hashData does not match hash algorithm insignScheme (for an RSA
//                                         key); invalid commit status or failed to generate r value (for an ECC
//                                         key)
//
TPM_RC
CryptSign(
   TPMI_DH_OBJECT            signHandle,          //   IN: The handle of sign key
   TPMT_SIG_SCHEME          *signScheme,          //   IN: sign scheme.
   TPM2B_DIGEST             *digest,              //   IN: The digest being signed
   TPMT_SIGNATURE           *signature            //   OUT: signature
   )
{
   OBJECT                   *signKey = ObjectGet(signHandle);
   TPM_RC                    result = TPM_RC_SCHEME;
   // check if input handle is a sign key
   pAssert(signKey->publicArea.objectAttributes.sign == SET);
   // Must have the private portion loaded. This check is made during
   // authorization.
   pAssert(signKey->attributes.publicOnly == CLEAR);
   // Initialize signature scheme
   signature->sigAlg = signScheme->scheme;
   // If the signature algorithm is TPM_ALG_NULL, then we are done
   if(signature->sigAlg == TPM_ALG_NULL)
       return TPM_RC_SUCCESS;
   // All the schemes other than TPM_ALG_NULL have a hash algorithm
    TEST_HASH(signScheme->details.any.hashAlg);
    // Initialize signature hash
    // Note: need to do the check for alg null first because the null scheme
    // doesn't have a hashAlg member.
    signature->signature.any.hashAlg = signScheme->details.any.hashAlg;
    // perform sign operation based on different key type
    switch (signKey->publicArea.type)
    {
#ifdef TPM_ALG_RSA
       case TPM_ALG_RSA:
           result = CryptSignRSA(signKey, signScheme, digest, signature);
           break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       case TPM_ALG_ECC:
           result = CryptSignECC(signKey, signScheme, digest, signature);
           break;
#endif //TPM_ALG_ECC
       case TPM_ALG_KEYEDHASH:
           result = CryptSignHMAC(signKey, signScheme, digest, signature);
           break;
       default:
           break;
   }
    return result;
}
//
//
//       10.2.9.21 CryptVerifySignature()
//
//       This function is used to verify a signature.               It is called by TPM2_VerifySignature() and
//       TPM2_PolicySigned().
//       Since this operation only requires use of a public key, no consistency checks are necessary for the key to
//       signature type because a caller can load any public key that they like with any scheme that they like. This
//       routine simply makes sure that the signature is correct, whatever the type.
//       This function requires that auth is not a NULL pointer.
//
//       Error Returns                    Meaning
//
//       TPM_RC_SIGNATURE                 the signature is not genuine
//       TPM_RC_SCHEME                    the scheme is not supported
//       TPM_RC_HANDLE                    an HMAC key was selected but the private part of the key is not
//                                        loaded
//
TPM_RC
CryptVerifySignature(
    TPMI_DH_OBJECT       keyHandle,         // IN: The handle of sign key
    TPM2B_DIGEST        *digest,            // IN: The digest being validated
    TPMT_SIGNATURE      *signature          // IN: signature
    )
{
    // NOTE: ObjectGet will either return a pointer to a loaded object or
    // will assert. It will never return a non-valid value. This makes it save
    // to initialize 'publicArea' with the return value from ObjectGet() without
    // checking it first.
    OBJECT              *authObject = ObjectGet(keyHandle);
    TPMT_PUBLIC         *publicArea = &authObject->publicArea;
    TPM_RC                    result = TPM_RC_SCHEME;
    // The input unmarshaling should prevent any input signature from being
    // a NULL signature, but just in case
    if(signature->sigAlg == TPM_ALG_NULL)
        return TPM_RC_SIGNATURE;
    switch (publicArea->type)
    {
#ifdef TPM_ALG_RSA
   case TPM_ALG_RSA:
       result = CryptRSAVerifySignature(authObject, digest, signature);
       break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
   case TPM_ALG_ECC:
       result = CryptECCVerifySignature(authObject, digest, signature);
       break;
#endif // TPM_ALG_ECC
    case TPM_ALG_KEYEDHASH:
        if(authObject->attributes.publicOnly)
             result = TPM_RC_HANDLE;
        else
             result = CryptHMACVerifySignature(authObject, digest, signature);
        break;
    default:
        break;
    }
    return result;
}
//
//
//       10.2.10 Math functions
//
//       10.2.10.1 CryptDivide()
//
//       This function interfaces to the math library for large number divide.
//
//       Error Returns                     Meaning
//
//       TPM_RC_SIZE                       quotient or remainder is too small to receive the result
//
TPM_RC
CryptDivide(
    TPM2B               *numerator,           //   IN: numerator
    TPM2B               *denominator,         //   IN: denominator
    TPM2B               *quotient,            //   OUT: quotient = numerator / denominator.
    TPM2B               *remainder            //   OUT: numerator mod denominator.
    )
{
    pAssert(   numerator != NULL         && denominator!= NULL
            && (quotient != NULL         || remainder != NULL)
           );
    // assume denominator is not         0
    pAssert(denominator->size !=         0);
    return TranslateCryptErrors(_math__Div(numerator,
                                           denominator,
                                                              quotient,
                                                              remainder)
                                           );
}
//
//
//       10.2.10.2 CryptCompare()
//
//       This function interfaces to the math library for large number, unsigned compare.
//
//       Return Value                         Meaning
//
//       1                                    if a > b
//       0                                    if a = b
//       -1                                   if a < b
//
LIB_EXPORT int
CryptCompare(
    const   UINT32         aSize,                  //   IN:   size of a
    const   BYTE          *a,                      //   IN:   a buffer
    const   UINT32         bSize,                  //   IN:   size of b
    const   BYTE          *b                       //   IN:   b buffer
    )
{
    return _math__uComp(aSize, a, bSize, b);
}
//
//
//       10.2.10.3 CryptCompareSigned()
//
//       This function interfaces to the math library for large number, signed compare.
//
//       Return Value                         Meaning
//
//       1                                    if a > b
//       0                                    if a = b
//       -1                                   if a < b
//
int
CryptCompareSigned(
    UINT32                 aSize,                  //   IN:   size of a
    BYTE                  *a,                      //   IN:   a buffer
    UINT32                 bSize,                  //   IN:   size of b
    BYTE                  *b                       //   IN:   b buffer
    )
{
    return _math__Comp(aSize, a, bSize, b);
}
//
//
//       10.2.10.4 CryptGetTestResult
//
//       This function returns the results of a self-test function.
//
//       NOTE:            the behavior in this function is NOT the correct behavior for a real TPM implementation. An artificial behavior is
//                        placed here due to the limitation of a software simulation environment. For the correct behavior, consult the
//                        part 3 specification for TPM2_GetTestResult().
//
TPM_RC
CryptGetTestResult(
    TPM2B_MAX_BUFFER            *outData                 // OUT: test result data
     )
{
     outData->t.size = 0;
     return TPM_RC_SUCCESS;
}
//
//
//       10.2.11 Capability Support
//
//       10.2.11.1 CryptCapGetECCCurve()
//
//       This function returns the list of implemented ECC curves.
//
//       Return Value                      Meaning
//
//       YES                               if no more ECC curve is available
//       NO                                if there are more ECC curves not reported
//
#ifdef TPM_ALG_ECC //% 5
TPMI_YES_NO
CryptCapGetECCCurve(
     TPM_ECC_CURVE      curveID,             // IN: the starting ECC curve
     UINT32             maxCount,            // IN: count of returned curve
     TPML_ECC_CURVE    *curveList            // OUT: ECC curve list
     )
{
     TPMI_YES_NO         more = NO;
     UINT16              i;
     UINT32              count = _cpri__EccGetCurveCount();
     TPM_ECC_CURVE       curve;
     // Initialize output property list
     curveList->count = 0;
     // The maximum count of curves we may return is MAX_ECC_CURVES
     if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES;
     // Scan the eccCurveValues array
     for(i = 0; i < count; i++)
     {
         curve = _cpri__GetCurveIdByIndex(i);
         // If curveID is less than the starting curveID, skip it
         if(curve < curveID)
             continue;
         if(curveList->count < maxCount)
         {
              // If we have not filled up the return list, add more curves to
              // it
              curveList->eccCurves[curveList->count] = curve;
              curveList->count++;
         }
         else
         {
              // If the return list is full but we still have curves
              // available, report this and stop iterating
              more = YES;
              break;
         }
     }
     return more;
}
//
//
//       10.2.11.2 CryptCapGetEccCurveNumber()
//
//       This function returns the number of ECC curves supported by the TPM.
//
UINT32
CryptCapGetEccCurveNumber(
   void
   )
{
   // There is an array that holds the curve data. Its size divided by the
   // size of an entry is the number of values in the table.
   return _cpri__EccGetCurveCount();
}
#endif //TPM_ALG_ECC //% 5
//
//
//       10.2.11.3 CryptAreKeySizesConsistent()
//
//       This function validates that the public key size values are consistent for an asymmetric key.
//
//       NOTE:           This is not a comprehensive test of the public key.
//
//
//       Return Value                        Meaning
//
//       TRUE                                sizes are consistent
//       FALSE                               sizes are not consistent
//
BOOL
CryptAreKeySizesConsistent(
   TPMT_PUBLIC           *publicArea              // IN: the public area to check
   )
{
   BOOL                  consistent = FALSE;
   switch (publicArea->type)
   {
#ifdef TPM_ALG_RSA
       case TPM_ALG_RSA:
           // The key size in bits is filtered by the unmarshaling
           consistent = (     ((publicArea->parameters.rsaDetail.keyBits+7)/8)
                           == publicArea->unique.rsa.t.size);
           break;
#endif //TPM_ALG_RSA
#ifdef TPM_ALG_ECC
       case TPM_ALG_ECC:
           {
               UINT16                        keySizeInBytes;
               TPM_ECC_CURVE                 curveId = publicArea->parameters.eccDetail.curveID;
                   keySizeInBytes = CryptEccGetKeySizeInBytes(curveId);
                   consistent =         keySizeInBytes > 0
                                     && publicArea->unique.ecc.x.t.size <= keySizeInBytes
                                     && publicArea->unique.ecc.y.t.size <= keySizeInBytes;
           }
           break;
#endif //TPM_ALG_ECC
       default:
           break;
      }
      return consistent;
}
//
//
//       10.2.11.4 CryptAlgSetImplemented()
//
//       This function initializes the bit vector with one bit for each implemented algorithm. This function is called
//       from _TPM_Init(). The vector of implemented algorithms should be generated by the part 2 parser so that
//       the g_implementedAlgorithms vector can be a const. That's not how it is now
//
void
CryptAlgsSetImplemented(
      void
      )
{
      AlgorithmGetImplementedVector(&g_implementedAlgorithms);
}