diff options
Diffstat (limited to 'src/lib/libcrypto/gost/gostr341001.c')
-rw-r--r-- | src/lib/libcrypto/gost/gostr341001.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/src/lib/libcrypto/gost/gostr341001.c b/src/lib/libcrypto/gost/gostr341001.c new file mode 100644 index 0000000000..3c314765f7 --- /dev/null +++ b/src/lib/libcrypto/gost/gostr341001.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* $OpenBSD: gostr341001.c,v 1.1 2014/11/09 19:17:13 miod 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/err.h> | ||
58 | #include <openssl/gost.h> | ||
59 | #include "gost_locl.h" | ||
60 | |||
61 | /* Convert little-endian byte array into bignum */ | ||
62 | BIGNUM *GOST_le2bn(const unsigned char * buf, size_t len, BIGNUM * bn) | ||
63 | { | ||
64 | unsigned char temp[64]; | ||
65 | int i; | ||
66 | if (len > 64) | ||
67 | return NULL; | ||
68 | |||
69 | for (i = 0; i < len; i++) { | ||
70 | temp[len - 1 - i] = buf[i]; | ||
71 | } | ||
72 | |||
73 | return BN_bin2bn(temp, len, bn); | ||
74 | } | ||
75 | |||
76 | int GOST_bn2le(BIGNUM * bn, unsigned char * buf, int len) | ||
77 | { | ||
78 | unsigned char temp[64]; | ||
79 | int i, bytes; | ||
80 | |||
81 | bytes = BN_num_bytes(bn); | ||
82 | if (len > 64 || bytes > len) | ||
83 | return 0; | ||
84 | |||
85 | BN_bn2bin(bn, temp); | ||
86 | |||
87 | for (i = 0; i < bytes; i++) { | ||
88 | buf[bytes - 1 - i] = temp[i]; | ||
89 | } | ||
90 | |||
91 | memset(buf + bytes, 0, len - bytes); | ||
92 | |||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | |||
97 | int gost2001_compute_public(GOST_KEY * ec) | ||
98 | { | ||
99 | const EC_GROUP *group = GOST_KEY_get0_group(ec); | ||
100 | EC_POINT *pub_key = NULL; | ||
101 | const BIGNUM *priv_key = NULL; | ||
102 | BN_CTX *ctx = NULL; | ||
103 | int ok = 0; | ||
104 | |||
105 | if (!group) { | ||
106 | GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, | ||
107 | GOST_R_KEY_IS_NOT_INITIALIZED); | ||
108 | return 0; | ||
109 | } | ||
110 | ctx = BN_CTX_new(); | ||
111 | BN_CTX_start(ctx); | ||
112 | if (!(priv_key = GOST_KEY_get0_private_key(ec))) { | ||
113 | GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); | ||
114 | goto err; | ||
115 | } | ||
116 | |||
117 | pub_key = EC_POINT_new(group); | ||
118 | if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) { | ||
119 | GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); | ||
120 | goto err; | ||
121 | } | ||
122 | if (!GOST_KEY_set_public_key(ec, pub_key)) { | ||
123 | GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); | ||
124 | goto err; | ||
125 | } | ||
126 | ok = 256; | ||
127 | err: | ||
128 | BN_CTX_end(ctx); | ||
129 | EC_POINT_free(pub_key); | ||
130 | BN_CTX_free(ctx); | ||
131 | return ok; | ||
132 | } | ||
133 | |||
134 | ECDSA_SIG *gost2001_do_sign(BIGNUM * md, GOST_KEY * eckey) | ||
135 | { | ||
136 | ECDSA_SIG *newsig = NULL; | ||
137 | BIGNUM *order = NULL; | ||
138 | const EC_GROUP *group; | ||
139 | const BIGNUM *priv_key; | ||
140 | BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k = | ||
141 | NULL, *e = NULL; | ||
142 | EC_POINT *C = NULL; | ||
143 | BN_CTX *ctx = BN_CTX_new(); | ||
144 | BN_CTX_start(ctx); | ||
145 | newsig = ECDSA_SIG_new(); | ||
146 | if (!newsig) { | ||
147 | GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE); | ||
148 | goto err; | ||
149 | } | ||
150 | s = newsig->s; | ||
151 | r = newsig->r; | ||
152 | group = GOST_KEY_get0_group(eckey); | ||
153 | order = BN_CTX_get(ctx); | ||
154 | EC_GROUP_get_order(group, order, ctx); | ||
155 | priv_key = GOST_KEY_get0_private_key(eckey); | ||
156 | e = BN_CTX_get(ctx); | ||
157 | BN_mod(e, md, order, ctx); | ||
158 | if (BN_is_zero(e)) { | ||
159 | BN_one(e); | ||
160 | } | ||
161 | k = BN_CTX_get(ctx); | ||
162 | X = BN_CTX_get(ctx); | ||
163 | C = EC_POINT_new(group); | ||
164 | do { | ||
165 | do { | ||
166 | if (!BN_rand_range(k, order)) { | ||
167 | GOSTerr(GOST_F_GOST2001_DO_SIGN, | ||
168 | GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); | ||
169 | ECDSA_SIG_free(newsig); | ||
170 | newsig = NULL; | ||
171 | goto err; | ||
172 | } | ||
173 | /* We do not want timing information to leak the length of k, | ||
174 | * so we compute G*k using an equivalent scalar of fixed | ||
175 | * bit-length. */ | ||
176 | if (!BN_add(k, k, order)) | ||
177 | goto err; | ||
178 | if (BN_num_bits(k) <= BN_num_bits(order)) | ||
179 | if (!BN_add(k, k, order)) | ||
180 | goto err; | ||
181 | |||
182 | if (!EC_POINT_mul(group, C, k, NULL, NULL, ctx)) { | ||
183 | GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB); | ||
184 | ECDSA_SIG_free(newsig); | ||
185 | newsig = NULL; | ||
186 | goto err; | ||
187 | } | ||
188 | if (!EC_POINT_get_affine_coordinates_GFp | ||
189 | (group, C, X, NULL, ctx)) { | ||
190 | GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB); | ||
191 | ECDSA_SIG_free(newsig); | ||
192 | newsig = NULL; | ||
193 | goto err; | ||
194 | } | ||
195 | BN_nnmod(r, X, order, ctx); | ||
196 | } | ||
197 | while (BN_is_zero(r)); | ||
198 | /* s = (r*priv_key+k*e) mod order */ | ||
199 | if (!tmp) | ||
200 | tmp = BN_CTX_get(ctx); | ||
201 | BN_mod_mul(tmp, priv_key, r, order, ctx); | ||
202 | if (!tmp2) | ||
203 | tmp2 = BN_CTX_get(ctx); | ||
204 | BN_mod_mul(tmp2, k, e, order, ctx); | ||
205 | BN_mod_add(s, tmp, tmp2, order, ctx); | ||
206 | } | ||
207 | while (BN_is_zero(s)); | ||
208 | |||
209 | err: | ||
210 | BN_CTX_end(ctx); | ||
211 | BN_CTX_free(ctx); | ||
212 | EC_POINT_free(C); | ||
213 | BN_free(md); | ||
214 | return newsig; | ||
215 | } | ||
216 | |||
217 | int gost2001_do_verify(BIGNUM * md, ECDSA_SIG * sig, GOST_KEY * ec) | ||
218 | { | ||
219 | BN_CTX *ctx = BN_CTX_new(); | ||
220 | const EC_GROUP *group = GOST_KEY_get0_group(ec); | ||
221 | BIGNUM *order; | ||
222 | BIGNUM *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 = NULL; | ||
223 | BIGNUM *X = NULL, *tmp = NULL; | ||
224 | EC_POINT *C = NULL; | ||
225 | const EC_POINT *pub_key = NULL; | ||
226 | int ok = 0; | ||
227 | |||
228 | BN_CTX_start(ctx); | ||
229 | order = BN_CTX_get(ctx); | ||
230 | e = BN_CTX_get(ctx); | ||
231 | z1 = BN_CTX_get(ctx); | ||
232 | z2 = BN_CTX_get(ctx); | ||
233 | tmp = BN_CTX_get(ctx); | ||
234 | X = BN_CTX_get(ctx); | ||
235 | R = BN_CTX_get(ctx); | ||
236 | v = BN_CTX_get(ctx); | ||
237 | |||
238 | EC_GROUP_get_order(group, order, ctx); | ||
239 | pub_key = GOST_KEY_get0_public_key(ec); | ||
240 | if (BN_is_zero(sig->s) || BN_is_zero(sig->r) || | ||
241 | (BN_cmp(sig->s, order) >= 1) || (BN_cmp(sig->r, order) >= 1)) { | ||
242 | GOSTerr(GOST_F_GOST2001_DO_VERIFY, GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); | ||
243 | goto err; | ||
244 | |||
245 | } | ||
246 | |||
247 | BN_mod(e, md, order, ctx); | ||
248 | if (BN_is_zero(e)) | ||
249 | BN_one(e); | ||
250 | v = BN_mod_inverse(v, e, order, ctx); | ||
251 | BN_mod_mul(z1, sig->s, v, order, ctx); | ||
252 | BN_sub(tmp, order, sig->r); | ||
253 | BN_mod_mul(z2, tmp, v, order, ctx); | ||
254 | C = EC_POINT_new(group); | ||
255 | if (!EC_POINT_mul(group, C, z1, pub_key, z2, ctx)) { | ||
256 | GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB); | ||
257 | goto err; | ||
258 | } | ||
259 | if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) { | ||
260 | GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB); | ||
261 | goto err; | ||
262 | } | ||
263 | BN_mod(R, X, order, ctx); | ||
264 | if (BN_cmp(R, sig->r) != 0) { | ||
265 | GOSTerr(GOST_F_GOST2001_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH); | ||
266 | } else { | ||
267 | ok = 1; | ||
268 | } | ||
269 | err: | ||
270 | EC_POINT_free(C); | ||
271 | BN_CTX_end(ctx); | ||
272 | BN_CTX_free(ctx); | ||
273 | return ok; | ||
274 | } | ||
275 | |||
276 | |||
277 | /* Implementation of CryptoPro VKO 34.10-2001 algorithm */ | ||
278 | void VKO_compute_key(BIGNUM * X, BIGNUM * Y, | ||
279 | const GOST_KEY * pkey, GOST_KEY * priv_key, | ||
280 | const BIGNUM * ukm) | ||
281 | { | ||
282 | BIGNUM *p = NULL, *order = NULL; | ||
283 | const BIGNUM *key = GOST_KEY_get0_private_key(priv_key); | ||
284 | const EC_POINT *pub_key = GOST_KEY_get0_public_key(pkey); | ||
285 | EC_POINT *pnt = EC_POINT_new(GOST_KEY_get0_group(priv_key)); | ||
286 | BN_CTX *ctx = BN_CTX_new(); | ||
287 | |||
288 | BN_CTX_start(ctx); | ||
289 | p = BN_CTX_get(ctx); | ||
290 | order = BN_CTX_get(ctx); | ||
291 | EC_GROUP_get_order(GOST_KEY_get0_group(priv_key), order, ctx); | ||
292 | BN_mod_mul(p, key, ukm, order, ctx); | ||
293 | EC_POINT_mul(GOST_KEY_get0_group(priv_key), pnt, NULL, pub_key, p, ctx); | ||
294 | EC_POINT_get_affine_coordinates_GFp(GOST_KEY_get0_group(priv_key), | ||
295 | pnt, X, Y, ctx); | ||
296 | BN_CTX_end(ctx); | ||
297 | BN_CTX_free(ctx); | ||
298 | EC_POINT_free(pnt); | ||
299 | } | ||
300 | |||
301 | int gost2001_keygen(GOST_KEY * ec) | ||
302 | { | ||
303 | BIGNUM *order = BN_new(), *d = BN_new(); | ||
304 | const EC_GROUP *group = GOST_KEY_get0_group(ec); | ||
305 | EC_GROUP_get_order(group, order, NULL); | ||
306 | |||
307 | do { | ||
308 | if (!BN_rand_range(d, order)) { | ||
309 | GOSTerr(GOST_F_GOST2001_KEYGEN, | ||
310 | GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); | ||
311 | BN_free(d); | ||
312 | BN_free(order); | ||
313 | return 0; | ||
314 | } | ||
315 | } while (BN_is_zero(d)); | ||
316 | GOST_KEY_set_private_key(ec, d); | ||
317 | BN_free(d); | ||
318 | BN_free(order); | ||
319 | return gost2001_compute_public(ec); | ||
320 | } | ||
321 | #endif | ||