/* rsa.c
 *
 * Copyright (C) 2006-2021 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */


#ifdef HAVE_CONFIG_H /* configure options when using autoconf */
    #include <config.h>
#endif

#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>

#ifndef NO_RSA

#define USER_CRYPTO_ERROR -101

#ifdef OPENSSL_EXTRA
    #include <wolfssl/openssl/rsa.h> /* include for openssl compatibility */
    #include <wolfssl/openssl/bn.h>
#endif
#include "user_rsa.h"

#ifdef DEBUG_WOLFSSL /* debug done without variadric to allow older compilers */
    #include <stdio.h>
    #define USER_DEBUG(x) printf x
#else
    #define USER_DEBUG(x)
#endif

#define ASN_INTEGER    0x02
#define ASN_BIT_STRING 0x03
#define ASN_TAG_NULL   0x05
#define ASN_OBJECT_ID  0x06


/* Make sure compiler doesn't skip -- used from wolfSSL */
static inline void ForceZero(const void* mem, word32 len)
{
    volatile byte* z = (volatile byte*)mem;

    while (len--) *z++ = 0;
}

enum {
    RSA_PUBLIC_ENCRYPT  = 0,
    RSA_PUBLIC_DECRYPT  = 1,
    RSA_PRIVATE_ENCRYPT = 2,
    RSA_PRIVATE_DECRYPT = 3,

    RSA_BLOCK_TYPE_1 = 1,
    RSA_BLOCK_TYPE_2 = 2,

    RSA_MIN_SIZE = 512,
    RSA_MAX_SIZE = 4096, /* max allowed in IPP library */

    RSA_MIN_PAD_SZ   = 11      /* separator + 0 + pad value + 8 pads */
};


int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId)
{

    USER_DEBUG(("Entering wc_InitRsaKey\n"));

    if (key == NULL)
        return USER_CRYPTO_ERROR;

    /* set full struct as 0 */
    ForceZero(key, sizeof(RsaKey));

    USER_DEBUG(("\tExit wc_InitRsaKey\n"));

    (void)devId;
    (void)heap;
    return 0;
}

int wc_InitRsaKey(RsaKey* key, void* heap)
{
    return wc_InitRsaKey_ex(key, heap, INVALID_DEVID);
}


/* three functions needed for cert and key gen */
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)
/* return 1 if there is a leading bit*/
int wc_Rsa_leading_bit(void* bn)
{
    int ret = 0;
    int dataSz;
    Ipp32u* data;
    Ipp32u  q;
    int qSz = sizeof(Ipp32u);

    if (ippsExtGet_BN(NULL, &dataSz, NULL, bn) != ippStsNoErr) {
        USER_DEBUG(("ippsExtGet_BN Rsa leading bit error\n"));
        return USER_CRYPTO_ERROR;
    }

    /* convert from size in binary to Ipp32u */
    dataSz = dataSz / 32 + ((dataSz % 32)? 1 : 0);
    data = (Ipp32u*)XMALLOC(dataSz * sizeof(Ipp32u), NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (data == NULL) {
        USER_DEBUG(("Rsa leading bit memory error\n"));
        return 0;
    }

    /* extract value from BN */
    if (ippsExtGet_BN(NULL, NULL, data, bn) != ippStsNoErr) {
        USER_DEBUG(("Rsa leading bit error\n"));
        XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return 0;
    }

    /* use method like what's used in wolfssl tfm.c  */
    q = data[dataSz - 1];

    ret = 0;
    while (qSz > 0) {
        if (q != 0)
            ret = (q & 0x80) != 0;
        q >>= 8;
        qSz--;
    }

    XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return ret;
}


/* get the size in bytes of BN */
int wc_Rsa_unsigned_bin_size(void* bn)
{
    int ret = 0;
    if (ippsExtGet_BN(NULL, &ret, NULL, bn) != ippStsNoErr) {
        USER_DEBUG(("Rsa unsigned bin size error\n"));
        return USER_CRYPTO_ERROR;
    }
    return (ret / 8) + ((ret % 8)? 1: 0); /* size in bytes */
}

#ifndef MP_OKAY
#define MP_OKAY 0
#endif

/* extract the bn value to a unsigned byte array and return MP_OKAY on success */
int wc_Rsa_to_unsigned_bin(void* bn, byte* in, int inLen)
{
    if (ippsGetOctString_BN((Ipp8u*)in, inLen, bn) != ippStsNoErr) {
        USER_DEBUG(("Rsa to unsigned bin error\n"));
        return USER_CRYPTO_ERROR;
    }
    return MP_OKAY;
}
#endif /* WOLFSSL_CERT_GEN || WOLFSSL_KEY_GEN || OPENSSL_EXTRA */


#ifdef OPENSSL_EXTRA /* functions needed for openssl compatibility layer */
static int SetIndividualExternal(WOLFSSL_BIGNUM** bn, IppsBigNumState* in)
{
    IppStatus ret;
    byte* data;
    int sz;

    USER_DEBUG(("Entering SetIndividualExternal\n"));

    if (bn == NULL || in == NULL) {
        USER_DEBUG(("inputs NULL error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (*bn == NULL) {
        *bn = wolfSSL_BN_new();
        if (*bn == NULL) {
            USER_DEBUG(("SetIndividualExternal alloc failed\n"));
            return USER_CRYPTO_ERROR;
        }
    }

    /* get size of array needed and extract oct array of data */
    ret = ippsGetSize_BN(in, &sz);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    data = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (data == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsGetOctString_BN(data, sz, in);
    if (ret != ippStsNoErr) {
        XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return USER_CRYPTO_ERROR;
    }

    /* store the data into a wolfSSL Big Number */
    *bn = wolfSSL_BN_bin2bn(data, sz, *bn);

    XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return 0;
}


static int SetIndividualInternal(WOLFSSL_BIGNUM* bn, IppsBigNumState** mpi)
{
    int length, ctxSz, sz;
    IppStatus ret;
    Ipp8u* data;

    USER_DEBUG(("Entering SetIndividualInternal\n"));

    if (bn == NULL || bn->internal == NULL) {
        USER_DEBUG(("bn NULL error\n"));
        return USER_CRYPTO_ERROR;
    }

    length = wolfSSL_BN_num_bytes(bn);

    /* if not IPP BN then create one */
    if (*mpi == NULL) {
        ret = ippsBigNumGetSize(length, &ctxSz);
        if (ret != ippStsNoErr)
            return USER_CRYPTO_ERROR;

        *mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
        if (*mpi == NULL)
            return USER_CRYPTO_ERROR;

        ret = ippsBigNumInit(length, *mpi);
        if (ret != ippStsNoErr) {
            XFREE(*mpi, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            return USER_CRYPTO_ERROR;
        }

    }

    /* get the size of array needed and check IPP BigNum */
    if (ippsGetSize_BN(*mpi, &sz) != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    if (sz < length) {
        USER_DEBUG(("big num size is too small\n"));
        return USER_CRYPTO_ERROR;
    }

    data = (Ipp8u*)XMALLOC(length, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (data == NULL)
        return USER_CRYPTO_ERROR;

    /* extract the wolfSSL BigNum and store it into IPP BigNum */
    if (wolfSSL_BN_bn2bin(bn, data) < 0) {
        XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        USER_DEBUG(("error in getting bin from wolfssl bn\n"));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsSetOctString_BN(data, length, *mpi);
    if (ret != ippStsNoErr) {
        XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return USER_CRYPTO_ERROR;
    }

    XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return 0;
}


/* WolfSSL -> OpenSSL */
int SetRsaExternal(WOLFSSL_RSA* rsa)
{
    RsaKey* key;
    USER_DEBUG(("Entering SetRsaExternal\n"));

    if (rsa == NULL || rsa->internal == NULL) {
        USER_DEBUG(("rsa key NULL error\n"));
        return USER_CRYPTO_ERROR;
    }

    key = (RsaKey*)rsa->internal;

    if (SetIndividualExternal(&rsa->n, key->n) != 0) {
        USER_DEBUG(("rsa n key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (SetIndividualExternal(&rsa->e, key->e) != 0) {
        USER_DEBUG(("rsa e key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (key->type == RSA_PRIVATE) {
        if (SetIndividualExternal(&rsa->d, key->dipp) != 0) {
            USER_DEBUG(("rsa d key error\n"));
            return USER_CRYPTO_ERROR;
        }

        if (SetIndividualExternal(&rsa->p, key->pipp) != 0) {
            USER_DEBUG(("rsa p key error\n"));
            return USER_CRYPTO_ERROR;
        }

        if (SetIndividualExternal(&rsa->q, key->qipp) != 0) {
            USER_DEBUG(("rsa q key error\n"));
            return USER_CRYPTO_ERROR;
        }

        if (SetIndividualExternal(&rsa->dmp1, key->dPipp) != 0) {
            USER_DEBUG(("rsa dP key error\n"));
            return USER_CRYPTO_ERROR;
        }

        if (SetIndividualExternal(&rsa->dmq1, key->dQipp) != 0) {
            USER_DEBUG(("rsa dQ key error\n"));
            return USER_CRYPTO_ERROR;
        }

        if (SetIndividualExternal(&rsa->iqmp, key->uipp) != 0) {
            USER_DEBUG(("rsa u key error\n"));
            return USER_CRYPTO_ERROR;
        }
    }

    rsa->exSet = 1;

    /* SSL_SUCCESS */
    return 1;
}


/* Openssl -> WolfSSL */
int SetRsaInternal(WOLFSSL_RSA* rsa)
{
    int ctxSz, pSz, qSz;
    IppStatus ret;
    RsaKey* key;
    USER_DEBUG(("Entering SetRsaInternal\n"));

    if (rsa == NULL || rsa->internal == NULL) {
        USER_DEBUG(("rsa key NULL error\n"));
        return USER_CRYPTO_ERROR;
    }

    key = (RsaKey*)rsa->internal;

    if (SetIndividualInternal(rsa->n, &key->n) != 0) {
        USER_DEBUG(("rsa n key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (SetIndividualInternal(rsa->e, &key->e) != 0) {
        USER_DEBUG(("rsa e key error\n"));
        return USER_CRYPTO_ERROR;
    }

    /* public key */
    key->type = RSA_PUBLIC;

    if (rsa->d != NULL) {
        if (SetIndividualInternal(rsa->d, &key->dipp) != 0) {
            USER_DEBUG(("rsa d key error\n"));
            return USER_CRYPTO_ERROR;
        }

        /* private key */
        key->type = RSA_PRIVATE;
    }

    if (rsa->p != NULL &&
        SetIndividualInternal(rsa->p, &key->pipp) != 0) {
        USER_DEBUG(("rsa p key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (rsa->q != NULL &&
        SetIndividualInternal(rsa->q, &key->qipp) != 0) {
        USER_DEBUG(("rsa q key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (rsa->dmp1 != NULL &&
        SetIndividualInternal(rsa->dmp1, &key->dPipp) != 0) {
        USER_DEBUG(("rsa dP key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (rsa->dmq1 != NULL &&
        SetIndividualInternal(rsa->dmq1, &key->dQipp) != 0) {
        USER_DEBUG(("rsa dQ key error\n"));
        return USER_CRYPTO_ERROR;
    }

    if (rsa->iqmp != NULL &&
        SetIndividualInternal(rsa->iqmp, &key->uipp) != 0) {
        USER_DEBUG(("rsa u key error\n"));
        return USER_CRYPTO_ERROR;
    }

    rsa->inSet = 1;

    /* get sizes of IPP BN key states created from input */
    ret = ippsGetSize_BN(key->n, &key->nSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsGetSize_BN(key->e, &key->eSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->sz = key->nSz; /* set modulus size */

    /* convert to size in bits */
    key->nSz = key->nSz * 8;
    key->eSz = key->eSz * 8;

    /* set up public key state */
    ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
                ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPub == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_SetPublicKey error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    if (key->pipp != NULL && key->qipp != NULL && key->dipp != NULL &&
            key->dPipp != NULL && key->dQipp != NULL && key->uipp != NULL) {
        /* get bn sizes needed for private key set up */
        ret = ippsGetSize_BN(key->pipp, &pSz);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }

        ret = ippsGetSize_BN(key->qipp, &qSz);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }

        /* store sizes needed for creating tmp private keys */
        ret = ippsGetSize_BN(key->dipp, &key->dSz);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }

        /* convert to size in bits */
        key->dSz = key->dSz * 8;
        pSz = pSz * 8;
        qSz = qSz * 8;

        /* set up private key state */
        ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
                    ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }

        key->prvSz = ctxSz;
        key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
        if (key->pPrv == NULL)
            return USER_CRYPTO_ERROR;

        ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
                        ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }

        ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
                key->dQipp, key->uipp, key->pPrv);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n", ippGetStatusString(ret)));
            return USER_CRYPTO_ERROR;
        }
    }

    /* SSL_SUCCESS */
    return 1;
}
#endif /* OPENSSLEXTRA */


/* Padding scheme function used in wolfSSL for signing needed for matching
   existing API signing scheme
    input : the msg to be signed
    inputLen : length of input msg
    pkcsBlock : the outputted padded msg
    pkcsBlockLen : length of outputted padded msg buffer
    padValue : the padded value after first 00 , is either 01 or 02
    rng : random number generator structure
 */
static int wc_RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
                   word32 pkcsBlockLen, byte padValue, WC_RNG* rng)
{
    if (inputLen == 0 || pkcsBlockLen == 0) {
        return USER_CRYPTO_ERROR;
    }

    pkcsBlock[0] = 0x0;       /* set first byte to zero and advance */
    pkcsBlock++; pkcsBlockLen--;
    pkcsBlock[0] = padValue;  /* insert padValue */

    if (padValue == RSA_BLOCK_TYPE_1) {
        if (pkcsBlockLen < inputLen + 2) {
            return USER_CRYPTO_ERROR;
        }

        /* pad with 0xff bytes */
        XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
    }
    else {
        /* pad with non-zero random bytes */
        word32 padLen, i;
        int    ret;

        if (pkcsBlockLen < inputLen + 1) {
            return USER_CRYPTO_ERROR;
        }

        padLen = pkcsBlockLen - inputLen - 1;
        ret = wc_RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);

        if (ret != 0)
            return ret;

        /* remove zeros */
        for (i = 1; i < padLen; i++)
            if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
    }

    pkcsBlock[pkcsBlockLen-inputLen-1] = 0;     /* separator */
    XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);

    return 0;
}


/* UnPad plaintext, set start to *output, return length of plaintext,
 * < 0 on error */
static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
                       byte **output, byte padValue)
{
    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0,
           invalid = 0,
           i = 1,
           outputLen;

    if (pkcsBlockLen == 0) {
        return USER_CRYPTO_ERROR;
    }

    if (pkcsBlock[0] != 0x0) /* skip past zero */
        invalid = 1;
    pkcsBlock++; pkcsBlockLen--;

    /* Require block type padValue */
    invalid = (pkcsBlock[0] != padValue) || invalid;

    /* verify the padding until we find the separator */
    if (padValue == RSA_BLOCK_TYPE_1) {
        while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
    }
    else {
        while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
    }

    if(!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
        USER_DEBUG(("RsaUnPad error, bad formatting\n"));
        return USER_CRYPTO_ERROR;
    }

    outputLen = pkcsBlockLen - i;
    invalid = (outputLen > maxOutputLen) || invalid;

    if (invalid) {
        USER_DEBUG(("RsaUnPad error, bad formatting\n"));
        return USER_CRYPTO_ERROR;
    }

    *output = (byte *)(pkcsBlock + i);
    return outputLen;
}


/* Set up memory and structure for a Big Number
 * returns ippStsNoErr on success
 */
static IppStatus init_bn(IppsBigNumState** in, int sz)
{
    int ctxSz;
    IppStatus ret;

    ret = ippsBigNumGetSize(sz, &ctxSz);
    if (ret != ippStsNoErr) {
        return ret;
    }

    *in = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (*in == NULL) {
        return ippStsNoMemErr;
    }

    ret = ippsBigNumInit(sz, *in);
    if (ret != ippStsNoErr) {
        XFREE(*in, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        *in = NULL;
        return ret;
    }

    return ippStsNoErr;
}


/* Set up memory and structure for a Montgomery struct
 * returns ippStsNoErr on success
 */
static IppStatus init_mont(IppsMontState** mont, int* ctxSz,
                                                         IppsBigNumState* modul)
{
    int       mSz;
    Ipp32u*   m;
    IppStatus ret;

    ret = ippsExtGet_BN(NULL, ctxSz, NULL, modul);
    if (ret != ippStsNoErr) {
        return ret;
    }

    /* convert bits to Ipp32u array size and round up
       32 is number of bits in type */
    mSz = (*ctxSz/32)+((*ctxSz % 32)? 1: 0);
    m = (Ipp32u*)XMALLOC(mSz * sizeof(Ipp32u), 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (m == NULL) {
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return ippStsNoMemErr;
    }

    ret = ippsExtGet_BN(NULL, NULL, m, modul);
    if (ret != ippStsNoErr) {
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return ret;
    }

    ret = ippsMontGetSize(IppsSlidingWindows, mSz, ctxSz);
    if (ret != ippStsNoErr) {
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return ret;
    }

    /* 2. Allocate working buffer using malloc */
    *mont = (IppsMontState*)XMALLOC(*ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (*mont == NULL) {
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return ippStsNoMemErr;
    }
    ret = ippsMontInit(IppsSlidingWindows, mSz, *mont);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMontInit error of %s\n", ippGetStatusString(ret)));
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        *mont = NULL;
        return ret;
    }

    /* 3. Call the function MontSet to set big number module */
    ret = ippsMontSet(m, mSz, *mont);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMontSet error of %s\n", ippGetStatusString(ret)));
        XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        *mont = NULL;
        return ret;
    }

    XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return ippStsNoErr;
}



int wc_FreeRsaKey(RsaKey* key)
{
    if (key == NULL)
        return 0;

    USER_DEBUG(("Entering wc_FreeRsaKey\n"));

    if (key->pPub != NULL) {
        XFREE(key->pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->pPub = NULL;
    }

    if (key->pPrv != NULL) {
        /* write over sensitive information */
        ForceZero(key->pPrv, key->prvSz);
        XFREE(key->pPrv, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->pPrv = NULL;
    }

    if (key->n != NULL) {
        XFREE(key->n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->n = NULL;
    }

    if (key->e != NULL) {
        XFREE(key->e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->e = NULL;
    }

    if (key->dipp != NULL) {
        XFREE(key->dipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->dipp = NULL;
    }

    if (key->pipp != NULL) {
        XFREE(key->pipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->pipp = NULL;
    }

    if (key->qipp != NULL) {
        XFREE(key->qipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->qipp = NULL;
    }

    if (key->dPipp != NULL) {
        XFREE(key->dPipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->dPipp = NULL;
    }

    if (key->dQipp != NULL) {
        XFREE(key->dQipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->dQipp = NULL;
    }

    if (key->uipp != NULL) {
        XFREE(key->uipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        key->uipp = NULL;
    }

    USER_DEBUG(("\tExit wc_FreeRsaKey\n"));
    (void)key;

    return 0;
}


/* Some parsing functions from wolfSSL code needed to match wolfSSL API used */
static int GetLength(const byte* input, word32* inOutIdx, int* len,
                           word32 maxIdx)
{
    int     length = 0;
    word32  idx = *inOutIdx;
    byte    b;

    *len = 0;    /* default length */

    if ((idx + 1) > maxIdx) {   /* for first read */
        USER_DEBUG(("GetLength bad index on input\n"));
        return USER_CRYPTO_ERROR;
    }

    b = input[idx++];
    if (b >= 0x80) {
        word32 bytes = b & 0x7F;

        if ((idx + bytes) > maxIdx) {   /* for reading bytes */
            USER_DEBUG(("GetLength bad long length\n"));
            return USER_CRYPTO_ERROR;
        }

        while (bytes--) {
            b = input[idx++];
            length = (length << 8) | b;
        }
    }
    else
        length = b;

    if ((idx + length) > maxIdx) {   /* for user of length */
        USER_DEBUG(("GetLength value exceeds buffer length\n"));
        return USER_CRYPTO_ERROR;
    }

    *inOutIdx = idx;
    if (length > 0)
        *len = length;

    return length;
}

static int GetASNHeader(const byte* input, byte tag, word32* inOutIdx, int* len,
                        word32 maxIdx)
{
    word32 idx = *inOutIdx;
    byte   b;
    int    length;

    if ((idx + 1) > maxIdx)
        return USER_CRYPTO_ERROR;

    b = input[idx++];
    if (b != tag)
        return USER_CRYPTO_ERROR;

    if (GetLength(input, &idx, &length, maxIdx) < 0)
        return USER_CRYPTO_ERROR;

    *len      = length;
    *inOutIdx = idx;
    return length;
}

static int GetASNInt(const byte* input, word32* inOutIdx, int* len,
                     word32 maxIdx)
{
    int    ret;

    ret = GetASNHeader(input, ASN_INTEGER, inOutIdx, len, maxIdx);
    if (ret < 0)
        return ret;

    if (*len > 0) {
        /* remove leading zero, unless there is only one 0x00 byte */
        if ((input[*inOutIdx] == 0x00) && (*len > 1)) {
            (*inOutIdx)++;
            (*len)--;

            if (*len > 0 && (input[*inOutIdx] & 0x80) == 0)
                return USER_CRYPTO_ERROR;
        }
    }

    return 0;
}

static int GetInt(IppsBigNumState** mpi, const byte* input, word32* inOutIdx,
                  word32 maxIdx)
{
    IppStatus ret;
    word32 idx = *inOutIdx;
    int    length;
    int    ctxSz;

    if (GetASNInt(input, &idx, &length, maxIdx) < 0) {
        return USER_CRYPTO_ERROR;
    }

    ret = ippsBigNumGetSize(length, &ctxSz);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    *mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (*mpi == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsBigNumInit(length, *mpi);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    ret = ippsSetOctString_BN((Ipp8u*)input + idx, length, *mpi);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    *inOutIdx = idx + length;
    return 0;
}


static int GetSequence(const byte* input, word32* inOutIdx, int* len,
                           word32 maxIdx)
{
    int    length = -1;
    word32 idx    = *inOutIdx;

    if ((idx + 1) > maxIdx)
        return USER_CRYPTO_ERROR;

    if (input[idx++] != (0x10 | 0x20) ||
            GetLength(input, &idx, &length, maxIdx) < 0)
        return USER_CRYPTO_ERROR;

    *len      = length;
    *inOutIdx = idx;

    return length;
}


static int GetMyVersion(const byte* input, word32* inOutIdx,
                               int* version, word32 maxIdx)
{
    word32 idx = *inOutIdx;

    if ((idx + 3) > maxIdx)
        return USER_CRYPTO_ERROR;

    if (input[idx++] != 0x02)
        return USER_CRYPTO_ERROR;

    if (input[idx++] != 0x01)
        return USER_CRYPTO_ERROR;

    *version  = input[idx++];
    *inOutIdx = idx;

    return *version;
}


int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
                        word32 inSz)
{
    int    version, length;
    int  ctxSz, pSz, qSz;
    IppStatus ret;

    if (input == NULL || inOutIdx == NULL || key == NULL) {
        return USER_CRYPTO_ERROR;
    }

    USER_DEBUG(("Entering wc_RsaPrivateKeyDecode\n"));

    /* read in key information */
    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
        return USER_CRYPTO_ERROR;

    if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
        return USER_CRYPTO_ERROR;

    key->type = RSA_PRIVATE;

    if (GetInt(&key->n,  input, inOutIdx, inSz) < 0 ||
        GetInt(&key->e,  input, inOutIdx, inSz) < 0 ||
        GetInt(&key->dipp,  input, inOutIdx, inSz) < 0 ||
        GetInt(&key->pipp,  input, inOutIdx, inSz) < 0 ||
        GetInt(&key->qipp,  input, inOutIdx, inSz) < 0 ||
        GetInt(&key->dPipp, input, inOutIdx, inSz) < 0 ||
        GetInt(&key->dQipp, input, inOutIdx, inSz) < 0 ||
        GetInt(&key->uipp,  input, inOutIdx, inSz) < 0 )
        return USER_CRYPTO_ERROR;

    /* get sizes of IPP BN key states created from input */
    ret = ippsGetSize_BN(key->n, &key->nSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsGetSize_BN(key->e, &key->eSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->sz = key->nSz; /* set modulus size */

    /* convert to size in bits */
    key->nSz = key->nSz * 8;
    key->eSz = key->eSz * 8;

    /* set up public key state */
    ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
                ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPub == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    /* get bn sizes needed for private key set up */
    ret = ippsGetSize_BN(key->pipp, &pSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsGetSize_BN(key->qipp, &qSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    /* store sizes needed for creating tmp private keys */
    ret = ippsGetSize_BN(key->dipp, &key->dSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    /* convert to size in bits */
    key->dSz = key->dSz * 8;
    pSz = pSz * 8;
    qSz = qSz * 8;

    /* set up private key state */
    ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
                ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->prvSz = ctxSz;
    key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPrv == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
            key->dQipp, key->uipp, key->pPrv);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    USER_DEBUG(("\tExit wc_RsaPrivateKeyDecode\n"));

    return 0;
}


int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx,
        word32 inSz, const byte** n, word32* nSz, const byte** e, word32* eSz)
{
    IppStatus ret = 0;
    int length;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
    byte b;
#endif

    if (input == NULL || inOutIdx == NULL) {
        return USER_CRYPTO_ERROR;
    }

    USER_DEBUG(("Entering wc_RsaPublicKeyDecode_ex\n"));

    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
        return USER_CRYPTO_ERROR;

#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
    if ((*inOutIdx + 1) > inSz)
        return USER_CRYPTO_ERROR;

    b = input[*inOutIdx];
    if (b != ASN_INTEGER) {
        /* not from decoded cert, will have algo id, skip past */
        if (GetSequence(input, inOutIdx, &length, inSz) < 0)
            return USER_CRYPTO_ERROR;

        b = input[(*inOutIdx)++];
        if (b != ASN_OBJECT_ID)
            return USER_CRYPTO_ERROR;

        if (GetLength(input, inOutIdx, &length, inSz) < 0)
            return USER_CRYPTO_ERROR;

        *inOutIdx += length;   /* skip past */

        /* could have NULL tag and 0 terminator, but may not */
        b = input[(*inOutIdx)++];

        if (b == ASN_TAG_NULL) {
            b = input[(*inOutIdx)++];
            if (b != 0)
                return USER_CRYPTO_ERROR;
        }
        else {
            /* go back, didn't have it */
            (*inOutIdx)--;
        }

        /* should have bit tag length and seq next */
        b = input[(*inOutIdx)++];
        if (b != ASN_BIT_STRING)
            return USER_CRYPTO_ERROR;

        if (GetLength(input, inOutIdx, &length, inSz) <= 0)
            return USER_CRYPTO_ERROR;

        /* could have 0 */
        b = input[(*inOutIdx)++];
        if (b != 0)
            (*inOutIdx)--;

        if (GetSequence(input, inOutIdx, &length, inSz) < 0)
            return USER_CRYPTO_ERROR;
    }
#endif /* OPENSSL_EXTRA || RSA_DECODE_EXTRA */

    /* Get modulus */
    ret = GetASNInt(input, inOutIdx, &length, inSz);
    if (ret < 0) {
        return USER_CRYPTO_ERROR;
    }
    if (nSz)
        *nSz = length;
    if (n)
        *n = &input[*inOutIdx];
    *inOutIdx += length;

    /* Get exponent */
    ret = GetASNInt(input, inOutIdx, &length, inSz);
    if (ret < 0) {
        return USER_CRYPTO_ERROR;
    }
    if (eSz)
        *eSz = length;
    if (e)
        *e = &input[*inOutIdx];
    *inOutIdx += length;

    USER_DEBUG(("\tExit wc_RsaPublicKeyDecode_ex\n"));

    return ret;
}

/* read in a public RSA key */
int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
                       word32 inSz)
{
    IppStatus ret;
    const byte *n = NULL, *e = NULL;
    word32 nSz = 0, eSz = 0;

    if (key == NULL)
        return USER_CRYPTO_ERROR;

    USER_DEBUG(("Entering wc_RsaPublicKeyDecode\n"));

    ret = wc_RsaPublicKeyDecode_ex(input, inOutIdx, inSz, &n, &nSz, &e, &eSz);
    if (ret == 0) {
        ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key);
    }

    USER_DEBUG(("\tExit RsaPublicKeyDecode\n"));

    return ret;
}

/* import RSA public key elements (n, e) into RsaKey structure (key) */
int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e,
                             word32 eSz, RsaKey* key)
{
    IppStatus ret;
    int ctxSz;

    USER_DEBUG(("Entering wc_RsaPublicKeyDecodeRaw\n"));

    if (n == NULL || e == NULL || key == NULL)
        return USER_CRYPTO_ERROR;

    /* set up IPP key states -- read in n */
    ret = init_bn(&key->n, nSz);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    ret = ippsSetOctString_BN((Ipp8u*)n, nSz, key->n);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    /* read in e */
    ret = init_bn(&key->e, eSz);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    ret = ippsSetOctString_BN((Ipp8u*)e, eSz, key->e);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    /* store size and convert to binary */
    key->sz = nSz;
    nSz = nSz * 8;
    eSz = eSz * 8;

    /* set up public key state */
    ret = ippsRSA_GetSizePublicKey(nSz, eSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
                ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPub == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSA_InitPublicKey(nSz, eSz, key->pPub, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsRSA_SetPublicKey(key->n,key->e, key->pPub);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    key->nSz = nSz;
    key->eSz = eSz;
    key->type = RSA_PUBLIC;

    return 0;
}


/* encrypt using PKCS v15 */
int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
                     RsaKey* key, WC_RNG* rng)
{
    IppStatus ret;
    Ipp8u* scratchBuffer;
    int    scratchSz;

    if (key == NULL || in == NULL || out == NULL)
        return USER_CRYPTO_ERROR;

    if (key->pPub == NULL || outLen < key->sz)
        return USER_CRYPTO_ERROR;

    /* set size of scratch buffer */
    ret = ippsRSA_GetBufferSizePublicKey(&scratchSz, key->pPub);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (scratchBuffer == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSAEncrypt_PKCSv15((Ipp8u*)in, inLen, NULL, (Ipp8u*)out,
            key->pPub, scratchBuffer);
    if (ret != ippStsNoErr) {
        XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        USER_DEBUG(("encrypt error of %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    (void)rng;
    return key->sz;
}


/* decrypt using PLCS v15 */
int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
                     RsaKey* key)
{
    IppStatus ret;
    Ipp8u* scratchBuffer;
    int    scratchSz;
    int    outSz;

    if (in == NULL || out == NULL || key == NULL)
        return USER_CRYPTO_ERROR;

    if (key->pPrv == NULL || inLen != key->sz)
        return USER_CRYPTO_ERROR;

    outSz = outLen;

    /* set size of scratch buffer */
    ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
    if (ret != ippStsNoErr) {
        return USER_CRYPTO_ERROR;
    }

    scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (scratchBuffer == NULL) {
        return USER_CRYPTO_ERROR;
    }

    /* perform decryption using IPP */
    ret = ippsRSADecrypt_PKCSv15((Ipp8u*)in, (Ipp8u*)out, &outSz, key->pPrv,
            scratchBuffer);
    if (ret != ippStsNoErr) {
        XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return outSz;
}


/* out is a pointer that is set to the location in byte array "in" where input
 data has been decrypted */
int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
{
    int outSz;
    byte* tmp;

    USER_DEBUG(("Entering wc_RsaPrivateDecryptInline\n"));

    /* allocate a buffer for max decrypted text */
    tmp = (byte*)XMALLOC(key->sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (tmp == NULL)
        return USER_CRYPTO_ERROR;

    outSz = wc_RsaPrivateDecrypt(in, inLen, tmp, key->sz, key);
    if (outSz >= 0) {
        XMEMCPY(in, tmp, outSz);
        *out = in;
    }
    else {
        XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return USER_CRYPTO_ERROR;
    }

    XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    USER_DEBUG(("\tExit wc_RsaPrivateDecryptInline\n"));

    return outSz;
}


/* Used to clean up memory when exiting, clean up memory used */
static int FreeHelper(IppsBigNumState* pTxt, IppsBigNumState* cTxt,
        Ipp8u* scratchBuffer, void* pPub)
{
    if (pTxt != NULL)
        XFREE(pTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (cTxt != NULL)
        XFREE(cTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (scratchBuffer != NULL)
        XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (pPub != NULL)
        XFREE(pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return 0;
}


/* for Rsa Verify
    in : byte array to be verified
    inLen : length of input array
    out : pointer to location of in byte array that has been verified
 */
int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
{

    int ctxSz;
    int scratchSz;
    Ipp8u* scratchBuffer = NULL;
    IppStatus ret;
    IppsRSAPrivateKeyState* pPub = NULL;
    IppsBigNumState* pTxt = NULL;
    IppsBigNumState* cTxt = NULL;

    USER_DEBUG(("Entering wc_RsaSSL_VerifyInline\n"));

    if (key == NULL || key->n == NULL || key->e == NULL) {
        USER_DEBUG(("n or e element was null\n"));
        return USER_CRYPTO_ERROR;
    }

    if (in == NULL || inLen == 0 || out == NULL)
        return USER_CRYPTO_ERROR;

    /* set up a private key state using public key values */
    ret = ippsRSA_GetSizePrivateKeyType1(key->nSz, key->eSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
                ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    pPub = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (pPub == NULL)
        return USER_CRYPTO_ERROR;

    ret = ippsRSA_InitPrivateKeyType1(key->nSz, key->eSz, pPub, ctxSz);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    ret = ippsRSA_SetPrivateKeyType1(key->n, key->e, pPub);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
                    ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    /* set size of scratch buffer */
    ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, pPub);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }

    scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (scratchBuffer == NULL) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }

    /* load plain and cipher into big num states */
    ret = init_bn(&pTxt, key->sz);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }
    ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, pTxt);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }

    /* set up cipher to hold signature */
    ret = init_bn(&cTxt, key->sz);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }
    ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, cTxt);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        return USER_CRYPTO_ERROR;
    }

    /* decrypt using public key information */
    ret = ippsRSA_Decrypt(cTxt, pTxt, pPub, scratchBuffer);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    /* extract big num struct to octet string */
    ret = ippsGetOctString_BN((Ipp8u*)in, key->sz, pTxt);
    if (ret != ippStsNoErr) {
        FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
        USER_DEBUG(("BN get string error of %s\n", ippGetStatusString(ret)));
        return USER_CRYPTO_ERROR;
    }

    FreeHelper(pTxt, cTxt, scratchBuffer, pPub);

    /* unpad the decrypted information and return size of array */
    return RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
}


/* sets up and call VerifyInline to verify a signature */
int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
                     RsaKey* key)
{
    int plainLen;
    byte*  tmp;
    byte*  pad = 0;

    if (out == NULL || in == NULL || key == NULL)
        return USER_CRYPTO_ERROR;

    tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_USER_CRYPTO);
    if (tmp == NULL) {
        return USER_CRYPTO_ERROR;
    }

    XMEMCPY(tmp, in, inLen);

    /* verify signature and test if output buffer is large enough */
    plainLen = wc_RsaSSL_VerifyInline(tmp, inLen, &pad, key);
    if (plainLen < 0) {
        XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        return plainLen;
    }

    if (plainLen > (int)outLen)
        plainLen = USER_CRYPTO_ERROR;
    else
        XMEMCPY(out, pad, plainLen);

    ForceZero(tmp, inLen);
    XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    return plainLen;
}


/* Check if a > b , if so c = a mod b
   return ippStsNoErr on success */
static IppStatus reduce(IppsBigNumState* a, IppsBigNumState* b,
        IppsBigNumState* c)
{
    IppStatus ret;

    if ((ret = ippsMod_BN(a, b, c)) != ippStsNoErr)
        return ret;

    return ippStsNoErr;
}


static IppStatus exptmod(IppsBigNumState* a, IppsBigNumState* b,
        IppsMontState* mont, IppsBigNumState* out, IppsBigNumState* one)
{
    IppStatus ret;

    ret = ippsMontForm(a, mont, a);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMontForm error of %s\n", ippGetStatusString(ret)));
        return ret;
    }

    /* a = a^b mod mont */
    ret = ippsMontExp(a, b, mont, out);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMontExp error of %s\n", ippGetStatusString(ret)));
        return ret;
    }

    /* convert back from montgomery */
    ret = ippsMontMul(out, one, mont, out);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMontMul error of %s\n", ippGetStatusString(ret)));
        return ret;
    }

    return ippStsNoErr;
}


static void Free_BN(IppsBigNumState* bn)
{
    int sz, ctxSz;
    IppStatus ret;

    if (bn != NULL) {
        ret = ippStsNoErr;
        ret |= ippsGetSize_BN(bn, &sz);
        ret |= ippsBigNumGetSize(sz, &ctxSz);
        if (ret == ippStsNoErr) {
            ForceZero(bn, ctxSz);
        }
        else {
            USER_DEBUG(("Issue with clearing a struct in RsaSSL_Sign free\n"));
        }
        XFREE(bn, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    }
}


/* free up memory used during CRT sign operation */
static void FreeSignHelper(IppsBigNumState* one, IppsBigNumState* tmp,
        IppsBigNumState* tmpP, IppsBigNumState* tmpQ, IppsBigNumState* tmpa,
        IppsBigNumState* tmpb)
{
    Free_BN(one);
    Free_BN(tmp);
    Free_BN(tmpP);
    Free_BN(tmpQ);
    Free_BN(tmpa);
    Free_BN(tmpb);
}


/* for Rsa Sign */
int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
                      RsaKey* key, WC_RNG* rng)
{
    int sz, pSz, qSz;
    IppStatus ret;
    word32 outSz;

    IppsMontState* pMont = NULL;
    IppsMontState* qMont = NULL;

    IppsBigNumState* one  = NULL;
    IppsBigNumState* tmp  = NULL;
    IppsBigNumState* tmpP = NULL;
    IppsBigNumState* tmpQ = NULL;
    IppsBigNumState* tmpa = NULL;
    IppsBigNumState* tmpb = NULL;

    IppsBigNumSGN sa, sb;

    Ipp8u o[1];
    o[0] = 1;

    USER_DEBUG(("Entering wc_RsaSSL_Sign\n"));

    if (in == NULL || out == NULL || key == NULL || rng == NULL) {
        USER_DEBUG(("Bad argument to wc_RsaSSL_Sign\n"));
        return USER_CRYPTO_ERROR;
    }

    sz = key->sz;


    /* sanity check on key being used */
    if (key->pipp == NULL || key->qipp == NULL || key->uipp == NULL ||
            key->dPipp == NULL || key->dQipp == NULL) {
        USER_DEBUG(("Bad key argument to wc_RsaSSL_Sign\n"));
        return USER_CRYPTO_ERROR;
    }

    if (sz > (int)outLen) {
        USER_DEBUG(("Bad argument outLen to wc_RsaSSL_Sign\n"));
        return USER_CRYPTO_ERROR;
    }

    if (sz < RSA_MIN_PAD_SZ) {
        USER_DEBUG(("Key size is too small\n"));
        return USER_CRYPTO_ERROR;
    }

    if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) {
        USER_DEBUG(("Bad argument inLen to wc_RsaSSL_Sign\n"));
        return USER_CRYPTO_ERROR;
    }

    /* Set up needed pkcs v15 padding */
    if (wc_RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng) != 0) {
        USER_DEBUG(("RSA Padding error\n"));
        return USER_CRYPTO_ERROR;
    }

    /* tmp = input to sign */
    ret = init_bn(&tmp, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }
    ret = ippsSetOctString_BN(out, sz, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsSetOctString_BN error of %s\n",
                                                      ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpP = tmp mod p */
    ret = init_bn(&tmpP, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpQ = tmp mod q */
    ret = init_bn(&tmpQ, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpa */
    ret = init_bn(&tmpa, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpb */
    ret = init_bn(&tmpb, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* one : used for conversion from Montgomery to classical */
    ret = init_bn(&one, sz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }
    ret = ippsSetOctString_BN(o, 1, one);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsSetOctString_BN error of %s\n",
                    ippGetStatusString(ret)));
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /**
      Set up Montgomery state
      */
    ret = init_mont(&pMont, &pSz, key->pipp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
        if (pMont != NULL) {
            XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        }
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    ret = init_mont(&qMont, &qSz, key->qipp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
        if (qMont != NULL) {
            XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        }
        ForceZero(pMont, pSz);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /**
      Check and reduce input
      This is needed for calls to MontExp since required value of a < modulus
      */
    ret = reduce(tmp, key->pipp, tmpP);
    if (ret != ippStsNoErr)
    {
        USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    ret = reduce(tmp, key->qipp, tmpQ);
    if (ret != ippStsNoErr)
    {
        USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpa = (tmp mod p)^dP mod p */
    ret = exptmod(tmpP, key->dPipp, pMont, tmpa, one);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmpb = (tmp mod q)^dQ mod q */
    ret = exptmod(tmpQ, key->dQipp, qMont, tmpb, one);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* tmp = (tmpa - tmpb) * qInv (mod p) */
    ret = ippsSub_BN(tmpa, tmpb, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    ret = ippsMul_BN(tmp, key->uipp, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsMul_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* mod performed the same was as wolfSSL fp_mod -- tmpa is just scratch */
   ret = ippsDiv_BN(tmp, key->pipp, tmpa, tmp);
   if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsDiv_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
   }

    /* Check sign of values and perform conditional add */
    ret = ippsExtGet_BN(&sa, NULL, NULL, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }
    ret = ippsExtGet_BN(&sb, NULL, NULL, key->pipp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }
    if (sa != sb) {
        ret = ippsAdd_BN(tmp, key->pipp, tmp);
        if (ret != ippStsNoErr) {
            USER_DEBUG(("ippsAdd_BN error of %s\n", ippGetStatusString(ret)));
            ForceZero(pMont, pSz);
            ForceZero(qMont, qSz);
            XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
            return USER_CRYPTO_ERROR;
        }
    }

    /* tmp = tmpb + q * tmp */
    ret = ippsMul_BN(tmp, key->qipp, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }


    ret = ippsAdd_BN(tmp, tmpb, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    /* Extract the output */
    ret = ippsGetOctString_BN(out, sz, tmp);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetOctString_BN error of %s\n",
                    ippGetStatusString(ret)));
        ForceZero(pMont, pSz);
        ForceZero(qMont, qSz);
        XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
        return USER_CRYPTO_ERROR;
    }

    outSz = sz;

    /* clear memory and free */
    ForceZero(pMont, pSz);
    ForceZero(qMont, qSz);
    XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);

    return outSz;
}


int wc_RsaEncryptSize(RsaKey* key)
{
    if (key == NULL)
        return 0;

    return key->sz;
}


/* flatten RsaKey structure into individual elements (e, n) */
int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
                           word32* nSz)
{
    int sz, bytSz;
    IppStatus ret;

    USER_DEBUG(("Entering wc_RsaFlattenPublicKey\n"));

    if (key == NULL || e == NULL || eSz == NULL || n == NULL || nSz == NULL)
       return USER_CRYPTO_ERROR;

    bytSz = sizeof(byte) * 8;
    ret = ippsExtGet_BN(NULL, &sz, NULL, key->e);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    /* sz is in bits change to bytes */
    sz = (sz / bytSz) + ((sz % bytSz)? 1 : 0);

    if (*eSz < (word32)sz)
        return USER_CRYPTO_ERROR;

    ret = ippsGetOctString_BN(e, sz, key->e);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    *eSz = (word32)sz;

    /* flatten n */
    ret = ippsExtGet_BN(NULL, &sz, NULL, key->n);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    /* sz is in bits change to bytes */
    sz = (sz / bytSz) + ((sz % bytSz)? 1: 0);

    if (*nSz < (word32)sz)
        return USER_CRYPTO_ERROR;

    ret = ippsGetOctString_BN(n, sz, key->n);
    if (ret != ippStsNoErr)
        return USER_CRYPTO_ERROR;

    *nSz = (word32)sz;

    return 0;
}


IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams);
IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams)
{
    int nBytes;

    if (pData == NULL) {
        USER_DEBUG(("error with wolfSSL_rng argument\n"));
        return ippStsErr;
    }

    nBytes = (nBits/8) + ((nBits % 8)? 1: 0);
    if (wc_RNG_GenerateBlock((WC_RNG*)pEbsParams, (byte*)pData, nBytes) != 0) {
        USER_DEBUG(("error in generating random wolfSSL block\n"));
        return ippStsErr;
    }

    return ippStsNoErr;
}


#ifdef WOLFSSL_KEY_GEN
/* Make an RSA key for size bits, with e specified, 65537 is a good e */
int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
{
    IppStatus ret;
    int scratchSz;
    int i; /* for trys on calling make key */
    int ctxSz;

    IppsBigNumState* pSrcPublicExp = NULL;
    Ipp8u* scratchBuffer = NULL;
    Ipp8u  eAry[8];
    int trys = 8; /* Miller-Rabin test parameter */
    IppsPrimeState* pPrime = NULL;

    int qBitSz; /* size of q factor */
    int bytSz; /* size of key in bytes */
    int leng;

    USER_DEBUG(("Entering wc_MakeRsaKey\n"));

    /* get byte size and individual private key size -- round up */
    qBitSz = (size / 2) + ((size % 2)? 1: 0);
    bytSz  = (size / 8) + ((size % 8)? 1: 0);

    if (key == NULL || rng == NULL) {
        USER_DEBUG(("Error, NULL argument passed in\n"));
        return USER_CRYPTO_ERROR;
    }

    if (e < 3 || (e&1) == 0)
        return USER_CRYPTO_ERROR;

    if (size > RSA_MAX_SIZE || size < RSA_MIN_SIZE)
        return USER_CRYPTO_ERROR;

    key->type = RSA_PRIVATE;
    key->sz   = bytSz;

    /* initialize prime number */
    ret = ippsPrimeGetSize(size, &ctxSz); /* size in bits */
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsPrimeGetSize error of %s\n", ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    pPrime = (IppsPrimeState*)XMALLOC(ctxSz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (pPrime == NULL) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    ret = ippsPrimeInit(size, pPrime);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsPrimeInit error of %s\n", ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* define RSA privete key type 2 */
    /* length in bits of p and q factors */
    ret = ippsRSA_GetSizePrivateKeyType2(qBitSz, qBitSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePrivateKeyType2 error of %s\n",
                ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    key->prvSz = ctxSz; /* used when freeing private key */
    key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPrv == NULL) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* length in bits of p and q factors */
    ret = ippsRSA_InitPrivateKeyType2(qBitSz, qBitSz, key->pPrv, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPrivateKeyType2 error of %s\n",
                ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* allocate scratch buffer */
    ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetBufferSizePrivateKey error of %s\n",
                ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    scratchBuffer = (Ipp8u*)XMALLOC(scratchSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
    if (scratchBuffer == NULL) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up initial value of pScrPublicExp */
    leng = (int)sizeof(long); /* # of Ipp32u in long */

    /* place the value of e into the array eAry then load into BN */
    for (i = 0; i < leng; i++) {
        eAry[i] = (e >> (8 * (leng - 1 - i))) & 0XFF;
    }
    ret = init_bn(&pSrcPublicExp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    ret = ippsSetOctString_BN(eAry, leng, pSrcPublicExp);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* initializing key->n */
    ret = init_bn(&key->n, bytSz);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* initializing public exponent key->e */
    ret = init_bn(&key->e, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* private exponent key->dipp */
    ret = init_bn(&key->dipp, bytSz);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* call IPP to generate keys, if inseficent entropy error call again */
    ret = ippStsInsufficientEntropy;
    while (ret == ippStsInsufficientEntropy) {
        ret = ippsRSA_GenerateKeys(pSrcPublicExp, key->n, key->e,
                key->dipp, key->pPrv, scratchBuffer, trys, pPrime,
                wolfSSL_rng, rng);
        if (ret == ippStsNoErr) {
            break;
        }

        /* catch all errors other than entropy error */
        if (ret != ippStsInsufficientEntropy) {
            USER_DEBUG(("ippsRSA_GeneratKeys error of %s\n",
                    ippGetStatusString(ret)));
            ret = USER_CRYPTO_ERROR;
            goto makeKeyEnd;
        }
    }

    /* get bn sizes needed for private key set up */
    ret = ippsExtGet_BN(NULL, &key->eSz, NULL, key->e);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    ret = ippsExtGet_BN(NULL, &key->nSz, NULL, key->n);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up public key state */
    ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetSizePublicKey error %s nSz = %d eSz = %d\n",
                ippGetStatusString(ret), key->nSz, key->eSz));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
    if (key->pPub == NULL) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
                    ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
                    ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* get private key information for key struct */
    leng = size/16; /* size of q, p, u, dP, dQ */
    ret = init_bn(&key->pipp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up q BN for key */
    ret = init_bn(&key->qipp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up dP BN for key */
    ret = init_bn(&key->dPipp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up dQ BN for key */
    ret = init_bn(&key->dQipp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* set up u BN for key */
    ret = init_bn(&key->uipp, leng);
    if (ret != ippStsNoErr) {
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }

    /* get values from created key */
    ret = ippsRSA_GetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
            key->dQipp, key->uipp, key->pPrv);
    if (ret != ippStsNoErr) {
        USER_DEBUG(("ippsRSA_GetPrivateKeyType2 error %s\n",
                ippGetStatusString(ret)));
        ret = USER_CRYPTO_ERROR;
        goto makeKeyEnd;
    }
    ret = 0; /* success case */

makeKeyEnd:
    /* clean up memory used */
    XFREE(pSrcPublicExp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    XFREE(pPrime, NULL, DYNAMIC_TYPE_USER_CRYPTO);

    if (ret != 0) { /* with fail case free RSA components created */
        wc_FreeRsaKey(key);
    }

    return ret;
}

#endif

#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA)

/********** duplicate code needed -- future refactor */
#define MAX_VERSION_SZ 5
#define MAX_SEQ_SZ 5
#define ASN_CONTEXT_SPECIFIC 0x80
#define ASN_CONSTRUCTED 0x20
#define ASN_LONG_LENGTH 0x80
#define ASN_SEQUENCE 0x10
#define RSA_INTS 8
#define FALSE 0
#define TRUE 1

#define MAX_LENGTH_SZ 4
#define RSAk 645
#define keyType 2
#define MAX_RSA_INT_SZ 517
#define MAX_RSA_E_SZ 16
#define MAX_ALGO_SZ 20

static word32 BytePrecision(word32 value)
{
    word32 i;
    for (i = sizeof(value); i; --i)
        if (value >> ((i - 1) * WOLFSSL_BIT_SIZE))
            break;

    return i;
}


static int SetMyVersion(word32 version, byte* output, int header)
{
    int i = 0;

    if (output == NULL)
        return USER_CRYPTO_ERROR;

    if (header) {
        output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
        output[i++] = ASN_BIT_STRING;
    }
    output[i++] = ASN_INTEGER;
    output[i++] = 0x01;
    output[i++] = (byte)version;

    return i;
}


static word32 SetLength(word32 length, byte* output)
{
    word32 i = 0, j;

    if (length < 0x80)
        output[i++] = (byte)length;
    else {
        output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH);

        for (j = BytePrecision(length); j; --j) {
            output[i] = (byte)(length >> ((j - 1) * WOLFSSL_BIT_SIZE));
            i++;
        }
    }

    return i;
}


static word32 SetSequence(word32 len, byte* output)
{
    output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
    return SetLength(len, output + 1) + 1;
}


static word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
{
    /* adding TAG_NULL and 0 to end */

    /* RSA keyType */
    #ifndef NO_RSA
        static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
                                            0x01, 0x01, 0x01, 0x05, 0x00};
    #endif /* NO_RSA */

    int    algoSz = 0;
    int    tagSz  = 2;   /* tag null and terminator */
    word32 idSz, seqSz;
    const  byte* algoName = 0;
    byte ID_Length[MAX_LENGTH_SZ];
    byte seqArray[MAX_SEQ_SZ + 1];  /* add object_id to end */

    if (type == keyType) {    /* keyType */
        switch (algoOID) {
        #ifndef NO_RSA
            case RSAk:
                algoSz = sizeof(RSA_AlgoID);
                algoName = RSA_AlgoID;
                break;
        #endif /* NO_RSA */
        default:
            /* unknown key algo */
            return 0;
        }
    }
    else {
        /* unknown algo type */
        return 0;
    }

    idSz  = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */
    seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray);
                 /* +1 for object id, curveID of curveSz follows for ecc */
    seqArray[seqSz++] = ASN_OBJECT_ID;

    XMEMCPY(output, seqArray, seqSz);
    XMEMCPY(output + seqSz, ID_Length, idSz);
    XMEMCPY(output + seqSz + idSz, algoName, algoSz);

    return seqSz + idSz + algoSz;

}


/* Write a public RSA key to output */
static int SetRsaPublicKey(byte* output, RsaKey* key,
                           int outLen, int with_header)
{
#ifdef WOLFSSL_SMALL_STACK
    byte* n = NULL;
    byte* e = NULL;
#else
    byte n[MAX_RSA_INT_SZ];
    byte e[MAX_RSA_E_SZ];
#endif
    byte seq[MAX_SEQ_SZ];
    byte len[MAX_LENGTH_SZ + 1];  /* trailing 0 */
    int  nSz;
    int  eSz;
    int  seqSz;
    int  lenSz;
    int  idx;
    int  rawLen;
    int  leadingBit;
    int  err;

    if (output == NULL || key == NULL || outLen < MAX_SEQ_SZ)
        return USER_CRYPTO_ERROR;

    /* n */
#ifdef WOLFSSL_SMALL_STACK
    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (n == NULL)
        return USER_CRYPTO_ERROR;
#endif

    leadingBit = wc_Rsa_leading_bit(key->n);
    rawLen = wc_Rsa_unsigned_bin_size(key->n);
    if ((int)rawLen < 0) {
        return USER_CRYPTO_ERROR;
    }

    rawLen = rawLen + leadingBit;
    n[0] = ASN_INTEGER;
    nSz  = SetLength(rawLen, n + 1) + 1;  /* int tag */

    if ( (nSz + rawLen) < MAX_RSA_INT_SZ) {
        if (leadingBit)
            n[nSz] = 0;
        err = ippsGetOctString_BN((Ipp8u*)n + nSz, rawLen - leadingBit, key->n);
        if (err == ippStsNoErr)
            nSz += rawLen;
        else {
#ifdef WOLFSSL_SMALL_STACK
            XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
            return USER_CRYPTO_ERROR;
        }
    }
    else {
#ifdef WOLFSSL_SMALL_STACK
        XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
        return USER_CRYPTO_ERROR;
    }

    /* e */
#ifdef WOLFSSL_SMALL_STACK
    e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
    if (e == NULL) {
#ifdef WOLFSSL_SMALL_STACK
        XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
        return USER_CRYPTO_ERROR;
    }
#endif

    leadingBit = wc_Rsa_leading_bit(key->e);
    rawLen = wc_Rsa_unsigned_bin_size(key->e);
    if ((int)rawLen < 0) {
        return USER_CRYPTO_ERROR;
    }

    rawLen = rawLen + leadingBit;
    e[0] = ASN_INTEGER;
    eSz  = SetLength(rawLen, e + 1) + 1;  /* int tag */

    if ( (eSz + rawLen) < MAX_RSA_E_SZ) {
        if (leadingBit)
            e[eSz] = 0;
        err = ippsGetOctString_BN((Ipp8u*)e + eSz, rawLen - leadingBit, key->e);
        if (err == ippStsNoErr)
            eSz += rawLen;
        else {
#ifdef WOLFSSL_SMALL_STACK
            XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
            return USER_CRYPTO_ERROR;
        }
    }
    else {
#ifdef WOLFSSL_SMALL_STACK
        XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
        return USER_CRYPTO_ERROR;
    }

    seqSz  = SetSequence(nSz + eSz, seq);

    /* check output size */
    if ( (seqSz + nSz + eSz) > outLen) {
#ifdef WOLFSSL_SMALL_STACK
        XFREE(n,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
        XFREE(e,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
        return USER_CRYPTO_ERROR;
    }

    /* headers */
    if (with_header) {
        int  algoSz;
#ifdef WOLFSSL_SMALL_STACK
        byte* algo;

        algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
        if (algo == NULL) {
            XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            return USER_CRYPTO_ERROR;
        }
#else
        byte algo[MAX_ALGO_SZ];
#endif
        algoSz = SetAlgoID(RSAk, algo, keyType, 0);
        lenSz  = SetLength(seqSz + nSz + eSz + 1, len);
        len[lenSz++] = 0;   /* trailing 0 */

        /* write, 1 is for ASN_BIT_STRING */
        idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);

        /* check output size */
        if ( (idx + algoSz + 1 + lenSz + seqSz + nSz + eSz) > outLen) {
            #ifdef WOLFSSL_SMALL_STACK
                XFREE(n,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
                XFREE(e,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
                XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
            #endif

            return USER_CRYPTO_ERROR;
        }

        /* algo */
        XMEMCPY(output + idx, algo, algoSz);
        idx += algoSz;
        /* bit string */
        output[idx++] = ASN_BIT_STRING;
        /* length */
        XMEMCPY(output + idx, len, lenSz);
        idx += lenSz;
#ifdef WOLFSSL_SMALL_STACK
        XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif
    }
    else
        idx = 0;

    /* seq */
    XMEMCPY(output + idx, seq, seqSz);
    idx += seqSz;
    /* n */
    XMEMCPY(output + idx, n, nSz);
    idx += nSz;
    /* e */
    XMEMCPY(output + idx, e, eSz);
    idx += eSz;

#ifdef WOLFSSL_SMALL_STACK
    XFREE(n,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
    XFREE(e,    NULL, DYNAMIC_TYPE_USER_CRYPTO);
#endif

    return idx;
}


static IppsBigNumState* GetRsaInt(RsaKey* key, int idx)
{
    if (idx == 0)
        return key->n;
    if (idx == 1)
        return key->e;
    if (idx == 2)
        return key->dipp;
    if (idx == 3)
        return key->pipp;
    if (idx == 4)
        return key->qipp;
    if (idx == 5)
        return key->dPipp;
    if (idx == 6)
        return key->dQipp;
    if (idx == 7)
        return key->uipp;

    return NULL;
}


/* Release Tmp RSA resources */
static WC_INLINE void FreeTmpRsas(byte** tmps, void* heap)
{
    int i;

    (void)heap;

    for (i = 0; i < RSA_INTS; i++)
        XFREE(tmps[i], heap, DYNAMIC_TYPE_USER_CRYPTO);
}


/* Convert RsaKey key to DER format, write to output (inLen), return bytes
   written */
int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
{
    word32 seqSz, verSz, rawLen, intTotalLen = 0;
    word32 sizes[RSA_INTS];
    int    i, j, outLen, ret = 0, lbit;

    byte  seq[MAX_SEQ_SZ];
    byte  ver[MAX_VERSION_SZ];
    byte* tmps[RSA_INTS];

    USER_DEBUG(("Entering RsaKeyToDer\n"));

    if (!key)
        return USER_CRYPTO_ERROR;

    if (key->type != RSA_PRIVATE)
        return USER_CRYPTO_ERROR;

    for (i = 0; i < RSA_INTS; i++)
        tmps[i] = NULL;

    /* write all big ints from key to DER tmps */
    for (i = 0; i < RSA_INTS; i++) {
        Ipp32u isZero;
        IppsBigNumState* keyInt = GetRsaInt(key, i);

        ippsCmpZero_BN(keyInt, &isZero); /* makes isZero 0 if true */
        rawLen = wc_Rsa_unsigned_bin_size(keyInt);
        if ((int)rawLen < 0) {
            return USER_CRYPTO_ERROR;
        }

        /* leading zero */
        if (!isZero || wc_Rsa_leading_bit(keyInt))
            lbit = 1;
        else
            lbit = 0;

        rawLen += lbit;

        tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
                                                      DYNAMIC_TYPE_USER_CRYPTO);
        if (tmps[i] == NULL) {
            ret = USER_CRYPTO_ERROR;
            break;
        }

        tmps[i][0] = ASN_INTEGER;
        sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1 + lbit; /* tag & lbit */

        if (sizes[i] <= MAX_SEQ_SZ) {
            int err;

            /* leading zero */
            if (lbit)
                tmps[i][sizes[i]-1] = 0x00;

            /* extract data*/
            err = ippsGetOctString_BN((Ipp8u*)(tmps[i] + sizes[i]),
                    rawLen - lbit, keyInt);
            if (err == ippStsOk) {
                sizes[i] += (rawLen-lbit); /* lbit included in rawLen */
                intTotalLen += sizes[i];
                ret = 0;
            }
            else {
                ret = USER_CRYPTO_ERROR;
                USER_DEBUG(("ippsGetOctString_BN error %s\n",
                                                      ippGetStatusString(err)));
                break;
            }
        }
        else {
            ret = USER_CRYPTO_ERROR;
            break;
        }
    }

    if (ret != 0) {
        FreeTmpRsas(tmps, key->heap);
        return ret;
    }

    /* make headers */
    verSz = SetMyVersion(0, ver, FALSE);
    seqSz = SetSequence(verSz + intTotalLen, seq);

    outLen = seqSz + verSz + intTotalLen;
    if (output) {
        if (outLen > (int)inLen) {
            return USER_CRYPTO_ERROR;
        }

        /* write to output */
        XMEMCPY(output, seq, seqSz);
        j = seqSz;
        XMEMCPY(output + j, ver, verSz);
        j += verSz;

        for (i = 0; i < RSA_INTS; i++) {
            XMEMCPY(output + j, tmps[i], sizes[i]);
            j += sizes[i];
        }
    }
    FreeTmpRsas(tmps, key->heap);

    return outLen;
}


/* Convert Rsa Public key to DER format, write to output (inLen), return bytes
   written
*/
int wc_RsaKeyToPublicDer(RsaKey* key, byte* output, word32 inLen)
{
    return SetRsaPublicKey(output, key, inLen, 1);
}

/* Returns public DER version of the RSA key. If with_header is 0 then only a
 * seq + n + e is returned in ASN.1 DER format */
int wc_RsaKeyToPublicDer_ex(RsaKey* key, byte* output, word32 inLen,
    int with_header)
{
    return SetRsaPublicKey(output, key, inLen, with_header);
}

#endif /* WOLFSSL_KEY_GEN || OPENSSL_EXTRA */

#ifdef WC_RSA_BLINDING

int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
{
    if (key == NULL)
        return USER_CRYPTO_ERROR;

    (void)rng;

    return 0;
}

#endif /* WC_RSA_BLINDING */

#endif /* NO_RSA */

