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>
This commit is contained in:
Jouni Malinen 2015-06-25 11:33:34 +03:00
parent 9e286d5ea2
commit 16841ab246
2 changed files with 90 additions and 2 deletions

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

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