From 0bc16d47e26ff50a4c4bb86ec5b9584e0b3d027a Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 19 Sep 2019 09:08:15 +1000 Subject: [PATCH] Add support for prime checking to sp_int.c This allows SP to support: - DH parameter checking - DH parameter generation - RSA key generation Improved performance of sp_mod operation. Reworked some functions to have one exit point (return statement). Fixed sp_sub_d(). Changed tests to perform 2048-bit RSA key generation only when using SP math. Fixed Intel x86_64 C file to not have DH specific functions available unless WOLFSSL_HAVE_SP_DH is defined. Fixed tfm to return an error when t is not the correct size in fp_isprime_ex(). --- configure.ac | 9 +- tests/api.c | 82 +- wolfcrypt/benchmark/benchmark.c | 4 + wolfcrypt/src/dh.c | 5 - wolfcrypt/src/rsa.c | 2 +- wolfcrypt/src/sp_int.c | 1376 ++++++++++++++++++++++++++++--- wolfcrypt/src/sp_x86_64.c | 4 + wolfcrypt/src/tfm.c | 3 +- wolfcrypt/test/test.c | 4 + wolfssl/wolfcrypt/sp_int.h | 56 +- 10 files changed, 1376 insertions(+), 169 deletions(-) diff --git a/configure.ac b/configure.ac index cf9aaca21..0a4312222 100644 --- a/configure.ac +++ b/configure.ac @@ -4037,6 +4037,9 @@ if test "$ENABLED_SP_MATH" = "yes"; then if test "$ENABLED_SP_DH" = "no" && test "$ENABLED_DH" = "yes"; then AC_MSG_ERROR([Cannot use P256 single precision only math and DH]) fi + + ENABLED_FASTMATH="no" + ENABLED_SLOWMATH="no" fi if test "$ENABLED_SP_MATH" = "yes"; then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SP_MATH" @@ -4538,9 +4541,9 @@ then fi AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_WOLFSCEP" fi -if test "$ENABLED_SP_MATH" = "yes" && test "$ENABLED_KEYGEN" = "yes"; then - AC_MSG_ERROR([Cannot use single precision math and key generation]) -fi +#if test "$ENABLED_SP_MATH" = "yes" && test "$ENABLED_KEYGEN" = "yes"; then +# AC_MSG_ERROR([Cannot use single precision math and key generation]) +#fi if test "x$ENABLED_PKCS7" = "xyes" then diff --git a/tests/api.c b/tests/api.c index b6c221d0e..34b2e4bfc 100644 --- a/tests/api.c +++ b/tests/api.c @@ -11621,6 +11621,11 @@ static int test_wc_MakeRsaKey (void) RsaKey genKey; WC_RNG rng; + #ifndef WOLFSSL_SP_MATH + int bits = 1024; + #else + int bits = 2048; + #endif printf(testingFmt, "wc_MakeRsaKey()"); @@ -11628,7 +11633,7 @@ static int test_wc_MakeRsaKey (void) if (ret == 0) { ret = wc_InitRng(&rng); if (ret == 0) { - ret = MAKE_RSA_KEY(&genKey, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, WC_RSA_EXPONENT, &rng); if (ret == 0 && wc_FreeRsaKey(&genKey) != 0) { ret = WOLFSSL_FATAL_ERROR; } @@ -11637,17 +11642,17 @@ static int test_wc_MakeRsaKey (void) #ifndef HAVE_USER_RSA /* Test bad args. */ if (ret == 0) { - ret = MAKE_RSA_KEY(NULL, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(NULL, bits, WC_RSA_EXPONENT, &rng); if (ret == BAD_FUNC_ARG) { - ret = MAKE_RSA_KEY(&genKey, 1024, WC_RSA_EXPONENT, NULL); + ret = MAKE_RSA_KEY(&genKey, bits, WC_RSA_EXPONENT, NULL); } if (ret == BAD_FUNC_ARG) { /* e < 3 */ - ret = MAKE_RSA_KEY(&genKey, 1024, 2, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, 2, &rng); } if (ret == BAD_FUNC_ARG) { /* e & 1 == 0 */ - ret = MAKE_RSA_KEY(&genKey, 1024, 6, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, 6, &rng); } if (ret == BAD_FUNC_ARG) { ret = 0; @@ -11658,17 +11663,17 @@ static int test_wc_MakeRsaKey (void) #else /* Test bad args. */ if (ret == 0) { - ret = MAKE_RSA_KEY(NULL, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(NULL, bits, WC_RSA_EXPONENT, &rng); if (ret == USER_CRYPTO_ERROR) { - ret = MAKE_RSA_KEY(&genKey, 1024, WC_RSA_EXPONENT, NULL); + ret = MAKE_RSA_KEY(&genKey, bits, WC_RSA_EXPONENT, NULL); } if (ret == USER_CRYPTO_ERROR) { /* e < 3 */ - ret = MAKE_RSA_KEY(&genKey, 1024, 2, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, 2, &rng); } if (ret == USER_CRYPTO_ERROR) { /* e & 1 == 0 */ - ret = MAKE_RSA_KEY(&genKey, 1024, 6, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, 6, &rng); } if (ret == USER_CRYPTO_ERROR) { ret = 0; @@ -11832,10 +11837,18 @@ static int test_wc_RsaKeyToDer (void) RsaKey genKey; WC_RNG rng; byte* der; + #ifndef WOLFSSL_SP_MATH + int bits = 1024; word32 derSz = 611; - /* (2 x 128) + 2 (possible leading 00) + (5 x 64) + 5 (possible leading 00) + 3 (e) + 8 (ASN tag) + 10 (ASN length) + 4 seqSz + 3 version */ + #else + int bits = 2048; + word32 derSz = 1196; + /* (2 x 256) + 2 (possible leading 00) + (5 x 128) + 5 (possible leading 00) + + 3 (e) + 8 (ASN tag) + 17 (ASN length) + 4 seqSz + 3 version */ + #endif + der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (der == NULL) { ret = WOLFSSL_FATAL_ERROR; @@ -11849,7 +11862,7 @@ static int test_wc_RsaKeyToDer (void) } /* Make key. */ if (ret == 0) { - ret = MAKE_RSA_KEY(&genKey, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&genKey, bits, WC_RSA_EXPONENT, &rng); if (ret != 0) { ret = WOLFSSL_FATAL_ERROR; } @@ -11930,7 +11943,13 @@ static int test_wc_RsaKeyToPublicDer (void) RsaKey key; WC_RNG rng; byte* der; + #ifndef WOLFSSL_SP_MATH + int bits = 1024; word32 derLen = 162; + #else + int bits = 2048; + word32 derLen = 290; + #endif der = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (der == NULL) { @@ -11943,7 +11962,7 @@ static int test_wc_RsaKeyToPublicDer (void) ret = wc_InitRng(&rng); } if (ret == 0) { - ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&key, bits, WC_RSA_EXPONENT, &rng); } printf(testingFmt, "wc_RsaKeyToPublicDer()"); @@ -12018,9 +12037,15 @@ static int test_wc_RsaPublicEncryptDecrypt (void) RsaKey key; WC_RNG rng; const char* inStr = "Everyone gets Friday off."; - word32 cipherLen = 128; word32 plainLen = 25; word32 inLen = (word32)XSTRLEN(inStr); + #ifndef WOLFSSL_SP_MATH + int bits = 1024; + word32 cipherLen = 128; + #else + int bits = 2048; + word32 cipherLen = 256; + #endif DECLARE_VAR_INIT(in, byte, inLen, inStr, NULL); DECLARE_VAR(plain, byte, plainLen, NULL); @@ -12031,7 +12056,7 @@ static int test_wc_RsaPublicEncryptDecrypt (void) ret = wc_InitRng(&rng); } if (ret == 0) { - ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&key, bits, WC_RSA_EXPONENT, &rng); } /* Encrypt. */ printf(testingFmt, "wc_RsaPublicEncrypt()"); @@ -12101,10 +12126,16 @@ static int test_wc_RsaPublicEncryptDecrypt_ex (void) WC_RNG rng; const char* inStr = "Everyone gets Friday off."; word32 inLen = (word32)XSTRLEN(inStr); - const word32 cipherSz = 128; const word32 plainSz = 25; byte* res = NULL; int idx = 0; + #ifndef WOLFSSL_SP_MATH + int bits = 1024; + const word32 cipherSz = 128; + #else + int bits = 2048; + const word32 cipherSz = 256; + #endif DECLARE_VAR_INIT(in, byte, inLen, inStr, NULL); DECLARE_VAR(plain, byte, plainSz, NULL); @@ -12119,7 +12150,7 @@ static int test_wc_RsaPublicEncryptDecrypt_ex (void) ret = wc_InitRng(&rng); } if (ret == 0) { - ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&key, bits, WC_RSA_EXPONENT, &rng); } /* Encrypt */ printf(testingFmt, "wc_RsaPublicEncrypt_ex()"); @@ -12210,10 +12241,16 @@ static int test_wc_RsaSSL_SignVerify (void) RsaKey key; WC_RNG rng; const char* inStr = "Everyone gets Friday off."; - const word32 outSz = 128; const word32 plainSz = 25; word32 inLen = (word32)XSTRLEN(inStr); word32 idx = 0; + #ifndef WOLFSSL_SP_MATH + int bits = 1024; + const word32 outSz = 128; + #else + int bits = 2048; + const word32 outSz = 256; + #endif DECLARE_VAR_INIT(in, byte, inLen, inStr, NULL); DECLARE_VAR(out, byte, outSz, NULL); @@ -12226,7 +12263,7 @@ static int test_wc_RsaSSL_SignVerify (void) } if (ret == 0) { - ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&key, bits, WC_RSA_EXPONENT, &rng); } /* Sign. */ printf(testingFmt, "wc_RsaSSL_Sign()"); @@ -12369,6 +12406,7 @@ static int test_wc_RsaEncryptSize (void) } printf(testingFmt, "wc_RsaEncryptSize()"); +#ifndef WOLFSSL_SP_MATH if (ret == 0) { ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); if (ret == 0) { @@ -12385,6 +12423,7 @@ static int test_wc_RsaEncryptSize (void) } else { ret = 0; } +#endif if (ret == 0) { ret = MAKE_RSA_KEY(&key, 2048, WC_RSA_EXPONENT, &rng); @@ -12437,6 +12476,11 @@ static int test_wc_RsaFlattenPublicKey (void) byte n[256]; word32 eSz = sizeof(e); word32 nSz = sizeof(n); + #ifndef WOLFSSL_SP_MATH + int bits = 1024; + #else + int bits = 2048; + #endif ret = wc_InitRsaKey(&key, NULL); if (ret == 0) { @@ -12444,7 +12488,7 @@ static int test_wc_RsaFlattenPublicKey (void) } if (ret == 0) { - ret = MAKE_RSA_KEY(&key, 1024, WC_RSA_EXPONENT, &rng); + ret = MAKE_RSA_KEY(&key, bits, WC_RSA_EXPONENT, &rng); if (ret >= 0) { ret = 0; } else { diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 6b3899099..480845bd8 100755 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -4164,7 +4164,11 @@ exit: void bench_rsaKeyGen(int doAsync) { int k, keySz; +#ifndef WOLFSSL_SP_MATH const int keySizes[2] = {1024, 2048}; +#else + const int keySizes[1] = {2048}; +#endif for (k = 0; k < (int)(sizeof(keySizes)/sizeof(int)); k++) { keySz = keySizes[k]; diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 622d2f984..054e5c3c2 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -2060,7 +2060,6 @@ static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, keyP = &key->p; } -#ifndef WOLFSSL_SP_MATH if (ret == 0 && !trusted) { int isPrime = 0; if (rng != NULL) @@ -2071,10 +2070,6 @@ static int _DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, if (ret == 0 && isPrime == 0) ret = DH_CHECK_PUB_E; } -#else - (void)trusted; - (void)rng; -#endif if (ret == 0 && mp_init(&key->g) != MP_OKAY) ret = MP_INIT_E; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index c69833ee9..878d7ff39 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -606,7 +606,7 @@ int wc_CheckRsaKey(RsaKey* key) ret = MP_READ_E; } -#ifdef WOLFSSL_SP_RSA +#ifdef WOLFSSL_HAVE_SP_RSA #ifndef WOLFSSL_SP_NO_2048 if (mp_count_bits(&key->n) == 2048) { ret = sp_ModExp_2048(k, &key->e, &key->n, tmp); diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index d93d9203c..8b31a8861 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -39,6 +39,19 @@ #include +#if defined(WOLFSSL_HAVE_SP_DH) || defined(WOLFSSL_HAVE_SP_RSA) + +WOLFSSL_LOCAL int sp_ModExp_1024(sp_int* base, sp_int* exp, sp_int* mod, + sp_int* res); +WOLFSSL_LOCAL int sp_ModExp_1536(sp_int* base, sp_int* exp, sp_int* mod, + sp_int* res); +WOLFSSL_LOCAL int sp_ModExp_2048(sp_int* base, sp_int* exp, sp_int* mod, + sp_int* res); +WOLFSSL_LOCAL int sp_ModExp_3072(sp_int* base, sp_int* exp, sp_int* mod, + sp_int* res); + +#endif + /* Initialize the big number to be zero. * * a SP integer. @@ -173,45 +186,46 @@ int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz) */ int sp_read_radix(sp_int* a, const char* in, int radix) { - int i, j, k; - char ch; + int err = MP_OKAY; + int i, j = 0, k = 0; + char ch; - if (radix != 16) - return BAD_FUNC_ARG; + if ((radix != 16) || (*in == '-')) + err = BAD_FUNC_ARG; - if (*in == '-') { - return BAD_FUNC_ARG; + if (err == MP_OKAY) { + a->dp[0] = 0; + for (i = (int)(XSTRLEN(in) - 1); i >= 0; i--) { + ch = in[i]; + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'A' && ch <= 'F') + ch -= 'A' - 10; + else if (ch >= 'a' && ch <= 'f') + ch -= 'a' - 10; + else { + err = MP_VAL; + break; + } + + a->dp[k] |= ((sp_int_digit)ch) << j; + j += 4; + if (j == DIGIT_BIT && k < SP_INT_DIGITS) + a->dp[++k] = 0; + j &= DIGIT_BIT - 1; + } } - j = 0; - k = 0; - a->dp[0] = 0; - for (i = (int)(XSTRLEN(in) - 1); i >= 0; i--) { - ch = in[i]; - if (ch >= '0' && ch <= '9') - ch -= '0'; - else if (ch >= 'A' && ch <= 'F') - ch -= 'A' - 10; - else if (ch >= 'a' && ch <= 'f') - ch -= 'a' - 10; - else - return MP_VAL; + if (err == MP_OKAY) { + a->used = k + 1; + if (a->dp[k] == 0) + a->used--; - a->dp[k] |= ((sp_int_digit)ch) << j; - j += 4; - if (j == DIGIT_BIT && k < SP_INT_DIGITS) - a->dp[++k] = 0; - j &= DIGIT_BIT - 1; + for (k++; k < a->size; k++) + a->dp[k] = 0; } - a->used = k + 1; - if (a->dp[k] == 0) - a->used--; - - for (k++; k < a->size; k++) - a->dp[k] = 0; - - return MP_OKAY; + return err; } #endif @@ -224,20 +238,26 @@ int sp_read_radix(sp_int* a, const char* in, int radix) */ int sp_cmp(sp_int* a, sp_int* b) { + int ret = MP_EQ; int i; if (a->used > b->used) - return MP_GT; + ret = MP_GT; else if (a->used < b->used) - return MP_LT; - - for (i = a->used - 1; i >= 0; i--) { - if (a->dp[i] > b->dp[i]) - return MP_GT; - else if (a->dp[i] < b->dp[i]) - return MP_LT; + ret = MP_LT; + else { + for (i = a->used - 1; i >= 0; i--) { + if (a->dp[i] > b->dp[i]) { + ret = MP_GT; + break; + } + else if (a->dp[i] < b->dp[i]) { + ret = MP_LT; + break; + } + } } - return MP_EQ; + return ret; } /* Count the number of bits in the big number. @@ -354,17 +374,17 @@ void sp_forcezero(sp_int* a) #endif #if !defined(WOLFSSL_RSA_VERIFY_ONLY) || (!defined(NO_DH) || defined(HAVE_ECC)) -/* Copy value of big number a into b. +/* Copy value of big number a into r. * * a SP integer. - * b SP integer. + * r SP integer. * returns MP_OKAY always. */ -int sp_copy(sp_int* a, sp_int* b) +int sp_copy(sp_int* a, sp_int* r) { - if (a != b) { - XMEMCPY(b->dp, a->dp, a->used * sizeof(sp_int_digit)); - b->used = a->used; + if (a != r) { + XMEMCPY(r->dp, a->dp, a->used * sizeof(sp_int_digit)); + r->used = a->used; } return MP_OKAY; } @@ -383,18 +403,6 @@ int sp_set(sp_int* a, sp_int_digit d) return MP_OKAY; } -#if defined(WC_MP_TO_RADIX) || !defined(NO_DH) || defined(HAVE_ECC) -/* Checks whether the value of the big number is zero. - * - * a SP integer. - * returns 1 when value is zero and 0 otherwise. - */ -int sp_iszero(sp_int* a) -{ - return a->used == 0; -} -#endif - #if !defined(WOLFSSL_RSA_VERIFY_ONLY) || (!defined(NO_DH) || defined(HAVE_ECC)) /* Recalculate the number of digits used. * @@ -419,11 +427,12 @@ void sp_clamp(sp_int* a) */ int sp_grow(sp_int* a, int l) { + int err = MP_OKAY; + if (l > a->size) - return MP_MEM; - (void)a; - (void)l; - return MP_OKAY; + err = MP_MEM; + + return err; } /* Sub a one digit number from the big number. @@ -439,14 +448,14 @@ int sp_sub_d(sp_int* a, sp_int_digit d, sp_int* r) r->used = a->used; r->dp[0] = a->dp[0] - d; - if (r->dp[i] > a->dp[i]) { - for (; i < a->used; i++) { + if (r->dp[0] > a->dp[0]) { + for (++i; i < a->used; i++) { r->dp[i] = a->dp[i] - 1; if (r->dp[i] != (sp_int_digit)-1) break; } } - for (; i < a->used; i++) + for (++i; i < a->used; i++) r->dp[i] = a->dp[i]; return MP_OKAY; @@ -462,22 +471,26 @@ int sp_sub_d(sp_int* a, sp_int_digit d, sp_int* r) */ int sp_cmp_d(sp_int *a, sp_int_digit d) { + int ret = MP_EQ; + /* special case for zero*/ if (a->used == 0) { if (d == 0) - return MP_EQ; + ret = MP_EQ; else - return MP_LT; + ret = MP_LT; } else if (a->used > 1) - return MP_GT; + ret = MP_GT; + else { + /* compare the only digit of a to d */ + if (a->dp[0] > d) + ret = MP_GT; + else if (a->dp[0] < d) + ret = MP_LT; + } - /* compare the only digit of a to d */ - if (a->dp[0] > d) - return MP_GT; - else if (a->dp[0] < d) - return MP_LT; - return MP_EQ; + return ret; } #if !defined(NO_DH) || defined(HAVE_ECC) || !defined(WOLFSSL_RSA_VERIFY_ONLY) @@ -497,16 +510,15 @@ static int sp_lshb(sp_int* a, int n) n %= SP_WORD_SIZE; } - if (n == 0) - return MP_OKAY; - - a->dp[a->used] = 0; - for (i = a->used - 1; i >= 0; i--) { - a->dp[i+1] |= a->dp[i] >> (SP_WORD_SIZE - n); - a->dp[i] = a->dp[i] << n; + if (n != 0) { + a->dp[a->used] = 0; + for (i = a->used - 1; i >= 0; i--) { + a->dp[i+1] |= a->dp[i] >> (SP_WORD_SIZE - n); + a->dp[i] = a->dp[i] << n; + } + if (a->dp[a->used] != 0) + a->used++; } - if (a->dp[a->used] != 0) - a->used++; return MP_OKAY; } @@ -519,7 +531,7 @@ static int sp_lshb(sp_int* a, int n) * r SP integer. * returns MP_OKAY always. */ -static int sp_sub(sp_int* a, sp_int* b, sp_int* r) +int sp_sub(sp_int* a, sp_int* b, sp_int* r) { int i; sp_int_digit c = 0; @@ -543,40 +555,165 @@ static int sp_sub(sp_int* a, sp_int* b, sp_int* r) return MP_OKAY; } -/* Calculate the r = a mod m. +/* Shift a right by n bits into r: r = a >> n + * + * a SP integer operand. + * n Number of bits to shift. + * r SP integer result. + */ +static void sp_rshb(sp_int* a, int n, sp_int* r) +{ + int i; + int j; + + for (i = n / SP_WORD_SIZE, j = 0; i < a->used-1; i++, j++) + r->dp[i] = (a->dp[j] >> n) | (a->dp[j+1] << (SP_WORD_SIZE - n)); + r->dp[i] = a->dp[j] >> n; + r->used = j + 1; + sp_clamp(r); +} + +/* Multiply a by digit n and put result into r shifting up o digits. + * r = (a * n) << (o * SP_WORD_SIZE) + * + * a SP integer to be multiplied. + * n Number to multiply by. + * r SP integer result. + * o Number of digits to move result up by. + */ +static void _sp_mul_d(sp_int* a, sp_int_digit n, sp_int* r, int o) +{ + int i; + sp_int_word t = 0; + + for (i = 0; i < o; i++) + r->dp[i] = 0; + + for (i = 0; i < a->used; i++) { + t += (sp_int_word)n * a->dp[i]; + r->dp[i + o] = (sp_int_digit)t; + t >>= SP_WORD_SIZE; + } + + r->dp[i+o] = (sp_int_digit)t; + r->used = i+o+1; + sp_clamp(r); +} + +/* Divide a by d and return the quotient in r and the remainder in rem. + * r = a / d; rem = a % d + * + * a SP integer to be divided. + * d SP integer to divide by. + * r SP integer of quotient. + * rem SP integer of remainder. + * returns MP_VAL when d is 0, MP_MEM when dynamic memory allocation fails and + * MP_OKAY otherwise. + */ +static int sp_div(sp_int* a, sp_int* d, sp_int* r, sp_int* rem) +{ + int err = MP_OKAY; + int i; + int s; + sp_int_word w = 0; + sp_int_digit dt; + sp_int_digit t; +#ifdef WOLFSSL_SMALL_STACK + sp_int* sa = NULL; + sp_int* sd; + sp_int* tr; + sp_int* trial; +#else + sp_int sa[1]; + sp_int sd[1]; + sp_int tr[1]; + sp_int trial[1]; +#endif + + if (sp_iszero(d)) + err = MP_VAL; + +#ifdef WOLFSSL_SMALL_STACK + if (err == MP_OKAY) { + sa = (sp_int*)XMALLOC(sizeof(sp_int) * 4, NULL, DYNAMIC_TYPE_BIGINT); + if (sa == NULL) + err = MP_MEM; + else { + sd = &sa[1]; + tr = &sa[2]; + trial = &sa[3]; + } + } +#endif + + if (err == MP_OKAY) { + sp_init(sa); + sp_init(sd); + sp_init(tr); + sp_init(trial); + + s = sp_count_bits(d); + s = SP_WORD_SIZE - (s % SP_WORD_SIZE); + sp_copy(a, sa); + if (s != SP_WORD_SIZE) { + sp_lshb(sa, s); + sp_copy(d, sd); + sp_lshb(sd, s); + d = sd; + } + + tr->used = sa->used - d->used; + if ((sa->dp[sa->used-1] >> (SP_WORD_SIZE - 1)) == 1) { + _sp_mul_d(d, 1, trial, sa->used - d->used); + if (sp_cmp(sa, trial) != MP_LT) { + tr->used++; + sp_sub(sa, trial, sa); + tr->dp[sa->used - d->used] = 1; + } + } + + dt = d->dp[d->used-1]; + for (i = sa->used - 1; i >= d->used; i--) { + w = ((sp_int_word)sa->dp[i] << SP_WORD_SIZE) | sa->dp[i-1]; + t = (sp_int_digit)(w / dt); + _sp_mul_d(d, t, trial, i - d->used); + while (sp_cmp(trial, sa) == MP_GT) { + t--; + _sp_mul_d(d, t, trial, i - d->used); + } + sp_sub(sa, trial, sa); + tr->dp[i - d->used] = t; + } + + sp_clamp(tr); + + if (rem != NULL) { + if (s != SP_WORD_SIZE) + sp_rshb(sa, s, sa); + sp_copy(sa, rem); + } + if (r != NULL) + sp_copy(tr, r); + } + +#ifdef WOLFSSL_SMALL_STACK + if (sa != NULL) + XFREE(sa, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Calculate the remainder of dividing a by m: r = a mod m. * * a SP integer. * m SP integer. * r SP integer. - * returns MP_OKAY always. + * returns MP_VAL when m is 0 and MP_OKAY otherwise. */ int sp_mod(sp_int* a, sp_int* m, sp_int* r) { - sp_int t; - int mBits = sp_count_bits(m); - int rBits; - - if (a != r) - sp_copy(a, r); - sp_init(&t); - - rBits = sp_count_bits(r); - while (rBits > mBits) { - sp_copy(m, &t); - sp_lshb(&t, rBits - mBits); - - if (sp_cmp(&t, r) == MP_GT) { - sp_copy(m, &t); - sp_lshb(&t, rBits - mBits - 1); - } - sp_sub(r, &t, r); - - rBits = sp_count_bits(r); - } - if (sp_cmp(r, m) != MP_LT) - sp_sub(r, m, r); - - return MP_OKAY; + return sp_div(a, m, NULL, r); } #endif @@ -643,8 +780,7 @@ int sp_lshd(sp_int* a, int s) } #endif -#if !defined(WOLFSSL_RSA_VERIFY_ONLY) || (!defined(NO_DH) || defined(HAVE_ECC)) -#ifndef NO_PWDBASED +#if !defined(NO_PWDBASED) || defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) /* Add two large numbers into result: r = a + b * * a SP integer. @@ -655,8 +791,8 @@ int sp_lshd(sp_int* a, int s) int sp_add(sp_int* a, sp_int* b, sp_int* r) { int i; - sp_digit c = 0; - sp_digit t; + sp_int_digit c = 0; + sp_int_digit t; for (i = 0; i < a->used && i < b->used; i++) { t = a->dp[i] + b->dp[i] + c; @@ -679,8 +815,7 @@ int sp_add(sp_int* a, sp_int* b, sp_int* r) return MP_OKAY; } -#endif /* NO_PWDBASED */ -#endif /* !WOLFSSL_RSA_VERIFY_ONLY || (!NO_DH || HAVE_ECC) */ +#endif /* !NO_PWDBASED || WOLFSSL_KEY_GEN || !NO_DH */ #ifndef NO_RSA /* Set a number into the big number. @@ -719,27 +854,1005 @@ int sp_tohex(sp_int* a, char* str) if (sp_iszero(a) == MP_YES) { *str++ = '0'; *str = '\0'; - return MP_OKAY; } - - i = a->used - 1; - for (j = SP_WORD_SIZE - 4; j >= 0; j -= 4) { - if (((a->dp[i] >> j) & 0xf) != 0) - break; - } - for (; j >= 0; j -= 4) - *(str++) = sp_hex_char[(a->dp[i] >> j) & 0xf]; - for (--i; i >= 0; i--) { - for (j = SP_WORD_SIZE - 4; j >= 0; j -= 4) + else { + i = a->used - 1; + for (j = SP_WORD_SIZE - 4; j >= 0; j -= 4) { + if (((a->dp[i] >> j) & 0xf) != 0) + break; + } + for (; j >= 0; j -= 4) *(str++) = sp_hex_char[(a->dp[i] >> j) & 0xf]; + for (--i; i >= 0; i--) { + for (j = SP_WORD_SIZE - 4; j >= 0; j -= 4) + *(str++) = sp_hex_char[(a->dp[i] >> j) & 0xf]; + } + *str = '\0'; } - *str = '\0'; return MP_OKAY; } #endif /* WC_MP_TO_RADIX */ -#if !defined(USE_FAST_MATH) +#if defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) +/* Set a bit of a: a |= 1 << i + * The field 'used' is updated in a. + * + * a SP integer to modify. + * i Index of bit to set. + * returns MP_OKAY always. + */ +static int sp_set_bit(sp_int* a, int i) +{ + if (i / SP_WORD_SIZE < SP_INT_DIGITS) { + a->dp[i/SP_WORD_SIZE] |= (sp_int_digit)1 << (i % SP_WORD_SIZE); + if (a->used <= i / SP_WORD_SIZE) + a->used = (i / SP_WORD_SIZE) + 1; + } + return MP_OKAY; +} + +/* Exponentiate 2 to the power of e: a = 2^e + * This is done by setting the 'e'th bit. + * + * a SP integer. + * e Exponent. + * returns MP_OKAY always. + */ +int sp_2expt(sp_int* a, int e) +{ + sp_zero(a); + return sp_set_bit(a, e); +} + +/* Generate a random prime for RSA only. + * + * r SP integer + * len Number of bytes to prime. + * rng Random number generator. + * heap Unused + * returns MP_OKAY on success and MP_VAL when length is not supported or random + * number genrator fails. + */ +int sp_rand_prime(sp_int* r, int len, WC_RNG* rng, void* heap) +{ + static const int USE_BBS = 1; + int err = 0, type; + int isPrime = MP_NO; + + (void)heap; + + /* get type */ + if (len < 0) { + type = USE_BBS; + len = -len; + } + else { + type = 0; + } + +#if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_KEY_GEN) + if (len == 32) { + } + else +#endif + /* Generate RSA primes that are half the modulus length. */ +#ifndef WOLFSSL_SP_NO_3072 + if (len != 128 && len != 192) +#else + if (len != 128) +#endif + { + err = MP_VAL; + } + + r->used = len / (SP_WORD_SIZE / 8); + + /* Assume the candidate is probably prime and then test until + * it is proven composite. */ + while (err == 0 && isPrime == MP_NO) { +#ifdef SHOW_GEN + printf("."); + fflush(stdout); +#endif + /* generate value */ + err = wc_RNG_GenerateBlock(rng, (byte*)r->dp, len); + if (err != 0) { + err = MP_VAL; + break; + } + + /* munge bits */ + ((byte*)r->dp)[len-1] |= 0x80 | 0x40; + r->dp[0] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00); + + /* 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 */ + sp_prime_is_prime_ex(r, 8, &isPrime, rng); + } + + return err; +} + +/* Multiply a by b and store in r: r = a * b + * + * a SP integer to multiply. + * b SP integer to multiply. + * r SP integer result. + * returns MP_OKAY always. + */ +int sp_mul(sp_int* a, sp_int* b, sp_int* r) +{ + int err = MP_OKAY; + int i; +#ifdef WOLFSSL_SMALL_STACK + sp_int* t = NULL; + sp_int* tr; +#else + sp_int t[1]; + sp_int tr[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + t = (sp_int*)XMALLOC(sizeof(sp_int) * 2, NULL, DYNAMIC_TYPE_BIGINT); + if (t == NULL) + err = MP_MEM; + else + tr = &t[1]; +#endif + + if (err == MP_OKAY) { + sp_init(t); + sp_init(tr); + + for (i = 0; i < b->used; i++) { + _sp_mul_d(a, b->dp[i], t, i); + sp_add(tr, t, tr); + } + sp_copy(tr, r); + } + +#ifdef WOLFSSL_SMALL_STACK + if (t != NULL) + XFREE(t, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Square a mod m and store in r: r = (a * a) mod m + * + * a SP integer to square. + * m SP integer modulus. + * r SP integer result. + * returns MP_VAL when m is 0, MP_MEM when dynamic memory allocation fails and + * MP_OKAY otherwise. + */ +static int sp_sqrmod(sp_int* a, sp_int* m, sp_int* r) +{ + int err; + + err = sp_mul(a, a, r); + if (err == MP_OKAY) + err = sp_mod(r, m, r); + + return err; +} + +#if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_KEY_GEN) +/* Multiply a by b mod m and store in r: r = (a * b) mod m + * + * a SP integer to multiply. + * b SP integer to multiply. + * m SP integer modulus. + * r SP integer result. + * returns MP_VAL when m is 0, MP_MEM when dynamic memory allocation fails and + * MP_OKAY otherwise. + */ +static int sp_mulmod(sp_int* a, sp_int* b, sp_int* m, sp_int* r) +{ + int err; + + err = sp_mul(a, b, r); + if (err == MP_OKAY) + err = sp_mod(r, m, r); + + return err; +} +#endif + +/* Calculate a modulo the digit d into r: r = a mod d + * + * a SP integer to square. + * d SP integer digit, modulus. + * r SP integer digit, result. + * returns MP_VAL when d is 0 and MP_OKAY otherwise. + */ +static int sp_mod_d(sp_int* a, const sp_int_digit d, sp_int_digit* r) +{ + int err = MP_OKAY; + int i; + sp_int_word w = 0; + sp_int_digit t; + + if (d == 0) + err = MP_VAL; + + if (err == MP_OKAY) { + for (i = a->used - 1; i >= 0; i--) { + w = (w << SP_WORD_SIZE) | a->dp[i]; + t = (sp_int_digit)(w / d); + w -= (sp_int_word)t * d; + } + + *r = (sp_int_digit)w; + } + + return err; +} + +/* Calculates the Greatest Common Denominator (GCD) of a and b into r. + * + * a SP integer operand. + * b SP integer operand. + * r SP integer result. + * returns MP_MEM when dynamic memory allocation fails and MP_OKAY otherwise. + */ +int sp_gcd(sp_int* a, sp_int* b, sp_int* r) +{ + int err = MP_OKAY; +#ifdef WOLFSSL_SMALL_STACK + sp_int* u = NULL; + sp_int* v; + sp_int* t; +#else + sp_int u[1], v[1], t[1]; +#endif + + if (sp_iszero(a)) + sp_copy(b, r); + else if (sp_iszero(b)) + sp_copy(a, r); + else { +#ifdef WOLFSSL_SMALL_STACK + u = (sp_int*)XMALLOC(sizeof(sp_int) * 3, NULL, DYNAMIC_TYPE_BIGINT); + if (u == NULL) + err = MP_MEM; + else { + v = &u[1]; + t = &u[2]; + } +#endif + + if (err == MP_OKAY) { + sp_init(u); + sp_init(v); + sp_init(t); + + if (sp_cmp(a, b) != MP_LT) { + sp_copy(b, u); + /* First iteration - u = a, v = b */ + if (b->used == 1) { + err = sp_mod_d(a, b->dp[0], &v->dp[0]); + if (err == MP_OKAY) + v->used = (v->dp[0] != 0); + } + else + err = sp_mod(a, b, v); + } + else { + sp_copy(a, u); + /* First iteration - u = b, v = a */ + if (a->used == 1) { + err = sp_mod_d(b, a->dp[0], &v->dp[0]); + if (err == MP_OKAY) + v->used = (v->dp[0] != 0); + } + else + err = sp_mod(b, a, v); + } + } + + if (err == MP_OKAY) { + while (!sp_iszero(v)) { + if (v->used == 1) { + sp_mod_d(u, v->dp[0], &t->dp[0]); + t->used = (t->dp[0] != 0); + } + else + sp_mod(u, v, t); + sp_copy(v, u); + sp_copy(t, v); + } + sp_copy(u, r); + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (u != NULL) + XFREE(u, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Divides a by 2 and stores in r: r = a >> 1 + * + * a SP integer to divide. + * r SP integer result. + * returns MP_OKAY always. + */ +static int sp_div_2(sp_int* a, sp_int* r) +{ + int i; + + for (i = 0; i < a->used-1; i++) + r->dp[i] = (a->dp[i] >> 1) | (a->dp[i+1] << (SP_WORD_SIZE - 1)); + r->dp[i] = a->dp[i] >> 1; + r->used = i + 1; + sp_clamp(r); + + return MP_OKAY; +} + + +/* Divides a by 2 and stores in r: r = a >> 1 + * + * a SP integer to divide. + * r SP integer result. + * returns MP_VAL when a or m is 0, MP_MEM when dynamic memory allocation fails + * and MP_OKAY otherwise. + */ +int sp_invmod(sp_int* a, sp_int* m, sp_int* r) +{ + int err = MP_OKAY; +#ifdef WOLFSSL_SMALL_STACK + sp_int* u = NULL; + sp_int* v; + sp_int* t; + sp_int* b; + sp_int* c; +#else + sp_int u[1], v[1], t[1], b[1], c[1]; +#endif + + if (sp_iszero(a) || sp_iszero(m)) + err = MP_VAL; + else if (sp_iseven(m)) { + /* a^-1 mod m = m + (1 - m*(m^-1 % a)) / a + * = m - (m*(m^-1 % a) - 1) / a + */ + err = sp_invmod(m, a, r); + if (err == MP_OKAY) { + sp_mul(r, m, r); + sp_sub_d(r, 1, r); + sp_div(r, a, r, NULL); + sp_sub(m, r, r); + } + } + else { +#ifdef WOLFSSL_SMALL_STACK + u = (sp_int*)XMALLOC(sizeof(sp_int) * 5, NULL, DYNAMIC_TYPE_BIGINT); + if (u == NULL) + err = MP_MEM; + else { + v = &u[1]; + t = &u[2]; + b = &u[3]; + c = &u[4]; + } +#endif + + if (err == MP_OKAY) { + sp_init(u); + sp_init(v); + sp_init(t); + sp_init(b); + sp_init(c); + + sp_copy(m, u); + sp_copy(a, v); + sp_zero(b); + sp_set(c, 1); + + while (!sp_isone(v)) { + if (sp_iseven(u)) { + sp_div_2(u, u); + if (sp_isodd(b)) + sp_add(b, m, b); + sp_div_2(b, b); + } + else if (sp_iseven(v)) { + sp_div_2(v, v); + if (sp_isodd(c)) + sp_add(c, m, c); + sp_div_2(c, c); + } + else if (sp_cmp(u, v) != MP_LT) { + sp_sub(u, v, u); + if (sp_cmp(b, c) == MP_LT) + sp_add(b, m, b); + sp_sub(b, c, b); + } + else { + sp_sub(v, u, v); + if (sp_cmp(c, b) == MP_LT) + sp_add(c, m, c); + sp_sub(c, b, c); + } + } + sp_copy(c, r); + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (u != NULL) + XFREE(u, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Calculates the Lowest Common Multiple (LCM) of a and b and stores in r. + * + * a SP integer operand. + * b SP integer operand. + * r SP integer result. + * returns MP_MEM when dynamic memory allocation fails and MP_OKAY otherwise. + */ +int sp_lcm(sp_int* a, sp_int* b, sp_int* r) +{ + int err = MP_OKAY; +#ifndef WOLFSSL_SMALL_STACK + sp_int t[2]; +#else + sp_int *t = NULL; +#endif + +#ifdef WOLFSSL_SMALL_STACK + t = (sp_int*)XMALLOC(sizeof(sp_int) * 2, NULL, DYNAMIC_TYPE_BIGINT); + if (t == NULL) { + err = MP_MEM; + } +#endif + + if (err == MP_OKAY) { + sp_init(&t[0]); + sp_init(&t[1]); + err = sp_gcd(a, b, &t[0]); + if (err == MP_OKAY) { + if (sp_cmp(a, b) == MP_GT) { + err = sp_div(a, &t[0], &t[1], NULL); + if (err == MP_OKAY) + err = sp_mul(b, &t[1], r); + } + else { + err = sp_div(b, &t[0], &t[1], NULL); + if (err == MP_OKAY) + err = sp_mul(a, &t[1], r); + } + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (t != NULL) + XFREE(t, NULL, DYNAMIC_TYPE_BIGINT); +#endif + return err; +} + +/* Exponentiates b to the power of e modulo m into r: r = b ^ e mod m + * + * b SP integer base. + * e SP integer exponent. + * m SP integer modulus. + * r SP integer result. + * returns MP_VAL when m is not 1024, 2048, 1536 or 3072 bits and otherwise + * MP_OKAY. + */ +int sp_exptmod(sp_int* b, sp_int* e, sp_int* m, sp_int* r) +{ + int err = MP_OKAY; + int bits = sp_count_bits(m); + +#ifndef WOLFSSL_SP_NO_2048 + if (bits == 1024) + sp_ModExp_1024(b, e, m, r); + else if (bits == 2048) + sp_ModExp_2048(b, e, m, r); + else +#endif +#ifndef WOLFSSL_SP_NO_3072 + if (bits == 1536) + sp_ModExp_1536(b, e, m, r); + else if (bits == 3072) + sp_ModExp_3072(b, e, m, r); + else +#endif +#if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_KEY_GEN) + if (bits == 256) { + int i; + + #ifdef WOLFSSL_SMALL_STACK + sp_int* t = NULL; + #else + sp_int t[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + t = (sp_int*)XMALLOC(sizeof(sp_int) * 2, NULL, DYNAMIC_TYPE_BIGINT); + if (t == NULL) { + err = MP_MEM; + } + #endif + if (err == MP_OKAY) { + sp_init(t); + sp_copy(b, t); + + bits = sp_count_bits(e); + } + for (i = bits-2; err == MP_OKAY && i >= 0; i--) { + err = sp_sqrmod(t, m, t); + if (err == MP_OKAY && + (e->dp[i / SP_WORD_SIZE] >> (i % SP_WORD_SIZE)) & 1) { + err = sp_mulmod(t, b, m, t); + } + } + if (err == MP_OKAY) + sp_copy(t, r); + + #ifdef WOLFSSL_SMALL_STACK + if (t != NULL) + XFREE(t, NULL, DYNAMIC_TYPE_BIGINT); + #endif + } + else +#endif + err = MP_VAL; + + (void)bits; + + return err; +} + + +/* Number of entries in array of number of least significant zero bits. */ +#define SP_LNZ_CNT 16 +/* Number of bits the array checks. */ +#define SP_LNZ_BITS 4 +/* Mask to apply to check with array. */ +#define SP_LNZ_MASK 0xf +/* Number of least significant zero bits in first SP_LNZ_CNT numbers. */ +static const int lnz[SP_LNZ_CNT] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Count the number of least significant zero bits. + * + * a Number to check + * retuns the count of least significant zero bits. + */ +static int sp_cnt_lsb(sp_int* a) +{ + int i, j; + int cnt = 0; + int bc = 0; + + if (!sp_iszero(a)) { + for (i = 0; i < a->used && a->dp[i] == 0; i++, cnt += SP_WORD_SIZE) { + } + + for (j = 0; j < SP_WORD_SIZE; j += SP_LNZ_BITS) { + bc = lnz[(a->dp[i] >> j) & SP_LNZ_MASK]; + if (bc != 4) { + bc += cnt + j; + break; + } + } + } + + return bc; +} + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + * + * a SP integer to check. + * b SP integer small prime. + * result Whether a is likely prime: MP_YES or MP_NO. + * n1 SP integer operand. + * y SP integer operand. + * r SP integer operand. + * returns MP_VAL when a is not 1024, 2048, 1536 or 3072 and MP_OKAY otherwise. + */ +static int sp_prime_miller_rabin_ex(sp_int * a, sp_int * b, int *result, + sp_int *n1, sp_int *y, sp_int *r) +{ + int s, j; + int err = MP_OKAY; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (sp_cmp_d(b, 1) == MP_GT) { + /* get n1 = a - 1 */ + sp_copy(a, n1); + sp_sub_d(n1, 1, n1); + /* set 2**s * r = n1 */ + sp_copy(n1, r); + + /* count the number of least significant bits + * which are zero + */ + s = sp_cnt_lsb(r); + + /* now divide n - 1 by 2**s */ + sp_rshb(r, s, r); + + /* compute y = b**r mod a */ + sp_zero(y); + + err = sp_exptmod(b, r, a, y); + + if (err == MP_OKAY) { + /* probably prime until shown otherwise */ + *result = MP_YES; + + /* if y != 1 and y != n1 do */ + if (sp_cmp_d(y, 1) != MP_EQ && sp_cmp(y, n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && sp_cmp(y, n1) != MP_EQ) { + sp_sqrmod(y, a, y); + + /* if y == 1 then composite */ + if (sp_cmp_d(y, 1) == MP_EQ) { + *result = MP_NO; + break; + } + ++j; + } + + /* if y != n1 then composite */ + if (*result == MP_YES && sp_cmp(y, n1) != MP_EQ) + *result = MP_NO; + } + } + } + + return err; +} + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + * + * a SP integer to check. + * b SP integer small prime. + * result Whether a is likely prime: MP_YES or MP_NO. + * returns MP_MEM when dynamic memory allocation fails, MP_VAL when a is not + * 1024, 2048, 1536 or 3072 and MP_OKAY otherwise. + */ +static int sp_prime_miller_rabin(sp_int * a, sp_int * b, int *result) +{ + int err = MP_OKAY; +#ifndef WOLFSSL_SMALL_STACK + sp_int n1[1], y[1], r[1]; +#else + sp_int *n1 = NULL, *y, *r; +#endif + +#ifdef WOLFSSL_SMALL_STACK + n1 = (sp_int*)XMALLOC(sizeof(sp_int) * 3, NULL, DYNAMIC_TYPE_BIGINT); + if (n1 == NULL) + err = MP_MEM; + else { + y = &n1[1]; + r = &n1[2]; + } +#endif + + if (err == MP_OKAY) { + sp_init(n1); + sp_init(y); + sp_init(r); + + err = sp_prime_miller_rabin_ex(a, b, result, n1, y, r); + + sp_clear(n1); + sp_clear(y); + sp_clear(r); + } + +#ifdef WOLFSSL_SMALL_STACK + if (n1 != NULL) + XFREE(n1, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Number of pre-computed primes. First n primes. */ +#define SP_PRIME_SIZE 256 + +/* a few primes */ +static const sp_int_digit primes[SP_PRIME_SIZE] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +}; + + +/* Check whether a is prime. + * Checks against a number of small primes and does t iterations of + * Miller-Rabin. + * + * a SP integer to check. + * t Number of iterations of Muller-Rabin to perform. + * result MP_YES when prime. + * MP_NO when not prime. + * returns MP_VAL when t is out of range, MP_MEM when dynamic memory allocation + * failes and otherwiese MP_OKAY. + */ +int sp_prime_is_prime(sp_int *a, int t, int* result) +{ + int err = MP_OKAY; + int i; + int haveRes = 0; +#ifndef WOLFSSL_SMALL_STACK + sp_int b[1]; +#else + sp_int *b = NULL; +#endif + sp_int_digit d; + + if (t <= 0 || t > SP_PRIME_SIZE) { + *result = MP_NO; + err = MP_VAL; + } + + if (err == MP_OKAY && a->used == 1) { + /* check against primes table */ + for (i = 0; i < SP_PRIME_SIZE; i++) { + if (sp_cmp_d(a, primes[i]) == MP_EQ) { + *result = MP_YES; + haveRes = 1; + break; + } + } + } + + if (err == MP_OKAY && !haveRes) { + /* do trial division */ + for (i = 0; i < SP_PRIME_SIZE; i++) { + err = sp_mod_d(a, primes[i], &d); + if (err != MP_OKAY || d == 0) { + *result = MP_NO; + haveRes = 1; + break; + } + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (err == MP_OKAY && !haveRes) { + b = (sp_int*)XMALLOC(sizeof(sp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (b == NULL) + err = MP_MEM; + } +#endif + + if (err == MP_OKAY && !haveRes) { + /* now do 't' miller rabins */ + sp_init(b); + for (i = 0; i < t; i++) { + sp_set(b, primes[i]); + err = sp_prime_miller_rabin(a, b, result); + if (err != MP_OKAY || *result == MP_NO) + break; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (b != NULL) + XFREE(b, NULL, DYNAMIC_TYPE_BIGINT); +#endif + + return err; +} + +/* Check whether a is prime. + * Checks against a number of small primes and does t iterations of + * Miller-Rabin. + * + * a SP integer to check. + * t Number of iterations of Muller-Rabin to perform. + * result MP_YES when prime. + * MP_NO when not prime. + * rng Random number generator. + * returns MP_VAL when t is out of range, MP_MEM when dynamic memory allocation + * failes and otherwiese MP_OKAY. + */ +int sp_prime_is_prime_ex(sp_int* a, int t, int* result, WC_RNG* rng) +{ + int err = MP_OKAY; + int ret = MP_YES; + int haveRes = 0; + int i; +#ifndef WC_NO_RNG + #ifndef WOLFSSL_SMALL_STACK + sp_int b[1], c[1], n1[1], y[1], r[1]; + #else + sp_int *b = NULL, *c = NULL, *n1 = NULL, *y = NULL, *r = NULL; + #endif + word32 baseSz; +#endif + + if (a == NULL || result == NULL || rng == NULL) + err = MP_VAL; + + if (err == MP_OKAY && a->used == 1) { + /* check against primes table */ + for (i = 0; i < SP_PRIME_SIZE; i++) { + if (sp_cmp_d(a, primes[i]) == MP_EQ) { + ret = MP_YES; + haveRes = 1; + break; + } + } + } + + if (err == MP_OKAY && !haveRes) { + sp_int_digit d; + + /* do trial division */ + for (i = 0; i < SP_PRIME_SIZE; i++) { + err = sp_mod_d(a, primes[i], &d); + if (err != MP_OKAY || d == 0) { + ret = MP_NO; + haveRes = 1; + break; + } + } + } + +#ifndef WC_NO_RNG + /* now do a miller rabin with up to t random numbers, this should + * give a (1/4)^t chance of a false prime. */ + #ifdef WOLFSSL_SMALL_STACK + if (err == MP_OKAY && !haveRes) { + b = (sp_int*)XMALLOC(sizeof(sp_int) * 5, NULL, DYNAMIC_TYPE_BIGINT); + if (b == NULL) { + err = MP_MEM; + } + else { + c = &b[1]; n1 = &b[2]; y= &b[3]; r = &b[4]; + } + } + #endif + + if (err == MP_OKAY && !haveRes) { + sp_init(b); + sp_init(c); + sp_init(n1); + sp_init(y); + sp_init(r); + + err = sp_sub_d(a, 2, c); + } + + if (err == MP_OKAY && !haveRes) { + baseSz = (sp_count_bits(a) + 7) / 8; + + while (t > 0) { + err = wc_RNG_GenerateBlock(rng, (byte*)b->dp, baseSz); + if (err != MP_OKAY) + break; + b->used = a->used; + + if (sp_cmp_d(b, 2) != MP_GT || sp_cmp(b, c) != MP_LT) + continue; + + err = sp_prime_miller_rabin_ex(a, b, &ret, n1, y, r); + if (err != MP_OKAY || ret == MP_NO) + break; + + t--; + } + + sp_clear(n1); + sp_clear(y); + sp_clear(r); + sp_clear(b); + sp_clear(c); + } + + #ifdef WOLFSSL_SMALL_STACK + if (b != NULL) + XFREE(b, NULL, DYNAMIC_TYPE_BIGINT); + #endif +#else + (void)t; +#endif /* !WC_NO_RNG */ + + *result = ret; + return err; +} + +#ifndef NO_DH +int sp_exch (sp_int* a, sp_int* b) +{ + int err = MP_OKAY; +#ifndef WOLFSSL_SMALL_STACK + sp_int t[1]; +#else + sp_int *t = NULL; +#endif + +#ifdef WOLFSSL_SMALL_STACK + t = (sp_int*)XMALLOC(sizeof(sp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (t == NULL) + err = MP_MEM; +#endif + + if (err == MP_OKAY) { + *t = *a; + *a = *b; + *b = *t; + } + +#ifdef WOLFSSL_SMALL_STACK + if (t != NULL) + XFREE(t, NULL, DYNAMIC_TYPE_BIGINT); +#endif + return MP_OKAY; +} +#endif +#endif + /* Returns the run time settings. * * returns the settings value. @@ -748,7 +1861,6 @@ word32 CheckRunTimeSettings(void) { return CTC_SETTINGS; } -#endif /* !USE_FAST_MATH */ #endif /* WOLFSSL_SP_MATH */ diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 4375c16d3..1cf567ff2 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -1774,6 +1774,7 @@ int sp_ModExp_2048(mp_int* base, mp_int* exp, mp_int* mod, mp_int* res) return err; } +#ifdef WOLFSSL_HAVE_SP_DH #ifdef HAVE_FFDHE_2048 extern void sp_2048_lshift_32(sp_digit* r, const sp_digit* a, int n); #ifdef HAVE_INTEL_AVX2 @@ -2055,6 +2056,7 @@ int sp_DhExp_2048(mp_int* base, const byte* exp, word32 expLen, return err; } +#endif /* Perform the modular exponentiation for Diffie-Hellman. * * base Base. MP integer. @@ -3832,6 +3834,7 @@ int sp_ModExp_3072(mp_int* base, mp_int* exp, mp_int* mod, mp_int* res) return err; } +#ifdef WOLFSSL_HAVE_SP_DH #ifdef HAVE_FFDHE_3072 extern void sp_3072_lshift_48(sp_digit* r, const sp_digit* a, int n); #ifdef HAVE_INTEL_AVX2 @@ -4113,6 +4116,7 @@ int sp_DhExp_3072(mp_int* base, const byte* exp, word32 expLen, return err; } +#endif /* Perform the modular exponentiation for Diffie-Hellman. * * base Base. MP integer. diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 2d2c1e274..1c9487cf4 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -4063,7 +4063,8 @@ int fp_isprime_ex(fp_int *a, int t, int* result) int r, res; if (t <= 0 || t > FP_PRIME_SIZE) { - return FP_NO; + *result = FP_NO; + return FP_VAL; } /* check against primes table */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6911040a9..b9c0de182 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -11470,7 +11470,11 @@ static int rsa_keygen_test(WC_RNG* rng) byte* pem = NULL; word32 idx = 0; int derSz = 0; +#ifndef WOLFSSL_SP_MATH int keySz = 1024; +#else + int keySz = 2048; +#endif XMEMSET(&genKey, 0, sizeof(genKey)); diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index ba69e1512..ed6787f45 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -60,11 +60,13 @@ #if SP_WORD_SIZE == 32 typedef int32_t sp_digit; typedef uint32_t sp_int_digit; + typedef uint64_t sp_int_word; #elif SP_WORD_SIZE == 64 typedef int64_t sp_digit; typedef uint64_t sp_int_digit; typedef unsigned long uint128_t __attribute__ ((mode(TI))); typedef long int128_t __attribute__ ((mode(TI))); + typedef uint128_t sp_int_word; #else #error Word size not defined #endif @@ -72,11 +74,13 @@ #if SP_WORD_SIZE == 32 typedef uint32_t sp_digit; typedef uint32_t sp_int_digit; + typedef uint64_t sp_int_word; #elif SP_WORD_SIZE == 64 typedef uint64_t sp_digit; typedef uint64_t sp_int_digit; typedef unsigned long uint128_t __attribute__ ((mode(TI))); typedef long int128_t __attribute__ ((mode(TI))); + typedef uint128_t sp_int_word; #else #error Word size not defined #endif @@ -92,12 +96,24 @@ #define SP_INT_DIGITS ((256 + SP_WORD_SIZE) / SP_WORD_SIZE) #endif #elif defined(WOLFSSL_SP_NO_3072) - #define SP_INT_DIGITS ((2048 + SP_WORD_SIZE) / SP_WORD_SIZE) + #if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_KEY_GEN) + #define SP_INT_DIGITS ((4096 + SP_WORD_SIZE) / SP_WORD_SIZE) + #else + #define SP_INT_DIGITS ((2048 + SP_WORD_SIZE) / SP_WORD_SIZE) + #endif #else - #define SP_INT_DIGITS ((3072 + SP_WORD_SIZE) / SP_WORD_SIZE) + #if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_KEY_GEN) + #define SP_INT_DIGITS ((6144 + SP_WORD_SIZE) / SP_WORD_SIZE) + #else + #define SP_INT_DIGITS ((3072 + SP_WORD_SIZE) / SP_WORD_SIZE) + #endif #endif -#define sp_isodd(a) (a->used != 0 && (a->dp[0] & 1)) +#define sp_isodd(a) ((a)->used != 0 && ((a)->dp[0] & 1)) +#define sp_iseven(a) ((a)->used != 0 && ((a)->dp[0] & 1) == 0) +#define sp_iszero(a) ((a)->used == 0) +#define sp_isone(a) ((a)->used == 1 && (a)->dp[0] == 1) +#define sp_abs(a, b) sp_copy(a, b) #ifdef HAVE_WOLF_BIGINT /* raw big integer */ @@ -137,13 +153,13 @@ MP_API int sp_leading_bit(sp_int* a); MP_API int sp_to_unsigned_bin(sp_int* a, byte* out); MP_API int sp_to_unsigned_bin_len(sp_int* a, byte* out, int outSz); MP_API void sp_forcezero(sp_int* a); -MP_API int sp_copy(sp_int* a, sp_int* b); +MP_API int sp_copy(sp_int* a, sp_int* r); MP_API int sp_set(sp_int* a, sp_int_digit d); -MP_API int sp_iszero(sp_int* a); MP_API void sp_clamp(sp_int* a); MP_API int sp_grow(sp_int* a, int l); MP_API int sp_sub_d(sp_int* a, sp_int_digit d, sp_int* r); MP_API int sp_cmp_d(sp_int* a, sp_int_digit d); +MP_API int sp_sub(sp_int* a, sp_int* b, sp_int* r); MP_API int sp_mod(sp_int* a, sp_int* m, sp_int* r); MP_API void sp_zero(sp_int* a); MP_API int sp_add_d(sp_int* a, sp_int_digit d, sp_int* r); @@ -151,7 +167,16 @@ MP_API int sp_lshd(sp_int* a, int s); MP_API int sp_add(sp_int* a, sp_int* b, sp_int* r); MP_API int sp_set_int(sp_int* a, unsigned long b); MP_API int sp_tohex(sp_int* a, char* str); - +MP_API int sp_2expt(sp_int* a, int e); +MP_API int sp_rand_prime(sp_int* r, int len, WC_RNG* rng, void* heap); +MP_API int sp_mul(sp_int* a, sp_int* b, sp_int* r); +MP_API int sp_gcd(sp_int* a, sp_int* b, sp_int* r); +MP_API int sp_invmod(sp_int* a, sp_int* m, sp_int* r); +MP_API int sp_lcm(sp_int* a, sp_int* b, sp_int* r); +MP_API int sp_exptmod(sp_int* b, sp_int* e, sp_int* m, sp_int* r); +MP_API int sp_prime_is_prime(mp_int* a, int t, int* result); +MP_API int sp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng); +MP_API int sp_exch(sp_int* a, sp_int* b); #define MP_OKAY 0 #define MP_NO 0 @@ -172,6 +197,12 @@ MP_API int sp_tohex(sp_int* a, char* str); #define mp_free(a) +#define mp_isodd sp_isodd +#define mp_iseven sp_iseven +#define mp_iszero sp_iszero +#define mp_isone sp_isone +#define mp_abs sp_abs + #define mp_init sp_init #define mp_init_multi sp_init_multi #define mp_clear sp_clear @@ -186,19 +217,28 @@ MP_API int sp_tohex(sp_int* a, char* str); #define mp_forcezero sp_forcezero #define mp_copy sp_copy #define mp_set sp_set -#define mp_iszero sp_iszero #define mp_clamp sp_clamp #define mp_grow sp_grow #define mp_sub_d sp_sub_d #define mp_cmp_d sp_cmp_d +#define mp_sub sp_sub #define mp_mod sp_mod #define mp_zero sp_zero #define mp_add_d sp_add_d #define mp_lshd sp_lshd #define mp_add sp_add -#define mp_isodd sp_isodd #define mp_set_int sp_set_int #define mp_tohex sp_tohex +#define mp_2expt sp_2expt +#define mp_rand_prime sp_rand_prime +#define mp_mul sp_mul +#define mp_gcd sp_gcd +#define mp_invmod sp_invmod +#define mp_lcm sp_lcm +#define mp_exptmod sp_exptmod +#define mp_prime_is_prime sp_prime_is_prime +#define mp_prime_is_prime_ex sp_prime_is_prime_ex +#define mp_exch sp_exch #endif