diff --git a/src/internal.c b/src/internal.c index 230039540d..eab007237b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19269,11 +19269,21 @@ int SendClientKeyExchange(WOLFSSL* ssl) goto exit_scke; } +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); +#else ret = wc_DhSetKey(ssl->buffers.serverDH_Key, ssl->buffers.serverDH_P.buffer, ssl->buffers.serverDH_P.length, ssl->buffers.serverDH_G.buffer, ssl->buffers.serverDH_G.length); +#endif if (ret != 0) { goto exit_scke; } @@ -19364,11 +19374,21 @@ int SendClientKeyExchange(WOLFSSL* ssl) goto exit_scke; } +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); +#else ret = wc_DhSetKey(ssl->buffers.serverDH_Key, ssl->buffers.serverDH_P.buffer, ssl->buffers.serverDH_P.length, ssl->buffers.serverDH_G.buffer, ssl->buffers.serverDH_G.length); +#endif if (ret != 0) { goto exit_scke; } @@ -21058,11 +21078,21 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto exit_sske; } +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); +#else ret = wc_DhSetKey(ssl->buffers.serverDH_Key, ssl->buffers.serverDH_P.buffer, ssl->buffers.serverDH_P.length, ssl->buffers.serverDH_G.buffer, ssl->buffers.serverDH_G.length); +#endif if (ret != 0) { goto exit_sske; } @@ -24580,11 +24610,21 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto exit_dcke; } +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); +#else ret = wc_DhSetKey(ssl->buffers.serverDH_Key, ssl->buffers.serverDH_P.buffer, ssl->buffers.serverDH_P.length, ssl->buffers.serverDH_G.buffer, ssl->buffers.serverDH_G.length); +#endif /* set the max agree result size */ ssl->arrays->preMasterSz = ENCRYPT_LEN; @@ -24636,11 +24676,21 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto exit_dcke; } +#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLFSSL_OLD_PRIME_CHECK) + ret = wc_DhSetCheckKey(ssl->buffers.serverDH_Key, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + NULL, 0, 0, ssl->rng); +#else ret = wc_DhSetKey(ssl->buffers.serverDH_Key, ssl->buffers.serverDH_P.buffer, ssl->buffers.serverDH_P.length, ssl->buffers.serverDH_G.buffer, ssl->buffers.serverDH_G.length); +#endif break; } diff --git a/src/ssl.c b/src/ssl.c index ececd2c7eb..601c220cde 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -22764,7 +22764,14 @@ int wolfSSL_BN_add(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b) int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int nbchecks, WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb) { - int res; + WC_RNG* rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRNG = NULL; +#else + WC_RNG tmpRNG[1]; +#endif + int initTmpRng = 0; + int res = MP_NO; (void)ctx; (void)cb; @@ -22776,13 +22783,40 @@ int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int nbchecks, return WOLFSSL_FATAL_ERROR; } - if (mp_prime_is_prime((mp_int*)bn->internal, nbchecks, &res) != MP_OKAY) { - WOLFSSL_MSG("mp_prime_is_prime error"); - return WOLFSSL_FATAL_ERROR; +#ifdef WOLFSSL_SMALL_STACK + tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (tmpRNG == NULL) + return WOLFSSL_FAILURE; +#endif + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + if (initGlobalRNG == 0) { + WOLFSSL_MSG("Global RNG no Init"); + } + else + rng = &globalRNG; } + if (rng) { + if (mp_prime_is_prime_ex((mp_int*)bn->internal, + nbchecks, &res, rng) != MP_OKAY) { + WOLFSSL_MSG("mp_prime_is_prime_ex error"); + res = MP_NO; + } + } + + if (initTmpRng) + wc_FreeRng(tmpRNG); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); +#endif + if (res != MP_YES) { - WOLFSSL_MSG("mp_prime_is_prime not prime"); + WOLFSSL_MSG("mp_prime_is_prime_ex not prime"); return WOLFSSL_FAILURE; } diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index b8fea8177e..e82d143494 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -765,7 +765,7 @@ static const byte dh_ffdhe8192_p[] = { }; static const byte dh_ffdhe8192_g[] = { 0x02 }; #ifdef HAVE_FFDHE_Q -static const byte dh_ffdhe8192_g[] = { +static const byte dh_ffdhe8192_q[] = { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD6, 0xFC, 0x2A, 0x2C, 0x51, 0x5D, 0xA5, 0x4D, 0x57, 0xEE, 0x2B, 0x10, 0x13, 0x9E, 0x9E, 0x78, @@ -1925,8 +1925,9 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv, } -int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, - word32 gSz, const byte* q, word32 qSz) +static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, + word32 gSz, const byte* q, word32 qSz, int trusted, + WC_RNG* rng) { int ret = 0; mp_int* keyP = NULL; @@ -1963,6 +1964,18 @@ int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, else keyP = &key->p; } + + if (ret == 0 && !trusted) { + int isPrime = 0; + if (rng != NULL) + ret = mp_prime_is_prime_ex(keyP, 8, &isPrime, rng); + else + ret = mp_prime_is_prime(keyP, 8, &isPrime); + + if (ret == 0 && isPrime == 0) + ret = DH_CHECK_PUB_E; + } + if (ret == 0 && mp_init(&key->g) != MP_OKAY) ret = MP_INIT_E; if (ret == 0) { @@ -1996,11 +2009,26 @@ int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, } +int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz, const byte* g, + word32 gSz, const byte* q, word32 qSz, int trusted, + WC_RNG* rng) +{ + return _DhSetKey(key, p, pSz, g, gSz, q, qSz, trusted, rng); +} + + +int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, + word32 gSz, const byte* q, word32 qSz) +{ + return _DhSetKey(key, p, pSz, g, gSz, q, qSz, 1, NULL); +} + + /* not in asn anymore since no actual asn types used */ int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz) { - return wc_DhSetKey_ex(key, p, pSz, g, gSz, NULL, 0); + return _DhSetKey(key, p, pSz, g, gSz, NULL, 0, 1, NULL); } @@ -2097,7 +2125,7 @@ int wc_DhGenerateParams(WC_RNG *rng, int modSz, DhKey *dh) /* loop until p is prime */ if (ret == 0) { do { - if (mp_prime_is_prime(&dh->p, 8, &primeCheck) != MP_OKAY) + if (mp_prime_is_prime_ex(&dh->p, 8, &primeCheck, rng) != MP_OKAY) ret = PRIME_GEN_E; if (primeCheck != MP_YES) { diff --git a/wolfcrypt/src/dsa.c b/wolfcrypt/src/dsa.c index 86d6015603..b7911555a9 100644 --- a/wolfcrypt/src/dsa.c +++ b/wolfcrypt/src/dsa.c @@ -337,7 +337,7 @@ int wc_MakeDsaParameters(WC_RNG *rng, int modulus_size, DsaKey *dsa) /* loop until p is prime */ while (check_prime == MP_NO) { - err = mp_prime_is_prime(&dsa->p, 8, &check_prime); + err = mp_prime_is_prime_ex(&dsa->p, 8, &check_prime, rng); if (err != MP_OKAY) { mp_clear(&dsa->q); mp_clear(&dsa->p); @@ -426,21 +426,8 @@ int wc_MakeDsaParameters(WC_RNG *rng, int modulus_size, DsaKey *dsa) #endif /* WOLFSSL_KEY_GEN */ -/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(), - * input parameters (p,q,g) should be represented as ASCII hex values. - * - * dsa - pointer to initialized DsaKey structure - * p - DSA (p) parameter, ASCII hex string - * pSz - length of p - * q - DSA (q) parameter, ASCII hex string - * qSz - length of q - * g - DSA (g) parameter, ASCII hex string - * gSz - length of g - * - * returns 0 on success, negative upon failure - */ -int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, - const char* g) +static int _DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, + const char* g, int trusted, WC_RNG* rng) { int err; word32 pSz, qSz; @@ -450,6 +437,18 @@ int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, /* read p */ err = mp_read_radix(&dsa->p, p, MP_RADIX_HEX); + if (err == MP_OKAY && !trusted) { + int isPrime = 1; + if (rng == NULL) + err = mp_prime_is_prime(&dsa->p, 8, &isPrime); + else + err = mp_prime_is_prime_ex(&dsa->p, 8, &isPrime, rng); + + if (err == MP_OKAY) { + if (!isPrime) + err = DH_CHECK_PUB_E; + } + } /* read q */ if (err == MP_OKAY) @@ -478,6 +477,49 @@ int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, } +/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(), + * input parameters (p,q,g) should be represented as ASCII hex values. + * + * dsa - pointer to initialized DsaKey structure + * p - DSA (p) parameter, ASCII hex string + * pSz - length of p + * q - DSA (q) parameter, ASCII hex string + * qSz - length of q + * g - DSA (g) parameter, ASCII hex string + * gSz - length of g + * + * returns 0 on success, negative upon failure + */ +int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, + const char* g) +{ + return _DsaImportParamsRaw(dsa, p, q, g, 1, NULL); +} + + +/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(), + * input parameters (p,q,g) should be represented as ASCII hex values. Check + * that the p value is probably prime. + * + * dsa - pointer to initialized DsaKey structure + * p - DSA (p) parameter, ASCII hex string + * pSz - length of p + * q - DSA (q) parameter, ASCII hex string + * qSz - length of q + * g - DSA (g) parameter, ASCII hex string + * gSz - length of g + * trusted - trust that p is OK + * rng - random number generator for the prime test + * + * returns 0 on success, negative upon failure + */ +int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p, const char* q, + const char* g, int trusted, WC_RNG* rng) +{ + return _DsaImportParamsRaw(dsa, p, q, g, trusted, rng); +} + + /* Export raw DSA parameters from DsaKey structure * * dsa - pointer to initialized DsaKey structure diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index 84290c64f0..13a1ab5c1b 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -3978,7 +3978,8 @@ int mp_set_int (mp_int * a, unsigned long b) } -#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC) +#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_RSA) || \ + !defined(NO_DSA) | !defined(NO_DH) /* c = a * a (mod b) */ int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) @@ -4172,7 +4173,8 @@ int mp_sub_d (mp_int * a, mp_digit b, mp_int * c) #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(HAVE_ECC) || \ - defined(DEBUG_WOLFSSL) + defined(DEBUG_WOLFSSL) || !defined(NO_RSA) || !defined(NO_DSA) || \ + !defined(NO_DH) static const int lnz[16] = { 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 @@ -4320,7 +4322,7 @@ int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) #endif /* WOLFSSL_KEY_GEN || HAVE_COMP_KEY || HAVE_ECC || DEBUG_WOLFSSL */ -#ifdef WOLFSSL_KEY_GEN +#if defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA) const mp_digit ltm_prime_tab[PRIME_SIZE] = { 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, @@ -4476,71 +4478,6 @@ static int mp_prime_is_divisible (mp_int * a, int *result) return MP_OKAY; } -static const int USE_BBS = 1; - -int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap) -{ - int err, res, type; - byte* buf; - - if (N == NULL || rng == NULL) - return MP_VAL; - - /* get type */ - if (len < 0) { - type = USE_BBS; - len = -len; - } else { - type = 0; - } - - /* allow sizes between 2 and 512 bytes for a prime size */ - if (len < 2 || len > 512) { - return MP_VAL; - } - - /* allocate buffer to work with */ - buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_RSA); - if (buf == NULL) { - return MP_MEM; - } - XMEMSET(buf, 0, len); - - do { -#ifdef SHOW_GEN - printf("."); - fflush(stdout); -#endif - /* generate value */ - err = wc_RNG_GenerateBlock(rng, buf, len); - if (err != 0) { - XFREE(buf, heap, DYNAMIC_TYPE_RSA); - return err; - } - - /* munge bits */ - buf[0] |= 0x80 | 0x40; - buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00); - - /* load value */ - if ((err = mp_read_unsigned_bin(N, buf, len)) != MP_OKAY) { - XFREE(buf, heap, DYNAMIC_TYPE_RSA); - return err; - } - - /* test */ - if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) { - XFREE(buf, heap, DYNAMIC_TYPE_RSA); - return err; - } - } while (res == MP_NO); - - XMEMSET(buf, 0, len); - XFREE(buf, heap, DYNAMIC_TYPE_RSA); - - return MP_OKAY; -} - /* * Sets result to 1 if probably prime, 0 otherwise */ @@ -4602,6 +4539,170 @@ LBL_B:mp_clear (&b); } +/* + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng) +{ + mp_int b, c; + int ix, err, res; + byte* base = NULL; + word32 baseSz = 0; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) { + *result = MP_YES; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + if ((err = mp_init (&c)) != MP_OKAY) { + mp_clear(&b); + return err; + } + + baseSz = mp_count_bits(a); + baseSz = (baseSz / 8) + ((baseSz % 8) ? 1 : 0); + + base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (base == NULL) { + err = MP_MEM; + goto LBL_B; + } + + if ((err = mp_sub_d(a, 2, &c)) != MP_OKAY) { + goto LBL_B; + } + + /* now do a miller rabin with up to t random numbers, this should + * give a (1/4)^t chance of a false prime. */ + for (ix = 0; ix < t; ix++) { + /* Set a test candidate. */ + if ((err = wc_RNG_GenerateBlock(rng, base, baseSz)) != 0) { + goto LBL_B; + } + + if ((err = mp_read_unsigned_bin(&b, base, baseSz)) != MP_OKAY) { + goto LBL_B; + } + + if (mp_cmp_d(&b, 2) != MP_GT || mp_cmp(&b, &c) != MP_LT) + continue; + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + + if (res == MP_NO) { + goto LBL_B; + } + } + + /* passed the test */ + *result = MP_YES; +LBL_B:mp_clear (&b); + mp_clear (&c); + XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return err; +} + +#endif /* WOLFSSL_KEY_GEN NO_DH NO_DSA NO_RSA */ + +#ifdef WOLFSSL_KEY_GEN + +static const int USE_BBS = 1; + +int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap) +{ + int err, res, type; + byte* buf; + + if (N == NULL || rng == NULL) + return MP_VAL; + + /* get type */ + if (len < 0) { + type = USE_BBS; + len = -len; + } else { + type = 0; + } + + /* allow sizes between 2 and 512 bytes for a prime size */ + if (len < 2 || len > 512) { + return MP_VAL; + } + + /* allocate buffer to work with */ + buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_RSA); + if (buf == NULL) { + return MP_MEM; + } + XMEMSET(buf, 0, len); + + do { +#ifdef SHOW_GEN + printf("."); + fflush(stdout); +#endif + /* generate value */ + err = wc_RNG_GenerateBlock(rng, buf, len); + if (err != 0) { + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return err; + } + + /* munge bits */ + buf[0] |= 0x80 | 0x40; + buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00); + + /* load value */ + if ((err = mp_read_unsigned_bin(N, buf, len)) != MP_OKAY) { + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return err; + } + + /* test */ + /* Running Miller-Rabin up to 3 times gives us a 2^{-80} chance + * of a 1024-bit candidate being a false positive, when it is our + * prime candidate. (Note 4.49 of Handbook of Applied Cryptography.) + * Using 8 because we've always used 8. */ + if ((err = mp_prime_is_prime_ex(N, 8, &res, rng)) != MP_OKAY) { + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return err; + } + } while (res == MP_NO); + + XMEMSET(buf, 0, len); + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + + return MP_OKAY; +} + + /* computes least common multiple as |a*b|/(a, b) */ int mp_lcm (mp_int * a, mp_int * b, mp_int * c) { diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 53eca73c7a..ab8d59b941 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -2769,8 +2769,8 @@ static WC_INLINE int RsaSizeCheck(int size) } -static int wc_CheckProbablePrime_ex(mp_int* p, mp_int* q, mp_int* e, int nlen, - int* isPrime) +static int _CheckProbablePrime(mp_int* p, mp_int* q, mp_int* e, int nlen, + int* isPrime, WC_RNG* rng) { int ret; mp_int tmp1, tmp2; @@ -2811,10 +2811,17 @@ static int wc_CheckProbablePrime_ex(mp_int* p, mp_int* q, mp_int* e, int nlen, ret = mp_cmp_d(&tmp2, 1); if (ret != MP_EQ) goto exit; /* e divides p-1 */ - /* 4.5.1,5.6.1 - Check primality of p with 8 iterations */ - ret = mp_prime_is_prime(prime, 8, isPrime); - /* Performs some divides by a table of primes, and then does M-R, - * it sets isPrime as a side-effect. */ + /* 4.5.1,5.6.1 - Check primality of p with 8 rounds of M-R. + * mp_prime_is_prime_ex() performs test divisons against the first 256 + * prime numbers. After that it performs 8 rounds of M-R using random + * bases between 2 and n-2. + * mp_prime_is_prime() performs the same test divisions and then does + * M-R with the first 8 primes. Both functions set isPrime as a + * side-effect. */ + if (rng != NULL) + ret = mp_prime_is_prime_ex(prime, 8, isPrime, rng); + else + ret = mp_prime_is_prime(prime, 8, isPrime); if (ret != MP_OKAY) goto notOkay; exit: @@ -2826,11 +2833,10 @@ notOkay: } - -int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz, +int wc_CheckProbablePrime_ex(const byte* pRaw, word32 pRawSz, const byte* qRaw, word32 qRawSz, const byte* eRaw, word32 eRawSz, - int nlen, int* isPrime) + int nlen, int* isPrime, WC_RNG* rng) { mp_int p, q, e; mp_int* Q = NULL; @@ -2863,7 +2869,7 @@ int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz, ret = mp_read_unsigned_bin(&e, eRaw, eRawSz); if (ret == MP_OKAY) - ret = wc_CheckProbablePrime_ex(&p, Q, &e, nlen, isPrime); + ret = _CheckProbablePrime(&p, Q, &e, nlen, isPrime, rng); ret = (ret == MP_OKAY) ? 0 : PRIME_GEN_E; @@ -2875,6 +2881,16 @@ int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz, } +int wc_CheckProbablePrime(const byte* pRaw, word32 pRawSz, + const byte* qRaw, word32 qRawSz, + const byte* eRaw, word32 eRawSz, + int nlen, int* isPrime) +{ + return wc_CheckProbablePrime_ex(pRaw, pRawSz, qRaw, qRawSz, + eRaw, eRawSz, nlen, isPrime, NULL); +} + + /* 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) { @@ -2950,7 +2966,7 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) } if (err == MP_OKAY) - err = wc_CheckProbablePrime_ex(&p, NULL, &tmp3, size, &isPrime); + err = _CheckProbablePrime(&p, NULL, &tmp3, size, &isPrime, rng); #ifdef WOLFSSL_FIPS i++; @@ -2986,7 +3002,7 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) } if (err == MP_OKAY) - err = wc_CheckProbablePrime_ex(&p, &q, &tmp3, size, &isPrime); + err = _CheckProbablePrime(&p, &q, &tmp3, size, &isPrime, rng); #ifdef WOLFSSL_FIPS i++; diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index f223f35c00..3e4a8e8d04 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -2564,7 +2564,8 @@ int mp_set_bit(mp_int *a, mp_digit b) return fp_set_bit(a, b); } -#if defined(WOLFSSL_KEY_GEN) || defined (HAVE_ECC) +#if defined(WOLFSSL_KEY_GEN) || defined (HAVE_ECC) || !defined(NO_DH) || \ + !defined(NO_DSA) || !defined(NO_RSA) /* c = a * a (mod b) */ int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c) @@ -2607,7 +2608,8 @@ int mp_montgomery_calc_normalization(mp_int *a, mp_int *b) #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \ defined(WOLFSSL_DEBUG_MATH) || defined(DEBUG_WOLFSSL) || \ - defined(WOLFSSL_PUBLIC_MP) + defined(WOLFSSL_PUBLIC_MP) || !defined(NO_DH) || !defined(NO_DSA) || \ + !defined(NO_RSA) #ifdef WOLFSSL_KEY_GEN /* swap the elements of two integers, for cases where you can't simply swap the @@ -2755,57 +2757,20 @@ int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c) #endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(WOLFSSL_DEBUG_MATH) */ -#ifdef WOLFSSL_KEY_GEN -static void fp_gcd(fp_int *a, fp_int *b, fp_int *c); -static void fp_lcm(fp_int *a, fp_int *b, fp_int *c); +#if !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA) || defined(WOLFSSL_KEY_GEN) + static int fp_isprime_ex(fp_int *a, int t); -static int fp_isprime(fp_int *a); -static int fp_randprime(fp_int* N, int len, WC_RNG* rng, void* heap); - -int mp_gcd(fp_int *a, fp_int *b, fp_int *c) -{ - fp_gcd(a, b, c); - return MP_OKAY; -} - - -int mp_lcm(fp_int *a, fp_int *b, fp_int *c) -{ - fp_lcm(a, b, c); - return MP_OKAY; -} +/* static int fp_isprime(fp_int *a); */ int mp_prime_is_prime(mp_int* a, int t, int* result) { (void)t; - *result = fp_isprime(a); + *result = fp_isprime_ex(a, t); return MP_OKAY; } -int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap) -{ - int err; - - err = fp_randprime(N, len, rng, heap); - switch(err) { - case FP_VAL: - return MP_VAL; - case FP_MEM: - return MP_MEM; - default: - break; - } - - return MP_OKAY; -} - -int mp_exch (mp_int * a, mp_int * b) -{ - fp_exch(a, b); - return MP_OKAY; -} /* Miller-Rabin test of "a" to the base of "b" as described in * HAC pp. 139 Algorithm 4.24 @@ -2920,6 +2885,12 @@ int fp_isprime_ex(fp_int *a, int t) return FP_NO; } + for (r = 0; r < FP_PRIME_SIZE; r++) { + if (fp_cmp_d(a, primes[r]) == FP_EQ) { + return FP_YES; + } + } + /* do trial division */ for (r = 0; r < FP_PRIME_SIZE; r++) { res = fp_mod_d(a, primes[r], &d); @@ -2940,15 +2911,144 @@ int fp_isprime_ex(fp_int *a, int t) return FP_YES; } +#if 0 +/* Removed in favor of fp_isprime_ex(). */ int fp_isprime(fp_int *a) { return fp_isprime_ex(a, 8); } +#endif + +int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng) +{ + int ret = FP_YES; + + if (a == NULL || result == NULL || rng == NULL) + return FP_VAL; + + /* do trial division */ + if (ret == FP_YES) { + fp_digit d; + int r; + + for (r = 0; r < FP_PRIME_SIZE; r++) { + if (fp_cmp_d(a, primes[r]) == FP_EQ) { + *result = FP_YES; + return FP_OKAY; + } + } + + for (r = 0; r < FP_PRIME_SIZE; r++) { + if (fp_mod_d(a, primes[r], &d) == MP_OKAY) { + if (d == 0) + ret = FP_NO; + } + else + return FP_VAL; + } + } + + /* now do a miller rabin with up to t random numbers, this should + * give a (1/4)^t chance of a false prime. */ + if (ret == FP_YES) { + fp_int b, c; + /* FP_MAX_BITS is 2 times the modulus size. The modulus size is + * 2 times the prime size. */ + word32 baseSz; + #ifndef WOLFSSL_SMALL_STACK + byte base[FP_MAX_BITS/32]; + #else + byte* base; + #endif + + baseSz = fp_count_bits(a); + baseSz = (baseSz / 8) + ((baseSz % 8) ? 1 : 0); + + #ifdef WOLFSSL_SMALL_STACK + base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (base == NULL) + return FP_MEM; + #endif + + fp_init(&b); + fp_init(&c); + fp_sub_d(a, 2, &c); + while (t > 0) { + wc_RNG_GenerateBlock(rng, base, baseSz); + fp_read_unsigned_bin(&b, base, baseSz); + if (fp_cmp_d(&b, 2) != FP_GT || fp_cmp(&b, &c) != FP_LT) + continue; + fp_prime_miller_rabin(a, &b, &ret); + if (ret == FP_NO) + break; + fp_zero(&b); + t--; + } + fp_clear(&b); + fp_clear(&c); + #ifdef WOLFSSL_SMALL_STACK + XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } + + *result = ret; + return FP_OKAY; +} + +#endif /* NO_RSA NO_DSA NO_DH WOLFSSL_KEY_GEN */ + + +#ifdef WOLFSSL_KEY_GEN + +static void fp_gcd(fp_int *a, fp_int *b, fp_int *c); +static void fp_lcm(fp_int *a, fp_int *b, fp_int *c); +static int fp_randprime(fp_int* N, int len, WC_RNG* rng, void* heap); + +int mp_gcd(fp_int *a, fp_int *b, fp_int *c) +{ + fp_gcd(a, b, c); + return MP_OKAY; +} + + +int mp_lcm(fp_int *a, fp_int *b, fp_int *c) +{ + fp_lcm(a, b, c); + return MP_OKAY; +} + +int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap) +{ + int err; + + err = fp_randprime(N, len, rng, heap); + switch(err) { + case FP_VAL: + return MP_VAL; + case FP_MEM: + return MP_MEM; + default: + break; + } + + return MP_OKAY; +} + +int mp_exch (mp_int * a, mp_int * b) +{ + fp_exch(a, b); + return MP_OKAY; +} + + int fp_randprime(fp_int* N, int len, WC_RNG* rng, void* heap) { static const int USE_BBS = 1; int err, type; + int isPrime = FP_YES; + /* Assume the candidate is probably prime and then test until + * it is proven composite. */ byte* buf; /* get type */ @@ -2991,7 +3091,12 @@ int fp_randprime(fp_int* N, int len, WC_RNG* rng, void* heap) fp_read_unsigned_bin(N, buf, len); /* test */ - } while (fp_isprime(N) == FP_NO); + /* Running Miller-Rabin up to 3 times gives us a 2^{-80} chance + * of a 1024-bit candidate being a false positive, when it is our + * prime candidate. (Note 4.49 of Handbook of Applied Cryptography.) + * Using 8 because we've always used 8 */ + mp_prime_is_prime_ex(N, 8, &isPrime, rng); + } while (isPrime == FP_NO); XMEMSET(buf, 0, len); XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 94dd18b642..fbeda379b2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -341,6 +341,9 @@ int memory_test(void); #ifdef HAVE_VALGRIND int mp_test(void); #endif +#ifdef WOLFSSL_PUBLIC_MP +int prime_test(void); +#endif #ifdef ASN_BER_TO_DER int berder_test(void); #endif @@ -955,6 +958,13 @@ initDefaultName(); printf( "mp test passed!\n"); #endif +#ifdef WOLFSSL_PUBLIC_MP + if ( (ret = prime_test()) != 0) + return err_sys("prime test failed!\n", ret); + else + printf( "prime test passed!\n"); +#endif + #if defined(ASN_BER_TO_DER) && \ (defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL)) @@ -19331,6 +19341,189 @@ done: } #endif + +#ifdef WOLFSSL_PUBLIC_MP + +typedef struct pairs_t { + const unsigned char* coeff; + int coeffSz; + int exp; +} pairs_t; + + +/* +n =p1p2p3, where pi = ki(p1−1)+1 with (k2,k3) = (173,293) +p1 = 2^192 * 0x000000000000e24fd4f6d6363200bf2323ec46285cac1d3a + + 2^0 * 0x0b2488b0c29d96c5e67f8bec15b54b189ae5636efe89b45b +*/ + +static const unsigned char c192a[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x4f, + 0xd4, 0xf6, 0xd6, 0x36, 0x32, 0x00, 0xbf, 0x23, + 0x23, 0xec, 0x46, 0x28, 0x5c, 0xac, 0x1d, 0x3a +}; +static const unsigned char c0a[] = +{ + 0x0b, 0x24, 0x88, 0xb0, 0xc2, 0x9d, 0x96, 0xc5, + 0xe6, 0x7f, 0x8b, 0xec, 0x15, 0xb5, 0x4b, 0x18, + 0x9a, 0xe5, 0x63, 0x6e, 0xfe, 0x89, 0xb4, 0x5b +}; + +static const pairs_t ecPairsA[] = +{ + {c192a, sizeof(c192a), 192}, + {c0a, sizeof(c0a), 0} +}; + +static const int kA[] = {173, 293}; + +static const unsigned char controlPrime[] = { + 0xe1, 0x76, 0x45, 0x80, 0x59, 0xb6, 0xd3, 0x49, + 0xdf, 0x0a, 0xef, 0x12, 0xd6, 0x0f, 0xf0, 0xb7, + 0xcb, 0x2a, 0x37, 0xbf, 0xa7, 0xf8, 0xb5, 0x4d, + 0xf5, 0x31, 0x35, 0xad, 0xe4, 0xa3, 0x94, 0xa1, + 0xdb, 0xf1, 0x96, 0xad, 0xb5, 0x05, 0x64, 0x85, + 0x83, 0xfc, 0x1b, 0x5b, 0x29, 0xaa, 0xbe, 0xf8, + 0x26, 0x3f, 0x76, 0x7e, 0xad, 0x1c, 0xf0, 0xcb, + 0xd7, 0x26, 0xb4, 0x1b, 0x05, 0x8e, 0x56, 0x86, + 0x7e, 0x08, 0x62, 0x21, 0xc1, 0x86, 0xd6, 0x47, + 0x79, 0x3e, 0xb7, 0x5d, 0xa4, 0xc6, 0x3a, 0xd7, + 0xb1, 0x74, 0x20, 0xf6, 0x50, 0x97, 0x41, 0x04, + 0x53, 0xed, 0x3f, 0x26, 0xd6, 0x6f, 0x91, 0xfa, + 0x68, 0x26, 0xec, 0x2a, 0xdc, 0x9a, 0xf1, 0xe7, + 0xdc, 0xfb, 0x73, 0xf0, 0x79, 0x43, 0x1b, 0x21, + 0xa3, 0x59, 0x04, 0x63, 0x52, 0x07, 0xc9, 0xd7, + 0xe6, 0xd1, 0x1b, 0x5d, 0x5e, 0x96, 0xfa, 0x53 +}; + + +static int GenerateNextP(mp_int* p1, mp_int* p2, int k) +{ + int ret; + + ret = mp_sub_d(p1, 1, p2); + if (ret == 0) + ret = mp_mul_d(p2, k, p2); + if (ret == 0) + ret = mp_add_d(p2, 1, p2); + + return ret; +} + + +static int GenerateP(mp_int* p1, mp_int* p2, mp_int* p3, + const pairs_t* ecPairs, int ecPairsSz, + const int* k) +{ + mp_int x,y; + int ret, i; + + ret = mp_init(&x); + if (ret == 0) { + ret = mp_init(&y); + if (ret != 0) { + mp_clear(&x); + return MP_MEM; + } + } + for (i = 0; ret == 0 && i < ecPairsSz; i++) { + ret = mp_read_unsigned_bin(&x, ecPairs[i].coeff, ecPairs[i].coeffSz); + /* p1 = 2^exp */ + if (ret == 0) + ret = mp_2expt(&y, ecPairs[i].exp); + /* p1 = p1 * m */ + if (ret == 0) + ret = mp_mul(&x, &y, &x); + /* p1 += */ + if (ret == 0) + ret = mp_add(p1, &x, p1); + mp_zero(&x); + mp_zero(&y); + } + mp_clear(&x); + mp_clear(&y); + + if (ret == 0) + ret = GenerateNextP(p1, p2, k[0]); + if (ret == 0) + ret = GenerateNextP(p1, p3, k[1]); + + return ret; +} + +int prime_test(void) +{ + mp_int n, p1, p2, p3; + int ret, isPrime = 0; + WC_RNG rng; + + ret = wc_InitRng(&rng); + if (ret == 0) + ret = mp_init_multi(&n, &p1, &p2, &p3, NULL, NULL); + if (ret == 0) + ret = GenerateP(&p1, &p2, &p3, + ecPairsA, sizeof(ecPairsA) / sizeof(ecPairsA[0]), kA); + if (ret == 0) + ret = mp_mul(&p1, &p2, &n); + if (ret == 0) + ret = mp_mul(&n, &p3, &n); + if (ret != 0) + return -9650; + + /* Check the old prime test using the number that false positives. + * This test result should indicate as not prime. */ + ret = mp_prime_is_prime(&n, 40, &isPrime); + if (ret != 0) + return -9651; + if (isPrime) + return -9652; + + /* This test result should fail. It should indicate the value as prime. */ + ret = mp_prime_is_prime(&n, 8, &isPrime); + if (ret != 0) + return -9653; + if (!isPrime) + return -9654; + + /* This test result should indicate the value as not prime. */ + ret = mp_prime_is_prime_ex(&n, 8, &isPrime, &rng); + if (ret != 0) + return -9655; + if (isPrime) + return -9656; + + ret = mp_read_unsigned_bin(&n, controlPrime, sizeof(controlPrime)); + if (ret != 0) + return -9657; + + /* This test result should indicate the value as prime. */ + ret = mp_prime_is_prime_ex(&n, 8, &isPrime, &rng); + if (ret != 0) + return -9658; + if (!isPrime) + return -9659; + + /* This test result should indicate the value as prime. */ + isPrime = -1; + ret = mp_prime_is_prime(&n, 8, &isPrime); + if (ret != 0) + return -9660; + if (!isPrime) + return -9661; + + mp_clear(&p3); + mp_clear(&p2); + mp_clear(&p1); + mp_clear(&n); + wc_FreeRng(&rng); + + return 0; +} + +#endif /* WOLFSSL_PUBLIC_MP */ + + #if defined(ASN_BER_TO_DER) && \ (defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL)) diff --git a/wolfssl/wolfcrypt/dh.h b/wolfssl/wolfcrypt/dh.h index f30a19f3c3..edb59d0ccb 100644 --- a/wolfssl/wolfcrypt/dh.h +++ b/wolfssl/wolfcrypt/dh.h @@ -98,6 +98,9 @@ WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g word32 gSz); WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz, const byte* q, word32 qSz); +WOLFSSL_API int wc_DhSetCheckKey(DhKey* key, const byte* p, word32 pSz, + const byte* g, word32 gSz, const byte* q, word32 qSz, + int trusted, WC_RNG* rng); WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz, byte* g, word32* gInOutSz); WOLFSSL_API int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz); diff --git a/wolfssl/wolfcrypt/dsa.h b/wolfssl/wolfcrypt/dsa.h index 752cf41865..3a0c0f3d01 100644 --- a/wolfssl/wolfcrypt/dsa.h +++ b/wolfssl/wolfcrypt/dsa.h @@ -80,6 +80,9 @@ WOLFSSL_API int wc_MakeDsaParameters(WC_RNG *rng, int modulus_size, DsaKey *dsa) /* raw export functions */ WOLFSSL_API int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, const char* g); +WOLFSSL_API int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p, + const char* q, const char* g, + int trusted, WC_RNG* rng); WOLFSSL_API int wc_DsaExportParamsRaw(DsaKey* dsa, byte* p, word32* pSz, byte* q, word32* qSz, byte* g, word32* gSz); diff --git a/wolfssl/wolfcrypt/integer.h b/wolfssl/wolfcrypt/integer.h index 0f9c925b2d..88aaabac03 100644 --- a/wolfssl/wolfcrypt/integer.h +++ b/wolfssl/wolfcrypt/integer.h @@ -368,15 +368,19 @@ MP_API int mp_radix_size (mp_int * a, int radix, int *size); #define mp_dump(desc, a, verbose) #endif -#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) +#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || !defined(NO_RSA) || \ + !defined(NO_DSA) || !defined(NO_DH) MP_API int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c); #endif #if !defined(NO_DSA) || defined(HAVE_ECC) MP_API int mp_read_radix(mp_int* a, const char* str, int radix); #endif -#ifdef WOLFSSL_KEY_GEN +#if defined(WOLFSSL_KEY_GEN) || !defined(NO_RSA) || !defined(NO_DSA) || !defined(NO_DH) MP_API int mp_prime_is_prime (mp_int * a, int t, int *result); + MP_API int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG*); +#endif /* WOLFSSL_KEY_GEN NO_RSA NO_DSA NO_DH */ +#ifdef WOLFSSL_KEY_GEN MP_API int mp_gcd (mp_int * a, mp_int * b, mp_int * c); MP_API int mp_lcm (mp_int * a, mp_int * b, mp_int * c); MP_API int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap); diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 127af0faea..ff3e962541 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -272,6 +272,10 @@ WOLFSSL_API int wc_RsaKeyToPublicDer(RsaKey*, byte* output, word32 inLen); #ifdef WOLFSSL_KEY_GEN WOLFSSL_API int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng); + WOLFSSL_API int wc_CheckProbablePrime_ex(const byte* p, word32 pSz, + const byte* q, word32 qSz, + const byte* e, word32 eSz, + int nlen, int* isPrime, WC_RNG* rng); WOLFSSL_API int wc_CheckProbablePrime(const byte* p, word32 pSz, const byte* q, word32 qSz, const byte* e, word32 eSz, diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 43217f584a..8aebfd2e03 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -723,15 +723,19 @@ MP_API int mp_radix_size (mp_int * a, int radix, int *size); MP_API int mp_set(fp_int *a, fp_digit b); #endif -#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) +#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || !defined(NO_RSA) || \ + !defined(NO_DSA) || !defined(NO_DH) MP_API int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c); MP_API int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); #endif +#if !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA) || defined(WOLFSSL_KEY_GEN) +MP_API int mp_prime_is_prime(mp_int* a, int t, int* result); +MP_API int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng); +#endif /* NO_DH NO_DSA NO_RSA WOLFSSL_KEY_GEN */ #ifdef WOLFSSL_KEY_GEN MP_API int mp_gcd(fp_int *a, fp_int *b, fp_int *c); MP_API int mp_lcm(fp_int *a, fp_int *b, fp_int *c); -MP_API int mp_prime_is_prime(mp_int* a, int t, int* result); MP_API int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap); MP_API int mp_exch(mp_int *a, mp_int *b); #endif /* WOLFSSL_KEY_GEN */