|  | /* | 
|  | * Shared Dragonfly functionality | 
|  | * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi> | 
|  | * Copyright (c) 2019, The Linux Foundation | 
|  | * | 
|  | * This software may be distributed under the terms of the BSD license. | 
|  | * See README for more details. | 
|  | */ | 
|  |  | 
|  | #include "utils/includes.h" | 
|  |  | 
|  | #include "utils/common.h" | 
|  | #include "utils/const_time.h" | 
|  | #include "crypto/crypto.h" | 
|  | #include "dragonfly.h" | 
|  |  | 
|  |  | 
|  | int dragonfly_suitable_group(int group, int ecc_only) | 
|  | { | 
|  | /* Enforce REVmd rules on which SAE groups are suitable for production | 
|  | * purposes: FFC groups whose prime is >= 3072 bits and ECC groups | 
|  | * defined over a prime field whose prime is >= 256 bits. Furthermore, | 
|  | * ECC groups defined over a characteristic 2 finite field and ECC | 
|  | * groups with a co-factor greater than 1 are not suitable. Disable | 
|  | * groups that use Brainpool curves as well for now since they leak more | 
|  | * timing information due to the prime not being close to a power of | 
|  | * two. */ | 
|  | return group == 19 || group == 20 || group == 21 || | 
|  | (!ecc_only && | 
|  | (group == 15 || group == 16 || group == 17 || group == 18)); | 
|  | } | 
|  |  | 
|  |  | 
|  | unsigned int dragonfly_min_pwe_loop_iter(int group) | 
|  | { | 
|  | if (group == 22 || group == 23 || group == 24) { | 
|  | /* FFC groups for which pwd-value is likely to be >= p | 
|  | * frequently */ | 
|  | return 40; | 
|  | } | 
|  |  | 
|  | if (group == 1 || group == 2 || group == 5 || group == 14 || | 
|  | group == 15 || group == 16 || group == 17 || group == 18) { | 
|  | /* FFC groups that have prime that is close to a power of two */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Default to 40 (this covers most ECC groups) */ | 
|  | return 40; | 
|  | } | 
|  |  | 
|  |  | 
|  | int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime, | 
|  | struct crypto_bignum **qr, | 
|  | struct crypto_bignum **qnr) | 
|  | { | 
|  | *qr = *qnr = NULL; | 
|  |  | 
|  | while (!(*qr) || !(*qnr)) { | 
|  | struct crypto_bignum *tmp; | 
|  | int res; | 
|  |  | 
|  | tmp = crypto_bignum_init(); | 
|  | if (!tmp || crypto_bignum_rand(tmp, prime) < 0) { | 
|  | crypto_bignum_deinit(tmp, 0); | 
|  | break; | 
|  | } | 
|  |  | 
|  | res = crypto_bignum_legendre(tmp, prime); | 
|  | if (res == 1 && !(*qr)) | 
|  | *qr = tmp; | 
|  | else if (res == -1 && !(*qnr)) | 
|  | *qnr = tmp; | 
|  | else | 
|  | crypto_bignum_deinit(tmp, 0); | 
|  | } | 
|  |  | 
|  | if (*qr && *qnr) | 
|  | return 0; | 
|  | crypto_bignum_deinit(*qr, 0); | 
|  | crypto_bignum_deinit(*qnr, 0); | 
|  | *qr = *qnr = NULL; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | static struct crypto_bignum * | 
|  | dragonfly_get_rand_1_to_p_1(const struct crypto_bignum *prime) | 
|  | { | 
|  | struct crypto_bignum *tmp, *pm1, *one; | 
|  |  | 
|  | tmp = crypto_bignum_init(); | 
|  | pm1 = crypto_bignum_init(); | 
|  | one = crypto_bignum_init_set((const u8 *) "\x01", 1); | 
|  | if (!tmp || !pm1 || !one || | 
|  | crypto_bignum_sub(prime, one, pm1) < 0 || | 
|  | crypto_bignum_rand(tmp, pm1) < 0 || | 
|  | crypto_bignum_add(tmp, one, tmp) < 0) { | 
|  | crypto_bignum_deinit(tmp, 0); | 
|  | tmp = NULL; | 
|  | } | 
|  |  | 
|  | crypto_bignum_deinit(pm1, 0); | 
|  | crypto_bignum_deinit(one, 0); | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  |  | 
|  | int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec, | 
|  | const u8 *qr, const u8 *qnr, | 
|  | const struct crypto_bignum *val) | 
|  | { | 
|  | struct crypto_bignum *r, *num, *qr_or_qnr = NULL; | 
|  | int check, res = -1; | 
|  | u8 qr_or_qnr_bin[DRAGONFLY_MAX_ECC_PRIME_LEN]; | 
|  | const struct crypto_bignum *prime; | 
|  | size_t prime_len; | 
|  | unsigned int mask; | 
|  |  | 
|  | prime = crypto_ec_get_prime(ec); | 
|  | prime_len = crypto_ec_prime_len(ec); | 
|  |  | 
|  | /* | 
|  | * Use a blinding technique to mask val while determining whether it is | 
|  | * a quadratic residue modulo p to avoid leaking timing information | 
|  | * while determining the Legendre symbol. | 
|  | * | 
|  | * v = val | 
|  | * r = a random number between 1 and p-1, inclusive | 
|  | * num = (v * r * r) modulo p | 
|  | */ | 
|  | r = dragonfly_get_rand_1_to_p_1(prime); | 
|  | if (!r) | 
|  | return -1; | 
|  |  | 
|  | num = crypto_bignum_init(); | 
|  | if (!num || | 
|  | crypto_bignum_mulmod(val, r, prime, num) < 0 || | 
|  | crypto_bignum_mulmod(num, r, prime, num) < 0) | 
|  | goto fail; | 
|  |  | 
|  | /* | 
|  | * Need to minimize differences in handling different cases, so try to | 
|  | * avoid branches and timing differences. | 
|  | * | 
|  | * If r is odd: | 
|  | * num = (num * qr) module p | 
|  | * LGR(num, p) = 1 ==> quadratic residue | 
|  | * else: | 
|  | * num = (num * qnr) module p | 
|  | * LGR(num, p) = -1 ==> quadratic residue | 
|  | * | 
|  | * mask is set to !odd(r) | 
|  | */ | 
|  | mask = const_time_is_zero(crypto_bignum_is_odd(r)); | 
|  | const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin); | 
|  | qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len); | 
|  | if (!qr_or_qnr || | 
|  | crypto_bignum_mulmod(num, qr_or_qnr, prime, num) < 0) | 
|  | goto fail; | 
|  | /* branchless version of check = odd(r) ? 1 : -1, */ | 
|  | check = const_time_select_int(mask, -1, 1); | 
|  |  | 
|  | /* Determine the Legendre symbol on the masked value */ | 
|  | res = crypto_bignum_legendre(num, prime); | 
|  | if (res == -2) { | 
|  | res = -1; | 
|  | goto fail; | 
|  | } | 
|  | /* branchless version of res = res == check | 
|  | * (res is -1, 0, or 1; check is -1 or 1) */ | 
|  | mask = const_time_eq(res, check); | 
|  | res = const_time_select_int(mask, 1, 0); | 
|  | fail: | 
|  | crypto_bignum_deinit(num, 1); | 
|  | crypto_bignum_deinit(r, 1); | 
|  | crypto_bignum_deinit(qr_or_qnr, 1); | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int dragonfly_get_rand_2_to_r_1(struct crypto_bignum *val, | 
|  | const struct crypto_bignum *order) | 
|  | { | 
|  | return crypto_bignum_rand(val, order) == 0 && | 
|  | !crypto_bignum_is_zero(val) && | 
|  | !crypto_bignum_is_one(val); | 
|  | } | 
|  |  | 
|  |  | 
|  | int dragonfly_generate_scalar(const struct crypto_bignum *order, | 
|  | struct crypto_bignum *_rand, | 
|  | struct crypto_bignum *_mask, | 
|  | struct crypto_bignum *scalar) | 
|  | { | 
|  | int count; | 
|  |  | 
|  | /* Select two random values rand,mask such that 1 < rand,mask < r and | 
|  | * rand + mask mod r > 1. */ | 
|  | for (count = 0; count < 100; count++) { | 
|  | if (dragonfly_get_rand_2_to_r_1(_rand, order) && | 
|  | dragonfly_get_rand_2_to_r_1(_mask, order) && | 
|  | crypto_bignum_add(_rand, _mask, scalar) == 0 && | 
|  | crypto_bignum_mod(scalar, order, scalar) == 0 && | 
|  | !crypto_bignum_is_zero(scalar) && | 
|  | !crypto_bignum_is_one(scalar)) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* This should not be reachable in practice if the random number | 
|  | * generation is working. */ | 
|  | wpa_printf(MSG_INFO, | 
|  | "dragonfly: Unable to get randomness for own scalar"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* res = sqrt(val) */ | 
|  | int dragonfly_sqrt(struct crypto_ec *ec, const struct crypto_bignum *val, | 
|  | struct crypto_bignum *res) | 
|  | { | 
|  | const struct crypto_bignum *prime; | 
|  | struct crypto_bignum *tmp, *one; | 
|  | int ret = 0; | 
|  | u8 prime_bin[DRAGONFLY_MAX_ECC_PRIME_LEN]; | 
|  | size_t prime_len; | 
|  |  | 
|  | /* For prime p such that p = 3 mod 4, sqrt(w) = w^((p+1)/4) mod p */ | 
|  |  | 
|  | prime = crypto_ec_get_prime(ec); | 
|  | prime_len = crypto_ec_prime_len(ec); | 
|  | tmp = crypto_bignum_init(); | 
|  | one = crypto_bignum_init_uint(1); | 
|  |  | 
|  | if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin), | 
|  | prime_len) < 0 || | 
|  | (prime_bin[prime_len - 1] & 0x03) != 3 || | 
|  | !tmp || !one || | 
|  | /* tmp = (p+1)/4 */ | 
|  | crypto_bignum_add(prime, one, tmp) < 0 || | 
|  | crypto_bignum_rshift(tmp, 2, tmp) < 0 || | 
|  | /* res = sqrt(val) */ | 
|  | crypto_bignum_exptmod(val, tmp, prime, res) < 0) | 
|  | ret = -1; | 
|  |  | 
|  | crypto_bignum_deinit(tmp, 0); | 
|  | crypto_bignum_deinit(one, 0); | 
|  | return ret; | 
|  | } |