]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
crypto: Add functions for computing the Legendre symbol and EC y^2
authorJouni Malinen <j@w1.fi>
Thu, 25 Jun 2015 08:33:34 +0000 (11:33 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 26 Jun 2015 19:41:51 +0000 (22:41 +0300)
These are needed to implement side-channel protection for SAE PWE
derivation for ECC.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/crypto/crypto.h
src/crypto/crypto_openssl.c

index 5fd1768580099d1e4235d2f8a8d4d87848e26d47..534c4bd78654347c092128b2636ff70accef4159 100644 (file)
@@ -613,6 +613,15 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
  */
 int crypto_bignum_is_one(const struct crypto_bignum *a);
 
+/**
+ * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
+ * @a: Bignum
+ * @p: Bignum
+ * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
+ */
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+                          const struct crypto_bignum *p);
+
 /**
  * struct crypto_ec - Elliptic curve context
  *
@@ -757,6 +766,16 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
                                  struct crypto_ec_point *p,
                                  const struct crypto_bignum *x, int y_bit);
 
+/**
+ * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
+ * @e: EC context from crypto_ec_init()
+ * @x: x coordinate
+ * Returns: y^2 on success, %NULL failure
+ */
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+                             const struct crypto_bignum *x);
+
 /**
  * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
  * @e: EC context from crypto_ec_init()
index dbe812c652f60bdae1f63c145b85c0153e0ac56f..3923b8be41576758ac2d292b000d92c8f1ace9eb 100644 (file)
@@ -1107,6 +1107,42 @@ int crypto_bignum_is_one(const struct crypto_bignum *a)
 }
 
 
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+                          const struct crypto_bignum *p)
+{
+       BN_CTX *bnctx;
+       BIGNUM *exp = NULL, *tmp = NULL;
+       int res = -2;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -2;
+
+       exp = BN_new();
+       tmp = BN_new();
+       if (!exp || !tmp ||
+           /* exp = (p-1) / 2 */
+           !BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
+           !BN_rshift1(exp, exp) ||
+           !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
+                       bnctx))
+               goto fail;
+
+       if (BN_is_word(tmp, 1))
+               res = 1;
+       else if (BN_is_zero(tmp))
+               res = 0;
+       else
+               res = -1;
+
+fail:
+       BN_clear_free(tmp);
+       BN_clear_free(exp);
+       BN_CTX_free(bnctx);
+       return res;
+}
+
+
 #ifdef CONFIG_ECC
 
 struct crypto_ec {
@@ -1114,6 +1150,8 @@ struct crypto_ec {
        BN_CTX *bnctx;
        BIGNUM *prime;
        BIGNUM *order;
+       BIGNUM *a;
+       BIGNUM *b;
 };
 
 struct crypto_ec * crypto_ec_init(int group)
@@ -1170,9 +1208,11 @@ struct crypto_ec * crypto_ec_init(int group)
        e->group = EC_GROUP_new_by_curve_name(nid);
        e->prime = BN_new();
        e->order = BN_new();
+       e->a = BN_new();
+       e->b = BN_new();
        if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
-           e->order == NULL ||
-           !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+           e->order == NULL || e->a == NULL || e->b == NULL ||
+           !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
            !EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
                crypto_ec_deinit(e);
                e = NULL;
@@ -1186,6 +1226,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
 {
        if (e == NULL)
                return;
+       BN_clear_free(e->b);
+       BN_clear_free(e->a);
        BN_clear_free(e->order);
        BN_clear_free(e->prime);
        EC_GROUP_free(e->group);
@@ -1333,6 +1375,33 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
 }
 
 
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+                             const struct crypto_bignum *x)
+{
+       BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+
+       tmp = BN_new();
+       tmp2 = BN_new();
+
+       /* y^2 = x^3 + ax + b */
+       if (tmp && tmp2 &&
+           BN_mod_sqr(tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+           BN_mod_mul(tmp, tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+           BN_mod_mul(tmp2, e->a, (const BIGNUM *) x, e->prime, e->bnctx) &&
+           BN_mod_add_quick(tmp2, tmp2, tmp, e->prime) &&
+           BN_mod_add_quick(tmp2, tmp2, e->b, e->prime)) {
+               y_sqr = tmp2;
+               tmp2 = NULL;
+       }
+
+       BN_clear_free(tmp);
+       BN_clear_free(tmp2);
+
+       return (struct crypto_bignum *) y_sqr;
+}
+
+
 int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
                                   const struct crypto_ec_point *p)
 {