Add a parameter to probable_prime if we look for a safe prime

Currently probable_prime makes sure that p-1 does not have
any prime factors from 3..17863, which is useful for safe primes,
but not necessarily for the general case.

Issue was initially reported here:
MIRONOV, I. Factoring RSA Moduli II.
https://windowsontheory.org/2012/05/17/factoring-rsa-moduli-part-ii/

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/9309)
This commit is contained in:
Bernd Edlinger 2019-07-04 14:52:41 +02:00
parent 8c47e55ee6
commit 3ce0566dab

View file

@ -19,11 +19,14 @@
*/ */
#include "bn_prime.h" #include "bn_prime.h"
static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods, BN_CTX *ctx); static int probable_prime(BIGNUM *rnd, int bits, int safe, prime_t *mods,
BN_CTX *ctx);
static int probable_prime_dh_safe(BIGNUM *rnd, int bits, static int probable_prime_dh_safe(BIGNUM *rnd, int bits,
const BIGNUM *add, const BIGNUM *rem, const BIGNUM *add, const BIGNUM *rem,
BN_CTX *ctx); BN_CTX *ctx);
#define square(x) ((BN_ULONG)(x) * (BN_ULONG)(x))
#if BN_BITS2 == 64 #if BN_BITS2 == 64
# define BN_DEF(lo, hi) (BN_ULONG)hi<<32|lo # define BN_DEF(lo, hi) (BN_ULONG)hi<<32|lo
#else #else
@ -119,7 +122,7 @@ int BN_generate_prime_ex2(BIGNUM *ret, int bits, int safe,
loop: loop:
/* make a random number and set the top and bottom bits */ /* make a random number and set the top and bottom bits */
if (add == NULL) { if (add == NULL) {
if (!probable_prime(ret, bits, mods, ctx)) if (!probable_prime(ret, bits, safe, mods, ctx))
goto err; goto err;
} else { } else {
if (safe) { if (safe) {
@ -400,17 +403,19 @@ err:
return ret; return ret;
} }
static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods, BN_CTX *ctx) static int probable_prime(BIGNUM *rnd, int bits, int safe, prime_t *mods,
BN_CTX *ctx)
{ {
int i; int i;
BN_ULONG delta; BN_ULONG delta;
BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1]; BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
char is_single_word = bits <= BN_BITS2;
again: again:
/* TODO: Not all primes are private */ /* TODO: Not all primes are private */
if (!BN_priv_rand_ex(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD, ctx)) if (!BN_priv_rand_ex(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD, ctx))
return 0; return 0;
if (safe && !BN_set_bit(rnd, 1))
return 0;
/* we now have a random number 'rnd' to test. */ /* we now have a random number 'rnd' to test. */
for (i = 1; i < NUMPRIMES; i++) { for (i = 1; i < NUMPRIMES; i++) {
BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]); BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
@ -418,61 +423,25 @@ static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods, BN_CTX *ctx)
return 0; return 0;
mods[i] = (prime_t) mod; mods[i] = (prime_t) mod;
} }
/*
* If bits is so small that it fits into a single word then we
* additionally don't want to exceed that many bits.
*/
if (is_single_word) {
BN_ULONG size_limit;
if (bits == BN_BITS2) {
/*
* Shifting by this much has undefined behaviour so we do it a
* different way
*/
size_limit = ~((BN_ULONG)0) - BN_get_word(rnd);
} else {
size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1;
}
if (size_limit < maxdelta)
maxdelta = size_limit;
}
delta = 0; delta = 0;
loop: loop:
if (is_single_word) { for (i = 1; i < NUMPRIMES; i++) {
BN_ULONG rnd_word = BN_get_word(rnd); /*
* check that rnd is a prime and also that
/*- * gcd(rnd-1,primes) == 1 (except for 2)
* In the case that the candidate prime is a single word then * do the second check only if we are interested in safe primes
* we check that: * in the case that the candidate prime is a single word then
* 1) It's greater than primes[i] because we shouldn't reject * we check only the primes up to sqrt(rnd)
* 3 as being a prime number because it's a multiple of
* three.
* 2) That it's not a multiple of a known prime. We don't
* check that rnd-1 is also coprime to all the known
* primes because there aren't many small primes where
* that's true.
*/ */
for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) { if (bits <= 31 && delta <= 0x7fffffff
if ((mods[i] + delta) % primes[i] == 0) { && square(primes[i]) > BN_get_word(rnd) + delta)
delta += 2; break;
if (delta > maxdelta) if (safe ? (mods[i] + delta) % primes[i] <= 1
goto again; : (mods[i] + delta) % primes[i] == 0) {
goto loop; delta += safe ? 4 : 2;
} if (delta > maxdelta)
} goto again;
} else { goto loop;
for (i = 1; i < NUMPRIMES; i++) {
/*
* check that rnd is not a prime and also that gcd(rnd-1,primes)
* == 1 (except for 2)
*/
if (((mods[i] + delta) % primes[i]) <= 1) {
delta += 2;
if (delta > maxdelta)
goto again;
goto loop;
}
} }
} }
if (!BN_add_word(rnd, delta)) if (!BN_add_word(rnd, delta))