diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 5fd176858..534c4bd78 100644 --- a/src/crypto/crypto.h +++ b/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() diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index dbe812c65..3923b8be4 100644 --- a/src/crypto/crypto_openssl.c +++ b/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) {