]>
Commit | Line | Data |
---|---|---|
a04549cc DSH |
1 | /********************************************************************** |
2 | * gost_sign.c * | |
3 | * Copyright (c) 2005-2006 Cryptocom LTD * | |
4 | * This file is distributed under the same license as OpenSSL * | |
5 | * * | |
8711efb4 | 6 | * Implementation of GOST R 34.10-94 signature algorithm * |
a04549cc DSH |
7 | * for OpenSSL * |
8 | * Requires OpenSSL 0.9.9 for compilation * | |
9 | **********************************************************************/ | |
10 | #include <string.h> | |
11 | #include <openssl/rand.h> | |
12 | #include <openssl/bn.h> | |
13 | #include <openssl/dsa.h> | |
f50ffd10 | 14 | #include <openssl/err.h> |
a04549cc DSH |
15 | #include <openssl/evp.h> |
16 | ||
926c41bd DSH |
17 | #include "gost_params.h" |
18 | #include "gost_lcl.h" | |
a04549cc DSH |
19 | #include "e_gost_err.h" |
20 | ||
926c41bd | 21 | #ifdef DEBUG_SIGN |
0f113f3e MC |
22 | void dump_signature(const char *message, const unsigned char *buffer, |
23 | size_t len) | |
24 | { | |
25 | size_t i; | |
26 | fprintf(stderr, "signature %s Length=%d", message, len); | |
27 | for (i = 0; i < len; i++) { | |
28 | if (i % 16 == 0) | |
29 | fputc('\n', stderr); | |
30 | fprintf(stderr, " %02x", buffer[i]); | |
31 | } | |
32 | fprintf(stderr, "\nEnd of signature\n"); | |
33 | } | |
a04549cc | 34 | |
926c41bd | 35 | void dump_dsa_sig(const char *message, DSA_SIG *sig) |
0f113f3e MC |
36 | { |
37 | fprintf(stderr, "%s\nR=", message); | |
38 | BN_print_fp(stderr, sig->r); | |
39 | fprintf(stderr, "\nS="); | |
40 | BN_print_fp(stderr, sig->s); | |
41 | fprintf(stderr, "\n"); | |
42 | } | |
a04549cc DSH |
43 | |
44 | #else | |
45 | ||
0f113f3e MC |
46 | # define dump_signature(a,b,c) |
47 | # define dump_dsa_sig(a,b) | |
a04549cc DSH |
48 | #endif |
49 | ||
50 | /* | |
51 | * Computes signature and returns it as DSA_SIG structure | |
52 | */ | |
0f113f3e MC |
53 | DSA_SIG *gost_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) |
54 | { | |
55 | BIGNUM *k = NULL, *tmp = NULL, *tmp2 = NULL; | |
56 | DSA_SIG *newsig = DSA_SIG_new(); | |
57 | BIGNUM *md = hashsum2bn(dgst); | |
58 | /* check if H(M) mod q is zero */ | |
59 | BN_CTX *ctx = BN_CTX_new(); | |
60 | BN_CTX_start(ctx); | |
61 | if (!newsig) { | |
62 | GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE); | |
63 | goto err; | |
64 | } | |
65 | tmp = BN_CTX_get(ctx); | |
66 | k = BN_CTX_get(ctx); | |
67 | tmp2 = BN_CTX_get(ctx); | |
68 | BN_mod(tmp, md, dsa->q, ctx); | |
69 | if (BN_is_zero(tmp)) { | |
70 | BN_one(md); | |
71 | } | |
72 | do { | |
73 | do { | |
74 | /* | |
75 | * Generate random number k less than q | |
76 | */ | |
77 | BN_rand_range(k, dsa->q); | |
78 | /* generate r = (a^x mod p) mod q */ | |
79 | BN_mod_exp(tmp, dsa->g, k, dsa->p, ctx); | |
80 | if (!(newsig->r)) | |
81 | newsig->r = BN_new(); | |
82 | BN_mod(newsig->r, tmp, dsa->q, ctx); | |
83 | } | |
84 | while (BN_is_zero(newsig->r)); | |
85 | /* generate s = (xr + k(Hm)) mod q */ | |
86 | BN_mod_mul(tmp, dsa->priv_key, newsig->r, dsa->q, ctx); | |
87 | BN_mod_mul(tmp2, k, md, dsa->q, ctx); | |
88 | if (!newsig->s) | |
89 | newsig->s = BN_new(); | |
90 | BN_mod_add(newsig->s, tmp, tmp2, dsa->q, ctx); | |
91 | } | |
92 | while (BN_is_zero(newsig->s)); | |
93 | err: | |
94 | BN_free(md); | |
95 | BN_CTX_end(ctx); | |
96 | BN_CTX_free(ctx); | |
97 | return newsig; | |
98 | } | |
a04549cc DSH |
99 | |
100 | /* | |
101 | * Packs signature according to Cryptocom rules | |
102 | * and frees up DSA_SIG structure | |
103 | */ | |
1d97c843 | 104 | /*- |
926c41bd | 105 | int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, size_t *siglen) |
0f113f3e MC |
106 | { |
107 | *siglen = 2*order; | |
108 | memset(sig,0,*siglen); | |
109 | store_bignum(s->r, sig,order); | |
110 | store_bignum(s->s, sig + order,order); | |
111 | dump_signature("serialized",sig,*siglen); | |
112 | DSA_SIG_free(s); | |
113 | return 1; | |
114 | } | |
10f0c85c | 115 | */ |
a04549cc DSH |
116 | /* |
117 | * Packs signature according to Cryptopro rules | |
118 | * and frees up DSA_SIG structure | |
119 | */ | |
0f113f3e MC |
120 | int pack_sign_cp(DSA_SIG *s, int order, unsigned char *sig, size_t *siglen) |
121 | { | |
122 | *siglen = 2 * order; | |
123 | memset(sig, 0, *siglen); | |
124 | store_bignum(s->s, sig, order); | |
125 | store_bignum(s->r, sig + order, order); | |
126 | dump_signature("serialized", sig, *siglen); | |
127 | DSA_SIG_free(s); | |
128 | return 1; | |
129 | } | |
a04549cc DSH |
130 | |
131 | /* | |
132 | * Verifies signature passed as DSA_SIG structure | |
133 | * | |
926c41bd | 134 | */ |
a04549cc DSH |
135 | |
136 | int gost_do_verify(const unsigned char *dgst, int dgst_len, | |
0f113f3e MC |
137 | DSA_SIG *sig, DSA *dsa) |
138 | { | |
139 | BIGNUM *md, *tmp = NULL; | |
140 | BIGNUM *q2 = NULL; | |
141 | BIGNUM *u = NULL, *v = NULL, *z1 = NULL, *z2 = NULL; | |
142 | BIGNUM *tmp2 = NULL, *tmp3 = NULL; | |
143 | int ok; | |
144 | BN_CTX *ctx = BN_CTX_new(); | |
145 | ||
146 | BN_CTX_start(ctx); | |
147 | if (BN_cmp(sig->s, dsa->q) >= 1 || BN_cmp(sig->r, dsa->q) >= 1) { | |
148 | GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); | |
149 | return 0; | |
150 | } | |
151 | md = hashsum2bn(dgst); | |
152 | ||
153 | tmp = BN_CTX_get(ctx); | |
154 | v = BN_CTX_get(ctx); | |
155 | q2 = BN_CTX_get(ctx); | |
156 | z1 = BN_CTX_get(ctx); | |
157 | z2 = BN_CTX_get(ctx); | |
158 | tmp2 = BN_CTX_get(ctx); | |
159 | tmp3 = BN_CTX_get(ctx); | |
160 | u = BN_CTX_get(ctx); | |
a04549cc | 161 | |
0f113f3e MC |
162 | BN_mod(tmp, md, dsa->q, ctx); |
163 | if (BN_is_zero(tmp)) { | |
164 | BN_one(md); | |
165 | } | |
166 | BN_copy(q2, dsa->q); | |
167 | BN_sub_word(q2, 2); | |
168 | BN_mod_exp(v, md, q2, dsa->q, ctx); | |
169 | BN_mod_mul(z1, sig->s, v, dsa->q, ctx); | |
170 | BN_sub(tmp, dsa->q, sig->r); | |
171 | BN_mod_mul(z2, tmp, v, dsa->p, ctx); | |
172 | BN_mod_exp(tmp, dsa->g, z1, dsa->p, ctx); | |
173 | BN_mod_exp(tmp2, dsa->pub_key, z2, dsa->p, ctx); | |
174 | BN_mod_mul(tmp3, tmp, tmp2, dsa->p, ctx); | |
175 | BN_mod(u, tmp3, dsa->q, ctx); | |
176 | ok = BN_cmp(u, sig->r); | |
177 | ||
178 | BN_free(md); | |
179 | BN_CTX_end(ctx); | |
180 | BN_CTX_free(ctx); | |
181 | if (ok != 0) { | |
182 | GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH); | |
183 | } | |
184 | return (ok == 0); | |
185 | } | |
a04549cc DSH |
186 | |
187 | /* | |
188 | * Computes public keys for GOST R 34.10-94 algorithm | |
926c41bd | 189 | * |
a04549cc DSH |
190 | */ |
191 | int gost94_compute_public(DSA *dsa) | |
0f113f3e MC |
192 | { |
193 | /* Now fill algorithm parameters with correct values */ | |
194 | BN_CTX *ctx = BN_CTX_new(); | |
195 | if (!dsa->g) { | |
196 | GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, GOST_R_KEY_IS_NOT_INITALIZED); | |
197 | return 0; | |
198 | } | |
199 | /* Compute public key y = a^x mod p */ | |
200 | dsa->pub_key = BN_new(); | |
201 | BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx); | |
202 | BN_CTX_free(ctx); | |
203 | return 1; | |
204 | } | |
a04549cc DSH |
205 | |
206 | /* | |
207 | * Fill GOST 94 params, searching them in R3410_paramset array | |
208 | * by nid of paramset | |
926c41bd DSH |
209 | * |
210 | */ | |
0f113f3e MC |
211 | int fill_GOST94_params(DSA *dsa, int nid) |
212 | { | |
213 | R3410_params *params = R3410_paramset; | |
214 | while (params->nid != NID_undef && params->nid != nid) | |
215 | params++; | |
216 | if (params->nid == NID_undef) { | |
217 | GOSTerr(GOST_F_FILL_GOST94_PARAMS, GOST_R_UNSUPPORTED_PARAMETER_SET); | |
218 | return 0; | |
219 | } | |
a04549cc | 220 | #define dump_signature(a,b,c) |
0f113f3e MC |
221 | if (dsa->p) { |
222 | BN_free(dsa->p); | |
223 | } | |
224 | dsa->p = NULL; | |
225 | BN_dec2bn(&(dsa->p), params->p); | |
226 | if (dsa->q) { | |
227 | BN_free(dsa->q); | |
228 | } | |
229 | dsa->q = NULL; | |
230 | BN_dec2bn(&(dsa->q), params->q); | |
231 | if (dsa->g) { | |
232 | BN_free(dsa->g); | |
233 | } | |
234 | dsa->g = NULL; | |
235 | BN_dec2bn(&(dsa->g), params->a); | |
236 | return 1; | |
237 | } | |
a04549cc DSH |
238 | |
239 | /* | |
240 | * Generate GOST R 34.10-94 keypair | |
a04549cc | 241 | * |
926c41bd DSH |
242 | * |
243 | */ | |
244 | int gost_sign_keygen(DSA *dsa) | |
0f113f3e MC |
245 | { |
246 | dsa->priv_key = BN_new(); | |
247 | BN_rand_range(dsa->priv_key, dsa->q); | |
248 | return gost94_compute_public(dsa); | |
249 | } | |
926c41bd | 250 | |
a04549cc | 251 | /* Unpack signature according to cryptocom rules */ |
1d97c843 | 252 | /*- |
926c41bd | 253 | DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) |
0f113f3e MC |
254 | { |
255 | DSA_SIG *s; | |
256 | s = DSA_SIG_new(); | |
257 | if (s == NULL) | |
258 | { | |
259 | GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,ERR_R_MALLOC_FAILURE); | |
260 | return(NULL); | |
261 | } | |
262 | s->r = getbnfrombuf(sig, siglen/2); | |
263 | s->s = getbnfrombuf(sig + siglen/2, siglen/2); | |
264 | return s; | |
265 | } | |
10f0c85c | 266 | */ |
a04549cc | 267 | /* Unpack signature according to cryptopro rules */ |
0f113f3e MC |
268 | DSA_SIG *unpack_cp_signature(const unsigned char *sig, size_t siglen) |
269 | { | |
270 | DSA_SIG *s; | |
a04549cc | 271 | |
0f113f3e MC |
272 | s = DSA_SIG_new(); |
273 | if (s == NULL) { | |
274 | GOSTerr(GOST_F_UNPACK_CP_SIGNATURE, ERR_R_MALLOC_FAILURE); | |
275 | return NULL; | |
276 | } | |
277 | s->s = getbnfrombuf(sig, siglen / 2); | |
278 | s->r = getbnfrombuf(sig + siglen / 2, siglen / 2); | |
279 | return s; | |
280 | } | |
926c41bd | 281 | |
a04549cc | 282 | /* Convert little-endian byte array into bignum */ |
926c41bd | 283 | BIGNUM *hashsum2bn(const unsigned char *dgst) |
0f113f3e MC |
284 | { |
285 | unsigned char buf[32]; | |
286 | int i; | |
287 | for (i = 0; i < 32; i++) { | |
288 | buf[31 - i] = dgst[i]; | |
289 | } | |
290 | return getbnfrombuf(buf, 32); | |
291 | } | |
a04549cc DSH |
292 | |
293 | /* Convert byte buffer to bignum, skipping leading zeros*/ | |
0f113f3e MC |
294 | BIGNUM *getbnfrombuf(const unsigned char *buf, size_t len) |
295 | { | |
296 | while (*buf == 0 && len > 0) { | |
297 | buf++; | |
298 | len--; | |
299 | } | |
300 | if (len) { | |
301 | return BN_bin2bn(buf, len, NULL); | |
302 | } else { | |
303 | BIGNUM *b = BN_new(); | |
304 | BN_zero(b); | |
305 | return b; | |
306 | } | |
307 | } | |
926c41bd | 308 | |
0f113f3e MC |
309 | /* |
310 | * Pack bignum into byte buffer of given size, filling all leading bytes by | |
311 | * zeros | |
312 | */ | |
313 | int store_bignum(BIGNUM *bn, unsigned char *buf, int len) | |
314 | { | |
315 | int bytes = BN_num_bytes(bn); | |
316 | if (bytes > len) | |
317 | return 0; | |
318 | memset(buf, 0, len); | |
319 | BN_bn2bin(bn, buf + len - bytes); | |
320 | return 1; | |
321 | } |