Adds new `wc_RsaSetNonblockTime` API and `WC_RSA_NONBLOCK_TIME` build option. This new function configures the maximum amount of blocking time in microseconds. It uses a pre-computed table along with the CPU speed in megahertz to determine if the next operation can be completed within the maximum blocking time provided.

This commit is contained in:
David Garske 2018-12-17 16:27:49 -08:00
parent 986b5d3951
commit 413506f2b5
6 changed files with 199 additions and 7 deletions

View File

@ -791,3 +791,81 @@ WOLFSSL_API int wc_RsaKeyToPublicDer(RsaKey*, byte* output, word32 inLen);
\sa none
*/
WOLFSSL_API int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng);
/*!
\ingroup RSA
\brief This function sets the non-blocking RSA context. When a RsaNb context
is set it enables fast math based non-blocking exptmod, which splits the RSA
function into many smaller operations.
Enabled when WC_RSA_NONBLOCK is defined.
\return 0 Success
\return BAD_FUNC_ARG Returned if key or nb is null.
\param key The RSA key structure
\param nb The RSA non-blocking structure for this RSA key to use.
_Example_
\code
int ret, count = 0;
RsaKey key;
RsaNb nb;
wc_RsaInitKey(&key, NULL);
// Enable non-blocking RSA mode - provide context
ret = wc_RsaSetNonBlock(key, &nb);
if (ret != 0)
return ret;
do {
ret = wc_RsaSSL_Sign(in, inLen, out, outSz, key, rng);
count++; // track number of would blocks
if (ret == FP_WOULDBLOCK) {
// do "other" work here
}
} while (ret == FP_WOULDBLOCK);
if (ret < 0) {
return ret;
}
printf("RSA non-block sign: size %d, %d times\n", ret, count);
\endcode
\sa wc_RsaSetNonBlockTime
*/
WOLFSSL_API int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb);
/*!
\ingroup RSA
\brief This function configures the maximum amount of blocking time in
microseconds. It uses a pre-computed table (see tfm.c exptModNbInst) along
with the CPU speed in megahertz to determine if the next operation can be
completed within the maximum blocking time provided.
Enabled when WC_RSA_NONBLOCK_TIME is defined.
\return 0 Success
\return BAD_FUNC_ARG Returned if key is null or wc_RsaSetNonBlock was not
previously called and key->nb is null.
\param key The RSA key structure.
\param maxBlockUs Maximum time to block microseconds.
\param cpuMHz CPU speed in megahertz.
_Example_
\code
RsaKey key;
RsaNb nb;
wc_RsaInitKey(&key, NULL);
wc_RsaSetNonBlock(key, &nb);
wc_RsaSetNonBlockTime(&key, 4000, 160); // Block Max = 4 ms, CPU = 160MHz
\endcode
\sa wc_RsaSetNonBlock
*/
WOLFSSL_API int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs,
word32 cpuMHz);

View File

@ -55,7 +55,9 @@ Possible RSA enable options:
* WOLFSSL_KEY_GEN: Allows Private Key Generation default: off
* RSA_LOW_MEM: NON CRT Private Operations, less memory default: off
* WC_NO_RSA_OAEP: Disables RSA OAEP padding default: on (not defined)
* WC_RSA_NONBLOCK: Enables support for RSA non-blocking default: off
* WC_RSA_NONBLOCK_TIME:Enables support for time based blocking default: off
* time calculation.
*/
/*
@ -2813,7 +2815,7 @@ int wc_RsaEncryptSize(RsaKey* key)
return BAD_FUNC_ARG;
}
ret = mp_unsigned_bin_size(&key->n);
ret = mp_unsigned_bin_size(&key->n);
#ifdef WOLF_CRYPTO_DEV
if (ret == 0 && key->devId != INVALID_DEVID) {
@ -3386,6 +3388,19 @@ int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb)
return 0;
}
#ifdef WC_RSA_NONBLOCK_TIME
int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs, word32 cpuMHz)
{
if (key == NULL || key->nb == NULL) {
return BAD_FUNC_ARG;
}
/* calculate maximum number of instructions to block */
key->nb->exptmod.maxBlockInst = cpuMHz * maxBlockUs;
return 0;
}
#endif /* WC_RSA_NONBLOCK_TIME */
#endif /* WC_RSA_NONBLOCK */
#endif /* NO_RSA */

View File

@ -1196,15 +1196,80 @@ int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
#ifdef WC_RSA_NONBLOCK
#ifdef WC_RSA_NONBLOCK_TIME
/* User can override the check-time at build-time using the
* FP_EXPTMOD_NB_CHECKTIME macro to define your own function */
#ifndef FP_EXPTMOD_NB_CHECKTIME
/* instruction count for each type of operation */
/* array lookup is using TFM_EXPTMOD_NB_* states */
static const word32 exptModNbInst[TFM_EXPTMOD_NB_COUNT] = {
#ifdef TFM_PPC32
#ifdef _DEBUG
11098, 8701, 3971, 178394, 858093, 1040, 822, 178056, 181574, 90883, 184339, 236813
#else
7050, 2554, 3187, 43178, 200422, 384, 275, 43024, 43550, 30450, 46270, 61376
#endif
#elif defined(TFM_X86_64)
#ifdef _DEBUG
954, 2377, 858, 19027, 90840, 287, 407, 20140, 7874, 11385, 8005, 6151
#else
765, 1007, 771, 5216, 34993, 248, 193, 4975, 4201, 3947, 4275, 3811
#endif
#else /* software only fast math */
#ifdef _DEBUG
798, 2245, 802, 16657, 66920, 352, 186, 16997, 16145, 12789, 16742, 15006
#else
775, 1084, 783, 4692, 37510, 207, 183, 4374, 4392, 3097, 4442, 4079
#endif
#endif
};
static int fp_exptmod_nb_checktime(exptModNb_t* nb)
{
word32 totalInst;
/* if no max time has been set then stop (do not block) */
if (nb->maxBlockInst == 0 || nb->state >= TFM_EXPTMOD_NB_COUNT) {
return TFM_EXPTMOD_NB_STOP;
}
/* if instruction table not set then use maxBlockInst as simple counter */
if (exptModNbInst[nb->state] == 0) {
if (++nb->totalInst < nb->maxBlockInst)
return TFM_EXPTMOD_NB_CONTINUE;
nb->totalInst = 0; /* reset counter */
return TFM_EXPTMOD_NB_STOP;
}
/* get total instruction count including next operation */
totalInst = nb->totalInst + exptModNbInst[nb->state];
/* if the next operation can completed within the maximum then continue */
if (totalInst <= nb->maxBlockInst) {
return TFM_EXPTMOD_NB_CONTINUE;
}
return TFM_EXPTMOD_NB_STOP;
}
#define FP_EXPTMOD_NB_CHECKTIME(nb) fp_exptmod_nb_checktime((nb))
#endif /* !FP_EXPTMOD_NB_CHECKTIME */
#endif /* WC_RSA_NONBLOCK_TIME */
/* non-blocking version of timing resistant fp_exptmod function */
/* supports cache resistance */
int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y)
{
int err;
int err, ret = FP_WOULDBLOCK;
if (nb == NULL)
return FP_VAL;
#ifdef WC_RSA_NONBLOCK_TIME
nb->totalInst = 0;
do {
nb->totalInst += exptModNbInst[nb->state];
#endif
switch (nb->state) {
case TFM_EXPTMOD_NB_INIT:
/* now setup montgomery */
@ -1224,7 +1289,7 @@ int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y)
case TFM_EXPTMOD_NB_MONT:
/* mod m -> R[0] */
fp_montgomery_calc_normalization (&nb->R[0], P);
fp_montgomery_calc_normalization(&nb->R[0], P);
nb->state = TFM_EXPTMOD_NB_MONT_RED;
break;
@ -1338,10 +1403,17 @@ int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y)
fp_copy(&nb->R[0], Y);
nb->state = TFM_EXPTMOD_NB_INIT;
return FP_OKAY;
ret = FP_OKAY;
break;
} /* switch */
return FP_WOULDBLOCK;
#ifdef WC_RSA_NONBLOCK_TIME
/* determine if maximum blocking time has been reached */
} while (ret == FP_WOULDBLOCK &&
FP_EXPTMOD_NB_CHECKTIME(nb) == TFM_EXPTMOD_NB_CONTINUE);
#endif
return ret;
}
#endif /* WC_RSA_NONBLOCK */

View File

@ -9383,6 +9383,13 @@ static int rsa_nb_test(RsaKey* key, const byte* in, word32 inLen, byte* out,
if (ret != 0)
return ret;
#ifdef WC_RSA_NONBLOCK_TIME
/* Enable time based RSA blocking. 8 microseconds max (3.1GHz) */
ret = wc_RsaSetNonBlockTime(key, 8, 3100);
if (ret != 0)
return ret;
#endif
count = 0;
do {
ret = wc_RsaSSL_Sign(in, inLen, out, outSz, key, rng);

View File

@ -43,6 +43,9 @@
#ifndef USE_FAST_MATH
#error RSA non-blocking mode only supported using fast math
#endif
#ifndef TFM_TIMING_RESISTANT
#error RSA non-blocking mode only supported with timing resistance enabled
#endif
/* RSA bounds check is not supported with RSA non-blocking mode */
#undef NO_RSA_BOUNDS_CHECK
@ -268,6 +271,10 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz,
#endif
#ifdef WC_RSA_NONBLOCK
WOLFSSL_API int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb);
#ifdef WC_RSA_NONBLOCK_TIME
WOLFSSL_API int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs,
word32 cpuMHz);
#endif
#endif
/*

View File

@ -554,6 +554,7 @@ enum tfmExptModNbState {
TFM_EXPTMOD_NB_SQR,
TFM_EXPTMOD_NB_SQR_RED,
TFM_EXPTMOD_NB_RED,
TFM_EXPTMOD_NB_COUNT /* last item for total state count only */
};
typedef struct {
@ -562,13 +563,25 @@ typedef struct {
#else
fp_int R[2];
#endif
fp_digit buf, mp;
fp_digit buf;
fp_digit mp;
int bitcnt;
int digidx;
int y;
int state; /* tfmExptModNbState */
#ifdef WC_RSA_NONBLOCK_TIME
word32 maxBlockInst; /* maximum instructions to block */
word32 totalInst; /* tracks total instructions */
#endif
} exptModNb_t;
#ifdef WC_RSA_NONBLOCK_TIME
enum {
TFM_EXPTMOD_NB_STOP = 0, /* stop and return FP_WOULDBLOCK */
TFM_EXPTMOD_NB_CONTINUE = 1, /* keep blocking */
};
#endif
/* non-blocking version of timing resistant fp_exptmod function */
/* supports cache resistance */
int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y);