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:
parent
8c47e55ee6
commit
3ce0566dab
1 changed files with 25 additions and 56 deletions
|
@ -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))
|
||||||
|
|
Loading…
Reference in a new issue