Implementation of the Digital Signature Algorithm.
[u/mdw/catacomb] / dsa-gen.c
CommitLineData
8b810a45 1/* -*-c-*-
2 *
3 * $Id: dsa-gen.c,v 1.1 1999/11/19 19:28:00 mdw Exp $
4 *
5 * Generate DSA shared parameters
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: dsa-gen.c,v $
33 * Revision 1.1 1999/11/19 19:28:00 mdw
34 * Implementation of the Digital Signature Algorithm.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <stdio.h>
41#include <stdlib.h>
42
43#include "dsa.h"
44#include "mp.h"
45#include "pgen.h"
46#include "rabin.h"
47#include "rc4.h"
48#include "sha.h"
49
50/*----- Main code ---------------------------------------------------------*/
51
52/* --- @dsa_seed@ --- *
53 *
54 * Arguments: @dsa_param *dp@ = where to store parameters
55 * @unsigned l@ = bitlength of @p@ in bits
56 * @const void *k@ = pointer to key material
57 * @void (*proc)(int ev, mp *m, void *p)@ = event procedure
58 * @size_t sz@ = size of key material
59 *
60 * Returns: Zero if all went well, nonzero if key material was
61 * unsuitable (one of the @DSAEV@ codes).
62 *
63 * Use: Generates the DSA shared parameters from a given seed value.
64 * This can take quite a long time. The size of @p@ in bits is
65 * %$l = 512 + 64l'$%. The DSA standard, FIPS 186, only allows
66 * %$0 \le l' \le 8$%. This implementation has no such limit,
67 * although @l@ must be a multiple of 8.
68 *
69 * The event procedure is informed of various happenings during
70 * generation. It is passed an event code describing what
71 * happened, and a multiprecision number which pertains to the
72 * event code.
73 */
74
75int dsa_seed(dsa_param *dp, unsigned l, const void *k, size_t sz,
76 void (*proc)(int /*ev*/, mp */*m*/, void */*p*/), void *arg)
77{
78 mp *q, *p, *g;
79 mp *s = mp_loadb(MP_NEW, k, sz);
80 octet *sbuf = xmalloc(sz);
81 rc4_ctx rc4;
82 int fail;
83
84 l /= 8;
85 rc4_init(&rc4, k, sz);
86
87 /* --- Generate @q@ --- */
88
89 {
90 octet xbuf[SHA_HASHSZ], ybuf[SHA_HASHSZ];
91 sha_ctx c;
92 int i;
93
94 sha_init(&c);
95 sha_hash(&c, k, sz);
96 sha_done(&c, xbuf);
97
98 MPX_UADDN(s->v, s->vl, 1);
99 mp_storeb(s, sbuf, sz);
100 sha_init(&c);
101 sha_hash(&c, sbuf, sz);
102 sha_done(&c, ybuf);
103
104 for (i = 0; i < sizeof(xbuf); i++)
105 xbuf[i] ^= ybuf[i];
106 xbuf[0] |= 0x80;
107 xbuf[SHA_HASHSZ - 1] |= 0x01;
108 q = mp_loadb(MP_NEW, xbuf, sizeof(xbuf));
109 }
110
111 /* --- Quick primality check --- */
112
113 {
114 pgen pg;
115 int rc = pgen_create(&pg, q);
116 pgen_destroy(&pg);
117 if (rc == PGEN_COMPOSITE) {
118 if (proc)
119 proc(DSAEV_FAILQ, q, arg);
120 fail = DSAEV_FAILQ;
121 goto fail_0;
122 }
123 }
124
125 /* --- Ensure that @q@ is prime --- *
126 *
127 * This requires 18 iterations, because the DSA spec is paranoid.
128 * Fortunately, it doesn't actually take very long.
129 */
130
131 {
132 rabin r;
133 int i;
134 mp *g = MP_NEW;
135 octet gbuf[SHA_HASHSZ];
136
137 rabin_create(&r, q);
138 for (i = 0; i < 18; i++) {
139 rc4_encrypt(&rc4, 0, gbuf, sizeof(gbuf));
140 g = mp_loadb(g, gbuf, sizeof(gbuf));
141 if (rabin_test(&r, g) == PGEN_COMPOSITE)
142 break;
143 if (proc)
144 proc(DSAEV_PASSQ, q, arg);
145 }
146 mp_drop(g);
147 rabin_destroy(&r);
148 if (i < 18) {
149 if (proc)
150 proc(DSAEV_FAILQ, q, arg);
151 fail = DSAEV_FAILQ;
152 goto fail_0;
153 }
154 if (proc)
155 proc(DSAEV_GOODQ, q, arg);
156 }
157
158 /* --- Now generate @p@ --- *
159 *
160 * This is, unfortunately, rather more messy and complicated.
161 */
162
163 {
164 mp *q2 = mp_lsl(MP_NEW, q, 1);
165 mp *ll = mp_lsl(MP_NEW, MP_ONE, l * 8 - 1);
166 unsigned n = l / SHA_HASHSZ, b = l % SHA_HASHSZ;
167 size_t psz = SHA_HASHSZ * (n + 1);
168 octet *pbuf = xmalloc(psz);
169 sha_ctx c;
170 unsigned i, j;
171
172 /* --- Fiddle with the leftover bytes count --- */
173
174 b = SHA_HASHSZ - b;
175
176 /* --- Go round 4096 times trying different @p@ values --- */
177
178 p = MP_NEW;
179 for (j = 0; j < 4096; j++) {
180
181 /* --- Build a prospective value of @p@ --- */
182
183 {
184 octet *pp = pbuf + SHA_HASHSZ * n;
185
186 for (i = 0; i <= n; i++) {
187 MPX_UADDN(s->v, s->vl, 1);
188 mp_storeb(s, sbuf, sz);
189 sha_init(&c);
190 sha_hash(&c, sbuf, sz);
191 sha_done(&c, pp);
192 pp -= SHA_HASHSZ;
193 }
194
195 pbuf[b] &= 0x7f;
196 p = mp_loadb(p, pbuf + b, psz - b);
197 p = mp_add(p, p, ll);
198 }
199
200 /* --- Adjust @p@ so that %$p \bmod 2q = 1$% --- */
201
202 {
203 mp *c = MP_NEW;
204 mp_div(0, &c, p, q2);
205 c = mp_sub(c, c, MP_ONE);
206 p = mp_sub(p, p, c);
207 mp_drop(c);
208 }
209
210 /* --- Check that @p@ is large enough --- */
211
212 if (MP_CMP(p, <, ll))
213 continue;
214
215 /* --- Run a simple primality test --- */
216
217 {
218 pgen pg;
219 int rc = pgen_create(&pg, p);
220 pgen_destroy(&pg);
221 if (rc == PGEN_COMPOSITE)
222 continue;
223 }
224
225 /* --- Run the Rabin-Miller test --- */
226
227 {
228 rabin r;
229 mp *g = MP_NEW;
230
231 if (proc)
232 proc(DSAEV_TRYP, p, arg);
233 rabin_create(&r, p);
234 for (i = 0; i < 5; i++) {
235 rc4_encrypt(&rc4, 0, pbuf, psz - b);
236 g = mp_loadb(g, pbuf, psz - b);
237 if (rabin_test(&r, g) == PGEN_COMPOSITE)
238 break;
239 if (proc)
240 proc(DSAEV_PASSP, p, arg);
241 }
242 mp_drop(g);
243 rabin_destroy(&r);
244 if (i < 5) {
245 if (proc)
246 proc(DSAEV_FAILP, p, arg);
247 fail = DSAEV_FAILP;
248 continue;
249 }
250 }
251
252 /* --- It worked! --- */
253
254 if (proc)
255 proc(DSAEV_GOODP, p, arg);
256 break;
257 }
258
259 free(pbuf);
260 mp_drop(q2);
261 mp_drop(ll);
262 if (j >= 4096)
263 goto fail_1;
264 }
265
266 /* --- Choose a generator of an order-%$q$% subgroup of %$Z^*_p$% --- */
267
268 {
269 mp *pp = MP_NEW;
270 mpw hw;
271 mp h;
272 unsigned i;
273 mpmont mm;
274
275 /* --- Calculate %$p' = (p - 1)/q$% --- */
276
277 {
278 mp *p1 = mp_sub(MP_NEW, p, MP_ONE);
279 mp_div(&pp, 0, p1, q);
280 mp_drop(p1);
281 }
282
283 /* --- Now find %$h$% where %$g = h^{p'} \bmod p \ne 1$% --- */
284
285 mp_build(&h, &hw, &hw + 1);
286 mpmont_create(&mm, p);
287 for (i = 0; i < NPRIME; i++) {
288 hw = ptab[i];
289 if (proc)
290 proc(DSAEV_TRYH, &h, arg);
291 g = mpmont_exp(&mm, &h, pp);
292 if (MP_CMP(g, !=, MP_ONE))
293 break;
294 if (proc)
295 proc(DSAEV_FAILH, &h, arg);
296 mp_drop(g);
297 }
298 mp_drop(pp);
299 if (i >= NPRIME) {
300 fail = DSAEV_FAILH;
301 goto fail_1;
302 }
303 }
304 if (proc)
305 proc(DSAEV_GOODG, g, arg);
306
307 /* --- Return the important information that I succeeded --- */
308
309 dp->p = p;
310 dp->q = q;
311 dp->g = g;
312 free(sbuf);
313 return (0);
314
315 /* --- Tidy up after failure --- */
316
317fail_1:
318 mp_drop(p);
319fail_0:
320 mp_drop(q);
321 mp_drop(s);
322 free(sbuf);
323 return (-1);
324}
325
326/*----- Test rig ----------------------------------------------------------*/
327
328#ifdef TEST_RIG
329
330static char baton[] = "/-\\|";
331static char *b = baton;
332
333static void event(int ev, mp *m, void *p)
334{
335 if (ev == DSAEV_TRYP || ev == DSAEV_PASSP) {
336 fputc(*b++, stdout);
337 fputc('\b', stdout);
338 fflush(stdout);
339 if (!*b)
340 b = baton;
341 }
342}
343
344static int verify(dstr *v)
345{
346 mp *q = *(mp **)v[2].buf;
347 mp *p = *(mp **)v[3].buf;
348 mp *g = *(mp **)v[4].buf;
349 dsa_param dp;
350 unsigned l = *(unsigned *)v[1].buf;
351 int ok = 1;
352 int rc;
353
354 rc = dsa_seed(&dp, l, v[0].buf, v[0].len, event, 0);
355 if (rc || MP_CMP(q, !=, dp.q) ||
356 MP_CMP(p, !=, dp.p) || MP_CMP(g, !=, dp.g)) {
357 fputs("\n*** gen failed", stderr);
358 fputs("\nseed = ", stderr); type_hex.dump(&v[0], stderr);
359 fprintf(stderr, "\nl = %u", l);
360 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
361 fputs("\n p = ", stderr); mp_writefile(q, stderr, 16);
362 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
363 if (!rc) {
364 fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
365 fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
366 fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
367 }
368 fputc('\n', stderr);
369 ok = 0;
370 }
371
372 mp_drop(q); mp_drop(p); mp_drop(g);
373 if (!rc) {
374 mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g);
375 }
376 return (ok);
377}
378
379static test_chunk tests[] = {
380 { "gen", verify,
381 { &type_hex, &type_int, &type_mp, &type_mp, &type_mp, 0 } },
382 { 0, 0, { 0 } }
383};
384
385int main(int argc, char *argv[])
386{
387 sub_init();
388 test_run(argc, argv, tests, SRCDIR "/tests/dsa");
389 return (0);
390}
391
392#endif
393
394/*----- That's all, folks -------------------------------------------------*/