gost2001.c revision 238384
1238384Sjkim/**********************************************************************
2238384Sjkim *                          gost2001.c                                *
3238384Sjkim *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4238384Sjkim *         This file is distributed under the same license as OpenSSL *
5238384Sjkim *                                                                    *
6238384Sjkim *          Implementation of GOST R 34.10-2001      				  *
7238384Sjkim *          Requires OpenSSL 0.9.9 for compilation                    *
8238384Sjkim **********************************************************************/
9238384Sjkim#include "gost_lcl.h"
10238384Sjkim#include "gost_params.h"
11238384Sjkim#include <string.h>
12238384Sjkim#include <openssl/rand.h>
13238384Sjkim#include <openssl/ecdsa.h>
14238384Sjkim#include <openssl/err.h>
15238384Sjkim#include "e_gost_err.h"
16238384Sjkim#ifdef DEBUG_SIGN
17238384Sjkimextern
18238384Sjkimvoid dump_signature(const char *message,const unsigned char *buffer,size_t len);
19238384Sjkimvoid dump_dsa_sig(const char *message, DSA_SIG *sig);
20238384Sjkim#else
21238384Sjkim
22238384Sjkim#define dump_signature(a,b,c)
23238384Sjkim#define dump_dsa_sig(a,b)
24238384Sjkim#endif
25238384Sjkim
26238384Sjkim/*
27238384Sjkim * Fills EC_KEY structure hidden in the app_data field of DSA structure
28238384Sjkim * with parameter information, extracted from parameter array in
29238384Sjkim * params.c file.
30238384Sjkim *
31238384Sjkim * Also fils DSA->q field with copy of EC_GROUP order field to make
32238384Sjkim * DSA_size function work
33238384Sjkim */
34238384Sjkimint fill_GOST2001_params(EC_KEY *eckey, int nid)
35238384Sjkim	{
36238384Sjkim	R3410_2001_params *params = R3410_2001_paramset;
37238384Sjkim	EC_GROUP *grp=NULL;
38238384Sjkim	BIGNUM *p=NULL,*q=NULL,*a=NULL,*b=NULL,*x=NULL,*y=NULL;
39238384Sjkim	EC_POINT *P=NULL;
40238384Sjkim	BN_CTX *ctx=BN_CTX_new();
41238384Sjkim	int ok=0;
42238384Sjkim
43238384Sjkim	BN_CTX_start(ctx);
44238384Sjkim	p=BN_CTX_get(ctx);
45238384Sjkim	a=BN_CTX_get(ctx);
46238384Sjkim	b=BN_CTX_get(ctx);
47238384Sjkim	x=BN_CTX_get(ctx);
48238384Sjkim	y=BN_CTX_get(ctx);
49238384Sjkim	q=BN_CTX_get(ctx);
50238384Sjkim	while (params->nid!=NID_undef && params->nid != nid) params++;
51238384Sjkim	if (params->nid == NID_undef)
52238384Sjkim		{
53238384Sjkim		GOSTerr(GOST_F_FILL_GOST2001_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET);
54238384Sjkim		goto err;
55238384Sjkim		}
56238384Sjkim	BN_hex2bn(&p,params->p);
57238384Sjkim	BN_hex2bn(&a,params->a);
58238384Sjkim	BN_hex2bn(&b,params->b);
59238384Sjkim
60238384Sjkim	grp = EC_GROUP_new_curve_GFp(p,a,b,ctx);
61238384Sjkim
62238384Sjkim	P = EC_POINT_new(grp);
63238384Sjkim
64238384Sjkim	BN_hex2bn(&x,params->x);
65238384Sjkim	BN_hex2bn(&y,params->y);
66238384Sjkim	EC_POINT_set_affine_coordinates_GFp(grp,P,x,y,ctx);
67238384Sjkim	BN_hex2bn(&q,params->q);
68238384Sjkim#ifdef DEBUG_KEYS
69238384Sjkim	fprintf(stderr,"Set params index %d oid %s\nq=",
70238384Sjkim		(params-R3410_2001_paramset),OBJ_nid2sn(params->nid));
71238384Sjkim	BN_print_fp(stderr,q);
72238384Sjkim	fprintf(stderr,"\n");
73238384Sjkim#endif
74238384Sjkim
75238384Sjkim	EC_GROUP_set_generator(grp,P,q,NULL);
76238384Sjkim	EC_GROUP_set_curve_name(grp,params->nid);
77238384Sjkim
78238384Sjkim	EC_KEY_set_group(eckey,grp);
79238384Sjkim	ok=1;
80238384Sjkim	err:
81238384Sjkim	EC_POINT_free(P);
82238384Sjkim	EC_GROUP_free(grp);
83238384Sjkim	BN_CTX_end(ctx);
84238384Sjkim	BN_CTX_free(ctx);
85238384Sjkim	return ok;
86238384Sjkim	}
87238384Sjkim
88238384Sjkim
89238384Sjkim/*
90238384Sjkim * Computes gost2001 signature as DSA_SIG structure
91238384Sjkim *
92238384Sjkim *
93238384Sjkim */
94238384SjkimDSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey)
95238384Sjkim	{
96238384Sjkim	DSA_SIG *newsig = NULL;
97238384Sjkim	BIGNUM *md = hashsum2bn(dgst);
98238384Sjkim	BIGNUM *order = NULL;
99238384Sjkim	const EC_GROUP *group;
100238384Sjkim	const BIGNUM *priv_key;
101238384Sjkim	BIGNUM *r=NULL,*s=NULL,*X=NULL,*tmp=NULL,*tmp2=NULL, *k=NULL,*e=NULL;
102238384Sjkim	EC_POINT *C=NULL;
103238384Sjkim	BN_CTX *ctx = BN_CTX_new();
104238384Sjkim	BN_CTX_start(ctx);
105238384Sjkim	OPENSSL_assert(dlen==32);
106238384Sjkim	newsig=DSA_SIG_new();
107238384Sjkim	if (!newsig)
108238384Sjkim		{
109238384Sjkim		GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_NO_MEMORY);
110238384Sjkim		goto err;
111238384Sjkim		}
112238384Sjkim	group = EC_KEY_get0_group(eckey);
113238384Sjkim	order=BN_CTX_get(ctx);
114238384Sjkim	EC_GROUP_get_order(group,order,ctx);
115238384Sjkim	priv_key = EC_KEY_get0_private_key(eckey);
116238384Sjkim	e = BN_CTX_get(ctx);
117238384Sjkim	BN_mod(e,md,order,ctx);
118238384Sjkim#ifdef DEBUG_SIGN
119238384Sjkim	fprintf(stderr,"digest as bignum=");
120238384Sjkim	BN_print_fp(stderr,md);
121238384Sjkim	fprintf(stderr,"\ndigest mod q=");
122238384Sjkim	BN_print_fp(stderr,e);
123238384Sjkim	fprintf(stderr,"\n");
124238384Sjkim#endif
125238384Sjkim	if (BN_is_zero(e))
126238384Sjkim		{
127238384Sjkim		BN_one(e);
128238384Sjkim		}
129238384Sjkim	k =BN_CTX_get(ctx);
130238384Sjkim	C=EC_POINT_new(group);
131238384Sjkim	do
132238384Sjkim		{
133238384Sjkim		do
134238384Sjkim			{
135238384Sjkim			if (!BN_rand_range(k,order))
136238384Sjkim				{
137238384Sjkim				GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
138238384Sjkim				DSA_SIG_free(newsig);
139238384Sjkim				newsig = NULL;
140238384Sjkim				goto err;
141238384Sjkim				}
142238384Sjkim			if (!EC_POINT_mul(group,C,k,NULL,NULL,ctx))
143238384Sjkim				{
144238384Sjkim				GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB);
145238384Sjkim				DSA_SIG_free(newsig);
146238384Sjkim				newsig = NULL;
147238384Sjkim				goto err;
148238384Sjkim				}
149238384Sjkim			if (!X) X=BN_CTX_get(ctx);
150238384Sjkim			if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx))
151238384Sjkim				{
152238384Sjkim				GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB);
153238384Sjkim				DSA_SIG_free(newsig);
154238384Sjkim				newsig = NULL;
155238384Sjkim				goto err;
156238384Sjkim				}
157238384Sjkim			if (!r) r=BN_CTX_get(ctx);
158238384Sjkim			BN_nnmod(r,X,order,ctx);
159238384Sjkim			}
160238384Sjkim		while (BN_is_zero(r));
161238384Sjkim		/* s =  (r*priv_key+k*e) mod order */
162238384Sjkim		if (!tmp) tmp = BN_CTX_get(ctx);
163238384Sjkim		BN_mod_mul(tmp,priv_key,r,order,ctx);
164238384Sjkim		if (!tmp2) tmp2 = BN_CTX_get(ctx);
165238384Sjkim		BN_mod_mul(tmp2,k,e,order,ctx);
166238384Sjkim		if (!s) s=BN_CTX_get(ctx);
167238384Sjkim		BN_mod_add(s,tmp,tmp2,order,ctx);
168238384Sjkim		}
169238384Sjkim	while (BN_is_zero(s));
170238384Sjkim
171238384Sjkim	newsig->s=BN_dup(s);
172238384Sjkim	newsig->r=BN_dup(r);
173238384Sjkim	err:
174238384Sjkim	BN_CTX_end(ctx);
175238384Sjkim	BN_CTX_free(ctx);
176238384Sjkim	EC_POINT_free(C);
177238384Sjkim	BN_free(md);
178238384Sjkim	return newsig;
179238384Sjkim	}
180238384Sjkim/*
181238384Sjkim * Verifies gost 2001 signature
182238384Sjkim *
183238384Sjkim */
184238384Sjkimint gost2001_do_verify(const unsigned char *dgst,int dgst_len,
185238384Sjkim	DSA_SIG *sig, EC_KEY *ec)
186238384Sjkim	{
187238384Sjkim	BN_CTX *ctx=BN_CTX_new();
188238384Sjkim	const EC_GROUP *group = EC_KEY_get0_group(ec);
189238384Sjkim	BIGNUM *order;
190238384Sjkim	BIGNUM *md = NULL,*e=NULL,*R=NULL,*v=NULL,*z1=NULL,*z2=NULL;
191238384Sjkim	BIGNUM *X=NULL,*tmp=NULL;
192238384Sjkim	EC_POINT *C = NULL;
193238384Sjkim	const EC_POINT *pub_key=NULL;
194238384Sjkim	int ok=0;
195238384Sjkim
196238384Sjkim	BN_CTX_start(ctx);
197238384Sjkim	order = BN_CTX_get(ctx);
198238384Sjkim	e = BN_CTX_get(ctx);
199238384Sjkim	z1 = BN_CTX_get(ctx);
200238384Sjkim	z2 = BN_CTX_get(ctx);
201238384Sjkim	tmp = BN_CTX_get(ctx);
202238384Sjkim	X= BN_CTX_get(ctx);
203238384Sjkim	R=BN_CTX_get(ctx);
204238384Sjkim	v=BN_CTX_get(ctx);
205238384Sjkim
206238384Sjkim	EC_GROUP_get_order(group,order,ctx);
207238384Sjkim	pub_key = EC_KEY_get0_public_key(ec);
208238384Sjkim	if (BN_is_zero(sig->s) || BN_is_zero(sig->r) ||
209238384Sjkim		(BN_cmp(sig->s,order)>=1) || (BN_cmp(sig->r,order)>=1))
210238384Sjkim		{
211238384Sjkim		GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
212238384Sjkim		goto err;
213238384Sjkim
214238384Sjkim		}
215238384Sjkim	md = hashsum2bn(dgst);
216238384Sjkim
217238384Sjkim	BN_mod(e,md,order,ctx);
218238384Sjkim#ifdef DEBUG_SIGN
219238384Sjkim	fprintf(stderr,"digest as bignum: ");
220238384Sjkim	BN_print_fp(stderr,md);
221238384Sjkim	fprintf(stderr,"\ndigest mod q: ");
222238384Sjkim	BN_print_fp(stderr,e);
223238384Sjkim#endif
224238384Sjkim	if (BN_is_zero(e)) BN_one(e);
225238384Sjkim	v=BN_mod_inverse(v,e,order,ctx);
226238384Sjkim	BN_mod_mul(z1,sig->s,v,order,ctx);
227238384Sjkim	BN_sub(tmp,order,sig->r);
228238384Sjkim	BN_mod_mul(z2,tmp,v,order,ctx);
229238384Sjkim#ifdef DEBUG_SIGN
230238384Sjkim	fprintf(stderr,"\nInverted digest value: ");
231238384Sjkim	BN_print_fp(stderr,v);
232238384Sjkim	fprintf(stderr,"\nz1: ");
233238384Sjkim	BN_print_fp(stderr,z1);
234238384Sjkim	fprintf(stderr,"\nz2: ");
235238384Sjkim	BN_print_fp(stderr,z2);
236238384Sjkim#endif
237238384Sjkim	C = EC_POINT_new(group);
238238384Sjkim	if (!EC_POINT_mul(group,C,z1,pub_key,z2,ctx))
239238384Sjkim		{
240238384Sjkim		GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB);
241238384Sjkim		goto err;
242238384Sjkim		}
243238384Sjkim	if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx))
244238384Sjkim		{
245238384Sjkim		GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB);
246238384Sjkim		goto err;
247238384Sjkim		}
248238384Sjkim	BN_mod(R,X,order,ctx);
249238384Sjkim#ifdef DEBUG_SIGN
250238384Sjkim	fprintf(stderr,"\nX=");
251238384Sjkim	BN_print_fp(stderr,X);
252238384Sjkim	fprintf(stderr,"\nX mod q=");
253238384Sjkim	BN_print_fp(stderr,R);
254238384Sjkim	fprintf(stderr,"\n");
255238384Sjkim#endif
256238384Sjkim	if (BN_cmp(R,sig->r)!=0)
257238384Sjkim		{
258238384Sjkim		GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH);
259238384Sjkim		}
260238384Sjkim	else
261238384Sjkim		{
262238384Sjkim		ok = 1;
263238384Sjkim		}
264238384Sjkim	err:
265238384Sjkim	EC_POINT_free(C);
266238384Sjkim	BN_CTX_end(ctx);
267238384Sjkim	BN_CTX_free(ctx);
268238384Sjkim	BN_free(md);
269238384Sjkim	return ok;
270238384Sjkim	}
271238384Sjkim/*
272238384Sjkim * Computes GOST R 34.10-2001 public key
273238384Sjkim *
274238384Sjkim *
275238384Sjkim */
276238384Sjkimint gost2001_compute_public(EC_KEY *ec)
277238384Sjkim	{
278238384Sjkim	const EC_GROUP *group = EC_KEY_get0_group(ec);
279238384Sjkim	EC_POINT *pub_key=NULL;
280238384Sjkim	const BIGNUM *priv_key=NULL;
281238384Sjkim	BN_CTX *ctx=NULL;
282238384Sjkim	int ok=0;
283238384Sjkim
284238384Sjkim	if (!group)
285238384Sjkim		{
286238384Sjkim		GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITIALIZED);
287238384Sjkim		return 0;
288238384Sjkim		}
289238384Sjkim	ctx=BN_CTX_new();
290238384Sjkim	BN_CTX_start(ctx);
291238384Sjkim	if (!(priv_key=EC_KEY_get0_private_key(ec)))
292238384Sjkim		{
293238384Sjkim		GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
294238384Sjkim		goto err;
295238384Sjkim		}
296238384Sjkim
297238384Sjkim	pub_key = EC_POINT_new(group);
298238384Sjkim	if (!EC_POINT_mul(group,pub_key,priv_key,NULL,NULL,ctx))
299238384Sjkim		{
300238384Sjkim		GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
301238384Sjkim		goto err;
302238384Sjkim		}
303238384Sjkim	if (!EC_KEY_set_public_key(ec,pub_key))
304238384Sjkim		{
305238384Sjkim		GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
306238384Sjkim		goto err;
307238384Sjkim		}
308238384Sjkim	ok = 256;
309238384Sjkim	err:
310238384Sjkim	BN_CTX_end(ctx);
311238384Sjkim	EC_POINT_free(pub_key);
312238384Sjkim	BN_CTX_free(ctx);
313238384Sjkim	return ok;
314238384Sjkim	}
315238384Sjkim/*
316238384Sjkim *
317238384Sjkim * Generates GOST R 34.10-2001 keypair
318238384Sjkim *
319238384Sjkim *
320238384Sjkim */
321238384Sjkimint gost2001_keygen(EC_KEY *ec)
322238384Sjkim	{
323238384Sjkim	BIGNUM *order = BN_new(),*d=BN_new();
324238384Sjkim	const EC_GROUP *group = EC_KEY_get0_group(ec);
325238384Sjkim	EC_GROUP_get_order(group,order,NULL);
326238384Sjkim
327238384Sjkim	do
328238384Sjkim		{
329238384Sjkim		if (!BN_rand_range(d,order))
330238384Sjkim			{
331238384Sjkim			GOSTerr(GOST_F_GOST2001_KEYGEN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
332238384Sjkim			BN_free(d);
333238384Sjkim			BN_free(order);
334238384Sjkim			return 0;
335238384Sjkim			}
336238384Sjkim		}
337238384Sjkim	while (BN_is_zero(d));
338238384Sjkim	EC_KEY_set_private_key(ec,d);
339238384Sjkim	BN_free(d);
340238384Sjkim	BN_free(order);
341238384Sjkim	return gost2001_compute_public(ec);
342238384Sjkim	}
343238384Sjkim
344