1 /*
2 * Copyright (C) 2021 - This file is part of libecc project
3 *
4 * Authors:
5 * Ryad BENADJILA <ryadbenadjila@gmail.com>
6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7 *
8 * This software is licensed under a dual BSD and GPL v2 license.
9 * See LICENSE file at the root folder of the project.
10 */
11 #include "gostr34_10_94.h"
12
13
14 /* We include the rand external dependency because we have to generate
15 * some random data for the nonces.
16 */
17 #include <libecc/external_deps/rand.h>
18 /* We include the printf external dependency for printf output */
19 #include <libecc/external_deps/print.h>
20 /* We include our common helpers */
21 #include "../common/common.h"
22
23 /*
24 * The purpose of this example is to implement the GOSTR34-10-94
25 * based on libecc arithmetic primitives.
26 *
27 * XXX: Please be aware that libecc has been designed for Elliptic
28 * Curve cryptography, and as so the arithmetic primitives are
29 * not optimized for big numbers >= 1024 bits usually used for GOSTR.
30 * Additionnaly, a hard limit of our NN values makes it impossible
31 * to exceed ~5300 bits in the best case (words of size 64 bits).
32 *
33 * All in all, please see this as a proof of concept.
34 * Use it at your own risk!
35 *
36 * !! DISCLAIMER !!
37 * ================
38 *
39 * Althoug some efforts have been made to secure this implementation
40 * of GOSTR (e.g. by protecting the private key and nonces using constant
41 * time and blinding WHEN activated with BLINDING=1), please consider this
42 * code as a proof of concept and use it at your own risk.
43 *
44 * All-in-all, this piece of code can be useful in some contexts, or risky to
45 * use in other sensitive ones where advanced side-channels or fault attacks
46 * have to be considered. Use this GOSTR code knowingly and at your own risk!
47 *
48 */
49
50 /* NOTE: since GOSTR34_10_94 is very similar to DSA, we reuse some of our DSA
51 * primitives to factorize some code. Also, GOSTR34_10_94 private and public keys
52 * have the exact same type as DSA keys.
53 */
54
55 /* Import a GOSTR34_10_94 private key from buffers */
gostr34_10_94_import_priv_key(gostr34_10_94_priv_key * priv,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * x,u16 xlen)56 int gostr34_10_94_import_priv_key(gostr34_10_94_priv_key *priv, const u8 *p, u16 plen,
57 const u8 *q, u16 qlen,
58 const u8 *g, u16 glen,
59 const u8 *x, u16 xlen)
60 {
61 return dsa_import_priv_key(priv, p, plen, q, qlen, g, glen, x, xlen);
62 }
63
64 /* Import a GOSTR34_10_94 public key from buffers */
gostr34_10_94_import_pub_key(gostr34_10_94_pub_key * pub,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * y,u16 ylen)65 int gostr34_10_94_import_pub_key(gostr34_10_94_pub_key *pub, const u8 *p, u16 plen,
66 const u8 *q, u16 qlen,
67 const u8 *g, u16 glen,
68 const u8 *y, u16 ylen)
69 {
70 return dsa_import_pub_key(pub, p, plen, q, qlen, g, glen, y, ylen);
71 }
72
73
74
75 /* Compute a GOSTR34_10_94 public key from a private key.
76 * The public key is computed using modular exponentiation of the generator
77 * with the private key.
78 */
gostr34_10_94_compute_pub_from_priv(gostr34_10_94_pub_key * pub,const gostr34_10_94_priv_key * priv)79 int gostr34_10_94_compute_pub_from_priv(gostr34_10_94_pub_key *pub, const gostr34_10_94_priv_key *priv)
80 {
81 return dsa_compute_pub_from_priv(pub, priv);
82 }
83
84 /* Generate a GOSTR34_10_94 signature
85 */
gostr34_10_94_sign(const gostr34_10_94_priv_key * priv,const u8 * msg,u32 msglen,const u8 * nonce,u16 noncelen,u8 * sig,u16 siglen,gen_hash_alg_type gostr34_10_94_hash)86 int gostr34_10_94_sign(const gostr34_10_94_priv_key *priv, const u8 *msg, u32 msglen,
87 const u8 *nonce, u16 noncelen,
88 u8 *sig, u16 siglen, gen_hash_alg_type gostr34_10_94_hash)
89 {
90 int ret, iszero;
91 /* N is the bit length of q */
92 bitcnt_t N, rshift;
93 /* Length of the hash function */
94 u8 hlen, block_size;
95 nn_src_t p, q, g, x;
96 /* The nonce and its protected version */
97 nn k, k_;
98 /* r, s and z */
99 nn r, s, z;
100 /* Hash */
101 u8 hash[MAX_DIGEST_SIZE];
102 #ifdef USE_SIG_BLINDING
103 /* b is the blinding mask */
104 nn b;
105 b.magic = WORD(0);
106 #endif /* USE_SIG_BLINDING */
107 k.magic = k_.magic = r.magic = s.magic = z.magic = WORD(0);
108
109 /* Sanity checks */
110 MUST_HAVE((priv != NULL) && (msg != NULL) && (sig != NULL), ret, err);
111
112 ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
113
114 /* Make things more readable */
115 p = &(priv->p);
116 q = &(priv->q);
117 g = &(priv->g);
118 x = &(priv->x);
119
120 /* Sanity checks */
121 ret = nn_check_initialized(p); EG(ret, err);
122 ret = nn_check_initialized(q); EG(ret, err);
123 ret = nn_check_initialized(g); EG(ret, err);
124 ret = nn_check_initialized(x); EG(ret, err);
125
126 /* Let N be the bit length of q. Let min(N, outlen) denote the minimum
127 * of the positive integers N and outlen, where outlen is the bit length
128 * of the hash function output block.
129 */
130 ret = nn_bitlen(q, &N); EG(ret, err);
131 ret = gen_hash_get_hash_sizes(gostr34_10_94_hash, &hlen, &block_size); EG(ret, err);
132 MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
133
134 /* Sanity check on the signature length */
135 MUST_HAVE((siglen == (2 * BYTECEIL(N))), ret, err);
136
137 restart:
138 /* If the nonce is imposed, use it. Else get a random modulo q */
139 if(nonce != NULL){
140 ret = _os2ip(&k, nonce, noncelen); EG(ret, err);
141 }
142 else{
143 ret = nn_get_random_mod(&k, q); EG(ret, err);
144 }
145
146 /* Fix the MSB of our scalar */
147 ret = nn_copy(&k_, &k); EG(ret, err);
148 #ifdef USE_SIG_BLINDING
149 /* Blind the scalar */
150 ret = _blind_scalar(&k_, q, &k_); EG(ret, err);
151 #endif /* USE_SIG_BLINDING */
152 ret = _fix_scalar_msb(&k_, q, &k_); EG(ret, err);
153 /* r = (g**k mod p) mod q */
154 ret = nn_init(&r, 0); EG(ret, err);
155 /* Exponentiation modulo p */
156 ret = nn_mod_pow(&r, g, &k_, p); EG(ret, err);
157 /* Modulo q */
158 ret = nn_mod(&r, &r, q); EG(ret, err);
159
160 /* If r is 0, restart the process */
161 ret = nn_iszero(&r, &iszero); EG(ret, err);
162 if (iszero) {
163 goto restart;
164 }
165
166 /* Export r */
167 ret = _i2osp(&r, sig, (siglen / 2)); EG(ret, err);
168
169 /* Compute the hash */
170 ret = gen_hash_hfunc(msg, msglen, hash, gostr34_10_94_hash); EG(ret, err);
171 /* Reverse the endianness of the hash as little endian is needed here */
172 ret = _reverse_endianness(hash, hlen); EG(ret, err);
173
174 /* z = the leftmost min(N, outlen) bits of Hash(M) */
175 rshift = 0;
176 if ((hlen * 8) > N) {
177 rshift = (bitcnt_t)((hlen * 8) - N);
178 }
179 ret = _os2ip(&z, hash, hlen); EG(ret, err);
180 if (rshift) {
181 ret = nn_rshift_fixedlen(&z, &z, rshift); EG(ret, err);
182 }
183 ret = nn_mod(&z, &z, q); EG(ret, err);
184 /* If z = 0, then set it to 1 */
185 ret = nn_iszero(&z, &iszero); EG(ret, err);
186 if(iszero){
187 ret = nn_one(&z); EG(ret, err);
188 }
189
190 #ifdef USE_SIG_BLINDING
191 /* Note: if we use blinding, r and e are multiplied by
192 * a random value b in ]0,q[ */
193 ret = nn_get_random_mod(&b, q); EG(ret, err);
194 /* Blind r with b */
195 ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);
196 /* Blind the message z */
197 ret = nn_mod_mul(&z, &z, &b, q); EG(ret, err);
198 /*
199 * In case of blinding, we compute b^-1 with
200 * little Fermat theorem. This will be used to
201 * unblind s.
202 */
203 ret = nn_modinv_fermat(&b, &b, q); EG(ret, err);
204 #endif /* USE_SIG_BLINDING */
205
206 /* Compute s = (xr + kz) mod q */
207 ret = nn_mod_mul(&s, &r, x, q); EG(ret, err);
208 ret = nn_mod_mul(&r, &k, &z, q); EG(ret, err);
209 ret = nn_mod_add(&s, &s, &r, q); EG(ret, err);
210
211 #ifdef USE_SIG_BLINDING
212 /* In case of blinding, unblind s */
213 ret = nn_mod_mul(&s, &s, &b, q); EG(ret, err);
214 #endif /* USE_SIG_BLINDING */
215 /* If s is 0, restart the process */
216 ret = nn_iszero(&s, &iszero); EG(ret, err);
217 if (iszero) {
218 goto restart;
219 }
220
221 /* Export s */
222 ret = _i2osp(&s, sig + (siglen / 2), (siglen / 2));
223
224 err:
225 if(ret && (sig != NULL)){
226 IGNORE_RET_VAL(local_memset(sig, 0, siglen));
227 }
228
229 nn_uninit(&k);
230 nn_uninit(&k_);
231 #ifdef USE_SIG_BLINDING
232 nn_uninit(&b);
233 #endif
234 nn_uninit(&r);
235 nn_uninit(&s);
236 nn_uninit(&z);
237
238 PTR_NULLIFY(p);
239 PTR_NULLIFY(q);
240 PTR_NULLIFY(g);
241 PTR_NULLIFY(x);
242
243 return ret;
244 }
245
246
247
248 /* Verify a GOSTR34_10_94 signature
249 */
gostr34_10_94_verify(const gostr34_10_94_pub_key * pub,const u8 * msg,u32 msglen,const u8 * sig,u16 siglen,gen_hash_alg_type gostr34_10_94_hash)250 int gostr34_10_94_verify(const gostr34_10_94_pub_key *pub, const u8 *msg, u32 msglen,
251 const u8 *sig, u16 siglen, gen_hash_alg_type gostr34_10_94_hash)
252 {
253 int ret, iszero, cmp;
254 /* N is the bit length of q */
255 bitcnt_t N, rshift;
256 /* Length of the hash function */
257 u8 hlen, block_size;
258 nn_src_t p, q, g, y;
259 /* r, s */
260 nn r, s, z;
261 /* u1, u2, and v */
262 nn u1, u2, v;
263 /* Hash */
264 u8 hash[MAX_DIGEST_SIZE];
265 r.magic = s.magic = z.magic = u1.magic = u2.magic = WORD(0);
266
267 /* Sanity checks */
268 MUST_HAVE((pub != NULL) && (msg != NULL) && (sig != NULL), ret, err);
269
270 ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
271
272 /* Make things more readable */
273 p = &(pub->p);
274 q = &(pub->q);
275 g = &(pub->g);
276 y = &(pub->y);
277
278 /* Sanity checks */
279 ret = nn_check_initialized(p); EG(ret, err);
280 ret = nn_check_initialized(q); EG(ret, err);
281 ret = nn_check_initialized(g); EG(ret, err);
282 ret = nn_check_initialized(y); EG(ret, err);
283
284 /* Sanity check on the signature length */
285 ret = nn_bitlen(q, &N); EG(ret, err);
286 MUST_HAVE((siglen == (2 * BYTECEIL(N))), ret, err);
287
288 /* Extract r and s */
289 ret = _os2ip(&r, sig, (siglen / 2)); EG(ret, err);
290 ret = _os2ip(&s, sig + (siglen / 2), (siglen / 2)); EG(ret, err);
291
292 /* Return an error if r = 0 or s = 0 */
293 ret = nn_iszero(&r, &iszero); EG(ret, err);
294 MUST_HAVE((!iszero), ret, err);
295 ret = nn_iszero(&s, &iszero); EG(ret, err);
296 MUST_HAVE((!iszero), ret, err);
297 /* Check that 0 < r < q and 0 < s < q */
298 ret = nn_cmp(&r, q, &cmp); EG(ret, err);
299 MUST_HAVE((cmp < 0), ret, err);
300 ret = nn_cmp(&s, q, &cmp); EG(ret, err);
301 MUST_HAVE((cmp < 0), ret, err);
302
303 /* Compute the hash */
304 ret = gen_hash_get_hash_sizes(gostr34_10_94_hash, &hlen, &block_size); EG(ret, err);
305 MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
306 ret = gen_hash_hfunc(msg, msglen, hash, gostr34_10_94_hash); EG(ret, err);
307 /* Reverse the endianness of the hash as little endian is needed here */
308 ret = _reverse_endianness(hash, hlen); EG(ret, err);
309
310 /* z = the leftmost min(N, outlen) bits of Hash(M) */
311 rshift = 0;
312 if ((hlen * 8) > N) {
313 rshift = (bitcnt_t)((hlen * 8) - N);
314 }
315 ret = _os2ip(&z, hash, hlen); EG(ret, err);
316 if (rshift) {
317 ret = nn_rshift_fixedlen(&z, &z, rshift); EG(ret, err);
318 }
319 ret = nn_mod(&z, &z, q); EG(ret, err);
320 /* If z = 0, then set it to 1 */
321 ret = nn_iszero(&z, &iszero); EG(ret, err);
322 if(iszero){
323 ret = nn_one(&z); EG(ret, err);
324 }
325
326 /* Initialize internal variables */
327 ret = nn_init(&v, 0); EG(ret, err);
328 ret = nn_init(&u1, 0); EG(ret, err);
329 ret = nn_init(&u2, 0); EG(ret, err);
330
331 /* Compute v = z ** (q-2) mod (q) in s */
332 ret = nn_dec(&u1, q); EG(ret, err); /* use u1 as temp here */
333 ret = nn_dec(&u1, &u1); EG(ret, err);
334 ret = _nn_mod_pow_insecure(&v, &z, &u1, q); EG(ret, err);
335 /* u1 = (s * v) mod q */
336 ret = nn_mod_mul(&u1, &s, &v, q); EG(ret, err);
337 /* u2 = ((q-r) * v) mod q */
338 ret = nn_sub(&u2, q, &r); EG(ret, err);
339 ret = nn_mod_mul(&u2, &u2, &v, q); EG(ret, err);
340 /* Now compute v = ((g**u1 y**u2) mod p) mod q */
341 /* NOTE: no need to use a secure exponentiation here as we only
342 * manipulate public data.
343 */
344 ret = _nn_mod_pow_insecure(&v, g, &u1, p); EG(ret, err);
345 ret = _nn_mod_pow_insecure(&s, y, &u2, p); EG(ret, err);
346 ret = nn_mod_mul(&v, &v, &s, p); EG(ret, err);
347 ret = nn_mod(&v, &v, q); EG(ret, err);
348
349 /* Check that v = r */
350 ret = nn_cmp(&v, &r, &cmp); EG(ret, err);
351 ret = (cmp != 0) ? -1 : 0;
352
353 err:
354 nn_uninit(&r);
355 nn_uninit(&s);
356 nn_uninit(&z);
357 nn_uninit(&u1);
358 nn_uninit(&u2);
359 nn_uninit(&v);
360
361 PTR_NULLIFY(p);
362 PTR_NULLIFY(q);
363 PTR_NULLIFY(g);
364 PTR_NULLIFY(y);
365
366 return ret;
367 }
368
369 #ifdef GOSTR34_10_94
370 #include <libecc/utils/print_buf.h>
main(int argc,char * argv[])371 int main(int argc, char *argv[])
372 {
373 int ret = 0;
374
375 /**** Self-signed certificate taken from RFC4491 ****/
376 /* NOTE1: we can only perform verification using this self-signed certificate as we do not have the private key!
377 * NOTE2: id-GostR3410-94-CryptoPro-A-ParamSet (values of p, q, g) are extracted from the same RFC
378 */
379 const u8 p[] = {
380 0x00, 0xB4, 0xE2, 0x5E, 0xFB, 0x01, 0x8E, 0x3C, 0x8B, 0x87, 0x50, 0x5E, 0x2A, 0x67, 0x55, 0x3C,
381 0x5E, 0xDC, 0x56, 0xC2, 0x91, 0x4B, 0x7E, 0x4F, 0x89, 0xD2, 0x3F, 0x03, 0xF0, 0x33, 0x77, 0xE7,
382 0x0A, 0x29, 0x03, 0x48, 0x9D, 0xD6, 0x0E, 0x78, 0x41, 0x8D, 0x3D, 0x85, 0x1E, 0xDB, 0x53, 0x17,
383 0xC4, 0x87, 0x1E, 0x40, 0xB0, 0x42, 0x28, 0xC3, 0xB7, 0x90, 0x29, 0x63, 0xC4, 0xB7, 0xD8, 0x5D,
384 0x52, 0xB9, 0xAA, 0x88, 0xF2, 0xAF, 0xDB, 0xEB, 0x28, 0xDA, 0x88, 0x69, 0xD6, 0xDF, 0x84, 0x6A,
385 0x1D, 0x98, 0x92, 0x4E, 0x92, 0x55, 0x61, 0xBD, 0x69, 0x30, 0x0B, 0x9D, 0xDD, 0x05, 0xD2, 0x47,
386 0xB5, 0x92, 0x2D, 0x96, 0x7C, 0xBB, 0x02, 0x67, 0x18, 0x81, 0xC5, 0x7D, 0x10, 0xE5, 0xEF, 0x72,
387 0xD3, 0xE6, 0xDA, 0xD4, 0x22, 0x3D, 0xC8, 0x2A, 0xA1, 0xF7, 0xD0, 0x29, 0x46, 0x51, 0xA4, 0x80,
388 0xDF,
389 };
390
391 const u8 q[] = {
392 0x00, 0x97, 0x24, 0x32, 0xA4, 0x37, 0x17, 0x8B, 0x30, 0xBD, 0x96, 0x19, 0x5B, 0x77, 0x37, 0x89,
393 0xAB, 0x2F, 0xFF, 0x15, 0x59, 0x4B, 0x17, 0x6D, 0xD1, 0x75, 0xB6, 0x32, 0x56, 0xEE, 0x5A, 0xF2,
394 0xCF,
395 };
396
397 const u8 g[] = {
398 0x00, 0x8F, 0xD3, 0x67, 0x31, 0x23, 0x76, 0x54, 0xBB, 0xE4, 0x1F, 0x5F, 0x1F, 0x84, 0x53, 0xE7,
399 0x1C, 0xA4, 0x14, 0xFF, 0xC2, 0x2C, 0x25, 0xD9, 0x15, 0x30, 0x9E, 0x5D, 0x2E, 0x62, 0xA2, 0xA2,
400 0x6C, 0x71, 0x11, 0xF3, 0xFC, 0x79, 0x56, 0x8D, 0xAF, 0xA0, 0x28, 0x04, 0x2F, 0xE1, 0xA5, 0x2A,
401 0x04, 0x89, 0x80, 0x5C, 0x0D, 0xE9, 0xA1, 0xA4, 0x69, 0xC8, 0x44, 0xC7, 0xCA, 0xBB, 0xEE, 0x62,
402 0x5C, 0x30, 0x78, 0x88, 0x8C, 0x1D, 0x85, 0xEE, 0xA8, 0x83, 0xF1, 0xAD, 0x5B, 0xC4, 0xE6, 0x77,
403 0x6E, 0x8E, 0x1A, 0x07, 0x50, 0x91, 0x2D, 0xF6, 0x4F, 0x79, 0x95, 0x64, 0x99, 0xF1, 0xE1, 0x82,
404 0x47, 0x5B, 0x0B, 0x60, 0xE2, 0x63, 0x2A, 0xDC, 0xD8, 0xCF, 0x94, 0xE9, 0xC5, 0x4F, 0xD1, 0xF3,
405 0xB1, 0x09, 0xD8, 0x1F, 0x00, 0xBF, 0x2A, 0xB8, 0xCB, 0x86, 0x2A, 0xDF, 0x7D, 0x40, 0xB9, 0x36,
406 0x9A,
407 };
408
409 u8 x[sizeof(q)];
410
411 u8 y_self_signed[] = {
412 0xBB, 0x84, 0x66, 0xE1, 0x79, 0x9E, 0x5B, 0x34, 0xD8, 0x2C, 0x80, 0x7F, 0x13, 0xA8, 0x19, 0x66,
413 0x71, 0x57, 0xFE, 0x8C, 0x54, 0x25, 0x21, 0x47, 0x6F, 0x30, 0x0B, 0x27, 0x77, 0x46, 0x98, 0xC6,
414 0xFB, 0x47, 0x55, 0xBE, 0xB7, 0xB2, 0xF3, 0x93, 0x6C, 0x39, 0xB5, 0x42, 0x37, 0x26, 0x84, 0xE2,
415 0x0D, 0x10, 0x8A, 0x24, 0x0E, 0x1F, 0x0C, 0x42, 0x4D, 0x2B, 0x3B, 0x11, 0x2B, 0xA8, 0xBF, 0x66,
416 0x39, 0x32, 0x5C, 0x94, 0x8B, 0xC1, 0xA8, 0xFE, 0x1B, 0x63, 0x12, 0xF6, 0x09, 0x25, 0x87, 0xCC,
417 0x75, 0x1B, 0xF4, 0xE5, 0x89, 0x8A, 0x09, 0x82, 0x68, 0xD3, 0x5C, 0x77, 0xA6, 0x0F, 0xB6, 0x90,
418 0x10, 0x13, 0x8D, 0xE3, 0x3E, 0x7C, 0x9C, 0x91, 0xD6, 0xAC, 0x0D, 0x08, 0x2C, 0x3E, 0x78, 0xC1,
419 0xB5, 0xC2, 0xB6, 0xB7, 0x1A, 0xA8, 0x2A, 0x8B, 0x45, 0x81, 0x93, 0x32, 0x32, 0x76, 0xFA, 0x7B,
420 };
421
422 const u8 sig[32*2] = {
423 /* r' */
424 0x22, 0xf7, 0x85, 0xf3, 0x55, 0xbd, 0x94, 0xec, 0x46, 0x91, 0x9c, 0x67, 0xac, 0x58, 0xd7, 0x05, 0x2a, 0xa7,
425 0x8c, 0xb7, 0x85, 0x2a, 0x01, 0x75, 0x85, 0xf7, 0xd7, 0x38, 0x03, 0xfb, 0xcd, 0x43,
426 /* s */
427 0x11, 0xc7, 0x08, 0x7e, 0x12, 0xdc, 0x02, 0xf1, 0x02, 0x23, 0x29, 0x47, 0x76, 0x8f, 0x47, 0x2a, 0x81, 0x83,
428 0x50, 0xe3, 0x07, 0xcc, 0xf2, 0xe4, 0x31, 0x23, 0x89, 0x42, 0xc8, 0x73, 0xe1, 0xde,
429 };
430 u8 check_sig[32*2];
431
432 const u8 msg[] = {
433 0x30, 0x82, 0x01, 0xba, 0x02, 0x10, 0x23, 0x0e, 0xe3, 0x60, 0x46, 0x95,
434 0x24, 0xce, 0xc7, 0x0b, 0xe4, 0x94, 0x18, 0x2e, 0x7e, 0xeb, 0x30, 0x08,
435 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x04, 0x30, 0x69, 0x31, 0x1d,
436 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x47, 0x6f, 0x73,
437 0x74, 0x52, 0x33, 0x34, 0x31, 0x30, 0x2d, 0x39, 0x34, 0x20, 0x65, 0x78,
438 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
439 0x04, 0x0a, 0x0c, 0x09, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x50, 0x72,
440 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
441 0x52, 0x55, 0x31, 0x27, 0x30, 0x25, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
442 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x18, 0x47, 0x6f, 0x73, 0x74, 0x52,
443 0x33, 0x34, 0x31, 0x30, 0x2d, 0x39, 0x34, 0x40, 0x65, 0x78, 0x61, 0x6d,
444 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30,
445 0x35, 0x30, 0x38, 0x31, 0x36, 0x31, 0x32, 0x33, 0x32, 0x35, 0x30, 0x5a,
446 0x17, 0x0d, 0x31, 0x35, 0x30, 0x38, 0x31, 0x36, 0x31, 0x32, 0x33, 0x32,
447 0x35, 0x30, 0x5a, 0x30, 0x69, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55,
448 0x04, 0x03, 0x0c, 0x14, 0x47, 0x6f, 0x73, 0x74, 0x52, 0x33, 0x34, 0x31,
449 0x30, 0x2d, 0x39, 0x34, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
450 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x43,
451 0x72, 0x79, 0x70, 0x74, 0x6f, 0x50, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
452 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x27, 0x30,
453 0x25, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
454 0x16, 0x18, 0x47, 0x6f, 0x73, 0x74, 0x52, 0x33, 0x34, 0x31, 0x30, 0x2d,
455 0x39, 0x34, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63,
456 0x6f, 0x6d, 0x30, 0x81, 0xa5, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03,
457 0x02, 0x02, 0x14, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
458 0x20, 0x02, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x03,
459 0x81, 0x84, 0x00, 0x04, 0x81, 0x80, 0xbb, 0x84, 0x66, 0xe1, 0x79, 0x9e,
460 0x5b, 0x34, 0xd8, 0x2c, 0x80, 0x7f, 0x13, 0xa8, 0x19, 0x66, 0x71, 0x57,
461 0xfe, 0x8c, 0x54, 0x25, 0x21, 0x47, 0x6f, 0x30, 0x0b, 0x27, 0x77, 0x46,
462 0x98, 0xc6, 0xfb, 0x47, 0x55, 0xbe, 0xb7, 0xb2, 0xf3, 0x93, 0x6c, 0x39,
463 0xb5, 0x42, 0x37, 0x26, 0x84, 0xe2, 0x0d, 0x10, 0x8a, 0x24, 0x0e, 0x1f,
464 0x0c, 0x42, 0x4d, 0x2b, 0x3b, 0x11, 0x2b, 0xa8, 0xbf, 0x66, 0x39, 0x32,
465 0x5c, 0x94, 0x8b, 0xc1, 0xa8, 0xfe, 0x1b, 0x63, 0x12, 0xf6, 0x09, 0x25,
466 0x87, 0xcc, 0x75, 0x1b, 0xf4, 0xe5, 0x89, 0x8a, 0x09, 0x82, 0x68, 0xd3,
467 0x5c, 0x77, 0xa6, 0x0f, 0xb6, 0x90, 0x10, 0x13, 0x8d, 0xe3, 0x3e, 0x7c,
468 0x9c, 0x91, 0xd6, 0xac, 0x0d, 0x08, 0x2c, 0x3e, 0x78, 0xc1, 0xb5, 0xc2,
469 0xb6, 0xb7, 0x1a, 0xa8, 0x2a, 0x8b, 0x45, 0x81, 0x93, 0x32, 0x32, 0x76,
470 0xfa, 0x7b
471 };
472
473 gostr34_10_94_pub_key pub;
474 gostr34_10_94_priv_key priv;
475 nn x_;
476 x_.magic = WORD(0);
477
478 FORCE_USED_VAR(argc);
479 FORCE_USED_VAR(argv);
480
481 /* Sanity check on size for GOSTR34_10_94.
482 * NOTE: the double parentheses are here to handle -Wunreachable-code
483 */
484 if((NN_USABLE_MAX_BIT_LEN) < (4096)){
485 ext_printf("Error: you seem to have compiled libecc with usable NN size < 4096, not suitable for GOSTR34_10_94.\n");
486 ext_printf(" => Please recompile libecc with EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\"\n");
487 ext_printf(" This will increase usable NN for proper GOSTR34_10_94 up to 4096 bits.\n");
488 ext_printf(" Then recompile the current examples with the same EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\" flag and execute again!\n");
489 /* NOTE: ret = 0 here to pass self tests even if the library is not compatible */
490 ret = 0;
491 goto err;
492 }
493
494 /* Reverse the endianness of y in place as it is little endian encoded */
495 ret = _reverse_endianness(&y_self_signed[0], sizeof(y_self_signed)); EG(ret, err);
496
497 ret = gostr34_10_94_import_pub_key(&pub, p, sizeof(p), q, sizeof(q), g, sizeof(g), y_self_signed, sizeof(y_self_signed)); EG(ret, err);
498
499 /* Verify the signature */
500 ret = gostr34_10_94_verify(&pub, msg, sizeof(msg), sig, sizeof(sig), HASH_GOST34_11_94_RFC4357);
501 ext_printf("RFC4357 self-signed signature result %d\n", ret);
502
503 /****** Now check the signature procedure *********/
504 /* Get a random private key 0 < x < q */
505 ret = nn_get_random_mod(&x_, &(pub.q)); EG(ret, err);
506 ret = _i2osp(&x_, &x[0], sizeof(x)); EG(ret, err);
507 /* Import the private key */
508 ret = gostr34_10_94_import_priv_key(&priv, p, sizeof(p), q, sizeof(q), g, sizeof(g), x, sizeof(x)); EG(ret, err);
509 /* Compute the public key from the private key */
510 ret = gostr34_10_94_compute_pub_from_priv(&pub, &priv); EG(ret, err);
511 /* Sign the message */
512 ret = gostr34_10_94_sign(&priv, msg, sizeof(msg), NULL, 0, check_sig, sizeof(check_sig), HASH_GOST34_11_94_RFC4357); EG(ret, err);
513 /* Verify the message */
514 ret = gostr34_10_94_verify(&pub, msg, sizeof(msg), check_sig, sizeof(check_sig), HASH_GOST34_11_94_RFC4357);
515 ext_printf("Random signature result %d\n", ret);
516
517 err:
518 nn_uninit(&x_);
519 return ret;
520 }
521 #endif
522