gost2001.c revision 280304
1238384Sjkim/**********************************************************************
2238384Sjkim *                          gost2001.c                                *
3238384Sjkim *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4238384Sjkim *         This file is distributed under the same license as OpenSSL *
5238384Sjkim *                                                                    *
6280304Sjkim *          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
17280304Sjkimextern
18280304Sjkimvoid dump_signature(const char *message, const unsigned char *buffer,
19280304Sjkim                    size_t len);
20238384Sjkimvoid dump_dsa_sig(const char *message, DSA_SIG *sig);
21238384Sjkim#else
22238384Sjkim
23280304Sjkim# define dump_signature(a,b,c)
24280304Sjkim# define dump_dsa_sig(a,b)
25238384Sjkim#endif
26238384Sjkim
27238384Sjkim/*
28238384Sjkim * Fills EC_KEY structure hidden in the app_data field of DSA structure
29238384Sjkim * with parameter information, extracted from parameter array in
30238384Sjkim * params.c file.
31238384Sjkim *
32238384Sjkim * Also fils DSA->q field with copy of EC_GROUP order field to make
33238384Sjkim * DSA_size function work
34280304Sjkim */
35238384Sjkimint fill_GOST2001_params(EC_KEY *eckey, int nid)
36280304Sjkim{
37280304Sjkim    R3410_2001_params *params = R3410_2001_paramset;
38280304Sjkim    EC_GROUP *grp = NULL;
39280304Sjkim    BIGNUM *p = NULL, *q = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL;
40280304Sjkim    EC_POINT *P = NULL;
41280304Sjkim    BN_CTX *ctx = BN_CTX_new();
42280304Sjkim    int ok = 0;
43238384Sjkim
44280304Sjkim    BN_CTX_start(ctx);
45280304Sjkim    p = BN_CTX_get(ctx);
46280304Sjkim    a = BN_CTX_get(ctx);
47280304Sjkim    b = BN_CTX_get(ctx);
48280304Sjkim    x = BN_CTX_get(ctx);
49280304Sjkim    y = BN_CTX_get(ctx);
50280304Sjkim    q = BN_CTX_get(ctx);
51280304Sjkim    while (params->nid != NID_undef && params->nid != nid)
52280304Sjkim        params++;
53280304Sjkim    if (params->nid == NID_undef) {
54280304Sjkim        GOSTerr(GOST_F_FILL_GOST2001_PARAMS,
55280304Sjkim                GOST_R_UNSUPPORTED_PARAMETER_SET);
56280304Sjkim        goto err;
57280304Sjkim    }
58280304Sjkim    BN_hex2bn(&p, params->p);
59280304Sjkim    BN_hex2bn(&a, params->a);
60280304Sjkim    BN_hex2bn(&b, params->b);
61238384Sjkim
62280304Sjkim    grp = EC_GROUP_new_curve_GFp(p, a, b, ctx);
63280304Sjkim
64280304Sjkim    P = EC_POINT_new(grp);
65280304Sjkim
66280304Sjkim    BN_hex2bn(&x, params->x);
67280304Sjkim    BN_hex2bn(&y, params->y);
68280304Sjkim    EC_POINT_set_affine_coordinates_GFp(grp, P, x, y, ctx);
69280304Sjkim    BN_hex2bn(&q, params->q);
70238384Sjkim#ifdef DEBUG_KEYS
71280304Sjkim    fprintf(stderr, "Set params index %d oid %s\nq=",
72280304Sjkim            (params - R3410_2001_paramset), OBJ_nid2sn(params->nid));
73280304Sjkim    BN_print_fp(stderr, q);
74280304Sjkim    fprintf(stderr, "\n");
75280304Sjkim#endif
76238384Sjkim
77280304Sjkim    EC_GROUP_set_generator(grp, P, q, NULL);
78280304Sjkim    EC_GROUP_set_curve_name(grp, params->nid);
79238384Sjkim
80280304Sjkim    EC_KEY_set_group(eckey, grp);
81280304Sjkim    ok = 1;
82280304Sjkim err:
83280304Sjkim    EC_POINT_free(P);
84280304Sjkim    EC_GROUP_free(grp);
85280304Sjkim    BN_CTX_end(ctx);
86280304Sjkim    BN_CTX_free(ctx);
87280304Sjkim    return ok;
88280304Sjkim}
89238384Sjkim
90238384Sjkim/*
91280304Sjkim * Computes gost2001 signature as DSA_SIG structure
92238384Sjkim *
93238384Sjkim *
94280304Sjkim */
95280304SjkimDSA_SIG *gost2001_do_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey)
96280304Sjkim{
97280304Sjkim    DSA_SIG *newsig = NULL;
98280304Sjkim    BIGNUM *md = hashsum2bn(dgst);
99280304Sjkim    BIGNUM *order = NULL;
100280304Sjkim    const EC_GROUP *group;
101280304Sjkim    const BIGNUM *priv_key;
102280304Sjkim    BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k =
103280304Sjkim        NULL, *e = NULL;
104280304Sjkim    EC_POINT *C = NULL;
105280304Sjkim    BN_CTX *ctx = BN_CTX_new();
106280304Sjkim    BN_CTX_start(ctx);
107280304Sjkim    OPENSSL_assert(dlen == 32);
108280304Sjkim    newsig = DSA_SIG_new();
109280304Sjkim    if (!newsig) {
110280304Sjkim        GOSTerr(GOST_F_GOST2001_DO_SIGN, GOST_R_NO_MEMORY);
111280304Sjkim        goto err;
112280304Sjkim    }
113280304Sjkim    group = EC_KEY_get0_group(eckey);
114280304Sjkim    order = BN_CTX_get(ctx);
115280304Sjkim    EC_GROUP_get_order(group, order, ctx);
116280304Sjkim    priv_key = EC_KEY_get0_private_key(eckey);
117280304Sjkim    e = BN_CTX_get(ctx);
118280304Sjkim    BN_mod(e, md, order, ctx);
119238384Sjkim#ifdef DEBUG_SIGN
120280304Sjkim    fprintf(stderr, "digest as bignum=");
121280304Sjkim    BN_print_fp(stderr, md);
122280304Sjkim    fprintf(stderr, "\ndigest mod q=");
123280304Sjkim    BN_print_fp(stderr, e);
124280304Sjkim    fprintf(stderr, "\n");
125280304Sjkim#endif
126280304Sjkim    if (BN_is_zero(e)) {
127280304Sjkim        BN_one(e);
128280304Sjkim    }
129280304Sjkim    k = BN_CTX_get(ctx);
130280304Sjkim    C = EC_POINT_new(group);
131280304Sjkim    do {
132280304Sjkim        do {
133280304Sjkim            if (!BN_rand_range(k, order)) {
134280304Sjkim                GOSTerr(GOST_F_GOST2001_DO_SIGN,
135280304Sjkim                        GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
136280304Sjkim                DSA_SIG_free(newsig);
137280304Sjkim                newsig = NULL;
138280304Sjkim                goto err;
139280304Sjkim            }
140280304Sjkim            if (!EC_POINT_mul(group, C, k, NULL, NULL, ctx)) {
141280304Sjkim                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB);
142280304Sjkim                DSA_SIG_free(newsig);
143280304Sjkim                newsig = NULL;
144280304Sjkim                goto err;
145280304Sjkim            }
146280304Sjkim            if (!X)
147280304Sjkim                X = BN_CTX_get(ctx);
148280304Sjkim            if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) {
149280304Sjkim                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB);
150280304Sjkim                DSA_SIG_free(newsig);
151280304Sjkim                newsig = NULL;
152280304Sjkim                goto err;
153280304Sjkim            }
154280304Sjkim            if (!r)
155280304Sjkim                r = BN_CTX_get(ctx);
156280304Sjkim            BN_nnmod(r, X, order, ctx);
157280304Sjkim        }
158280304Sjkim        while (BN_is_zero(r));
159280304Sjkim        /* s =  (r*priv_key+k*e) mod order */
160280304Sjkim        if (!tmp)
161280304Sjkim            tmp = BN_CTX_get(ctx);
162280304Sjkim        BN_mod_mul(tmp, priv_key, r, order, ctx);
163280304Sjkim        if (!tmp2)
164280304Sjkim            tmp2 = BN_CTX_get(ctx);
165280304Sjkim        BN_mod_mul(tmp2, k, e, order, ctx);
166280304Sjkim        if (!s)
167280304Sjkim            s = BN_CTX_get(ctx);
168280304Sjkim        BN_mod_add(s, tmp, tmp2, order, ctx);
169280304Sjkim    }
170280304Sjkim    while (BN_is_zero(s));
171238384Sjkim
172280304Sjkim    newsig->s = BN_dup(s);
173280304Sjkim    newsig->r = BN_dup(r);
174280304Sjkim err:
175280304Sjkim    BN_CTX_end(ctx);
176280304Sjkim    BN_CTX_free(ctx);
177280304Sjkim    EC_POINT_free(C);
178280304Sjkim    BN_free(md);
179280304Sjkim    return newsig;
180280304Sjkim}
181280304Sjkim
182238384Sjkim/*
183238384Sjkim * Verifies gost 2001 signature
184238384Sjkim *
185280304Sjkim */
186280304Sjkimint gost2001_do_verify(const unsigned char *dgst, int dgst_len,
187280304Sjkim                       DSA_SIG *sig, EC_KEY *ec)
188280304Sjkim{
189280304Sjkim    BN_CTX *ctx = BN_CTX_new();
190280304Sjkim    const EC_GROUP *group = EC_KEY_get0_group(ec);
191280304Sjkim    BIGNUM *order;
192280304Sjkim    BIGNUM *md = NULL, *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 =
193280304Sjkim        NULL;
194280304Sjkim    BIGNUM *X = NULL, *tmp = NULL;
195280304Sjkim    EC_POINT *C = NULL;
196280304Sjkim    const EC_POINT *pub_key = NULL;
197280304Sjkim    int ok = 0;
198238384Sjkim
199280304Sjkim    BN_CTX_start(ctx);
200280304Sjkim    order = BN_CTX_get(ctx);
201280304Sjkim    e = BN_CTX_get(ctx);
202280304Sjkim    z1 = BN_CTX_get(ctx);
203280304Sjkim    z2 = BN_CTX_get(ctx);
204280304Sjkim    tmp = BN_CTX_get(ctx);
205280304Sjkim    X = BN_CTX_get(ctx);
206280304Sjkim    R = BN_CTX_get(ctx);
207280304Sjkim    v = BN_CTX_get(ctx);
208238384Sjkim
209280304Sjkim    EC_GROUP_get_order(group, order, ctx);
210280304Sjkim    pub_key = EC_KEY_get0_public_key(ec);
211280304Sjkim    if (BN_is_zero(sig->s) || BN_is_zero(sig->r) ||
212280304Sjkim        (BN_cmp(sig->s, order) >= 1) || (BN_cmp(sig->r, order) >= 1)) {
213280304Sjkim        GOSTerr(GOST_F_GOST2001_DO_VERIFY,
214280304Sjkim                GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
215280304Sjkim        goto err;
216238384Sjkim
217280304Sjkim    }
218280304Sjkim    md = hashsum2bn(dgst);
219280304Sjkim
220280304Sjkim    BN_mod(e, md, order, ctx);
221238384Sjkim#ifdef DEBUG_SIGN
222280304Sjkim    fprintf(stderr, "digest as bignum: ");
223280304Sjkim    BN_print_fp(stderr, md);
224280304Sjkim    fprintf(stderr, "\ndigest mod q: ");
225280304Sjkim    BN_print_fp(stderr, e);
226280304Sjkim#endif
227280304Sjkim    if (BN_is_zero(e))
228280304Sjkim        BN_one(e);
229280304Sjkim    v = BN_mod_inverse(v, e, order, ctx);
230280304Sjkim    BN_mod_mul(z1, sig->s, v, order, ctx);
231280304Sjkim    BN_sub(tmp, order, sig->r);
232280304Sjkim    BN_mod_mul(z2, tmp, v, order, ctx);
233238384Sjkim#ifdef DEBUG_SIGN
234280304Sjkim    fprintf(stderr, "\nInverted digest value: ");
235280304Sjkim    BN_print_fp(stderr, v);
236280304Sjkim    fprintf(stderr, "\nz1: ");
237280304Sjkim    BN_print_fp(stderr, z1);
238280304Sjkim    fprintf(stderr, "\nz2: ");
239280304Sjkim    BN_print_fp(stderr, z2);
240280304Sjkim#endif
241280304Sjkim    C = EC_POINT_new(group);
242280304Sjkim    if (!EC_POINT_mul(group, C, z1, pub_key, z2, ctx)) {
243280304Sjkim        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB);
244280304Sjkim        goto err;
245280304Sjkim    }
246280304Sjkim    if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) {
247280304Sjkim        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB);
248280304Sjkim        goto err;
249280304Sjkim    }
250280304Sjkim    BN_mod(R, X, order, ctx);
251238384Sjkim#ifdef DEBUG_SIGN
252280304Sjkim    fprintf(stderr, "\nX=");
253280304Sjkim    BN_print_fp(stderr, X);
254280304Sjkim    fprintf(stderr, "\nX mod q=");
255280304Sjkim    BN_print_fp(stderr, R);
256280304Sjkim    fprintf(stderr, "\n");
257280304Sjkim#endif
258280304Sjkim    if (BN_cmp(R, sig->r) != 0) {
259280304Sjkim        GOSTerr(GOST_F_GOST2001_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH);
260280304Sjkim    } else {
261280304Sjkim        ok = 1;
262280304Sjkim    }
263280304Sjkim err:
264280304Sjkim    EC_POINT_free(C);
265280304Sjkim    BN_CTX_end(ctx);
266280304Sjkim    BN_CTX_free(ctx);
267280304Sjkim    BN_free(md);
268280304Sjkim    return ok;
269280304Sjkim}
270280304Sjkim
271238384Sjkim/*
272238384Sjkim * Computes GOST R 34.10-2001 public key
273238384Sjkim *
274238384Sjkim *
275280304Sjkim */
276280304Sjkimint gost2001_compute_public(EC_KEY *ec)
277280304Sjkim{
278280304Sjkim    const EC_GROUP *group = EC_KEY_get0_group(ec);
279280304Sjkim    EC_POINT *pub_key = NULL;
280280304Sjkim    const BIGNUM *priv_key = NULL;
281280304Sjkim    BN_CTX *ctx = NULL;
282280304Sjkim    int ok = 0;
283238384Sjkim
284280304Sjkim    if (!group) {
285280304Sjkim        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,
286280304Sjkim                GOST_R_KEY_IS_NOT_INITIALIZED);
287280304Sjkim        return 0;
288280304Sjkim    }
289280304Sjkim    ctx = BN_CTX_new();
290280304Sjkim    BN_CTX_start(ctx);
291280304Sjkim    if (!(priv_key = EC_KEY_get0_private_key(ec))) {
292280304Sjkim        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
293280304Sjkim        goto err;
294280304Sjkim    }
295238384Sjkim
296280304Sjkim    pub_key = EC_POINT_new(group);
297280304Sjkim    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) {
298280304Sjkim        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
299280304Sjkim        goto err;
300280304Sjkim    }
301280304Sjkim    if (!EC_KEY_set_public_key(ec, pub_key)) {
302280304Sjkim        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
303280304Sjkim        goto err;
304280304Sjkim    }
305280304Sjkim    ok = 256;
306280304Sjkim err:
307280304Sjkim    BN_CTX_end(ctx);
308280304Sjkim    EC_POINT_free(pub_key);
309280304Sjkim    BN_CTX_free(ctx);
310280304Sjkim    return ok;
311280304Sjkim}
312280304Sjkim
313238384Sjkim/*
314280304Sjkim *
315238384Sjkim * Generates GOST R 34.10-2001 keypair
316238384Sjkim *
317238384Sjkim *
318280304Sjkim */
319238384Sjkimint gost2001_keygen(EC_KEY *ec)
320280304Sjkim{
321280304Sjkim    BIGNUM *order = BN_new(), *d = BN_new();
322280304Sjkim    const EC_GROUP *group = EC_KEY_get0_group(ec);
323280304Sjkim    EC_GROUP_get_order(group, order, NULL);
324238384Sjkim
325280304Sjkim    do {
326280304Sjkim        if (!BN_rand_range(d, order)) {
327280304Sjkim            GOSTerr(GOST_F_GOST2001_KEYGEN,
328280304Sjkim                    GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
329280304Sjkim            BN_free(d);
330280304Sjkim            BN_free(order);
331280304Sjkim            return 0;
332280304Sjkim        }
333280304Sjkim    }
334280304Sjkim    while (BN_is_zero(d));
335280304Sjkim    EC_KEY_set_private_key(ec, d);
336280304Sjkim    BN_free(d);
337280304Sjkim    BN_free(order);
338280304Sjkim    return gost2001_compute_public(ec);
339280304Sjkim}
340