The branch master has been updated
       via  bba0d270a6449910ee089a612b19eac3c3bab55e (commit)
       via  03b9393e15990f0e557e477e945cb5f334574696 (commit)
       via  28b4880b8b30c3c19ed34068f9cfa8a89af7e737 (commit)
       via  3ce0566dab2406fa419465aa8aad1148aae23ceb (commit)
      from  8c47e55ee69500e31e80458682c6e022294cd0be (commit)


- Log -----------------------------------------------------------------
commit bba0d270a6449910ee089a612b19eac3c3bab55e
Author: Bernd Edlinger <bernd.edlin...@hotmail.de>
Date:   Mon Jul 15 20:34:31 2019 +0200

    Add a CHANGES entry for BN_generate_prime_ex
    
    BN_generate_prime_ex no longer avoids factors 3..17863 in p-1
    when not computing safe primes.
    
    Reviewed-by: Paul Dale <paul.d...@oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9309)

commit 03b9393e15990f0e557e477e945cb5f334574696
Author: Bernd Edlinger <bernd.edlin...@hotmail.de>
Date:   Wed Jul 10 21:33:48 2019 +0200

    Update documentation of BN_generate_prime_ex
    
    Reviewed-by: Paul Dale <paul.d...@oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9309)

commit 28b4880b8b30c3c19ed34068f9cfa8a89af7e737
Author: Bernd Edlinger <bernd.edlin...@hotmail.de>
Date:   Fri Jul 5 11:55:56 2019 +0200

    Merge probable_prime_dh_safe with bn_probable_prime_dh
    
    This should avoid half of the trial divisions in probable_prime_dh_safe
    and avoid bn_probable_prime_dh generating primes with special properties.
    
    Reviewed-by: Paul Dale <paul.d...@oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9309)

commit 3ce0566dab2406fa419465aa8aad1148aae23ceb
Author: Bernd Edlinger <bernd.edlin...@hotmail.de>
Date:   Thu Jul 4 14:52:41 2019 +0200

    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.d...@oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9309)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                        |   9 ++
 crypto/bn/bn_lcl.h             |   5 +-
 crypto/bn/bn_prime.c           | 201 +++++++++++++----------------------------
 doc/man3/BN_generate_prime.pod |   8 +-
 4 files changed, 77 insertions(+), 146 deletions(-)

diff --git a/CHANGES b/CHANGES
index 5979cd89e3..e3131f0ef8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,15 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Revised BN_generate_prime_ex to not avoid factors 2..17863 in p-1
+     when primes for RSA keys are computed.
+     Since we previously always generated primes == 2 (mod 3) for RSA keys,
+     the 2-prime and 3-prime RSA modules were easy to distinguish, since
+     N = p*q = 1 (mod 3), but N = p*q*r = 2 (mod 3). Therefore fingerprinting
+     2-prime vs. 3-prime RSA keys was possible by computing N mod 3.
+     This avoids possible fingerprinting of newly generated RSA modules.
+     [Bernd Edlinger]
+
   *) Correct the extended master secret constant on EBCDIC systems. Without 
this
      fix TLS connections between an EBCDIC system and a non-EBCDIC system that
      negotiate EMS will fail. Unfortunately this also means that TLS 
connections
diff --git a/crypto/bn/bn_lcl.h b/crypto/bn/bn_lcl.h
index 5ba96f2b19..38e66ab123 100644
--- a/crypto/bn/bn_lcl.h
+++ b/crypto/bn/bn_lcl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -654,9 +654,6 @@ BIGNUM *int_bn_mod_inverse(BIGNUM *in,
                            const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
                            int *noinv);
 
-int bn_probable_prime_dh(BIGNUM *rnd, int bits,
-                         const BIGNUM *add, const BIGNUM *rem, BN_CTX *ctx);
-
 static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
 {
     if (bits > (INT_MAX - BN_BITS2 + 1))
diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c
index 1cfd95307c..9e735b7233 100644
--- a/crypto/bn/bn_prime.c
+++ b/crypto/bn/bn_prime.c
@@ -19,10 +19,13 @@
  */
 #include "bn_prime.h"
 
-static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods, BN_CTX *ctx);
-static int probable_prime_dh_safe(BIGNUM *rnd, int bits,
-                                  const BIGNUM *add, const BIGNUM *rem,
-                                  BN_CTX *ctx);
+static int probable_prime(BIGNUM *rnd, int bits, int safe, prime_t *mods,
+                          BN_CTX *ctx);
+static int probable_prime_dh(BIGNUM *rnd, int bits, int safe, prime_t *mods,
+                             const BIGNUM *add, const BIGNUM *rem,
+                             BN_CTX *ctx);
+
+#define square(x) ((BN_ULONG)(x) * (BN_ULONG)(x))
 
 #if BN_BITS2 == 64
 # define BN_DEF(lo, hi) (BN_ULONG)hi<<32|lo
@@ -119,16 +122,11 @@ int BN_generate_prime_ex2(BIGNUM *ret, int bits, int safe,
  loop:
     /* make a random number and set the top and bottom bits */
     if (add == NULL) {
-        if (!probable_prime(ret, bits, mods, ctx))
+        if (!probable_prime(ret, bits, safe, mods, ctx))
             goto err;
     } else {
-        if (safe) {
-            if (!probable_prime_dh_safe(ret, bits, add, rem, ctx))
-                goto err;
-        } else {
-            if (!bn_probable_prime_dh(ret, bits, add, rem, ctx))
-                goto err;
-        }
+        if (!probable_prime_dh(ret, bits, safe, mods, add, rem, ctx))
+            goto err;
     }
 
     if (!BN_GENCB_call(cb, 0, c1++))
@@ -400,17 +398,19 @@ err:
     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;
     BN_ULONG delta;
     BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
-    char is_single_word = bits <= BN_BITS2;
 
  again:
     /* TODO: Not all primes are private */
     if (!BN_priv_rand_ex(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD, ctx))
         return 0;
+    if (safe && !BN_set_bit(rnd, 1))
+        return 0;
     /* we now have a random number 'rnd' to test. */
     for (i = 1; i < NUMPRIMES; i++) {
         BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
@@ -418,61 +418,25 @@ static int probable_prime(BIGNUM *rnd, int bits, prime_t 
*mods, BN_CTX *ctx)
             return 0;
         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;
  loop:
-    if (is_single_word) {
-        BN_ULONG rnd_word = BN_get_word(rnd);
-
-        /*-
-         * In the case that the candidate prime is a single word then
-         * we check that:
-         *   1) It's greater than primes[i] because we shouldn't reject
-         *      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; i++) {
+        /*
+         * check that rnd is a prime and also that
+         * gcd(rnd-1,primes) == 1 (except for 2)
+         * do the second check only if we are interested in safe primes
+         * in the case that the candidate prime is a single word then
+         * we check only the primes up to sqrt(rnd)
          */
-        for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) {
-            if ((mods[i] + delta) % primes[i] == 0) {
-                delta += 2;
-                if (delta > maxdelta)
-                    goto again;
-                goto loop;
-            }
-        }
-    } else {
-        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 (bits <= 31 && delta <= 0x7fffffff
+                && square(primes[i]) > BN_get_word(rnd) + delta)
+            break;
+        if (safe ? (mods[i] + delta) % primes[i] <= 1
+                 : (mods[i] + delta) % primes[i] == 0) {
+            delta += safe ? 4 : 2;
+            if (delta > maxdelta)
+                goto again;
+            goto loop;
         }
     }
     if (!BN_add_word(rnd, delta))
@@ -483,16 +447,23 @@ static int probable_prime(BIGNUM *rnd, int bits, prime_t 
*mods, BN_CTX *ctx)
     return 1;
 }
 
-int bn_probable_prime_dh(BIGNUM *rnd, int bits,
-                         const BIGNUM *add, const BIGNUM *rem, BN_CTX *ctx)
+static int probable_prime_dh(BIGNUM *rnd, int bits, int safe, prime_t *mods,
+                             const BIGNUM *add, const BIGNUM *rem,
+                             BN_CTX *ctx)
 {
     int i, ret = 0;
     BIGNUM *t1;
+    BN_ULONG delta;
+    BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
 
     BN_CTX_start(ctx);
     if ((t1 = BN_CTX_get(ctx)) == NULL)
         goto err;
 
+    if (maxdelta > BN_MASK2 - BN_get_word(add))
+        maxdelta = BN_MASK2 - BN_get_word(add);
+
+ again:
     if (!BN_rand_ex(rnd, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD, ctx))
         goto err;
 
@@ -503,98 +474,48 @@ int bn_probable_prime_dh(BIGNUM *rnd, int bits,
     if (!BN_sub(rnd, rnd, t1))
         goto err;
     if (rem == NULL) {
-        if (!BN_add_word(rnd, 1))
+        if (!BN_add_word(rnd, safe ? 3u : 1u))
             goto err;
     } else {
         if (!BN_add(rnd, rnd, rem))
             goto err;
     }
 
-    /* we now have a random number 'rand' to test. */
+    if (BN_num_bits(rnd) < bits
+            || BN_get_word(rnd) < (safe ? 5u : 3u)) {
+        if (!BN_add(rnd, rnd, add))
+            goto err;
+    }
 
- loop:
+    /* we now have a random number 'rnd' to test. */
     for (i = 1; i < NUMPRIMES; i++) {
-        /* check that rnd is a prime */
         BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
         if (mod == (BN_ULONG)-1)
             goto err;
-        if (mod <= 1) {
-            if (!BN_add(rnd, rnd, add))
-                goto err;
-            goto loop;
-        }
-    }
-    ret = 1;
-
- err:
-    BN_CTX_end(ctx);
-    bn_check_top(rnd);
-    return ret;
-}
-
-static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
-                                  const BIGNUM *rem, BN_CTX *ctx)
-{
-    int i, ret = 0;
-    BIGNUM *t1, *qadd, *q;
-
-    bits--;
-    BN_CTX_start(ctx);
-    t1 = BN_CTX_get(ctx);
-    q = BN_CTX_get(ctx);
-    qadd = BN_CTX_get(ctx);
-    if (qadd == NULL)
-        goto err;
-
-    if (!BN_rshift1(qadd, padd))
-        goto err;
-
-    if (!BN_rand_ex(q, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD, ctx))
-        goto err;
-
-    /* we need ((rnd-rem) % add) == 0 */
-    if (!BN_mod(t1, q, qadd, ctx))
-        goto err;
-    if (!BN_sub(q, q, t1))
-        goto err;
-    if (rem == NULL) {
-        if (!BN_add_word(q, 1))
-            goto err;
-    } else {
-        if (!BN_rshift1(t1, rem))
-            goto err;
-        if (!BN_add(q, q, t1))
-            goto err;
+        mods[i] = (prime_t) mod;
     }
-
-    /* we now have a random number 'rand' to test. */
-    if (!BN_lshift1(p, q))
-        goto err;
-    if (!BN_add_word(p, 1))
-        goto err;
-
+    delta = 0;
  loop:
     for (i = 1; i < NUMPRIMES; i++) {
-        /* check that p and q are prime */
-        /*
-         * check that for p and q gcd(p-1,primes) == 1 (except for 2)
-         */
-        BN_ULONG pmod = BN_mod_word(p, (BN_ULONG)primes[i]);
-        BN_ULONG qmod = BN_mod_word(q, (BN_ULONG)primes[i]);
-        if (pmod == (BN_ULONG)-1 || qmod == (BN_ULONG)-1)
-            goto err;
-        if (pmod == 0 || qmod == 0) {
-            if (!BN_add(p, p, padd))
-                goto err;
-            if (!BN_add(q, q, qadd))
-                goto err;
+        /* check that rnd is a prime */
+        if (bits <= 31 && delta <= 0x7fffffff
+                && square(primes[i]) > BN_get_word(rnd) + delta)
+            break;
+        /* rnd mod p == 1 implies q = (rnd-1)/2 is divisible by p */
+        if (safe ? (mods[i] + delta) % primes[i] <= 1
+                 : (mods[i] + delta) % primes[i] == 0) {
+            delta += BN_get_word(add);
+            if (delta > maxdelta)
+                goto again;
             goto loop;
         }
     }
+    if (!BN_add_word(rnd, delta))
+        goto err;
     ret = 1;
 
  err:
     BN_CTX_end(ctx);
-    bn_check_top(p);
+    bn_check_top(rnd);
     return ret;
 }
diff --git a/doc/man3/BN_generate_prime.pod b/doc/man3/BN_generate_prime.pod
index 5de646d916..6a3376b1fd 100644
--- a/doc/man3/BN_generate_prime.pod
+++ b/doc/man3/BN_generate_prime.pod
@@ -58,6 +58,8 @@ BN_generate_prime_ex2() generates a pseudo-random prime 
number of
 at least bit length B<bits> using the BN_CTX provided in B<ctx>. The value of
 B<ctx> must not be NULL.
 The returned number is probably prime with a negligible error.
+If B<add> is B<NULL> the returned prime number will have exact bit
+length B<bits> with the top most two bits set.
 
 If B<ret> is not B<NULL>, it will be used to store the number.
 
@@ -94,7 +96,9 @@ If B<add> is not B<NULL>, the prime will fulfill the 
condition p % B<add>
 generator.
 
 If B<safe> is true, it will be a safe prime (i.e. a prime p so
-that (p-1)/2 is also prime).
+that (p-1)/2 is also prime). If B<safe> is true, and B<rem> == B<NULL>
+the condition will be p % B<add> == 3.
+It is recommended that B<add> is a multiple of 4.
 
 The random generator must be seeded prior to calling BN_generate_prime_ex().
 If the automatic seeding or reseeding of the OpenSSL CSPRNG fails due to
@@ -218,7 +222,7 @@ and BN_GENCB_get_arg() functions were added in OpenSSL 
1.1.0.
 
 =head1 COPYRIGHT
 
-Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy

Reply via email to