General utilities cleanup. Add signature support to catcrypt. Throw in
[u/mdw/catacomb] / dsa-gen.c
CommitLineData
8b810a45 1/* -*-c-*-
2 *
b817bfc6 3 * $Id: dsa-gen.c,v 1.10 2004/04/08 01:36:15 mdw Exp $
8b810a45 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
8b810a45 30/*----- Header files ------------------------------------------------------*/
31
32#include <stdio.h>
33#include <stdlib.h>
34
35#include "dsa.h"
b04a7659 36#include "dsarand.h"
ef5f4810 37#include "fibrand.h"
8b810a45 38#include "mp.h"
ef5f4810 39#include "mprand.h"
8b810a45 40#include "pgen.h"
b04a7659 41#include "prim.h"
8b810a45 42#include "sha.h"
43
b04a7659 44/*----- The DSA stepper ---------------------------------------------------*/
8b810a45 45
b04a7659 46/* --- @next@ --- *
8b810a45 47 *
b04a7659 48 * Arguments: @pgen_event *ev@ = pointer to event block
49 * @dsa_stepctx *d@ = pointer to stepping context
8b810a45 50 *
b04a7659 51 * Returns: A @PGEN@ result code.
8b810a45 52 *
b04a7659 53 * Use: Steps the generator once, reads the result, and tests it.
8b810a45 54 */
55
b04a7659 56static int next(pgen_event *ev, dsa_stepctx *d)
8b810a45 57{
b04a7659 58 mp *m;
59 int rc;
8b810a45 60
b04a7659 61 /* --- Load the new candidate --- */
8b810a45 62
a63f764a 63 if (d->seedbuf)
64 d->r->ops->misc(d->r, DSARAND_GETSEED, d->seedbuf);
65 m = mprand(ev->m, d->bits, d->r, 0);
8b810a45 66
b04a7659 67 /* --- Force to be a multiple of @q@ --- */
ef5f4810 68
b04a7659 69 if (d->q) {
70 mp *r = MP_NEW;
71 mp_div(0, &r, m, d->q);
72 m = mp_sub(m, m, r);
73 mp_drop(r);
8b810a45 74 }
b04a7659 75 m->v[0] |= d->or;
76 ev->m = m;
8b810a45 77
b04a7659 78 /* --- Do the trial division --- */
8b810a45 79
8a33545f 80 rc = pfilt_smallfactor(m);
a63f764a 81 d->count++;
8b810a45 82
b04a7659 83 /* --- Return the result --- */
8b810a45 84
b04a7659 85 return (rc);
86}
8b810a45 87
b04a7659 88/* --- @dsa_step@ --- */
89
90int dsa_step(int rq, pgen_event *ev, void *p)
91{
92 dsa_stepctx *d = p;
93
94 switch (rq) {
95 case PGEN_BEGIN:
b04a7659 96 case PGEN_TRY:
97 return (next(ev, d));
98 case PGEN_DONE:
99 return (PGEN_DONE);
8b810a45 100 }
b04a7659 101 return (PGEN_ABORT);
102}
8b810a45 103
b04a7659 104/*----- Glue code ---------------------------------------------------------*/
8b810a45 105
2b31b269 106/* --- @dsa_gen@ --- *
b04a7659 107 *
108 * Arguments: @dsa_param *dp@ = where to store parameters
109 * @unsigned ql@ = length of @q@ in bits
110 * @unsigned pl@ = length of @p@ in bits
111 * @unsigned steps@ = number of steps to find @q@
112 * @const void *k@ = pointer to key material
113 * @size_t sz@ = size of key material
a63f764a 114 * @dsa_seed *ds@ = optional pointer for output seed information
b04a7659 115 * @pgen_proc *event@ = event handler function
116 * @void *ectx@ = argument for event handler
117 *
118 * Returns: @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
119 *
120 * Use: Generates the DSA shared parameters from a given seed value.
052b36d0 121 *
122 * The parameters are a prime %$q$%, relatively small, and a
123 * large prime %$p = kq + 1$% for some %$k$%, together with a
124 * generator %$g$% of the cyclic subgroup of order %$q$%. These
125 * are actually the same as the Diffie-Hellman parameter set,
126 * but the generation algorithm is different.
b04a7659 127 *
128 * The algorithm used is a compatible extension of the method
129 * described in the DSA standard, FIPS 186. The standard
130 * requires that %$q$% be 160 bits in size (i.e., @ql == 160@)
131 * and that the length of %$p$% be %$L = 512 + 64l$% for some
132 * %$l$%. Neither limitation applies to this implementation.
133 */
8b810a45 134
2b31b269 135int dsa_gen(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
a63f764a 136 const void *k, size_t sz, dsa_seed *ds,
137 pgen_proc *event, void *ectx)
b04a7659 138{
139 dsa_stepctx s;
140 prim_ctx p;
141 int i;
142 rabin r;
143 mp *qc;
8b810a45 144
b04a7659 145 /* --- Initialize the stepping context --- */
8b810a45 146
b04a7659 147 s.r = dsarand_create(k, sz);
8b810a45 148
b04a7659 149 /* --- Find @q@ --- */
8b810a45 150
b04a7659 151 s.q = 0;
152 s.r->ops->misc(s.r, DSARAND_PASSES, 2);
153 s.bits = ql;
a63f764a 154 s.count = 0;
155 s.or = 1;
156 if (!ds)
157 s.seedbuf = 0;
158 else {
159 ds->sz = sz;
160 ds->p = s.seedbuf = xmalloc(sz);
161 }
b04a7659 162 if ((dp->q = pgen("q", MP_NEW, MP_NEW, event, ectx, steps, dsa_step, &s,
163 rabin_iters(ql), pgen_test, &r)) == 0)
164 goto fail_q;
8b810a45 165
b04a7659 166 /* --- Find @p@ --- */
8b810a45 167
a63f764a 168 s.count = ~0;
b04a7659 169 s.q = mp_lsl(MP_NEW, dp->q, 1);
170 s.r->ops->misc(s.r, DSARAND_PASSES, 1);
171 s.bits = pl;
a63f764a 172 s.seedbuf = 0;
b04a7659 173 if ((dp->p = pgen("p", MP_NEW, MP_NEW, event, ectx, 4096, dsa_step, &s,
174 rabin_iters(pl), pgen_test, &r)) == 0)
175 goto fail_p;
176 mp_drop(s.q);
a63f764a 177 if (ds)
178 ds->count = s.count;
b04a7659 179
180 /* --- Find @g@ --- *
181 *
182 * The division returns remainder 1. This doesn't matter.
183 */
184
185 mpmont_create(&p.mm, dp->p);
186 qc = MP_NEW; mp_div(&qc, 0, dp->p, dp->q);
187 i = 0;
2b31b269 188 p.exp = qc;
b04a7659 189 p.n = 0;
190 if ((dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
191 1, prim_test, &p)) == 0)
192 goto fail_g;
193
194 /* --- Done --- */
195
196 mp_drop(qc);
197 mpmont_destroy(&p.mm);
198 s.r->ops->destroy(s.r);
199 return (PGEN_DONE);
200
201 /* --- Tidy up when things go wrong --- */
202
203fail_g:
204 mp_drop(qc);
205 mpmont_destroy(&p.mm);
206fail_p:
207 mp_drop(dp->q);
208 mp_drop(s.q);
209fail_q:
210 s.r->ops->destroy(s.r);
a63f764a 211 if (ds)
212 xfree(ds->p);
b04a7659 213 return (PGEN_ABORT);
8b810a45 214}
215
b04a7659 216/*----- Test rig ----------------------------------------------------------*/
217
218#ifdef TEST_RIG
219
8b810a45 220static int verify(dstr *v)
221{
a63f764a 222 mp *q = *(mp **)v[4].buf;
223 mp *p = *(mp **)v[5].buf;
224 mp *g = *(mp **)v[6].buf;
8b810a45 225 dsa_param dp;
a63f764a 226 dsa_seed ds;
227 unsigned long l = *(unsigned long *)v[1].buf;
228 unsigned long n = *(unsigned long *)v[3].buf;
8b810a45 229 int ok = 1;
230 int rc;
a63f764a 231 keycheck kc;
232 keycheck_reportctx kcr;
8b810a45 233
a63f764a 234 rc = dsa_gen(&dp, 160, l, 16, v[0].buf, v[0].len, &ds, pgen_evspin, 0);
235 if (rc || ds.count != n || ds.sz != v[2].len ||
236 memcmp(ds.p, v[2].buf, v[2].len) != 0 ||
237 !MP_EQ(q, dp.q) || !MP_EQ(p, dp.p) || !MP_EQ(g, dp.g)) {
8b810a45 238 fputs("\n*** gen failed", stderr);
a63f764a 239 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
240 fprintf(stderr, "\nl = %lu", l);
241 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
242 fprintf(stderr, "\ncount = %lu", n);
8b810a45 243 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
b04a7659 244 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
8b810a45 245 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
246 if (!rc) {
a63f764a 247 dstr d;
248 d.buf = ds.p; d.len = ds.sz;
249 fputs("\nds.seed = ", stderr); type_hex.dump(&d, stderr);
250 fprintf(stderr, "\nds.count = %u", ds.count);
8b810a45 251 fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
252 fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
253 fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
254 }
255 fputc('\n', stderr);
256 ok = 0;
257 }
258
a63f764a 259 kcr.fp = stderr;
260 kcr.sev = KCSEV_ERR;
261 keycheck_init(&kc, keycheck_stdreport, &kcr);
262 if (!rc)
263 dsa_checkparam(&kc, &dp, &ds);
264 if (!keycheck_allclear(&kc, KCSEV_ERR)) {
265 fputs("\n*** gen failed check", stderr);
266 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
267 fprintf(stderr, "\nl = %lu", l);
268 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
269 fprintf(stderr, "\ncount = %lu", n);
270 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
271 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
272 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
273 fputc('\n', stderr);
274 ok = 0;
275 }
276
8b810a45 277 mp_drop(q); mp_drop(p); mp_drop(g);
278 if (!rc) {
a63f764a 279 mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g); xfree(ds.p);
8b810a45 280 }
8a33545f 281 assert(mparena_count(MPARENA_GLOBAL) == 0);
8b810a45 282 return (ok);
283}
284
285static test_chunk tests[] = {
286 { "gen", verify,
a63f764a 287 { &type_hex, &type_ulong, &type_hex, &type_ulong,
288 &type_mp, &type_mp, &type_mp, 0 } },
8b810a45 289 { 0, 0, { 0 } }
290};
291
292int main(int argc, char *argv[])
293{
294 sub_init();
295 test_run(argc, argv, tests, SRCDIR "/tests/dsa");
296 return (0);
297}
298
299#endif
300
301/*----- That's all, folks -------------------------------------------------*/