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