Reserve option to use BN_mod_exp_mont_consttime in ECDSA.
authorAndy Polyakov <appro@openssl.org>
Thu, 11 Sep 2014 22:13:20 +0000 (00:13 +0200)
committerAndy Polyakov <appro@openssl.org>
Thu, 11 Sep 2014 22:13:20 +0000 (00:13 +0200)
Submitted by Shay Gueron, Intel Corp.
RT: 3149

Reviewed-by: Rich Salz <rsalz@openssl.org>
crypto/ec/ec.h
crypto/ec/ec_lcl.h
crypto/ec/ec_lib.c
crypto/ecdsa/ecs_ossl.c

index 3601de2c0f86031e4ee70d7a7c4640935ba9fcea..99e161e753e03b218f478bde732f926b9e2d9515 100644 (file)
@@ -245,6 +245,12 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIG
  */
 const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group);
 
+/** Returns the montgomery data for order(Generator)
+ *  \param  group  EC_GROUP object
+ *  \return the currently used generator (possibly NULL).
+*/
+BN_MONT_CTX *EC_GROUP_get_mont_data(const EC_GROUP *group);
+
 /** Gets the order of a EC_GROUP
  *  \param  group  EC_GROUP object
  *  \param  order  BIGNUM to which the order is copied
index b0d48b6b5cc7f8a8af66523b24feda6cfaf6cd60..22b53d28a9f33a0b458ba26027501481d77f9b88 100644 (file)
@@ -235,6 +235,8 @@ struct ec_group_st {
        void *field_data1; /* method-specific (e.g., Montgomery structure) */
        void *field_data2; /* method-specific */
        int (*field_mod_func)(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); /* method-specific */
+
+       BN_MONT_CTX *mont_data;    /* data for ECDSA inverse */
 } /* EC_GROUP */;
 
 struct ec_key_st {
@@ -444,3 +446,12 @@ void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
        void (*felem_contract)(void *out, const void *in));
 void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign, unsigned char *digit, unsigned char in);
 #endif
+int ec_precompute_mont_data(EC_GROUP *);
+
+#ifdef ECP_NISTZ256_ASM
+/** Returns GFp methods using montgomery multiplication, with x86-64 optimized
+ * P256. See http://eprint.iacr.org/2013/816.
+ *  \return  EC_METHOD object
+ */
+const EC_METHOD *EC_GFp_nistz256_method(void);
+#endif
index a295a84f2b0167ec1928b3a7293e951408a08ec8..0a182d4229e76cc11561930738162dba0b312e5b 100644 (file)
@@ -101,6 +101,7 @@ EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
        ret->meth = meth;
 
        ret->extra_data = NULL;
+       ret->mont_data = NULL;
 
        ret->generator = NULL;
        BN_init(&ret->order);
@@ -132,6 +133,9 @@ void EC_GROUP_free(EC_GROUP *group)
 
        EC_EX_DATA_free_all_data(&group->extra_data);
 
+       if (group->mont_data)
+               BN_MONT_CTX_free(group->mont_data);
+
        if (group->generator != NULL)
                EC_POINT_free(group->generator);
        BN_free(&group->order);
@@ -155,6 +159,9 @@ void EC_GROUP_clear_free(EC_GROUP *group)
 
        EC_EX_DATA_clear_free_all_data(&group->extra_data);
 
+       if (group->mont_data)
+               BN_MONT_CTX_free(group->mont_data);
+
        if (group->generator != NULL)
                EC_POINT_clear_free(group->generator);
        BN_clear_free(&group->order);
@@ -200,6 +207,25 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
                        return 0;
                }
 
+       if (src->mont_data != NULL)
+               {
+               if (dest->mont_data == NULL)
+                       {
+                       dest->mont_data = BN_MONT_CTX_new();
+                       if (dest->mont_data == NULL) return 0;
+                       }
+               if (!BN_MONT_CTX_copy(dest->mont_data, src->mont_data)) return 0;
+               }
+       else
+               {
+               /* src->generator == NULL */
+               if (dest->mont_data != NULL)
+                       {
+                       BN_MONT_CTX_free(dest->mont_data);
+                       dest->mont_data = NULL;
+                       }
+               }
+
        if (src->generator != NULL)
                {
                if (dest->generator == NULL)
@@ -309,6 +335,11 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIG
        else
                BN_zero(&group->cofactor);
 
+       /* We ignore the return value because some groups have an order with
+        * factors of two, which makes the Montgomery setup fail.
+        * |group->mont_data| will be NULL in this case. */
+       ec_precompute_mont_data(group);
+
        return 1;
        }
 
@@ -318,6 +349,10 @@ const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group)
        return group->generator;
        }
 
+BN_MONT_CTX *EC_GROUP_get_mont_data(const EC_GROUP *group)
+       {
+       return group->mont_data;
+       }
 
 int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
        {
@@ -1097,3 +1132,39 @@ int EC_GROUP_have_precompute_mult(const EC_GROUP *group)
        else
                return 0; /* cannot tell whether precomputation has been performed */
        }
+
+/* ec_precompute_mont_data sets |group->mont_data| from |group->order| and
+ * returns one on success. On error it returns zero. */
+int ec_precompute_mont_data(EC_GROUP *group)
+       {
+       BN_CTX *ctx = BN_CTX_new();
+       int ret = 0;
+
+       if (group->mont_data)
+               {
+               BN_MONT_CTX_free(group->mont_data);
+               group->mont_data = NULL;
+               }
+
+       if (ctx == NULL)
+               goto err;
+
+       group->mont_data = BN_MONT_CTX_new();
+       if (!group->mont_data)
+               goto err;
+
+       if (!BN_MONT_CTX_set(group->mont_data, &group->order, ctx))
+               {
+               BN_MONT_CTX_free(group->mont_data);
+               group->mont_data = NULL;
+               goto err;
+               }
+
+       ret = 1;
+
+err:
+
+       if (ctx)
+               BN_CTX_free(ctx);
+       return ret;
+       }
index adab1f74b41daf6e719ca1fdae1ba817085c7802..97541a24b5feb2801b42d781408fab5385702c53 100644 (file)
@@ -219,11 +219,37 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
        while (BN_is_zero(r));
 
        /* compute the inverse of k */
-       if (!BN_mod_inverse(k, k, order, ctx))
-       {
-               ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
-               goto err;       
-       }
+       if (EC_GROUP_get_mont_data(group) != NULL)
+               {
+               /* We want inverse in constant time, therefore we utilize the
+                * fact order must be prime and use Fermats Little Theorem
+                * instead. */
+               if (!BN_set_word(X, 2) )
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               if (!BN_mod_sub(X, order, X, order, ctx))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               BN_set_flags(X, BN_FLG_CONSTTIME);
+               if (!BN_mod_exp_mont_consttime(k, k, X, order, ctx, EC_GROUP_get_mont_data(group)))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               }
+       else
+               {
+               if (!BN_mod_inverse(k, k, order, ctx))
+                       {
+                       ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
+                       goto err;       
+                       }
+               }
+
        /* clear old values if necessary */
        if (*rp != NULL)
                BN_clear_free(*rp);