mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
557 lines
20 KiB
C
557 lines
20 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File cryptrsa.c
|
|
|
|
\Description
|
|
This module is a from-scratch RSA implementation in order to avoid
|
|
any intellectual property issues. The 1024 bit RSA public key
|
|
encryption algorithm was implemented from a specification provided
|
|
by Netscape for SSL implementation (see protossl.h).
|
|
|
|
\Copyright
|
|
Copyright (c) Electronic Arts 2002-2011.
|
|
|
|
\Todo
|
|
64bit word support (UCRYPT_SIZE=8) has been tested to work with the unix64-gcc
|
|
(Linux) and ps3-gcc (PS3) compilers; however the current implementation does
|
|
not work with certain odd modulus sizes (for example the 1000-bit modulus of
|
|
the built-in RSA CA certificate), so it is not currently enabled.
|
|
|
|
\Version 1.0 03/08/2002 (gschaefer) First Version (protossl)
|
|
\Version 1.1 03/05/2003 (jbrookes) Split RSA encryption from protossl
|
|
\Version 1.2 11/16/2011 (jbrookes) Optimizations to improve dbg&opt performance
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <string.h> // memset
|
|
|
|
#include "DirtySDK/dirtysock.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
#include "DirtySDK/crypt/cryptrand.h"
|
|
|
|
#include "DirtySDK/crypt/cryptrsa.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
/*** Macros ***********************************************************************/
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
/*** Function Prototypes **********************************************************/
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
// Private variables
|
|
|
|
|
|
// Public variables
|
|
|
|
|
|
/*** Private functions ************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptRSAExponentiate
|
|
|
|
\Description
|
|
Do the actual encryption: result = (value ^ exponent) % modulus.
|
|
Exponentiation is done using a sliding window, this function needs to
|
|
be called iteratively until the function returns zero.
|
|
|
|
\Input *pState - crypt state
|
|
\Input *pAccumul - [out] where we accumulate our result
|
|
\Input *pPowerof - contains our initial value and is used for squaring
|
|
\Input *pExponent - the exponent of the equation
|
|
\Input *pModulus - the modulus of the equation
|
|
|
|
\Output
|
|
int32_t - zero=done, else call again
|
|
|
|
\Notes
|
|
See Handbook of Applied Cryptography Chapter 14.6.1 (14.85):
|
|
http://cacr.uwaterloo.ca/hac/about/chap14.pdf
|
|
|
|
\Version 05/08/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
static int32_t _CryptRSAExponentiate(CryptRSAT *pState, CryptBnT *pAccumul, CryptBnT *pPowerof, const CryptBnT *pExponent, const CryptBnT *pModulus)
|
|
{
|
|
uint64_t uTickUsecs = NetTickUsec();
|
|
int32_t iResult = 1;
|
|
int32_t iMaxExponentBit = CryptBnBitLen(pExponent);
|
|
/* use a fixed window size of 6 for larger exponents,
|
|
we provide a fallthrough for smaller exponents */
|
|
const int32_t iWindowSize = iMaxExponentBit > 512 ? 6 : 1;
|
|
|
|
// if this is the first time, handle our precomputations
|
|
if (pState->pTable == NULL)
|
|
{
|
|
const int32_t iTableSize = 1 << (iWindowSize - 1);
|
|
|
|
if (iTableSize == 1)
|
|
{
|
|
// point to fixed array
|
|
pState->pTable = pState->aTable;
|
|
}
|
|
else
|
|
{
|
|
DirtyMemGroupQuery(&pState->iMemGroup, &pState->pMemGroupUserData);
|
|
|
|
// allocate memory for the table to avoid large data on the stack
|
|
if ((pState->pTable = (CryptBnT *)DirtyMemAlloc(sizeof(CryptBnT) * iTableSize, CRYPTRSA_MEMID, pState->iMemGroup, pState->pMemGroupUserData)) == NULL)
|
|
{
|
|
NetPrintf(("cryptrsa: [%p] unable to allocate memory for precomputed table used for sliding window\n", pState));
|
|
return(0);
|
|
}
|
|
}
|
|
ds_memclr(pState->pTable, sizeof(CryptBnT) * iTableSize);
|
|
|
|
/* put the already reduced input into the first
|
|
index of the table, this will make it so further
|
|
entries in the table will not be too large
|
|
for our modulus operations */
|
|
CryptBnClone(&pState->pTable[0], pPowerof);
|
|
|
|
/* precompute the different powers of input
|
|
that we use when we have a window that is
|
|
greater than one */
|
|
if (iTableSize > 1)
|
|
{
|
|
int32_t iTableIndex;
|
|
CryptBnT Square;
|
|
|
|
// calculate (input^2) % mod as the basis for the other calculations
|
|
CryptBnModMultiply(&Square, &pState->pTable[0], &pState->pTable[0], pModulus);
|
|
|
|
// calculate (input^(2+iTableIndex)) % mod for the rest of the table
|
|
for (iTableIndex = 1; iTableIndex < iTableSize; iTableIndex += 1)
|
|
{
|
|
CryptBnModMultiply(&pState->pTable[iTableIndex], &pState->pTable[iTableIndex - 1], &Square, pModulus);
|
|
}
|
|
}
|
|
|
|
// set the defaults
|
|
pState->iExpBitIndex = iMaxExponentBit - 1;
|
|
}
|
|
|
|
/* scan backwards from the current exponent bit
|
|
until a set bit is found to denote the start of the window
|
|
squaring the results until such a bit is found */
|
|
if (CryptBnBitTest(pExponent, pState->iExpBitIndex))
|
|
{
|
|
int32_t iWindowBit, iWindowValue, iWindowEnd;
|
|
|
|
/* scan backwards from the start of the window until the last set bit in the range of the window size is found which denotes the end bit index of the window
|
|
calculate the value of the window that will be used when multiplying against our precomputed table
|
|
we skip the first bit as we know it is set based on the current exponent bit check we make right above */
|
|
for (iWindowBit = 1, iWindowValue = 1, iWindowEnd = 0; (iWindowBit < iWindowSize) && ((pState->iExpBitIndex - iWindowBit) >= 0); iWindowBit += 1)
|
|
{
|
|
if (CryptBnBitTest(pExponent, pState->iExpBitIndex - iWindowBit))
|
|
{
|
|
iWindowValue <<= (iWindowBit - iWindowEnd);
|
|
iWindowValue |= 1; /* force odd */
|
|
iWindowEnd = iWindowBit;
|
|
}
|
|
}
|
|
|
|
// square for all the bits in the window and moving the exponent bit index down each time
|
|
for (iWindowBit = 0; iWindowBit < iWindowEnd + 1; iWindowBit += 1, pState->iExpBitIndex -= 1)
|
|
{
|
|
CryptBnModMultiply(pAccumul, pAccumul, pAccumul, pModulus);
|
|
}
|
|
|
|
// use the window value to get which precomputed power we need to multiply skip the first multiply
|
|
if (!pState->bAccumulOne)
|
|
{
|
|
CryptBnModMultiply(pAccumul, pAccumul, &pState->pTable[iWindowValue/2], pModulus);
|
|
}
|
|
else
|
|
{
|
|
CryptBnClone(pAccumul, &pState->pTable[iWindowValue/2]);
|
|
pState->bAccumulOne = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CryptBnModMultiply(pAccumul, pAccumul, pAccumul, pModulus);
|
|
pState->iExpBitIndex -= 1;
|
|
}
|
|
|
|
// check if we are done
|
|
if (pState->iExpBitIndex < 0)
|
|
{
|
|
// we are done, update timings and return appropriate result
|
|
pState->uCryptMsecs = (pState->uCryptUsecs+500)/1000;
|
|
iResult = 0;
|
|
|
|
if (pState->pTable != pState->aTable)
|
|
{
|
|
// clean up the table memory
|
|
DirtyMemFree(pState->pTable, CRYPTRSA_MEMID, pState->iMemGroup, pState->pMemGroupUserData);
|
|
}
|
|
pState->pTable = NULL;
|
|
}
|
|
|
|
// update timing
|
|
pState->uCryptUsecs += (uint32_t)NetTickDiff(NetTickUsec(), uTickUsecs);
|
|
pState->uNumExpCalls += 1;
|
|
|
|
return(iResult);
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptRSAEncryptPublic
|
|
|
|
\Description
|
|
Handle the exponentiate calls when using the public key data
|
|
|
|
\Input *pState - crypt state
|
|
\Input iIter - number of iterations
|
|
|
|
\Output
|
|
int32_t - zero=done, else call again
|
|
|
|
\Version 04/11/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
static int32_t _CryptRSAEncryptPublic(CryptRSAT *pState, int32_t iIter)
|
|
{
|
|
int32_t iCount, iResult;
|
|
|
|
for (iCount = 0, iResult = 1; (iCount < iIter) && (iResult > 0); iCount += 1)
|
|
{
|
|
iResult = _CryptRSAExponentiate(pState, &pState->Working.PublicKey.Accumul, &pState->Working.PublicKey.Powerof, &pState->Working.PublicKey.Exponent, &pState->Working.PublicKey.Modulus);
|
|
}
|
|
// if we are done, return encrypted data
|
|
if (iResult == 0)
|
|
{
|
|
CryptBnFinal(&pState->Working.PublicKey.Accumul, pState->EncryptBlock, pState->iKeyModSize);
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptRSAEncryptPrivate
|
|
|
|
\Description
|
|
Handle the exponentiate calls when using the private key data which
|
|
using chinese remainder theorum
|
|
|
|
\Input *pState - crypt state
|
|
\Input iIter - number of iterations
|
|
|
|
\Output
|
|
int32_t - zero=done, else call again
|
|
|
|
\Version 04/11/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
static int32_t _CryptRSAEncryptPrivate(CryptRSAT *pState, int32_t iIter)
|
|
{
|
|
int32_t iCount = 0, iResult = 1;
|
|
|
|
if (pState->Working.PrivateKey.eState == CRT_COMPUTE_M1)
|
|
{
|
|
/* compute m1
|
|
m1 = c ^ dP % p */
|
|
for (; (iCount < iIter) && (iResult > 0); iCount += 1)
|
|
{
|
|
iResult = _CryptRSAExponentiate(pState, &pState->Working.PrivateKey.M1, &pState->Working.PrivateKey.PowerofP, &pState->Working.PrivateKey.ExponentP, &pState->Working.PrivateKey.PrimeP);
|
|
}
|
|
|
|
if (iResult == 0)
|
|
{
|
|
// reset the state and move to next part of computation
|
|
pState->Working.PrivateKey.eState = CRT_COMPUTE_M2;
|
|
pState->bAccumulOne = TRUE;
|
|
pState->iExpBitIndex = 0;
|
|
iResult = 1;
|
|
}
|
|
}
|
|
if (pState->Working.PrivateKey.eState == CRT_COMPUTE_M2)
|
|
{
|
|
/* compute m2
|
|
m2 = c ^ dQ % q */
|
|
for (; (iCount < iIter) && (iResult > 0); iCount += 1)
|
|
{
|
|
iResult = _CryptRSAExponentiate(pState, &pState->Working.PrivateKey.M2, &pState->Working.PrivateKey.PowerofQ, &pState->Working.PrivateKey.ExponentQ, &pState->Working.PrivateKey.PrimeQ);
|
|
}
|
|
|
|
if (iResult == 0)
|
|
{
|
|
CryptBnT Result;
|
|
|
|
/* compute h
|
|
h = qInv * (m1 - m2) % p */
|
|
CryptBnInit(&Result, 1);
|
|
CryptBnSubtract(&Result, &pState->Working.PrivateKey.M1, &pState->Working.PrivateKey.M2);
|
|
CryptBnModMultiply(&Result, &Result, &pState->Working.PrivateKey.Coeffecient, &pState->Working.PrivateKey.PrimeP);
|
|
|
|
/* compute m
|
|
m = m2 + h * q */
|
|
CryptBnMultiply(&Result, &Result, &pState->Working.PrivateKey.PrimeQ);
|
|
CryptBnAccumulate(&Result, &pState->Working.PrivateKey.M2);
|
|
|
|
// return final result
|
|
CryptBnFinal(&Result, pState->EncryptBlock, pState->iKeyModSize);
|
|
}
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptRSAInitEncrypt
|
|
|
|
\Description
|
|
Initializes the common encrypt data and data depending on the type
|
|
of key
|
|
|
|
\Input *pState - crypt state
|
|
|
|
\Version 04/11/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
static void _CryptRSAInitEncrypt(CryptRSAT *pState)
|
|
{
|
|
// initialize accumulator to 1 (and remember for first-multiply optimization)
|
|
pState->bAccumulOne = TRUE;
|
|
|
|
// convert data to encrypt to native word size we will operate in
|
|
if (!pState->bPrivate)
|
|
{
|
|
CryptBnInitFrom(&pState->Working.PublicKey.Powerof, -1, pState->EncryptBlock, pState->iKeyModSize);
|
|
}
|
|
else
|
|
{
|
|
/* we need to reduce before every operation to get the cipher
|
|
text to less than our modulus in the operations.
|
|
our modular multiply in bn doesn't handle the cases where they
|
|
are larger */
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.PowerofP, -1, pState->EncryptBlock, pState->iKeyModSize);
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.PowerofQ, -1, pState->EncryptBlock, pState->iKeyModSize);
|
|
CryptBnMod(&pState->Working.PrivateKey.PowerofP, &pState->Working.PrivateKey.PrimeP, &pState->Working.PrivateKey.PowerofP, NULL);
|
|
CryptBnMod(&pState->Working.PrivateKey.PowerofQ, &pState->Working.PrivateKey.PrimeQ, &pState->Working.PrivateKey.PowerofQ, NULL);
|
|
}
|
|
}
|
|
|
|
/*** Public functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAInit
|
|
|
|
\Description
|
|
Init RSA state.
|
|
|
|
\Input *pState - module state
|
|
\Input *pModulus - crypto modulus
|
|
\Input iModSize - size of modulus
|
|
\Input *pExponent - crypto exponent
|
|
\Input iExpSize - size of exponent
|
|
|
|
\Output
|
|
int32_t - zero for success, negative for error
|
|
|
|
\Notes
|
|
This module supports a max modulus size of 4096 (iModSize=512) and requires
|
|
a minimum size of 1024 (iModSize=64). The exponent must be between 1
|
|
and 512 bytes in size, inclusive.
|
|
|
|
\Version 03/05/03 (jbrookes) Split from protossl
|
|
*/
|
|
/********************************************************************************H*/
|
|
int32_t CryptRSAInit(CryptRSAT *pState, const uint8_t *pModulus, int32_t iModSize, const uint8_t *pExponent, int32_t iExpSize)
|
|
{
|
|
int32_t iResult = 0;
|
|
|
|
// validate modulus size
|
|
if ((iModSize < 64) || ((iModSize/UCRYPT_SIZE) > CRYPTBN_MAX_WIDTH))
|
|
{
|
|
NetPrintf(("cryptrsa: iModSize of %d is invalid\n", iModSize));
|
|
return(-1);
|
|
}
|
|
// validate exponent size
|
|
if ((iExpSize < 1) || ((iExpSize/UCRYPT_SIZE) > CRYPTBN_MAX_WIDTH))
|
|
{
|
|
NetPrintf(("cryptrsa: iExpSize of %d is invalid\n", iExpSize));
|
|
return(-2);
|
|
}
|
|
|
|
// initialize state
|
|
ds_memclr(pState, sizeof(*pState));
|
|
CryptBnInitFrom(&pState->Working.PublicKey.Modulus, -1, pModulus, pState->iKeyModSize = iModSize);
|
|
CryptBnInitFrom(&pState->Working.PublicKey.Exponent, -1, pExponent, iExpSize);
|
|
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAInit2
|
|
|
|
\Description
|
|
Init RSA state for private key operations
|
|
|
|
\Input *pState - module state
|
|
\Input iModSize - size of the public key modulus
|
|
\Input *pPrimeP - factor p of modulus
|
|
\Input *pPrimeQ - factor q of modulus
|
|
\Input *pExponentP - inverse of exponent mod p-1
|
|
\Input *pExponentQ - inverse of exponent mod q-1
|
|
\Input *pCoeffecient- inverse of q mod p
|
|
\Output
|
|
int32_t - zero for success, negative for error
|
|
|
|
\Version 04/11/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
int32_t CryptRSAInit2(CryptRSAT *pState, int32_t iModSize, const CryptBinaryObjT *pPrimeP, const CryptBinaryObjT *pPrimeQ, const CryptBinaryObjT *pExponentP, const CryptBinaryObjT *pExponentQ, const CryptBinaryObjT *pCoeffecient)
|
|
{
|
|
// initialize state
|
|
ds_memclr(pState, sizeof(*pState));
|
|
|
|
// init state
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.PrimeP, -1, pPrimeP->pObjData, pPrimeP->iObjSize);
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.PrimeQ, -1, pPrimeQ->pObjData, pPrimeQ->iObjSize);
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.ExponentP, -1, pExponentP->pObjData, pExponentP->iObjSize);
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.ExponentQ, -1, pExponentQ->pObjData, pExponentQ->iObjSize);
|
|
CryptBnInitFrom(&pState->Working.PrivateKey.Coeffecient, -1, pCoeffecient->pObjData, pCoeffecient->iObjSize);
|
|
pState->iKeyModSize = iModSize;
|
|
pState->bPrivate = TRUE;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAInitMaster
|
|
|
|
\Description
|
|
Setup the master shared secret for encryption
|
|
|
|
\Input *pState - module state
|
|
\Input *pMaster - the master shared secret to encrypt
|
|
\Input iMasterLen - the length of the master shared secret
|
|
|
|
\Version 02/07/2014 (jbrookes) Rewritten to use CryptRand
|
|
*/
|
|
/********************************************************************************H*/
|
|
void CryptRSAInitMaster(CryptRSAT *pState, const uint8_t *pMaster, int32_t iMasterLen)
|
|
{
|
|
int32_t iIndex;
|
|
uint32_t uRandom;
|
|
|
|
// fill encrypt block with random data
|
|
CryptRandGet(pState->EncryptBlock, pState->iKeyModSize);
|
|
/* As per PKCS1 http://www.emc.com/emc-plus/rsa-labs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf section 7.2.1,
|
|
the pseudo-random padding octets must be non-zero. Failing to adhere to this restriction (or any other errors in pkcs1 encoding)
|
|
will typically result in a bad_record_mac fatal alert from the remote host. The following code gets four random bytes as seed
|
|
and uses a simple Knuth RNG to fill in any zero bytes that were originally generated. */
|
|
CryptRandGet((uint8_t *)&uRandom, sizeof(uRandom));
|
|
for (iIndex = 0; iIndex < pState->iKeyModSize; iIndex += 1)
|
|
{
|
|
while (pState->EncryptBlock[iIndex] == 0)
|
|
{
|
|
uRandom = (uRandom * 69069) + 69069;
|
|
pState->EncryptBlock[iIndex] ^= (uint8_t)uRandom;
|
|
}
|
|
}
|
|
// set PKCS public key signature
|
|
pState->EncryptBlock[0] = 0; // zero pad
|
|
pState->EncryptBlock[1] = 2; // public key is type 2
|
|
// add data to encrypt block
|
|
iIndex = pState->iKeyModSize - iMasterLen;
|
|
pState->EncryptBlock[iIndex-1] = 0; // zero byte prior to data
|
|
ds_memcpy(pState->EncryptBlock+iIndex, pMaster, iMasterLen);
|
|
// handle initializing the state according to the type of key
|
|
_CryptRSAInitEncrypt(pState);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAInitPrivate
|
|
|
|
\Description
|
|
Setup the master shared secret for encryption using PKCS1.5
|
|
|
|
\Input *pState - module state
|
|
\Input *pMaster - the master shared secret to encrypt
|
|
\Input iMasterLen - the length of the master shared secret
|
|
|
|
\Version 11/03/2013 (jbrookes)
|
|
*/
|
|
/********************************************************************************H*/
|
|
void CryptRSAInitPrivate(CryptRSAT *pState, const uint8_t *pMaster, int32_t iMasterLen)
|
|
{
|
|
int32_t iIndex;
|
|
// put in PKCS1.5 signature
|
|
pState->EncryptBlock[0] = 0;
|
|
pState->EncryptBlock[1] = 1;
|
|
// PKCS1.5 signing pads with 0xff
|
|
ds_memset(pState->EncryptBlock+2, 0xff, pState->iKeyModSize-2);
|
|
// add data to encrypt block
|
|
iIndex = pState->iKeyModSize - iMasterLen;
|
|
pState->EncryptBlock[iIndex-1] = 0; // zero byte prior to data
|
|
ds_memcpy(pState->EncryptBlock+iIndex, pMaster, iMasterLen);
|
|
// handle initializing the state according to the type of key
|
|
_CryptRSAInitEncrypt(pState);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAInitSignature
|
|
|
|
\Description
|
|
Setup the encrypted signature for decryption.
|
|
|
|
\Input *pState - module state
|
|
\Input *pSig - the encrypted signature
|
|
\Input iSigLen - the length of the encrypted signature.
|
|
|
|
\Version 03/03/2004 (sbevan)
|
|
*/
|
|
/********************************************************************************H*/
|
|
void CryptRSAInitSignature(CryptRSAT *pState, const uint8_t *pSig, int32_t iSigLen)
|
|
{
|
|
ds_memcpy(pState->EncryptBlock, pSig, iSigLen);
|
|
// handle initializing the state according to the type of key
|
|
_CryptRSAInitEncrypt(pState);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptRSAEncrypt
|
|
|
|
\Description
|
|
Encrypt data.
|
|
|
|
\Input *pState - module state
|
|
\Input iIter - number of iterations to execute (zero=do all)
|
|
|
|
\Output
|
|
int32_t - zero=operation complete, else call again
|
|
|
|
\Version 03/05/2003 (jbrookes) Split from protossl
|
|
*/
|
|
/********************************************************************************H*/
|
|
int32_t CryptRSAEncrypt(CryptRSAT *pState, int32_t iIter)
|
|
{
|
|
if (iIter == 0)
|
|
{
|
|
iIter = 0x7fffffff;
|
|
}
|
|
|
|
return((!pState->bPrivate) ? _CryptRSAEncryptPublic(pState, iIter) : _CryptRSAEncryptPrivate(pState, iIter));
|
|
}
|
|
|
|
|