/src/libressl/crypto/gost/gostr341001.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: gostr341001.c,v 1.9 2022/01/07 09:40:03 tb Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
4 | | * Copyright (c) 2005-2006 Cryptocom LTD |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in |
15 | | * the documentation and/or other materials provided with the |
16 | | * distribution. |
17 | | * |
18 | | * 3. All advertising materials mentioning features or use of this |
19 | | * software must display the following acknowledgment: |
20 | | * "This product includes software developed by the OpenSSL Project |
21 | | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
22 | | * |
23 | | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
24 | | * endorse or promote products derived from this software without |
25 | | * prior written permission. For written permission, please contact |
26 | | * openssl-core@openssl.org. |
27 | | * |
28 | | * 5. Products derived from this software may not be called "OpenSSL" |
29 | | * nor may "OpenSSL" appear in their names without prior written |
30 | | * permission of the OpenSSL Project. |
31 | | * |
32 | | * 6. Redistributions of any form whatsoever must retain the following |
33 | | * acknowledgment: |
34 | | * "This product includes software developed by the OpenSSL Project |
35 | | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
36 | | * |
37 | | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
38 | | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
39 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
40 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
41 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
42 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
43 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
44 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
45 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
46 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
47 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
48 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
49 | | * ==================================================================== |
50 | | */ |
51 | | |
52 | | #include <string.h> |
53 | | |
54 | | #include <openssl/opensslconf.h> |
55 | | |
56 | | #ifndef OPENSSL_NO_GOST |
57 | | #include <openssl/bn.h> |
58 | | #include <openssl/err.h> |
59 | | #include <openssl/gost.h> |
60 | | |
61 | | #include "bn_lcl.h" |
62 | | #include "ecs_locl.h" |
63 | | #include "gost_locl.h" |
64 | | |
65 | | /* Convert little-endian byte array into bignum */ |
66 | | BIGNUM * |
67 | | GOST_le2bn(const unsigned char *buf, size_t len, BIGNUM *bn) |
68 | 106 | { |
69 | 106 | unsigned char temp[64]; |
70 | 106 | int i; |
71 | | |
72 | 106 | if (len > 64) |
73 | 0 | return NULL; |
74 | | |
75 | 3.20k | for (i = 0; i < len; i++) { |
76 | 3.10k | temp[len - 1 - i] = buf[i]; |
77 | 3.10k | } |
78 | | |
79 | 106 | return BN_bin2bn(temp, len, bn); |
80 | 106 | } |
81 | | |
82 | | int |
83 | | GOST_bn2le(BIGNUM *bn, unsigned char *buf, int len) |
84 | 0 | { |
85 | 0 | unsigned char temp[64]; |
86 | 0 | int i, bytes; |
87 | |
|
88 | 0 | bytes = BN_num_bytes(bn); |
89 | 0 | if (len > 64 || bytes > len) |
90 | 0 | return 0; |
91 | | |
92 | 0 | BN_bn2bin(bn, temp); |
93 | |
|
94 | 0 | for (i = 0; i < bytes; i++) { |
95 | 0 | buf[bytes - 1 - i] = temp[i]; |
96 | 0 | } |
97 | |
|
98 | 0 | memset(buf + bytes, 0, len - bytes); |
99 | |
|
100 | 0 | return 1; |
101 | 0 | } |
102 | | |
103 | | int |
104 | | gost2001_compute_public(GOST_KEY *ec) |
105 | 0 | { |
106 | 0 | const EC_GROUP *group = GOST_KEY_get0_group(ec); |
107 | 0 | EC_POINT *pub_key = NULL; |
108 | 0 | const BIGNUM *priv_key = NULL; |
109 | 0 | BN_CTX *ctx = NULL; |
110 | 0 | int ok = 0; |
111 | |
|
112 | 0 | if (group == NULL) { |
113 | 0 | GOSTerror(GOST_R_KEY_IS_NOT_INITIALIZED); |
114 | 0 | return 0; |
115 | 0 | } |
116 | 0 | ctx = BN_CTX_new(); |
117 | 0 | if (ctx == NULL) { |
118 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
119 | 0 | return 0; |
120 | 0 | } |
121 | 0 | BN_CTX_start(ctx); |
122 | 0 | if ((priv_key = GOST_KEY_get0_private_key(ec)) == NULL) |
123 | 0 | goto err; |
124 | | |
125 | 0 | pub_key = EC_POINT_new(group); |
126 | 0 | if (pub_key == NULL) |
127 | 0 | goto err; |
128 | 0 | if (EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx) == 0) |
129 | 0 | goto err; |
130 | 0 | if (GOST_KEY_set_public_key(ec, pub_key) == 0) |
131 | 0 | goto err; |
132 | 0 | ok = 1; |
133 | |
|
134 | 0 | if (ok == 0) { |
135 | 0 | err: |
136 | 0 | GOSTerror(ERR_R_EC_LIB); |
137 | 0 | } |
138 | 0 | EC_POINT_free(pub_key); |
139 | 0 | if (ctx != NULL) { |
140 | 0 | BN_CTX_end(ctx); |
141 | 0 | BN_CTX_free(ctx); |
142 | 0 | } |
143 | 0 | return ok; |
144 | 0 | } |
145 | | |
146 | | ECDSA_SIG * |
147 | | gost2001_do_sign(BIGNUM *md, GOST_KEY *eckey) |
148 | 0 | { |
149 | 0 | ECDSA_SIG *newsig = NULL; |
150 | 0 | BIGNUM *order = NULL; |
151 | 0 | const EC_GROUP *group; |
152 | 0 | const BIGNUM *priv_key; |
153 | 0 | BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k = |
154 | 0 | NULL, *e = NULL; |
155 | 0 | EC_POINT *C = NULL; |
156 | 0 | BN_CTX *ctx = BN_CTX_new(); |
157 | 0 | int ok = 0; |
158 | |
|
159 | 0 | if (ctx == NULL) { |
160 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
161 | 0 | return NULL; |
162 | 0 | } |
163 | 0 | BN_CTX_start(ctx); |
164 | 0 | newsig = ECDSA_SIG_new(); |
165 | 0 | if (newsig == NULL) { |
166 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
167 | 0 | goto err; |
168 | 0 | } |
169 | 0 | s = newsig->s; |
170 | 0 | r = newsig->r; |
171 | 0 | group = GOST_KEY_get0_group(eckey); |
172 | 0 | if ((order = BN_CTX_get(ctx)) == NULL) |
173 | 0 | goto err; |
174 | 0 | if (EC_GROUP_get_order(group, order, ctx) == 0) |
175 | 0 | goto err; |
176 | 0 | priv_key = GOST_KEY_get0_private_key(eckey); |
177 | 0 | if ((e = BN_CTX_get(ctx)) == NULL) |
178 | 0 | goto err; |
179 | 0 | if (BN_mod_ct(e, md, order, ctx) == 0) |
180 | 0 | goto err; |
181 | 0 | if (BN_is_zero(e)) |
182 | 0 | BN_one(e); |
183 | 0 | if ((k = BN_CTX_get(ctx)) == NULL) |
184 | 0 | goto err; |
185 | 0 | if ((X = BN_CTX_get(ctx)) == NULL) |
186 | 0 | goto err; |
187 | 0 | if ((C = EC_POINT_new(group)) == NULL) |
188 | 0 | goto err; |
189 | 0 | do { |
190 | 0 | do { |
191 | 0 | if (!BN_rand_range(k, order)) { |
192 | 0 | GOSTerror(GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); |
193 | 0 | goto err; |
194 | 0 | } |
195 | | /* |
196 | | * We do not want timing information to leak the length |
197 | | * of k, so we compute G*k using an equivalent scalar |
198 | | * of fixed bit-length. |
199 | | */ |
200 | 0 | if (BN_add(k, k, order) == 0) |
201 | 0 | goto err; |
202 | 0 | if (BN_num_bits(k) <= BN_num_bits(order)) |
203 | 0 | if (BN_add(k, k, order) == 0) |
204 | 0 | goto err; |
205 | | |
206 | 0 | if (EC_POINT_mul(group, C, k, NULL, NULL, ctx) == 0) { |
207 | 0 | GOSTerror(ERR_R_EC_LIB); |
208 | 0 | goto err; |
209 | 0 | } |
210 | 0 | if (EC_POINT_get_affine_coordinates(group, C, X, |
211 | 0 | NULL, ctx) == 0) { |
212 | 0 | GOSTerror(ERR_R_EC_LIB); |
213 | 0 | goto err; |
214 | 0 | } |
215 | 0 | if (BN_nnmod(r, X, order, ctx) == 0) |
216 | 0 | goto err; |
217 | 0 | } while (BN_is_zero(r)); |
218 | | /* s = (r*priv_key+k*e) mod order */ |
219 | 0 | if (tmp == NULL) { |
220 | 0 | if ((tmp = BN_CTX_get(ctx)) == NULL) |
221 | 0 | goto err; |
222 | 0 | } |
223 | 0 | if (BN_mod_mul(tmp, priv_key, r, order, ctx) == 0) |
224 | 0 | goto err; |
225 | 0 | if (tmp2 == NULL) { |
226 | 0 | if ((tmp2 = BN_CTX_get(ctx)) == NULL) |
227 | 0 | goto err; |
228 | 0 | } |
229 | 0 | if (BN_mod_mul(tmp2, k, e, order, ctx) == 0) |
230 | 0 | goto err; |
231 | 0 | if (BN_mod_add(s, tmp, tmp2, order, ctx) == 0) |
232 | 0 | goto err; |
233 | 0 | } while (BN_is_zero(s)); |
234 | 0 | ok = 1; |
235 | |
|
236 | 0 | err: |
237 | 0 | EC_POINT_free(C); |
238 | 0 | if (ctx != NULL) { |
239 | 0 | BN_CTX_end(ctx); |
240 | 0 | BN_CTX_free(ctx); |
241 | 0 | } |
242 | 0 | if (ok == 0) { |
243 | 0 | ECDSA_SIG_free(newsig); |
244 | 0 | newsig = NULL; |
245 | 0 | } |
246 | 0 | return newsig; |
247 | 0 | } |
248 | | |
249 | | int |
250 | | gost2001_do_verify(BIGNUM *md, ECDSA_SIG *sig, GOST_KEY *ec) |
251 | 0 | { |
252 | 0 | BN_CTX *ctx = BN_CTX_new(); |
253 | 0 | const EC_GROUP *group = GOST_KEY_get0_group(ec); |
254 | 0 | BIGNUM *order; |
255 | 0 | BIGNUM *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 = NULL; |
256 | 0 | BIGNUM *X = NULL, *tmp = NULL; |
257 | 0 | EC_POINT *C = NULL; |
258 | 0 | const EC_POINT *pub_key = NULL; |
259 | 0 | int ok = 0; |
260 | |
|
261 | 0 | if (ctx == NULL) |
262 | 0 | goto err; |
263 | 0 | BN_CTX_start(ctx); |
264 | 0 | if ((order = BN_CTX_get(ctx)) == NULL) |
265 | 0 | goto err; |
266 | 0 | if ((e = BN_CTX_get(ctx)) == NULL) |
267 | 0 | goto err; |
268 | 0 | if ((z1 = BN_CTX_get(ctx)) == NULL) |
269 | 0 | goto err; |
270 | 0 | if ((z2 = BN_CTX_get(ctx)) == NULL) |
271 | 0 | goto err; |
272 | 0 | if ((tmp = BN_CTX_get(ctx)) == NULL) |
273 | 0 | goto err; |
274 | 0 | if ((X = BN_CTX_get(ctx)) == NULL) |
275 | 0 | goto err; |
276 | 0 | if ((R = BN_CTX_get(ctx)) == NULL) |
277 | 0 | goto err; |
278 | 0 | if ((v = BN_CTX_get(ctx)) == NULL) |
279 | 0 | goto err; |
280 | | |
281 | 0 | if (EC_GROUP_get_order(group, order, ctx) == 0) |
282 | 0 | goto err; |
283 | 0 | pub_key = GOST_KEY_get0_public_key(ec); |
284 | 0 | if (BN_is_zero(sig->s) || BN_is_zero(sig->r) || |
285 | 0 | BN_cmp(sig->s, order) >= 1 || BN_cmp(sig->r, order) >= 1) { |
286 | 0 | GOSTerror(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); |
287 | 0 | goto err; |
288 | 0 | } |
289 | | |
290 | 0 | if (BN_mod_ct(e, md, order, ctx) == 0) |
291 | 0 | goto err; |
292 | 0 | if (BN_is_zero(e)) |
293 | 0 | BN_one(e); |
294 | 0 | if ((v = BN_mod_inverse_ct(v, e, order, ctx)) == NULL) |
295 | 0 | goto err; |
296 | 0 | if (BN_mod_mul(z1, sig->s, v, order, ctx) == 0) |
297 | 0 | goto err; |
298 | 0 | if (BN_sub(tmp, order, sig->r) == 0) |
299 | 0 | goto err; |
300 | 0 | if (BN_mod_mul(z2, tmp, v, order, ctx) == 0) |
301 | 0 | goto err; |
302 | 0 | if ((C = EC_POINT_new(group)) == NULL) |
303 | 0 | goto err; |
304 | 0 | if (EC_POINT_mul(group, C, z1, pub_key, z2, ctx) == 0) { |
305 | 0 | GOSTerror(ERR_R_EC_LIB); |
306 | 0 | goto err; |
307 | 0 | } |
308 | 0 | if (EC_POINT_get_affine_coordinates(group, C, X, NULL, ctx) == 0) { |
309 | 0 | GOSTerror(ERR_R_EC_LIB); |
310 | 0 | goto err; |
311 | 0 | } |
312 | 0 | if (BN_mod_ct(R, X, order, ctx) == 0) |
313 | 0 | goto err; |
314 | 0 | if (BN_cmp(R, sig->r) != 0) { |
315 | 0 | GOSTerror(GOST_R_SIGNATURE_MISMATCH); |
316 | 0 | } else { |
317 | 0 | ok = 1; |
318 | 0 | } |
319 | 0 | err: |
320 | 0 | EC_POINT_free(C); |
321 | 0 | if (ctx != NULL) { |
322 | 0 | BN_CTX_end(ctx); |
323 | 0 | BN_CTX_free(ctx); |
324 | 0 | } |
325 | 0 | return ok; |
326 | 0 | } |
327 | | |
328 | | /* Implementation of CryptoPro VKO 34.10-2001 algorithm */ |
329 | | int |
330 | | VKO_compute_key(BIGNUM *X, BIGNUM *Y, const GOST_KEY *pkey, GOST_KEY *priv_key, |
331 | | const BIGNUM *ukm) |
332 | 0 | { |
333 | 0 | BIGNUM *p = NULL, *order = NULL; |
334 | 0 | const BIGNUM *key = GOST_KEY_get0_private_key(priv_key); |
335 | 0 | const EC_GROUP *group = GOST_KEY_get0_group(priv_key); |
336 | 0 | const EC_POINT *pub_key = GOST_KEY_get0_public_key(pkey); |
337 | 0 | EC_POINT *pnt; |
338 | 0 | BN_CTX *ctx = NULL; |
339 | 0 | int ok = 0; |
340 | |
|
341 | 0 | pnt = EC_POINT_new(group); |
342 | 0 | if (pnt == NULL) |
343 | 0 | goto err; |
344 | 0 | ctx = BN_CTX_new(); |
345 | 0 | if (ctx == NULL) |
346 | 0 | goto err; |
347 | 0 | BN_CTX_start(ctx); |
348 | 0 | if ((p = BN_CTX_get(ctx)) == NULL) |
349 | 0 | goto err; |
350 | 0 | if ((order = BN_CTX_get(ctx)) == NULL) |
351 | 0 | goto err; |
352 | 0 | if (EC_GROUP_get_order(group, order, ctx) == 0) |
353 | 0 | goto err; |
354 | 0 | if (BN_mod_mul(p, key, ukm, order, ctx) == 0) |
355 | 0 | goto err; |
356 | 0 | if (EC_POINT_mul(group, pnt, NULL, pub_key, p, ctx) == 0) |
357 | 0 | goto err; |
358 | 0 | if (EC_POINT_get_affine_coordinates(group, pnt, X, Y, ctx) == 0) |
359 | 0 | goto err; |
360 | 0 | ok = 1; |
361 | |
|
362 | 0 | err: |
363 | 0 | if (ctx != NULL) { |
364 | 0 | BN_CTX_end(ctx); |
365 | 0 | BN_CTX_free(ctx); |
366 | 0 | } |
367 | 0 | EC_POINT_free(pnt); |
368 | 0 | return ok; |
369 | 0 | } |
370 | | |
371 | | int |
372 | | gost2001_keygen(GOST_KEY *ec) |
373 | 0 | { |
374 | 0 | BIGNUM *order = BN_new(), *d = BN_new(); |
375 | 0 | const EC_GROUP *group = GOST_KEY_get0_group(ec); |
376 | 0 | int rc = 0; |
377 | |
|
378 | 0 | if (order == NULL || d == NULL) |
379 | 0 | goto err; |
380 | 0 | if (EC_GROUP_get_order(group, order, NULL) == 0) |
381 | 0 | goto err; |
382 | | |
383 | 0 | do { |
384 | 0 | if (BN_rand_range(d, order) == 0) { |
385 | 0 | GOSTerror(GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); |
386 | 0 | goto err; |
387 | 0 | } |
388 | 0 | } while (BN_is_zero(d)); |
389 | | |
390 | 0 | if (GOST_KEY_set_private_key(ec, d) == 0) |
391 | 0 | goto err; |
392 | 0 | rc = gost2001_compute_public(ec); |
393 | |
|
394 | 0 | err: |
395 | 0 | BN_free(d); |
396 | 0 | BN_free(order); |
397 | 0 | return rc; |
398 | 0 | } |
399 | | #endif |