Integrate my implementation of a countermeasure against
authorBodo Möller <bodo@openssl.org>
Thu, 8 Feb 2001 12:20:25 +0000 (12:20 +0000)
committerBodo Möller <bodo@openssl.org>
Thu, 8 Feb 2001 12:20:25 +0000 (12:20 +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.)

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

index fe4fea55cfde4b2ec8b9d6b1be60a6cea193d968..9a40276a4559d08484f0030b19a8ea372d1451e4 100644 (file)
@@ -328,7 +328,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);
@@ -494,6 +494,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,int num);
 #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. */
@@ -505,6 +506,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,int num);
 #define BN_R_ENCODING_ERROR                             104
 #define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA               105
 #define BN_R_INVALID_LENGTH                             106
+#define BN_R_INVALID_RANGE                              115
 #define BN_R_NOT_INITIALIZED                            107
 #define BN_R_NO_INVERSE                                         108
 #define BN_R_TOO_MANY_TEMPORARY_VARIABLES               109
index f6b762818de26cfbc79094f0f41319e6f0d1a3f4..adc6a214fc6e14a68962eeb309cbc069c1d44c07 100644 (file)
@@ -84,6 +84,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}
        };
@@ -98,6 +99,7 @@ static ERR_STRING_DATA BN_str_reasons[]=
 {BN_R_ENCODING_ERROR                     ,"encoding error"},
 {BN_R_EXPAND_ON_STATIC_BIGNUM_DATA       ,"expand on static bignum data"},
 {BN_R_INVALID_LENGTH                     ,"invalid length"},
+{BN_R_INVALID_RANGE                      ,"invalid range"},
 {BN_R_NOT_INITIALIZED                    ,"not initialized"},
 {BN_R_NO_INVERSE                         ,"no inverse"},
 {BN_R_TOO_MANY_TEMPORARY_VARIABLES       ,"too many temporary variables"},
index dfa53bc2f38f602673dd866bf3e7535ae0bc9fc3..0826ce01e37ab3474af534328aed798ea9a1a5a3 100644 (file)
@@ -141,14 +141,63 @@ int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom)
        return bnrand(1, rnd, bits, top, bottom);
        }
 
-/* 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))
                {
-               if (!BN_rand(r, n, 0, 0)) return 0;
-               } while ((min && BN_cmp(r, min) < 0) || BN_cmp(r, max) >= 0);
+               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
+               {
+               /* 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 28e5a9e4073c8d5a0ec0e6e8ea3ac6aac7ecc49f..a26b47ed5af279e997a07b4b5b20bfef4d866653 100644 (file)
@@ -179,7 +179,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().