Browse Source

crypto: Add functions for computing the Legendre symbol and EC y^2

These are needed to implement side-channel protection for SAE PWE
derivation for ECC.

Signed-off-by: Jouni Malinen <j@w1.fi>
Jouni Malinen 9 years ago
parent
commit
16841ab246
2 changed files with 90 additions and 2 deletions
  1. 19 0
      src/crypto/crypto.h
  2. 71 2
      src/crypto/crypto_openssl.c

+ 19 - 0
src/crypto/crypto.h

@@ -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()

+ 71 - 2
src/crypto/crypto_openssl.c

@@ -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)
 {