// 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 <string.h>

#include "OsslCryptoEngine.h"
#ifdef TPM_ALG_RSA
//
//
//      Local Functions
//
//      RsaPrivateExponent()
//
//     This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus
//     and one of the primes.
//     The results are returned in the key->private structure. The size of that structure is expanded to hold the
//     private exponent. If the computed value is smaller than the public modulus, the private exponent is de-
//     normalized.
//
//     Return Value                      Meaning
//
//     CRYPT_SUCCESS                     private exponent computed
//     CRYPT_PARAMETER                   prime is not half the size of the modulus, or the modulus is not evenly
//                                       divisible by the prime, or no private exponent could be computed
//                                       from the input parameters
//
CRYPT_RESULT
RsaPrivateExponent(
   RSA_KEY             *key                  // IN: the key to augment with the private
                                             //     exponent
   )
{
   BN_CTX              *context;
   BIGNUM              *bnD;
   BIGNUM              *bnN;
   BIGNUM              *bnP;
   BIGNUM              *bnE;
   BIGNUM              *bnPhi;
   BIGNUM              *bnQ;
   BIGNUM              *bnQr;
   UINT32               fill;
   CRYPT_RESULT         retVal = CRYPT_SUCCESS;                // Assume success
   pAssert(key != NULL && key->privateKey != NULL && key->publicKey != NULL);
   context = BN_CTX_new();
   if(context == NULL)
       FAIL(FATAL_ERROR_ALLOCATION);
   BN_CTX_start(context);
   bnE = BN_CTX_get(context);
   bnD = BN_CTX_get(context);
   bnN = BN_CTX_get(context);
   bnP = BN_CTX_get(context);
   bnPhi = BN_CTX_get(context);
   bnQ = BN_CTX_get(context);
   bnQr = BN_CTX_get(context);
   if(bnQr == NULL)
       FAIL(FATAL_ERROR_ALLOCATION);
   // Assume the size of the public key value is within range
   pAssert(key->publicKey->size <= MAX_RSA_KEY_BYTES);
   if(   BN_bin2bn(key->publicKey->buffer, key->publicKey->size, bnN) == NULL
      || BN_bin2bn(key->privateKey->buffer, key->privateKey->size, bnP) == NULL)
        FAIL(FATAL_ERROR_INTERNAL);
   // If P size is not 1/2 of n size, then this is not a valid value for this
   // implementation. This will also catch the case were P is input as zero.
   // This generates a return rather than an assert because the key being loaded
   // might be SW generated and wrong.
   if(BN_num_bits(bnP) < BN_num_bits(bnN)/2)
   {
       retVal = CRYPT_PARAMETER;
       goto Cleanup;
   }
   // Get q = n/p;
   if (BN_div(bnQ, bnQr, bnN, bnP, context) != 1)
       FAIL(FATAL_ERROR_INTERNAL);
   // If there is a remainder, then this is not a valid n
   if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP))
   {
       retVal = CRYPT_PARAMETER;      // problem may be recoverable
       goto Cleanup;
   }
   // Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1
   if(   BN_copy(bnPhi, bnN) == NULL
      || !BN_sub(bnPhi, bnPhi, bnP)
      || !BN_sub(bnPhi, bnPhi, bnQ)
      || !BN_add_word(bnPhi, 1))
       FAIL(FATAL_ERROR_INTERNAL);
   // Compute the multiplicative inverse
   BN_set_word(bnE, key->exponent);
   if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL)
   {
       // Going to assume that the error is caused by a bad
       // set of parameters. Specifically, an exponent that is
       // not compatible with the primes. In an implementation that
       // has better visibility to the error codes, this might be
       // refined so that failures in the library would return
       // a more informative value. Should not assume here that
       // the error codes will remain unchanged.
        retVal = CRYPT_PARAMETER;
        goto Cleanup;
   }
   fill = key->publicKey->size - BN_num_bytes(bnD);
   BN_bn2bin(bnD, &key->privateKey->buffer[fill]);
   memset(key->privateKey->buffer, 0, fill);
   // Change the size of the private key so that it is known to contain
   // a private exponent rather than a prime.
   key->privateKey->size = key->publicKey->size;
Cleanup:
   BN_CTX_end(context);
   BN_CTX_free(context);
   return retVal;
}
//
//
//       _cpri__TestKeyRSA()
//
//      This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus
//      and one of the primes or two primes.
//      If both primes are provided, the public modulus is computed. If only one prime is provided, the second
//      prime is computed. In either case, a private exponent is produced and placed in d.
//      If no modular inverse exists, then CRYPT_PARAMETER is returned.
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     private exponent (d) was generated
//      CRYPT_PARAMETER                   one or more parameters are invalid
//
LIB_EXPORT CRYPT_RESULT
_cpri__TestKeyRSA(
   TPM2B              *d,                    //   OUT: the address to receive the private
                                             //       exponent
   UINT32              exponent,             //   IN: the public modulu
   TPM2B              *publicKey,            //   IN/OUT: an input if only one prime is
                                             //       provided. an output if both primes are
                                             //       provided
   TPM2B              *prime1,               //   IN: a first prime
   TPM2B              *prime2                //   IN: an optional second prime
   )
{
   BN_CTX             *context;
   BIGNUM             *bnD;
   BIGNUM             *bnN;
   BIGNUM             *bnP;
   BIGNUM             *bnE;
   BIGNUM             *bnPhi;
   BIGNUM             *bnQ;
   BIGNUM             *bnQr;
   UINT32             fill;
   CRYPT_RESULT       retVal = CRYPT_SUCCESS;               // Assume success
   pAssert(publicKey != NULL && prime1 != NULL);
   // Make sure that the sizes are within range
   pAssert(   prime1->size <= MAX_RSA_KEY_BYTES/2
           && publicKey->size <= MAX_RSA_KEY_BYTES);
   pAssert( prime2 == NULL || prime2->size < MAX_RSA_KEY_BYTES/2);
   if(publicKey->size/2 != prime1->size)
       return CRYPT_PARAMETER;
   context = BN_CTX_new();
   if(context == NULL)
       FAIL(FATAL_ERROR_ALLOCATION);
   BN_CTX_start(context);
   bnE = BN_CTX_get(context);       //   public exponent (e)
   bnD = BN_CTX_get(context);       //   private exponent (d)
   bnN = BN_CTX_get(context);       //   public modulus (n)
   bnP = BN_CTX_get(context);       //   prime1 (p)
   bnPhi = BN_CTX_get(context);     //   (p-1)(q-1)
   bnQ = BN_CTX_get(context);       //   prime2 (q)
   bnQr = BN_CTX_get(context);      //   n mod p
   if(bnQr == NULL)
       FAIL(FATAL_ERROR_ALLOCATION);
   if(BN_bin2bn(prime1->buffer, prime1->size, bnP) == NULL)
       FAIL(FATAL_ERROR_INTERNAL);
   // If prime2 is provided, then compute n
   if(prime2 != NULL)
   {
       // Two primes provided so use them to compute n
       if(BN_bin2bn(prime2->buffer, prime2->size, bnQ) == NULL)
           FAIL(FATAL_ERROR_INTERNAL);
        // Make sure that the sizes of the primes are compatible
        if(BN_num_bits(bnQ) != BN_num_bits(bnP))
        {
            retVal = CRYPT_PARAMETER;
            goto Cleanup;
        }
        // Multiply the primes to get the public modulus
        if(BN_mul(bnN, bnP, bnQ, context) != 1)
            FAIL(FATAL_ERROR_INTERNAL);
        // if the space provided for the public modulus is large enough,
        // save the created value
        if(BN_num_bits(bnN) != (publicKey->size * 8))
        {
            retVal = CRYPT_PARAMETER;
            goto Cleanup;
        }
        BN_bn2bin(bnN, publicKey->buffer);
   }
   else
   {
       // One prime provided so find the second prime by division
       BN_bin2bn(publicKey->buffer, publicKey->size, bnN);
        // Get q = n/p;
        if(BN_div(bnQ, bnQr, bnN, bnP, context) != 1)
            FAIL(FATAL_ERROR_INTERNAL);
        // If there is a remainder, then this is not a valid n
        if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP))
        {
            retVal = CRYPT_PARAMETER;      // problem may be recoverable
            goto Cleanup;
        }
   }
   // Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1
   BN_copy(bnPhi, bnN);
   BN_sub(bnPhi, bnPhi, bnP);
   BN_sub(bnPhi, bnPhi, bnQ);
   BN_add_word(bnPhi, 1);
   // Compute the multiplicative inverse
   BN_set_word(bnE, exponent);
   if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL)
   {
        // Going to assume that the error is caused by a bad set of parameters.
        // Specifically, an exponent that is not compatible with the primes.
        // In an implementation that has better visibility to the error codes,
        // this might be refined so that failures in the library would return
        // a more informative value.
        // Do not assume that the error codes will remain unchanged.
        retVal = CRYPT_PARAMETER;
        goto Cleanup;
   }
   // Return the private exponent.
   // Make sure it is normalized to have the correct size.
   d->size = publicKey->size;
   fill = d->size - BN_num_bytes(bnD);
   BN_bn2bin(bnD, &d->buffer[fill]);
   memset(d->buffer, 0, fill);
Cleanup:
   BN_CTX_end(context);
   BN_CTX_free(context);
   return retVal;
}
//
//
//       RSAEP()
//
//      This function performs the RSAEP operation defined in PKCS#1v2.1. It is an exponentiation of a value
//      (m) with the public exponent (e), modulo the public (n).
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     encryption complete
//      CRYPT_PARAMETER                   number to exponentiate is larger than the modulus
//
static CRYPT_RESULT
RSAEP (
   UINT32              dInOutSize,           // OUT size of the encrypted block
   BYTE               *dInOut,               // OUT: the encrypted data
   RSA_KEY            *key                   // IN: the key to use
   )
{
   UINT32       e;
   BYTE         exponent[4];
   CRYPT_RESULT retVal;
   e = key->exponent;
   if(e == 0)
       e = RSA_DEFAULT_PUBLIC_EXPONENT;
   UINT32_TO_BYTE_ARRAY(e, exponent);
   //!!! Can put check for test of RSA here
   retVal = _math__ModExp(dInOutSize, dInOut, dInOutSize, dInOut, 4, exponent,
                          key->publicKey->size, key->publicKey->buffer);
   // Exponentiation result is stored in-place, thus no space shortage is possible.
   pAssert(retVal != CRYPT_UNDERFLOW);
   return retVal;
}
//
//
//       RSADP()
//
//      This function performs the RSADP operation defined in PKCS#1v2.1. It is an exponentiation of a value (c)
//      with the private exponent (d), modulo the public modulus (n). The decryption is in place.
//
//      This function also checks the size of the private key. If the size indicates that only a prime value is
//      present, the key is converted to being a private exponent.
//
//      Return Value                   Meaning
//
//      CRYPT_SUCCESS                  decryption succeeded
//      CRYPT_PARAMETER                the value to decrypt is larger than the modulus
//
static CRYPT_RESULT
RSADP (
   UINT32              dInOutSize,        // IN/OUT: size of decrypted data
   BYTE               *dInOut,            // IN/OUT: the decrypted data
   RSA_KEY            *key                // IN: the key
   )
{
   CRYPT_RESULT retVal;
   //!!! Can put check for RSA tested here
   // Make sure that the pointers are provided and that the private key is present
   // If the private key is present it is assumed to have been created by
   // so is presumed good _cpri__PrivateExponent
   pAssert(key != NULL && dInOut != NULL &&
           key->publicKey->size == key->publicKey->size);
   // make sure that the value to be decrypted is smaller than the modulus
   // note: this check is redundant as is also performed by _math__ModExp()
   // which is optimized for use in RSA operations
   if(_math__uComp(key->publicKey->size, key->publicKey->buffer,
                   dInOutSize, dInOut) <= 0)
       return CRYPT_PARAMETER;
   // _math__ModExp can return CRYPT_PARAMTER or CRYPT_UNDERFLOW but actual
   // underflow is not possible because everything is in the same buffer.
   retVal = _math__ModExp(dInOutSize, dInOut, dInOutSize, dInOut,
                          key->privateKey->size, key->privateKey->buffer,
                          key->publicKey->size, key->publicKey->buffer);
   // Exponentiation result is stored in-place, thus no space shortage is possible.
   pAssert(retVal != CRYPT_UNDERFLOW);
   return retVal;
}
//
//
//       OaepEncode()
//
//      This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must
//      equal the size of the modulus
//
//      Return Value                   Meaning
//
//      CRYPT_SUCCESS                  encode successful
//      CRYPT_PARAMETER                hashAlg is not valid
//      CRYPT_FAIL                     message size is too large
//
static CRYPT_RESULT
OaepEncode(
   UINT32          paddedSize,       //   IN: pad value size
   BYTE           *padded,           //   OUT: the pad data
   TPM_ALG_ID      hashAlg,          //   IN: algorithm to use for padding
   const char     *label,            //   IN: null-terminated string (may be NULL)
   UINT32       messageSize,   // IN: the message size
   BYTE        *message        // IN: the message being padded
#ifdef TEST_RSA                 //
   , BYTE          *testSeed   // IN: optional seed used for testing.
#endif // TEST_RSA              //
)
{
   UINT32       padLen;
   UINT32       dbSize;
   UINT32       i;
   BYTE         mySeed[MAX_DIGEST_SIZE];
   BYTE        *seed = mySeed;
   INT32        hLen = _cpri__GetDigestSize(hashAlg);
   BYTE         mask[MAX_RSA_KEY_BYTES];
   BYTE        *pp;
   BYTE        *pm;
   UINT32       lSize = 0;
   CRYPT_RESULT retVal = CRYPT_SUCCESS;
   pAssert(padded != NULL && message != NULL);
   // A value of zero is not allowed because the KDF can't produce a result
   // if the digest size is zero.
   if(hLen <= 0)
       return CRYPT_PARAMETER;
   // If a label is provided, get the length of the string, including the
   // terminator
   if(label != NULL)
       lSize = (UINT32)strlen(label) + 1;
   // Basic size check
   // messageSize <= k 2hLen 2
   if(messageSize > paddedSize - 2 * hLen - 2)
       return CRYPT_FAIL;
   // Hash L even if it is null
   // Offset into padded leaving room for masked seed and byte of zero
   pp = &padded[hLen + 1];
   retVal = _cpri__HashBlock(hashAlg, lSize, (BYTE *)label, hLen, pp);
   // concatenate PS of k mLen 2hLen 2
   padLen = paddedSize - messageSize - (2 * hLen) - 2;
   memset(&pp[hLen], 0, padLen);
   pp[hLen+padLen] = 0x01;
   padLen += 1;
   memcpy(&pp[hLen+padLen], message, messageSize);
   // The total size of db = hLen + pad + mSize;
   dbSize = hLen+padLen+messageSize;
   // If testing, then use the provided seed. Otherwise, use values
   // from the RNG
#ifdef TEST_RSA
   if(testSeed != NULL)
       seed = testSeed;
   else
#endif // TEST_RSA
       _cpri__GenerateRandom(hLen, mySeed);
   // mask = MGF1 (seed, nSize hLen 1)
   if((retVal = _cpri__MGF1(dbSize, mask, hashAlg, hLen, seed)) < 0)
       return retVal; // Don't expect an error because hash size is not zero
                      // was detected in the call to _cpri__HashBlock() above.
   // Create the masked db
    pm = mask;
    for(i = dbSize; i > 0; i--)
        *pp++ ^= *pm++;
    pp = &padded[hLen + 1];
    // Run the masked data through MGF1
    if((retVal = _cpri__MGF1(hLen, &padded[1], hashAlg, dbSize, pp)) < 0)
        return retVal; // Don't expect zero here as the only case for zero
                       // was detected in the call to _cpri__HashBlock() above.
    // Now XOR the seed to create masked seed
    pp = &padded[1];
    pm = seed;
    for(i = hLen; i > 0; i--)
        *pp++ ^= *pm++;
    // Set the first byte to zero
    *padded = 0x00;
    return CRYPT_SUCCESS;
}
//
//
//       OaepDecode()
//
//      This function performs OAEP padding checking. The size of the buffer to receive the recovered data. If
//      the padding is not valid, the dSize size is set to zero and the function returns CRYPT_NO_RESULTS.
//      The dSize parameter is used as an input to indicate the size available in the buffer. If insufficient space is
//      available, the size is not changed and the return code is CRYPT_FAIL.
//
//      Return Value                     Meaning
//
//      CRYPT_SUCCESS                    decode complete
//      CRYPT_PARAMETER                  the value to decode was larger than the modulus
//      CRYPT_FAIL                       the padding is wrong or the buffer to receive the results is too small
//
static CRYPT_RESULT
OaepDecode(
    UINT32              *dataOutSize,        //   IN/OUT: the recovered data size
    BYTE                *dataOut,            //   OUT: the recovered data
    TPM_ALG_ID           hashAlg,            //   IN: algorithm to use for padding
    const char          *label,              //   IN: null-terminated string (may be NULL)
    UINT32               paddedSize,         //   IN: the size of the padded data
    BYTE                *padded              //   IN: the padded data
    )
{
    UINT32          dSizeSave;
    UINT32          i;
    BYTE            seedMask[MAX_DIGEST_SIZE];
    INT32           hLen = _cpri__GetDigestSize(hashAlg);
    BYTE         mask[MAX_RSA_KEY_BYTES];
    BYTE        *pp;
    BYTE        *pm;
    UINT32       lSize = 0;
    CRYPT_RESULT retVal = CRYPT_SUCCESS;
    // Unknown hash
    pAssert(hLen > 0 && dataOutSize != NULL && dataOut != NULL && padded != NULL);
    // If there is a label, get its size including the terminating 0x00
    if(label != NULL)
        lSize = (UINT32)strlen(label) + 1;
   // Set the return size to zero so that it doesn't have to be done on each
   // failure
   dSizeSave = *dataOutSize;
   *dataOutSize = 0;
   // Strange size (anything smaller can't be an OAEP padded block)
   // Also check for no leading 0
   if(paddedSize < (unsigned)((2 * hLen) + 2) || *padded != 0)
       return CRYPT_FAIL;
   // Use the hash size to determine what to put through MGF1 in order
   // to recover the seedMask
   if((retVal = _cpri__MGF1(hLen, seedMask, hashAlg,
                            paddedSize-hLen-1, &padded[hLen+1])) < 0)
       return retVal;
   // Recover the seed into seedMask
   pp = &padded[1];
   pm = seedMask;
   for(i = hLen; i > 0; i--)
       *pm++ ^= *pp++;
   // Use the seed to generate the data mask
   if((retVal = _cpri__MGF1(paddedSize-hLen-1, mask,     hashAlg,
                            hLen, seedMask)) < 0)
       return retVal;
   // Use the mask generated from seed to recover the padded data
   pp = &padded[hLen+1];
   pm = mask;
   for(i = paddedSize-hLen-1; i > 0; i--)
       *pm++ ^= *pp++;
   // Make sure that the recovered data has the hash of the label
   // Put trial value in the seed mask
   if((retVal=_cpri__HashBlock(hashAlg, lSize,(BYTE *)label, hLen, seedMask)) < 0)
       return retVal;
   if(memcmp(seedMask, mask, hLen) != 0)
       return CRYPT_FAIL;
   // find the start of the data
   pm = &mask[hLen];
   for(i = paddedSize-(2*hLen)-1; i > 0; i--)
   {
       if(*pm++ != 0)
           break;
   }

   // Magic value in the end of the fill area must be 1, anything else must be
   // rejected.
   if (pm[-1] != 1)
     return CRYPT_FAIL;

   if(i == 0)
       return CRYPT_PARAMETER;
   // pm should be pointing at the first part of the data
   // and i is one greater than the number of bytes to move
   i--;
   if(i > dSizeSave)
   {
        // Restore dSize
        *dataOutSize = dSizeSave;
        return CRYPT_FAIL;
   }
   memcpy(dataOut, pm, i);
   *dataOutSize = i;
   return CRYPT_SUCCESS;
}
//
//
//       PKSC1v1_5Encode()
//
//      This function performs the encoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1
//
//      Return Value                  Meaning
//
//      CRYPT_SUCCESS                 data encoded
//      CRYPT_PARAMETER               message size is too large
//
static CRYPT_RESULT
RSAES_PKSC1v1_5Encode(
   UINT32              paddedSize,        //   IN: pad value size
   BYTE               *padded,            //   OUT: the pad data
   UINT32              messageSize,       //   IN: the message size
   BYTE               *message            //   IN: the message being padded
   )
{
   UINT32      ps = paddedSize - messageSize - 3;
   if(messageSize > paddedSize - 11)
       return CRYPT_PARAMETER;
   // move the message to the end of the buffer
   memcpy(&padded[paddedSize - messageSize], message, messageSize);
   // Set the first byte to 0x00 and the second to 0x02
   *padded = 0;
   padded[1] = 2;
   // Fill with random bytes
   _cpri__GenerateRandom(ps, &padded[2]);
   // Set the delimiter for the random field to 0
   padded[2+ps] = 0;
   // Now, the only messy part. Make sure that all the ps bytes are non-zero
   // In this implementation, use the value of the current index
   for(ps++; ps > 1; ps--)
   {
       if(padded[ps] == 0)
           padded[ps] = 0x55;    // In the < 0.5% of the cases that the random
                                 // value is 0, just pick a value to put into
                                 // the spot.
   }
   return CRYPT_SUCCESS;
}
//
//
//       RSAES_Decode()
//
//      This function performs the decoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1
//
//      Return Value                  Meaning
//
//      CRYPT_SUCCESS                 decode successful
//      CRYPT_FAIL                    decoding error or results would no fit into provided buffer
//
static CRYPT_RESULT
RSAES_Decode(
   UINT32             *messageSize,       //   IN/OUT: recovered message size
   BYTE               *message,           //   OUT: the recovered message
   UINT32              codedSize,         //   IN: the encoded message size
   BYTE               *coded              //   IN: the encoded message
   )
{
   BOOL           fail = FALSE;
   UINT32         ps;
   fail = (codedSize < 11);
   fail |= (coded[0] != 0x00) || (coded[1] != 0x02);
   for(ps = 2; ps < codedSize; ps++)
   {
       if(coded[ps] == 0)
           break;
   }
   ps++;
   // Make sure that ps has not gone over the end and that there are at least 8
   // bytes of pad data.
   fail |= ((ps >= codedSize) || ((ps-2) < 8));
   if((*messageSize < codedSize - ps) || fail)
       return CRYPT_FAIL;
   *messageSize = codedSize - ps;
   memcpy(message, &coded[ps], codedSize - ps);
   return CRYPT_SUCCESS;
}
//
//
//       PssEncode()
//
//      This function creates an encoded block of data that is the size of modulus. The function uses the
//      maximum salt size that will fit in the encoded block.
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     encode successful
//      CRYPT_PARAMETER                   hashAlg is not a supported hash algorithm
//
static CRYPT_RESULT
PssEncode   (
   UINT32        eOutSize,        // IN: size of the encode data buffer
   BYTE         *eOut,            // OUT: encoded data buffer
   TPM_ALG_ID    hashAlg,         // IN: hash algorithm to use for the encoding
   UINT32        hashInSize,      // IN: size of digest to encode
   BYTE         *hashIn           // IN: the digest
#ifdef TEST_RSA                    //
   , BYTE          *saltIn        // IN: optional parameter for testing
#endif // TEST_RSA                 //
)
{
   INT32                  hLen = _cpri__GetDigestSize(hashAlg);
   BYTE                   salt[MAX_RSA_KEY_BYTES - 1];
   UINT16                 saltSize;
   BYTE                 *ps = salt;
   CRYPT_RESULT           retVal;
   UINT16                 mLen;
   CPRI_HASH_STATE        hashState;
   // These are fatal errors indicating bad TPM firmware
   pAssert(eOut != NULL && hLen > 0 && hashIn != NULL );
   // Get the size of the mask
   mLen = (UINT16)(eOutSize - hLen - 1);
   // Maximum possible salt size is mask length - 1
   saltSize = mLen - 1;
   // Use the maximum salt size allowed by FIPS 186-4
   if(saltSize > hLen)
       saltSize = (UINT16)hLen;
//using eOut for scratch space
   // Set the first 8 bytes to zero
   memset(eOut, 0, 8);
   // Get set the salt
#ifdef TEST_RSA
   if(saltIn != NULL)
   {
       saltSize = hLen;
       memcpy(salt, saltIn, hLen);
   }
   else
#endif // TEST_RSA
       _cpri__GenerateRandom(saltSize, salt);
   // Create the hash of the pad || input hash || salt
   _cpri__StartHash(hashAlg, FALSE, &hashState);
   _cpri__UpdateHash(&hashState, 8, eOut);
   _cpri__UpdateHash(&hashState, hashInSize, hashIn);
   _cpri__UpdateHash(&hashState, saltSize, salt);
   _cpri__CompleteHash(&hashState, hLen, &eOut[eOutSize - hLen - 1]);
   // Create a mask
   if((retVal = _cpri__MGF1(mLen, eOut, hashAlg, hLen, &eOut[mLen])) < 0)
   {
       // Currently _cpri__MGF1 is not expected to return a CRYPT_RESULT error.
       pAssert(0);
   }
   // Since this implementation uses key sizes that are all even multiples of
   // 8, just need to make sure that the most significant bit is CLEAR
   eOut[0] &= 0x7f;
   // Before we mess up the eOut value, set the last byte to 0xbc
   eOut[eOutSize - 1] = 0xbc;
   // XOR a byte of 0x01 at the position just before where the salt will be XOR'ed
   eOut = &eOut[mLen - saltSize - 1];
   *eOut++ ^= 0x01;
   // XOR the salt data into the buffer
   for(; saltSize > 0; saltSize--)
       *eOut++ ^= *ps++;
   // and we are done
   return CRYPT_SUCCESS;
}
//
//
//       PssDecode()
//
//      This function checks that the PSS encoded block was built from the provided digest. If the check is
//      successful, CRYPT_SUCCESS is returned. Any other value indicates an error.
//      This implementation of PSS decoding is intended for the reference TPM implementation and is not at all
//      generalized. It is used to check signatures over hashes and assumptions are made about the sizes of
//      values. Those assumptions are enforce by this implementation. This implementation does allow for a
//      variable size salt value to have been used by the creator of the signature.
//
//
//
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     decode successful
//      CRYPT_SCHEME                      hashAlg is not a supported hash algorithm
//      CRYPT_FAIL                        decode operation failed
//
static CRYPT_RESULT
PssDecode(
   TPM_ALG_ID          hashAlg,              //   IN:   hash algorithm to use for the encoding
   UINT32              dInSize,              //   IN:   size of the digest to compare
   BYTE               *dIn,                  //   In:   the digest to compare
   UINT32              eInSize,              //   IN:   size of the encoded data
   BYTE               *eIn,                  //   IN:   the encoded data
   UINT32              saltSize              //   IN:   the expected size of the salt
   )
{
   INT32            hLen = _cpri__GetDigestSize(hashAlg);
   BYTE             mask[MAX_RSA_KEY_BYTES];
   BYTE            *pm = mask;
   BYTE             pad[8] = {0};
   UINT32           i;
   UINT32           mLen;
   BOOL             fail = FALSE;
   CRYPT_RESULT     retVal;
   CPRI_HASH_STATE hashState;
   // These errors are indicative of failures due to programmer error
   pAssert(dIn != NULL && eIn != NULL);
   // check the hash scheme
   if(hLen == 0)
       return CRYPT_SCHEME;
   // most significant bit must be zero
   fail = ((eIn[0] & 0x80) != 0);
   // last byte must be 0xbc
   fail |= (eIn[eInSize - 1] != 0xbc);
   // Use the hLen bytes at the end of the buffer to generate a mask
   // Doesn't start at the end which is a flag byte
   mLen = eInSize - hLen - 1;
   if((retVal = _cpri__MGF1(mLen, mask, hashAlg, hLen, &eIn[mLen])) < 0)
       return retVal;
   if(retVal == 0)
       return CRYPT_FAIL;
   // Clear the MSO of the mask to make it consistent with the encoding.
   mask[0] &= 0x7F;
   // XOR the data into the mask to recover the salt. This sequence
   // advances eIn so that it will end up pointing to the seed data
   // which is the hash of the signature data
   for(i = mLen; i > 0; i--)
       *pm++ ^= *eIn++;
   // Find the first byte of 0x01 after a string of all 0x00
   for(pm = mask, i = mLen; i > 0; i--)
   {
       if(*pm == 0x01)
            break;
       else
            fail |= (*pm++ != 0);
   }
   fail |= (i == 0);
   // if we have failed, will continue using the entire mask as the salt value so
   // that the timing attacks will not disclose anything (I don't think that this
   // is a problem for TPM applications but, usually, we don't fail so this
   // doesn't cost anything).
   if(fail)
   {
       i = mLen;
       pm = mask;
   }
   else
   {
       pm++;
       i--;
   }
   // If the salt size was provided, then the recovered size must match
   fail |= (saltSize != 0 && i != saltSize);
   // i contains the salt size and pm points to the salt. Going to use the input
   // hash and the seed to recreate the hash in the lower portion of eIn.
   _cpri__StartHash(hashAlg, FALSE, &hashState);
   // add the pad of 8 zeros
   _cpri__UpdateHash(&hashState, 8, pad);
   // add the provided digest value
   _cpri__UpdateHash(&hashState, dInSize, dIn);
   // and the salt
   _cpri__UpdateHash(&hashState, i, pm);
   // get the result
   retVal = _cpri__CompleteHash(&hashState, MAX_DIGEST_SIZE, mask);
   // retVal will be the size of the digest or zero. If not equal to the indicated
   // digest size, then the signature doesn't match
   fail |= (retVal != hLen);
   fail |= (memcmp(mask, eIn, hLen) != 0);
   if(fail)
       return CRYPT_FAIL;
   else
       return CRYPT_SUCCESS;
}
//
//
//       PKSC1v1_5SignEncode()
//
//      Encode a message using PKCS1v1().5 method.
//
//      Return Value                  Meaning
//
//      CRYPT_SUCCESS                 encode complete
//      CRYPT_SCHEME                  hashAlg is not a supported hash algorithm
//      CRYPT_PARAMETER               eOutSize is not large enough or hInSize does not match the digest
//                                    size of hashAlg
//
static CRYPT_RESULT
RSASSA_Encode(
   UINT32              eOutSize,         //   IN: the size of the resulting block
   BYTE               *eOut,             //   OUT: the encoded block
   TPM_ALG_ID          hashAlg,          //   IN: hash algorithm for PKSC1v1_5
   UINT32              hInSize,          //   IN: size of hash to be signed
   BYTE               *hIn               //   IN: hash buffer
   )
{
   const BYTE         *der;
   INT32               derSize = _cpri__GetHashDER(hashAlg, &der);
   INT32               fillSize;
   pAssert(eOut != NULL && hIn != NULL);
   // Can't use this scheme if the algorithm doesn't have a DER string defined.
   if(derSize == 0 )
       return CRYPT_SCHEME;
   // If the digest size of 'hashAl' doesn't match the input digest size, then
   // the DER will misidentify the digest so return an error
   if((unsigned)_cpri__GetDigestSize(hashAlg) != hInSize)
       return CRYPT_PARAMETER;
   fillSize = eOutSize - derSize - hInSize - 3;
   // Make sure that this combination will fit in the provided space
   if(fillSize < 8)
       return CRYPT_PARAMETER;
   // Start filling
   *eOut++ = 0; // initial byte of zero
   *eOut++ = 1; // byte of 0x01
   for(; fillSize > 0; fillSize--)
       *eOut++ = 0xff; // bunch of 0xff
   *eOut++ = 0; // another 0
   for(; derSize > 0; derSize--)
       *eOut++ = *der++;   // copy the DER
   for(; hInSize > 0; hInSize--)
       *eOut++ = *hIn++;   // copy the hash
   return CRYPT_SUCCESS;
}
//
//
//       RSASSA_Decode()
//
//      This function performs the RSASSA decoding of a signature.
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     decode successful
//      CRYPT_FAIL                        decode unsuccessful
//      CRYPT_SCHEME                      haslAlg is not supported
//
static CRYPT_RESULT
RSASSA_Decode(
   TPM_ALG_ID          hashAlg,              //   IN:   hash algorithm to use for the encoding
   UINT32              hInSize,              //   IN:   size of the digest to compare
   BYTE               *hIn,                  //   In:   the digest to compare
   UINT32              eInSize,              //   IN:   size of the encoded data
   BYTE               *eIn                   //   IN:   the encoded data
   )
{
   BOOL                fail = FALSE;
   const BYTE         *der;
   INT32               derSize = _cpri__GetHashDER(hashAlg, &der);
   INT32               hashSize = _cpri__GetDigestSize(hashAlg);
   INT32               fillSize;
   pAssert(hIn != NULL && eIn != NULL);
   // Can't use this scheme if the algorithm doesn't have a DER string
    // defined or if the provided hash isn't the right size
    if(derSize == 0 || (unsigned)hashSize != hInSize)
        return CRYPT_SCHEME;
    // Make sure that this combination will fit in the provided space
    // Since no data movement takes place, can just walk though this
    // and accept nearly random values. This can only be called from
    // _cpri__ValidateSignature() so eInSize is known to be in range.
    fillSize = eInSize - derSize - hashSize - 3;
    // Start checking
    fail |= (*eIn++ != 0); // initial byte of zero
    fail |= (*eIn++ != 1); // byte of 0x01
    for(; fillSize > 0; fillSize--)
        fail |= (*eIn++ != 0xff); // bunch of 0xff
    fail |= (*eIn++ != 0); // another 0
    for(; derSize > 0; derSize--)
        fail |= (*eIn++ != *der++); // match the DER
    for(; hInSize > 0; hInSize--)
        fail |= (*eIn++ != *hIn++); // match the hash
    if(fail)
        return CRYPT_FAIL;
    return CRYPT_SUCCESS;
}
//
//
//       Externally Accessible Functions
//
//       _cpri__RsaStartup()
//
//      Function that is called to initialize the hash service. In this implementation, this function does nothing but
//      it is called by the CryptUtilStartup() function and must be present.
//
LIB_EXPORT BOOL
_cpri__RsaStartup(
    void
    )
{
    return TRUE;
}
//
//
//       _cpri__EncryptRSA()
//
//      This is the entry point for encryption using RSA. Encryption is use of the public exponent. The padding
//      parameter determines what padding will be used.
//      The cOutSize parameter must be at least as large as the size of the key.
//      If the padding is RSA_PAD_NONE, dIn is treaded as a number. It must be lower in value than the key
//      modulus.
//
//
//
//      NOTE:           If dIn has fewer bytes than cOut, then we don't add low-order zeros to dIn to make it the size of the RSA key for
//                      the call to RSAEP. This is because the high order bytes of dIn might have a numeric value that is greater than
//                      the value of the key modulus. If this had low-order zeros added, it would have a numeric value larger than the
//                      modulus even though it started out with a lower numeric value.
//
//
//      Return Value                        Meaning
//
//      CRYPT_SUCCESS                       encryption complete
//      CRYPT_PARAMETER                     cOutSize is too small (must be the size of the modulus)
//      CRYPT_SCHEME                        padType is not a supported scheme
//
LIB_EXPORT CRYPT_RESULT
_cpri__EncryptRSA(
   UINT32                *cOutSize,              //   OUT: the size of the encrypted data
   BYTE                  *cOut,                  //   OUT: the encrypted data
   RSA_KEY               *key,                   //   IN: the key to use for encryption
   TPM_ALG_ID             padType,               //   IN: the type of padding
   UINT32                 dInSize,               //   IN: the amount of data to encrypt
   BYTE                  *dIn,                   //   IN: the data to encrypt
   TPM_ALG_ID             hashAlg,               //   IN: in case this is needed
   const char            *label                  //   IN: in case it is needed
   )
{
   CRYPT_RESULT          retVal = CRYPT_SUCCESS;
   pAssert(cOutSize != NULL);
   // All encryption schemes return the same size of data
   if(*cOutSize < key->publicKey->size)
       return CRYPT_PARAMETER;
   *cOutSize = key->publicKey->size;
   switch (padType)
   {
   case TPM_ALG_NULL: // 'raw' encryption
       {
           // dIn can have more bytes than cOut as long as the extra bytes
           // are zero
           for(; dInSize > *cOutSize; dInSize--)
           {
               if(*dIn++ != 0)
                   return CRYPT_PARAMETER;
              }
              // If dIn is smaller than cOut, fill cOut with zeros
              if(dInSize < *cOutSize)
                  memset(cOut, 0, *cOutSize - dInSize);
              // Copy the rest of the value
              memcpy(&cOut[*cOutSize-dInSize], dIn, dInSize);
              // If the size of dIn is the same as cOut dIn could be larger than
              // the modulus. If it is, then RSAEP() will catch it.
       }
       break;
   case TPM_ALG_RSAES:
       retVal = RSAES_PKSC1v1_5Encode(*cOutSize, cOut, dInSize, dIn);
       break;
   case TPM_ALG_OAEP:
       retVal = OaepEncode(*cOutSize, cOut, hashAlg, label, dInSize, dIn
#ifdef TEST_RSA
                           ,NULL
#endif
                          );
       break;
   default:
       return CRYPT_SCHEME;
   }
   // All the schemes that do padding will come here for the encryption step
   // Check that the Encoding worked
   if(retVal != CRYPT_SUCCESS)
       return retVal;
   // Padding OK so do the encryption
   return RSAEP(*cOutSize, cOut, key);
}
//
//
//       _cpri__DecryptRSA()
//
//      This is the entry point for decryption using RSA. Decryption is use of the private exponent. The padType
//      parameter determines what padding was used.
//
//      Return Value                    Meaning
//
//      CRYPT_SUCCESS                   successful completion
//      CRYPT_PARAMETER                 cInSize is not the same as the size of the public modulus of key; or
//                                      numeric value of the encrypted data is greater than the modulus
//      CRYPT_FAIL                      dOutSize is not large enough for the result
//      CRYPT_SCHEME                    padType is not supported
//
LIB_EXPORT CRYPT_RESULT
_cpri__DecryptRSA(
   UINT32              *dOutSize,          //   OUT: the size of the decrypted data
   BYTE                *dOut,              //   OUT: the decrypted data
   RSA_KEY             *key,               //   IN: the key to use for decryption
   TPM_ALG_ID           padType,           //   IN: the type of padding
   UINT32               cInSize,           //   IN: the amount of data to decrypt
   BYTE                *cIn,               //   IN: the data to decrypt
   TPM_ALG_ID           hashAlg,           //   IN: in case this is needed for the scheme
   const char          *label              //   IN: in case it is needed for the scheme
   )
{
   CRYPT_RESULT        retVal;
   // Make sure that the necessary parameters are provided
   pAssert(cIn != NULL && dOut != NULL && dOutSize != NULL && key != NULL);
   // Size is checked to make sure that the decryption works properly
   if(cInSize != key->publicKey->size)
       return CRYPT_PARAMETER;
   // For others that do padding, do the decryption in place and then
   // go handle the decoding.
   if((retVal = RSADP(cInSize, cIn, key)) != CRYPT_SUCCESS)
       return retVal;      // Decryption failed
   // Remove padding
   switch (padType)
   {
   case TPM_ALG_NULL:
       if(*dOutSize < key->publicKey->size)
           return CRYPT_FAIL;
       *dOutSize = key->publicKey->size;
       memcpy(dOut, cIn, *dOutSize);
       return CRYPT_SUCCESS;
   case TPM_ALG_RSAES:
       return RSAES_Decode(dOutSize, dOut, cInSize, cIn);
       break;
   case TPM_ALG_OAEP:
       return OaepDecode(dOutSize, dOut, hashAlg, label, cInSize, cIn);
       break;
   default:
       return CRYPT_SCHEME;
       break;
   }
}
//
//
//       _cpri__SignRSA()
//
//      This function is used to generate an RSA signature of the type indicated in scheme.
//
//      Return Value                      Meaning
//
//      CRYPT_SUCCESS                     sign operation completed normally
//      CRYPT_SCHEME                      scheme or hashAlg are not supported
//      CRYPT_PARAMETER                   hInSize does not match hashAlg (for RSASSA)
//
LIB_EXPORT CRYPT_RESULT
_cpri__SignRSA(
   UINT32              *sigOutSize,          //   OUT: size of signature
   BYTE                *sigOut,              //   OUT: signature
   RSA_KEY             *key,                 //   IN: key to use
   TPM_ALG_ID           scheme,              //   IN: the scheme to use
   TPM_ALG_ID           hashAlg,             //   IN: hash algorithm for PKSC1v1_5
   UINT32               hInSize,             //   IN: size of digest to be signed
   BYTE                *hIn                  //   IN: digest buffer
   )
{
   CRYPT_RESULT        retVal;
   // Parameter checks
   pAssert(sigOutSize != NULL && sigOut != NULL && key != NULL && hIn != NULL);
   // For all signatures the size is the size of the key modulus
   *sigOutSize = key->publicKey->size;
   switch (scheme)
   {
   case TPM_ALG_NULL:
       *sigOutSize = 0;
       return CRYPT_SUCCESS;
   case TPM_ALG_RSAPSS:
       // PssEncode can return CRYPT_PARAMETER
       retVal = PssEncode(*sigOutSize, sigOut, hashAlg, hInSize, hIn
#ifdef TEST_RSA
                          , NULL
#endif
                         );
       break;
   case TPM_ALG_RSASSA:
       // RSASSA_Encode can return CRYPT_PARAMETER or CRYPT_SCHEME
       retVal = RSASSA_Encode(*sigOutSize, sigOut, hashAlg, hInSize, hIn);
       break;
   default:
       return CRYPT_SCHEME;
   }
   if(retVal != CRYPT_SUCCESS)
       return retVal;
   // Do the encryption using the private key
   // RSADP can return CRYPT_PARAMETR
   return RSADP(*sigOutSize,sigOut, key);
}
//
//
//       _cpri__ValidateSignatureRSA()
//
//      This function is used to validate an RSA signature. If the signature is valid CRYPT_SUCCESS is
//      returned. If the signature is not valid, CRYPT_FAIL is returned. Other return codes indicate either
//      parameter problems or fatal errors.
//
//      Return Value                  Meaning
//
//      CRYPT_SUCCESS                 the signature checks
//      CRYPT_FAIL                    the signature does not check
//      CRYPT_SCHEME                  unsupported scheme or hash algorithm
//
LIB_EXPORT CRYPT_RESULT
_cpri__ValidateSignatureRSA(
   RSA_KEY            *key,               //   IN:   key to use
   TPM_ALG_ID          scheme,            //   IN:   the scheme to use
   TPM_ALG_ID          hashAlg,           //   IN:   hash algorithm
   UINT32              hInSize,           //   IN:   size of digest to be checked
   BYTE               *hIn,               //   IN:   digest buffer
   UINT32              sigInSize,         //   IN:   size of signature
   BYTE               *sigIn,             //   IN:   signature
   UINT16              saltSize           //   IN:   salt size for PSS
   )
{
   CRYPT_RESULT        retVal;
   // Fatal programming errors
   pAssert(key != NULL && sigIn != NULL && hIn != NULL);
   // Errors that might be caused by calling parameters
   if(sigInSize != key->publicKey->size)
       return CRYPT_FAIL;
   // Decrypt the block
   if((retVal = RSAEP(sigInSize, sigIn, key)) != CRYPT_SUCCESS)
       return CRYPT_FAIL;
   switch (scheme)
   {
   case TPM_ALG_NULL:
       return CRYPT_SCHEME;
       break;
   case TPM_ALG_RSAPSS:
       return PssDecode(hashAlg, hInSize, hIn, sigInSize, sigIn, saltSize);
       break;
   case TPM_ALG_RSASSA:
       return RSASSA_Decode(hashAlg, hInSize, hIn, sigInSize, sigIn);
       break;
   default:
       break;
   }
   return CRYPT_SCHEME;
}
#ifndef RSA_KEY_SIEVE
//
//
//       _cpri__GenerateKeyRSA()
//
//      Generate an RSA key from a provided seed
//
//
//
//
//       Return Value                      Meaning
//
//       CRYPT_FAIL                        exponent is not prime or is less than 3; or could not find a prime using
//                                         the provided parameters
//       CRYPT_CANCEL                      operation was canceled
//
LIB_EXPORT CRYPT_RESULT
_cpri__GenerateKeyRSA(
   TPM2B              *n,                     //   OUT: The public modulu
   TPM2B              *p,                     //   OUT: One of the prime factors of n
   UINT16              keySizeInBits,         //   IN: Size of the public modulus in bit
   UINT32              e,                     //   IN: The public exponent
   TPM_ALG_ID          hashAlg,               //   IN: hash algorithm to use in the key
                                              //       generation proce
   TPM2B              *seed,                  //   IN: the seed to use
   const char         *label,                 //   IN: A label for the generation process.
   TPM2B              *extra,                 //   IN: Party 1 data for the KDF
   UINT32             *counter                //   IN/OUT: Counter value to allow KFD iteration
                                              //       to be propagated across multiple routine
   )
{
   UINT32              lLen;          // length of the label
                                      // (counting the terminating 0);
   UINT16              digestSize = _cpri__GetDigestSize(hashAlg);
   TPM2B_HASH_BLOCK         oPadKey;
   UINT32             outer;
   UINT32             inner;
   BYTE               swapped[4];
   CRYPT_RESULT    retVal;
   int             i, fill;
   const static char     defaultLabel[] = "RSA key";
   BYTE            *pb;
   CPRI_HASH_STATE     h1;                    // contains the hash of the
                                              //   HMAC key w/ iPad
   CPRI_HASH_STATE     h2;                    // contains the hash of the
                                              //   HMAC key w/ oPad
   CPRI_HASH_STATE     h;                     // the working hash context
   BIGNUM             *bnP;
   BIGNUM             *bnQ;
   BIGNUM             *bnT;
   BIGNUM             *bnE;
   BIGNUM             *bnN;
   BN_CTX             *context;
   UINT32              rem;
   // Make sure that hashAlg is valid hash
   pAssert(digestSize != 0);
   // if present, use externally provided counter
   if(counter != NULL)
       outer = *counter;
   else
       outer = 1;
   // Validate exponent
   UINT32_TO_BYTE_ARRAY(e, swapped);
   // Need to check that the exponent is prime and not less than 3
   if( e != 0 && (e < 3 || !_math__IsPrime(e)))
        return CRYPT_FAIL;
   // Get structures for the big number representations
   context = BN_CTX_new();
   if(context == NULL)
       FAIL(FATAL_ERROR_ALLOCATION);
   BN_CTX_start(context);
   bnP = BN_CTX_get(context);
   bnQ = BN_CTX_get(context);
   bnT = BN_CTX_get(context);
   bnE = BN_CTX_get(context);
   bnN = BN_CTX_get(context);
   if(bnN == NULL)
       FAIL(FATAL_ERROR_INTERNAL);
   // Set Q to zero. This is used as a flag. The prime is computed in P. When a
   // new prime is found, Q is checked to see if it is zero. If so, P is copied
   // to Q and a new P is found. When both P and Q are non-zero, the modulus and
   // private exponent are computed and a trial encryption/decryption is
   // performed. If the encrypt/decrypt fails, assume that at least one of the
   // primes is composite. Since we don't know which one, set Q to zero and start
   // over and find a new pair of primes.
   BN_zero(bnQ);
   // Need to have some label
   if(label == NULL)
       label = (const char *)&defaultLabel;
   // Get the label size
   for(lLen = 0; label[lLen++] != 0;);
   // Start the hash using the seed and get the intermediate hash value
   _cpri__StartHMAC(hashAlg, FALSE, &h1, seed->size, seed->buffer, &oPadKey.b);
   _cpri__StartHash(hashAlg, FALSE, &h2);
   _cpri__UpdateHash(&h2, oPadKey.b.size, oPadKey.b.buffer);
   n->size = (keySizeInBits +7)/8;
   pAssert(n->size <= MAX_RSA_KEY_BYTES);
   p->size = n->size / 2;
   if(e == 0)
       e = RSA_DEFAULT_PUBLIC_EXPONENT;
   BN_set_word(bnE, e);
   // The first test will increment the counter from zero.
   for(outer += 1; outer != 0; outer++)
   {
       if(_plat__IsCanceled())
       {
           retVal = CRYPT_CANCEL;
           goto Cleanup;
       }
        // Need to fill in the candidate with the hash
        fill = digestSize;
        pb = p->buffer;
        // Reset the inner counter
        inner = 0;
        for(i = p->size; i > 0; i -= digestSize)
        {
            inner++;
            // Initialize the HMAC with saved state
            _cpri__CopyHashState(&h, &h1);
              // Hash the inner counter (the one that changes on each HMAC iteration)
              UINT32_TO_BYTE_ARRAY(inner, swapped);
             _cpri__UpdateHash(&h, 4, swapped);
             _cpri__UpdateHash(&h, lLen, (BYTE *)label);
             // Is there any party 1 data
             if(extra != NULL)
                 _cpri__UpdateHash(&h, extra->size, extra->buffer);
             // Include the outer counter (the one that changes on each prime
             // prime candidate generation
             UINT32_TO_BYTE_ARRAY(outer, swapped);
             _cpri__UpdateHash(&h, 4, swapped);
             _cpri__UpdateHash(&h, 2, (BYTE *)&keySizeInBits);
             if(i < fill)
                 fill = i;
             _cpri__CompleteHash(&h, fill, pb);
             // Restart the oPad hash
             _cpri__CopyHashState(&h, &h2);
             // Add the last hashed data
             _cpri__UpdateHash(&h, fill, pb);
             // gives a completed HMAC
             _cpri__CompleteHash(&h, fill, pb);
             pb += fill;
        }
        // Set the Most significant 2 bits and the low bit of the candidate
        p->buffer[0] |= 0xC0;
        p->buffer[p->size - 1] |= 1;
        // Convert the candidate to a BN
        BN_bin2bn(p->buffer, p->size, bnP);
        // If this is the second prime, make sure that it differs from the
        // first prime by at least 2^100
        if(!BN_is_zero(bnQ))
        {
            // bnQ is non-zero if we already found it
            if(BN_ucmp(bnP, bnQ) < 0)
                BN_sub(bnT, bnQ, bnP);
            else
                BN_sub(bnT, bnP, bnQ);
            if(BN_num_bits(bnT) < 100) // Difference has to be at least 100 bits
                continue;
        }
        // Make sure that the prime candidate (p) is not divisible by the exponent
        // and that (p-1) is not divisible by the exponent
        // Get the remainder after dividing by the modulus
        rem = BN_mod_word(bnP, e);
        if(rem == 0) // evenly divisible so add two keeping the number odd and
            // making sure that 1 != p mod e
            BN_add_word(bnP, 2);
        else if(rem == 1) // leaves a remainder of 1 so subtract two keeping the
            // number odd and making (e-1) = p mod e
            BN_sub_word(bnP, 2);
        // Have a candidate, check for primality
        if((retVal = (CRYPT_RESULT)BN_is_prime_ex(bnP,
                     BN_prime_checks, NULL, NULL)) < 0)
            FAIL(FATAL_ERROR_INTERNAL);
        if(retVal != 1)
            continue;
        // Found a prime, is this the first or second.
        if(BN_is_zero(bnQ))
        {
              // copy p to q and compute another prime in p
              BN_copy(bnQ, bnP);
              continue;
        }
        //Form the public modulus
        BN_mul(bnN, bnP, bnQ, context);
        if(BN_num_bits(bnN) != keySizeInBits)
            FAIL(FATAL_ERROR_INTERNAL);
        // Save the public modulus
        BnTo2B(n, bnN, n->size); // Will pad the buffer to the correct size
        pAssert((n->buffer[0] & 0x80) != 0);
        // And one prime
        BnTo2B(p, bnP, p->size);
        pAssert((p->buffer[0] & 0x80) != 0);
        // Finish by making sure that we can form the modular inverse of PHI
        // with respect to the public exponent
        // Compute PHI = (p - 1)(q - 1) = n - p - q + 1
        // Make sure that we can form the modular inverse
        BN_sub(bnT, bnN, bnP);
        BN_sub(bnT, bnT, bnQ);
        BN_add_word(bnT, 1);
        // find d such that (Phi * d) mod e ==1
        // If there isn't then we are broken because we took the step
        // of making sure that the prime != 1 mod e so the modular inverse
        // must exist
        if(BN_mod_inverse(bnT, bnE, bnT, context) == NULL || BN_is_zero(bnT))
            FAIL(FATAL_ERROR_INTERNAL);
        // And, finally, do a trial encryption decryption
        {
            TPM2B_TYPE(RSA_KEY, MAX_RSA_KEY_BYTES);
            TPM2B_RSA_KEY        r;
            r.t.size = sizeof(n->size);
              // If we are using a seed, then results must be reproducible on each
              // call. Otherwise, just get a random number
              if(seed == NULL)
                  _cpri__GenerateRandom(n->size, r.t.buffer);
              else
              {
                  // this this version does not have a deterministic RNG, XOR the
                  // public key and private exponent to get a deterministic value
                  // for testing.
                  int          i;
                  // Generate a random-ish number starting with the public modulus
                  // XORed with the MSO of the seed
                  for(i = 0; i < n->size; i++)
                      r.t.buffer[i] = n->buffer[i] ^ seed->buffer[0];
              }
              // Make sure that the number is smaller than the public modulus
              r.t.buffer[0] &= 0x7F;
                     // Convert
              if(    BN_bin2bn(r.t.buffer, r.t.size, bnP) == NULL
                     // Encrypt with the public exponent
                  || BN_mod_exp(bnQ, bnP, bnE, bnN, context) != 1
                     // Decrypt with the private exponent
                  || BN_mod_exp(bnQ, bnQ, bnT, bnN, context) != 1)
                   FAIL(FATAL_ERROR_INTERNAL);
              // If the starting and ending values are not the same, start over )-;
              if(BN_ucmp(bnP, bnQ) != 0)
              {
                   BN_zero(bnQ);
                   continue;
             }
         }
         retVal = CRYPT_SUCCESS;
         goto Cleanup;
    }
    retVal = CRYPT_FAIL;
Cleanup:
   // Close out the hash sessions
   _cpri__CompleteHash(&h2, 0, NULL);
   _cpri__CompleteHash(&h1, 0, NULL);
    // Free up allocated BN values
    BN_CTX_end(context);
    BN_CTX_free(context);
    if(counter != NULL)
        *counter = outer;
    return retVal;
}
#endif      // RSA_KEY_SIEVE
#endif // TPM_ALG_RSA