blob: e98bce68233a164a1317e300a00955c944b81d33 [file] [log] [blame]
Hai Shalom878cf7b2019-07-15 14:55:18 -07001/*
2 * Shared Dragonfly functionality
3 * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2019, The Linux Foundation
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
11
12#include "utils/common.h"
13#include "utils/const_time.h"
14#include "crypto/crypto.h"
15#include "dragonfly.h"
16
17
18int dragonfly_suitable_group(int group, int ecc_only)
19{
20 /* Enforce REVmd rules on which SAE groups are suitable for production
21 * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
22 * defined over a prime field whose prime is >= 256 bits. Furthermore,
23 * ECC groups defined over a characteristic 2 finite field and ECC
24 * groups with a co-factor greater than 1 are not suitable. */
25 return group == 19 || group == 20 || group == 21 ||
26 group == 28 || group == 29 || group == 30 ||
27 (!ecc_only &&
28 (group == 15 || group == 16 || group == 17 || group == 18));
29}
30
31
32int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
33 struct crypto_bignum **qr,
34 struct crypto_bignum **qnr)
35{
36 *qr = *qnr = NULL;
37
38 while (!(*qr) || !(*qnr)) {
39 struct crypto_bignum *tmp;
40 int res;
41
42 tmp = crypto_bignum_init();
43 if (!tmp || crypto_bignum_rand(tmp, prime) < 0) {
44 crypto_bignum_deinit(tmp, 0);
45 break;
46 }
47
48 res = crypto_bignum_legendre(tmp, prime);
49 if (res == 1 && !(*qr))
50 *qr = tmp;
51 else if (res == -1 && !(*qnr))
52 *qnr = tmp;
53 else
54 crypto_bignum_deinit(tmp, 0);
55 }
56
57 if (*qr && *qnr)
58 return 0;
59 crypto_bignum_deinit(*qr, 0);
60 crypto_bignum_deinit(*qnr, 0);
61 *qr = *qnr = NULL;
62 return -1;
63}
64
65
66static struct crypto_bignum *
67dragonfly_get_rand_1_to_p_1(const struct crypto_bignum *prime)
68{
69 struct crypto_bignum *tmp, *pm1, *one;
70
71 tmp = crypto_bignum_init();
72 pm1 = crypto_bignum_init();
73 one = crypto_bignum_init_set((const u8 *) "\x01", 1);
74 if (!tmp || !pm1 || !one ||
75 crypto_bignum_sub(prime, one, pm1) < 0 ||
76 crypto_bignum_rand(tmp, pm1) < 0 ||
77 crypto_bignum_add(tmp, one, tmp) < 0) {
78 crypto_bignum_deinit(tmp, 0);
79 tmp = NULL;
80 }
81
82 crypto_bignum_deinit(pm1, 0);
83 crypto_bignum_deinit(one, 0);
84 return tmp;
85}
86
87
88int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
89 const u8 *qr, const u8 *qnr,
90 const struct crypto_bignum *val)
91{
92 struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
93 int check, res = -1;
94 u8 qr_or_qnr_bin[DRAGONFLY_MAX_ECC_PRIME_LEN];
95 const struct crypto_bignum *prime;
96 size_t prime_len;
97 unsigned int mask;
98
99 prime = crypto_ec_get_prime(ec);
100 prime_len = crypto_ec_prime_len(ec);
101
102 /*
103 * Use a blinding technique to mask val while determining whether it is
104 * a quadratic residue modulo p to avoid leaking timing information
105 * while determining the Legendre symbol.
106 *
107 * v = val
108 * r = a random number between 1 and p-1, inclusive
109 * num = (v * r * r) modulo p
110 */
111 r = dragonfly_get_rand_1_to_p_1(prime);
112 if (!r)
113 return -1;
114
115 num = crypto_bignum_init();
116 if (!num ||
117 crypto_bignum_mulmod(val, r, prime, num) < 0 ||
118 crypto_bignum_mulmod(num, r, prime, num) < 0)
119 goto fail;
120
121 /*
122 * Need to minimize differences in handling different cases, so try to
123 * avoid branches and timing differences.
124 *
125 * If r is odd:
126 * num = (num * qr) module p
127 * LGR(num, p) = 1 ==> quadratic residue
128 * else:
129 * num = (num * qnr) module p
130 * LGR(num, p) = -1 ==> quadratic residue
131 *
132 * mask is set to !odd(r)
133 */
134 mask = const_time_is_zero(crypto_bignum_is_odd(r));
135 const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
136 qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
137 if (!qr_or_qnr ||
138 crypto_bignum_mulmod(num, qr_or_qnr, prime, num) < 0)
139 goto fail;
140 /* branchless version of check = odd(r) ? 1 : -1, */
141 check = const_time_select_int(mask, -1, 1);
142
143 /* Determine the Legendre symbol on the masked value */
144 res = crypto_bignum_legendre(num, prime);
145 if (res == -2) {
146 res = -1;
147 goto fail;
148 }
149 /* branchless version of res = res == check
150 * (res is -1, 0, or 1; check is -1 or 1) */
151 mask = const_time_eq(res, check);
152 res = const_time_select_int(mask, 1, 0);
153fail:
154 crypto_bignum_deinit(num, 1);
155 crypto_bignum_deinit(r, 1);
156 crypto_bignum_deinit(qr_or_qnr, 1);
157 return res;
158}
159
160
161static int dragonfly_get_rand_2_to_r_1(struct crypto_bignum *val,
162 const struct crypto_bignum *order)
163{
164 return crypto_bignum_rand(val, order) == 0 &&
165 !crypto_bignum_is_zero(val) &&
166 !crypto_bignum_is_one(val);
167}
168
169
170int dragonfly_generate_scalar(const struct crypto_bignum *order,
171 struct crypto_bignum *_rand,
172 struct crypto_bignum *_mask,
173 struct crypto_bignum *scalar)
174{
175 int count;
176
177 /* Select two random values rand,mask such that 1 < rand,mask < r and
178 * rand + mask mod r > 1. */
179 for (count = 0; count < 100; count++) {
180 if (dragonfly_get_rand_2_to_r_1(_rand, order) &&
181 dragonfly_get_rand_2_to_r_1(_mask, order) &&
182 crypto_bignum_add(_rand, _mask, scalar) == 0 &&
183 crypto_bignum_mod(scalar, order, scalar) == 0 &&
184 !crypto_bignum_is_zero(scalar) &&
185 !crypto_bignum_is_one(scalar))
186 return 0;
187 }
188
189 /* This should not be reachable in practice if the random number
190 * generation is working. */
191 wpa_printf(MSG_INFO,
192 "dragonfly: Unable to get randomness for own scalar");
193 return -1;
194}