Integrate my implementation of a countermeasure against
authorBodo Möller <bodo@openssl.org>
Thu, 8 Feb 2001 12:14:51 +0000 (12:14 +0000)
committerBodo Möller <bodo@openssl.org>
Thu, 8 Feb 2001 12:14:51 +0000 (12:14 +0000)
Bleichenbacher's DSA attack.  With this implementation, the expected
number of iterations never exceeds 2.

New semantics for BN_rand_range():
BN_rand_range(r, min, range) now generates r such that
     min <= r < min+range.
(Previously, BN_rand_range(r, min, max) generated r such that
     min <= r < max.
It is more convenient to have the range; also the previous
prototype was misleading because max was larger than
the actual maximum.)

CHANGES
crypto/bn/bn.h
crypto/bn/bn_err.c
crypto/bn/bn_rand.c
crypto/dsa/dsa_ossl.c
doc/crypto/BN_rand.pod

diff --git a/CHANGES b/CHANGES
index 3e2d97daaab098559f85c670264601db691b8793..136dde4884708769cd900c81ea00231a21cd3ded 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -5,7 +5,7 @@
 
   *) Add new function BN_rand_range(), and fix DSA_sign_setup() to prevent
      Bleichenbacher's DSA attack.
-     [Ulf Moeller]
+     [Ulf Moeller, Bodo Moeller]
 
   *) Update Rijndael code to version 3.0 and change EVP AES ciphers to
      handle the new API. Currently only ECB, CBC modes supported. Add new
index be4e7ae2ba3e372d28960694a3114fd73751887c..8b2b9709952ea122a23d404d897386c123551e8b 100644 (file)
@@ -329,7 +329,7 @@ BIGNUM *BN_CTX_get(BN_CTX *ctx);
 void   BN_CTX_end(BN_CTX *ctx);
 int     BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
 int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
-int    BN_rand_range(BIGNUM *rnd, BIGNUM *min, BIGNUM *max);
+int    BN_rand_range(BIGNUM *rnd, BIGNUM *min, BIGNUM *range);
 int    BN_num_bits(const BIGNUM *a);
 int    BN_num_bits_word(BN_ULONG);
 BIGNUM *BN_new(void);
@@ -527,6 +527,7 @@ int BN_bntest_rand(BIGNUM *rnd, int bits, int top,int bottom);
 #define BN_F_BN_MPI2BN                                  112
 #define BN_F_BN_NEW                                     113
 #define BN_F_BN_RAND                                    114
+#define BN_F_BN_RAND_RANGE                              122
 #define BN_F_BN_USUB                                    115
 
 /* Reason codes. */
@@ -539,6 +540,7 @@ int BN_bntest_rand(BIGNUM *rnd, int bits, int top,int bottom);
 #define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA               105
 #define BN_R_INPUT_NOT_REDUCED                          110
 #define BN_R_INVALID_LENGTH                             106
+#define BN_R_INVALID_RANGE                              115
 #define BN_R_NOT_A_SQUARE                               111
 #define BN_R_NOT_INITIALIZED                            107
 #define BN_R_NO_INVERSE                                         108
index d7f0493f471adba098ade70ecaa46937d4b39936..c713e1f1544944686e7c6762445484b3da06a746 100644 (file)
@@ -87,6 +87,7 @@ static ERR_STRING_DATA BN_str_functs[]=
 {ERR_PACK(0,BN_F_BN_MPI2BN,0), "BN_mpi2bn"},
 {ERR_PACK(0,BN_F_BN_NEW,0),    "BN_new"},
 {ERR_PACK(0,BN_F_BN_RAND,0),   "BN_rand"},
+{ERR_PACK(0,BN_F_BN_RAND_RANGE,0),     "BN_rand_range"},
 {ERR_PACK(0,BN_F_BN_USUB,0),   "BN_usub"},
 {0,NULL}
        };
@@ -102,6 +103,7 @@ static ERR_STRING_DATA BN_str_reasons[]=
 {BN_R_EXPAND_ON_STATIC_BIGNUM_DATA       ,"expand on static bignum data"},
 {BN_R_INPUT_NOT_REDUCED                  ,"input not reduced"},
 {BN_R_INVALID_LENGTH                     ,"invalid length"},
+{BN_R_INVALID_RANGE                      ,"invalid range"},
 {BN_R_NOT_A_SQUARE                       ,"not a square"},
 {BN_R_NOT_INITIALIZED                    ,"not initialized"},
 {BN_R_NO_INVERSE                         ,"no inverse"},
index f2c79b5e319f537ddcf3d205155ee8c5e4f43c67..a7e35357d6d9d00f7e8175febb75cd3ba14ec2e0 100644 (file)
@@ -169,13 +169,62 @@ int     BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom)
        }
 #endif
 
-/* random number r: min <= r < max */
-int    BN_rand_range(BIGNUM *r, BIGNUM *min, BIGNUM *max)
+/* random number r: min <= r < min+range */
+int    BN_rand_range(BIGNUM *r, BIGNUM *min, BIGNUM *range)
        {
-       int n = BN_num_bits(max);
-       do
+       int n;
+
+       if (range->neg || BN_is_zero(range))
+               {
+               BNerr(BN_F_BN_RAND_RANGE, BN_R_INVALID_RANGE);
+               return 0;
+               }
+
+       n = BN_num_bits(range); /* n > 0 */
+
+       if (n == 1)
+               {
+               if (!BN_zero(r)) return 0;
+               }
+       else if (BN_is_bit_set(range, n - 2))
+               {
+               do
+                       {
+                       /* range = 11..._2, so each iteration succeeds with probability > .5 */
+                       if (!BN_rand(r, n, 0, 0)) return 0;
+                       fprintf(stderr, "?");
+                       }
+               while (BN_cmp(r, range) >= 0);
+               fprintf(stderr, "! (11...)\n");
+               }
+       else
                {
-               if (!BN_rand(r, n, 0, 0)) return 0;
-               } while ((min && BN_cmp(r, min) < 0) || BN_cmp(r, max) >= 0);
+               /* range = 10..._2,
+                * so  3*range (= 11..._2)  is exactly one bit longer than  range */
+               do
+                       {
+                       if (!BN_rand(r, n + 1, 0, 0)) return 0;
+                       /* If  r < 3*range,  use  r := r MOD range
+                        * (which is either  r, r - range,  or  r - 2*range).
+                        * Otherwise, iterate once more.
+                        * Since  3*range = 11..._2, each iteration succeeds with
+                        * probability > .5. */
+                       if (BN_cmp(r ,range) >= 0)
+                               {
+                               if (!BN_sub(r, r, range)) return 0;
+                               if (BN_cmp(r, range) >= 0)
+                                       if (!BN_sub(r, r, range)) return 0;
+                               }
+                       fprintf(stderr, "?");
+                       }
+               while (BN_cmp(r, range) >= 0);
+               fprintf(stderr, "! (10...)\n");
+               }
+
+       if (min != NULL)
+               {
+               if (!BN_add(r, r, min)) return 0;
+               }
+       
        return 1;
        }
index 7304037947e5db01c0e80e66f7bf1efc75a44b5e..1967290bafb01774f29ac400e346f9f830077922 100644 (file)
@@ -180,7 +180,9 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
        kinv=NULL;
 
        /* Get random k */
-       if (!BN_rand_range(&k, BN_value_one(), dsa->q)) goto err;
+       do
+               if (!BN_rand_range(&k, NULL, dsa->q)) goto err;
+       while (BN_is_zero(&k));
 
        if ((dsa->method_mont_p == NULL) && (dsa->flags & DSA_FLAG_CACHE_MONT_P))
                {
index dc93949246bc44718bc6066e45ba087e8b4b2e71..e4c94e3d12d02bb18eaed178123c592723a234ea 100644 (file)
@@ -12,7 +12,7 @@ BN_rand, BN_pseudo_rand - generate pseudo-random number
 
  int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
 
- int BN_rand_range(BIGNUM *rnd, BIGNUM *min, BIGNUM *max);
+ int BN_rand_range(BIGNUM *rnd, BIGNUM *min, BIGNUM *range);
 
 =head1 DESCRIPTION
 
@@ -28,8 +28,8 @@ non-cryptographic purposes and for certain purposes in cryptographic
 protocols, but usually not for key generation etc.
 
 BN_rand_range() generates a cryptographically strong pseudo-random
-number B<rnd> in the range B<min> E<lt>= B<rnd> E<lt> B<max>. B<min>
-may be NULL, in that case 0 E<lt>= B<rnd> E<lt> B<max>.
+number B<rnd> in the range B<min> E<lt>= B<rnd> E<lt> B<min> + B<range>.
+B<min> may be NULL, in that case 0 E<lt>= B<rnd> E<lt> B<range>.
 
 The PRNG must be seeded prior to calling BN_rand() or BN_rand_range().