ee33470f |
1 | /* -*-c-*- |
2 | * |
052b36d0 |
3 | * $Id: rspit.c,v 1.3 2000/02/12 18:21:03 mdw Exp $ |
ee33470f |
4 | * |
5 | * Spit out random numbers |
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: rspit.c,v $ |
052b36d0 |
33 | * Revision 1.3 2000/02/12 18:21:03 mdw |
34 | * Overhaul of key management (again). |
35 | * |
87de7c73 |
36 | * Revision 1.2 1999/12/22 15:59:51 mdw |
37 | * New prime-search system. Read BBS keys from key files. |
38 | * |
ee33470f |
39 | * Revision 1.1 1999/12/10 23:29:13 mdw |
40 | * Emit random numbers for statistical tests. |
41 | * |
42 | */ |
43 | |
44 | /*----- Header files ------------------------------------------------------*/ |
45 | |
46 | #include "config.h" |
47 | |
48 | #include <errno.h> |
49 | #include <signal.h> |
50 | #include <stdio.h> |
51 | #include <stdlib.h> |
52 | #include <string.h> |
53 | #include <time.h> |
54 | |
55 | #ifndef PORTABLE |
56 | # include <unistd.h> |
57 | #endif |
58 | |
59 | #include <mLib/darray.h> |
60 | #include <mLib/dstr.h> |
61 | #include <mLib/mdwopt.h> |
62 | #include <mLib/quis.h> |
63 | #include <mLib/report.h> |
64 | #include <mLib/sub.h> |
65 | |
66 | #include "grand.h" |
87de7c73 |
67 | #include "key.h" |
ee33470f |
68 | |
69 | #include "lcrand.h" |
70 | #include "fibrand.h" |
71 | #include "rand.h" |
72 | #include "noise.h" |
73 | |
74 | #include "bbs.h" |
75 | #include "mprand.h" |
76 | |
77 | #include "rc4.h" |
78 | |
79 | #include "des-ofb.h" |
80 | #include "des3-ofb.h" |
81 | #include "rc5-ofb.h" |
82 | #include "blowfish-ofb.h" |
83 | #include "idea-ofb.h" |
84 | |
85 | #include "rmd160.h" |
86 | |
87 | /*----- Data structures ---------------------------------------------------*/ |
88 | |
89 | typedef struct gen { |
90 | const char *name; |
91 | grand *(*seed)(unsigned /*i*/); |
92 | unsigned i; |
93 | const char *help; |
94 | } gen; |
95 | |
96 | static gen generators[]; |
97 | |
98 | /*----- Miscellaneous static data -----------------------------------------*/ |
99 | |
100 | static FILE *outfp = stdout; |
101 | static size_t outsz = 0; |
102 | |
103 | static int argc; |
104 | static char **argv; |
105 | |
106 | static unsigned flags = 0; |
107 | |
108 | enum { |
109 | f_progress = 1, |
110 | f_file = 2 |
111 | }; |
112 | |
113 | /*----- Help options ------------------------------------------------------*/ |
114 | |
115 | static void usage(FILE *fp) |
116 | { |
117 | pquis(fp, "Usage: $ generator [options]\n"); |
118 | } |
119 | |
120 | static void version(FILE *fp) |
121 | { |
122 | pquis(fp, "$, Catacomb version " VERSION "\n"); |
123 | } |
124 | |
125 | static void help(FILE *fp) |
126 | { |
127 | version(fp); |
128 | fputc('\n', fp); |
129 | usage(fp); |
130 | pquis(fp, "\n\ |
131 | Emits a stream of random bytes suitable for, well, all sorts of things.\n\ |
132 | The primary objective is to be able to generate streams of input for\n\ |
133 | statistical tests, such as Diehard.\n\ |
134 | \n\ |
135 | Options are specific to the particular generator, although there's a\n\ |
136 | common core set:\n\ |
137 | \n\ |
138 | -h, --help Display this help message.\n\ |
139 | -v, --version Display the program's version number.\n\ |
140 | -u, --usage Display a useless usage message.\n\ |
141 | \n\ |
142 | -l, --list Show a list of the supported generators, with\n\ |
143 | their options.\n\ |
144 | -o, --output FILE Write output to FILE, not stdout.\n\ |
145 | -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\ |
146 | -p, --progress Show a little progress meter (on stderr).\n\ |
147 | \n\ |
148 | (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\ |
149 | `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\ |
150 | "); |
151 | } |
152 | |
153 | /*----- Main options parser -----------------------------------------------*/ |
154 | |
155 | static struct option opts[] = { |
156 | |
157 | /* --- Standard GNU help options --- */ |
158 | |
159 | { "help", 0, 0, 'h' }, |
160 | { "version", 0, 0, 'v' }, |
161 | { "usage", 0, 0, 'u' }, |
162 | |
163 | /* --- Other useful things --- */ |
164 | |
165 | { "list", 0, 0, 'l' }, |
166 | { "output", OPTF_ARGREQ, 0, 'o' }, |
167 | { "size", OPTF_ARGREQ, 0, 'z' }, |
168 | { "progress", 0, 0, 'p' }, |
169 | |
170 | /* --- End of main table --- */ |
171 | |
172 | { 0, 0, 0, 0 } |
173 | }; |
174 | |
175 | static const char *sopts = "hvu lo:z:p"; |
176 | |
177 | #ifndef OPTION_V |
178 | DA_DECL(option_v, struct option); |
179 | # define OPTION_V |
180 | #endif |
181 | |
182 | static option_v optv = DA_INIT; |
183 | static dstr optd = DSTR_INIT; |
184 | |
185 | /* --- @addopts@ --- * |
186 | * |
187 | * Arguments: @const char *s@ = pointer to short options |
188 | * @struct option *l@ = pointer to long options |
189 | * |
190 | * Returns: --- |
191 | * |
192 | * Use: Adds a collection of options to the table. |
193 | */ |
194 | |
195 | static void addopts(const char *s, struct option *l) |
196 | { |
197 | dstr_puts(&optd, s); |
198 | if (DA_LEN(&optv)) |
199 | DA_SHRINK(&optv, 1); |
200 | while (l->name) |
201 | DA_PUSH(&optv, *l++); |
202 | DA_PUSH(&optv, *l); |
203 | } |
204 | |
205 | /* --- @opt@ --- * |
206 | * |
207 | * Arguments: --- |
208 | * |
209 | * Returns: Next option from argument array. |
210 | * |
211 | * Use: Fetches options, handling the standard ones. |
212 | */ |
213 | |
214 | static int opt(void) |
215 | { |
216 | for (;;) { |
217 | int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0); |
218 | switch (i) { |
219 | case 'h': |
220 | help(stdout); |
221 | exit(0); |
222 | case 'v': |
223 | version(stdout); |
224 | exit(0); |
225 | case 'u': |
226 | usage(stdout); |
227 | exit(0); |
228 | case 'l': { |
229 | gen *g; |
230 | puts("Generators supported:"); |
231 | for (g = generators; g->name; g++) |
232 | printf(" %s %s\n", g->name, g->help); |
233 | exit(0); |
234 | } break; |
235 | case 'o': |
236 | if (flags & f_file) |
237 | die(EXIT_FAILURE, "already set an output file"); |
238 | if (strcmp(optarg, "-") == 0) |
239 | outfp = stdout; |
240 | else { |
241 | outfp = fopen(optarg, "w"); |
242 | if (!outfp) { |
243 | die(EXIT_FAILURE, "couldn't open output file `%s': %s", |
244 | strerror(errno)); |
245 | } |
246 | } |
247 | flags |= f_file; |
248 | break; |
249 | case 'z': { |
250 | char *p; |
251 | outsz = strtoul(optarg, &p, 0); |
252 | if (!outsz) |
253 | die(EXIT_FAILURE, "bad number `%s'", optarg); |
254 | switch (*p) { |
255 | case 'G': case 'g': outsz *= 1024; |
256 | case 'M': case 'm': outsz *= 1024; |
257 | case 'K': case 'k': outsz *= 1024; |
258 | case 0: |
259 | break; |
260 | default: |
261 | die(EXIT_FAILURE, "bad suffix `%s'", p); |
262 | break; |
263 | } |
264 | if (*p && p[1] != 0) |
265 | die(EXIT_FAILURE, "bad suffix `%s'", p); |
266 | } break; |
267 | case 'p': |
268 | flags |= f_progress; |
269 | break; |
270 | default: |
271 | return (i); |
272 | } |
273 | } |
274 | } |
275 | |
276 | /*----- Manglers for seed strings -----------------------------------------*/ |
277 | |
278 | /* --- @unhex@ --- * |
279 | * |
280 | * Arguments: @const char *p@ = pointer to input string |
281 | * @char **end@ = where the end goes |
282 | * @dstr *d@ = output buffer |
283 | * |
284 | * Returns: --- |
285 | * |
286 | * Use: Transforms a hex string into a chunk of binary data. |
287 | */ |
288 | |
289 | static void unhex(const char *p, char **end, dstr *d) |
290 | { |
291 | while (p[0] && p[1]) { |
292 | int x = p[0], y = p[1]; |
293 | if ('0' <= x && x <= '9') x -= '0'; |
294 | else if ('A' <= x && x <= 'F') x -= 'A' - 10; |
295 | else if ('a' <= x && x <= 'f') x -= 'a' - 10; |
296 | else x = 0; |
297 | if ('0' <= y && y <= '9') y -= '0'; |
298 | else if ('A' <= y && y <= 'F') y -= 'A' - 10; |
299 | else if ('a' <= y && y <= 'f') y -= 'a' - 10; |
300 | else y = 0; |
301 | DPUTC(d, (x << 4) + y); |
302 | p += 2; |
303 | } |
304 | *end = (char *)p; |
305 | } |
306 | |
307 | /*----- Generators --------------------------------------------------------*/ |
308 | |
309 | /* --- Blum-Blum-Shub strong generator --- */ |
310 | |
ee33470f |
311 | static grand *gen_bbs(unsigned i) |
312 | { |
313 | /* --- Default modulus --- * |
314 | * |
315 | * The factors of this number are |
316 | * |
317 | * @p = 1229936431484295969649886203367009966370895964206162032259292413@ |
318 | * @7754313537966036459299022912838407755462506416274551744201653277@ |
319 | * @313130311731673973886822067@ |
320 | * |
321 | * @q = 9798171783943489959487301695884963889684294764514008432498259742@ |
322 | * @5374320073594018817245784145742769603334292182227671519041431067@ |
323 | * @61344781426317516045890159@ |
324 | * |
325 | * Both %$p$% and %$q$% are prime; %$(p - 1)/2%$ and %$(q - 1)/2$% have no |
326 | * common factors. They were found using this program, with random |
327 | * starting points. |
328 | * |
329 | * I hope that, by publishing these factors, I'll dissuade people from |
330 | * actually using this modulus in attempt to actually attain real |
331 | * security. The program is quite quick at finding Blum numbers, so |
332 | * there's no excuse for not generating your own. |
333 | */ |
334 | |
335 | const char *mt = |
336 | "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653"; |
337 | |
338 | /* --- Other things --- */ |
339 | |
340 | grand *r; |
341 | const char *xt = 0; |
87de7c73 |
342 | unsigned bits = 1024; |
ee33470f |
343 | mp *m, *x; |
344 | unsigned show = 0; |
87de7c73 |
345 | const char *kfile = 0, *id = 0, *ktype = 0; |
ee33470f |
346 | |
347 | /* --- Parse options --- */ |
348 | |
349 | static struct option opts[] = { |
350 | { "modulus", OPTF_ARGREQ, 0, 'm' }, |
351 | { "generate", 0, 0, 'g' }, |
352 | { "seed", OPTF_ARGREQ, 0, 's' }, |
353 | { "bits", OPTF_ARGREQ, 0, 'b' }, |
354 | { "show", 0, 0, 'S' }, |
87de7c73 |
355 | { "keyring", OPTF_ARGREQ, 0, 'k' }, |
356 | { "id", OPTF_ARGREQ, 0, 'i' }, |
357 | { "type", OPTF_ARGREQ, 0, 't' }, |
ee33470f |
358 | { 0, 0, 0, 0 } |
359 | }; |
360 | |
87de7c73 |
361 | addopts("m:gs:b:Sk:i:t:", opts); |
ee33470f |
362 | |
363 | for (;;) { |
364 | int o = opt(); |
365 | if (o < 0) |
366 | break; |
367 | switch (o) { |
368 | case 'm': |
369 | mt = optarg; |
370 | break; |
371 | case 'g': |
372 | mt = 0; |
373 | break; |
374 | case 's': |
375 | xt = optarg; |
376 | break; |
377 | case 'b': |
378 | bits = strtoul(optarg, 0, 0); |
379 | if (bits == 0) |
380 | die(EXIT_FAILURE, "bad number of bits `%s'", optarg); |
381 | break; |
382 | case 'S': |
383 | show = 1; |
384 | break; |
87de7c73 |
385 | case 'k': |
386 | kfile = optarg; |
387 | mt = 0; |
388 | break; |
389 | case 'i': |
390 | id = optarg; |
391 | mt = 0; |
392 | break; |
393 | case 't': |
394 | ktype = optarg; |
395 | mt = 0; |
396 | break; |
ee33470f |
397 | default: |
398 | return (0); |
399 | } |
400 | } |
401 | |
402 | /* --- Generate a modulus if one is requested --- */ |
403 | |
404 | if (mt) { |
405 | char *p; |
406 | m = mp_readstring(MP_NEW, mt, &p, 0); |
87de7c73 |
407 | if (!m || *p || (m->v[0] & 3) != 1) |
ee33470f |
408 | die(EXIT_FAILURE, "bad modulus `%s'", mt); |
409 | /* Unfortunately I don't know how to test for a Blum integer */ |
87de7c73 |
410 | } else if (kfile || id || ktype) { |
411 | key_file kf; |
412 | key *kk; |
413 | key_data *kd; |
414 | |
415 | /* --- Open the key file --- */ |
416 | |
417 | if (!kfile) |
418 | kfile = "keyring"; |
419 | if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) { |
420 | die(EXIT_FAILURE, "error opening key file `%s': %s", |
421 | kfile, strerror(errno)); |
422 | } |
423 | |
424 | /* --- Find the key --- */ |
425 | |
426 | if (id) { |
427 | if ((kk = key_bytag(&kf, id)) == 0) |
428 | die(EXIT_FAILURE, "key `%s' not found", id); |
429 | } else { |
430 | if (!ktype) |
431 | ktype = "bbs"; |
432 | if ((kk = key_bytype(&kf, ktype)) == 0) |
433 | die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype); |
434 | } |
435 | |
436 | /* --- Read the key data --- */ |
437 | |
438 | if ((kk->k.e & KF_ENCMASK) != KENC_STRUCT) |
439 | die(EXIT_FAILURE, "key is not structured"); |
440 | if ((kd = key_structfind(&kk->k, "n")) == 0) |
441 | die(EXIT_FAILURE, "key has no subkey `n'"); |
442 | if ((kd->e & KF_ENCMASK) != KENC_MP) |
443 | die(EXIT_FAILURE, "incomatible subkey encoding"); |
444 | m = MP_COPY(kd->u.m); |
445 | key_close(&kf); |
ee33470f |
446 | } else { |
87de7c73 |
447 | bbs_param bp; |
ee33470f |
448 | |
052b36d0 |
449 | if (bbs_gen(&bp, bits, &rand_global, 0, |
450 | (flags & f_progress) ? pgen_ev : 0, 0)) |
87de7c73 |
451 | die(EXIT_FAILURE, "modulus generation failed"); |
ee33470f |
452 | m = bp.n; |
453 | |
454 | if (show) { |
455 | fputs("p = ", stderr); |
456 | mp_writefile(bp.p, stderr, 10); |
457 | fputs("\nq = ", stderr); |
458 | mp_writefile(bp.q, stderr, 10); |
459 | fputs("\nn = ", stderr); |
460 | mp_writefile(bp.n, stderr, 10); |
461 | fputc('\n', stderr); |
462 | } |
463 | |
ee33470f |
464 | mp_drop(bp.p); |
465 | mp_drop(bp.q); |
466 | } |
467 | |
468 | /* --- Set up a seed --- */ |
469 | |
470 | if (!xt) |
471 | x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1); |
472 | else { |
473 | char *p; |
474 | x = mp_readstring(MP_NEW, xt, &p, 0); |
475 | if (*p) |
476 | die(EXIT_FAILURE, "bad modulus `%s'", xt); |
477 | } |
478 | |
479 | /* --- Right --- */ |
480 | |
481 | r = bbs_rand(m, x); |
482 | |
483 | mp_drop(m); |
484 | mp_drop(x); |
485 | return (r); |
486 | } |
487 | |
488 | /* --- Catacomb's random number generator --- */ |
489 | |
490 | static grand *gen_rand(unsigned i) |
491 | { |
492 | grand *r = rand_create(); |
493 | dstr d = DSTR_INIT; |
494 | |
495 | static struct option opts[] = { |
496 | { "key", OPTF_ARGREQ, 0, 'k' }, |
497 | { "text", OPTF_ARGREQ, 0, 't' }, |
498 | { "hex", OPTF_ARGREQ, 0, 'H' }, |
499 | { "noise", 0, 0, 'n' }, |
500 | { 0, 0, 0, 0 } |
501 | }; |
502 | |
503 | addopts("k:t:H:n", opts); |
504 | |
505 | for (;;) { |
506 | int o = opt(); |
507 | if (o < 0) |
508 | break; |
509 | switch (o) { |
510 | case 'k': { |
511 | rmd160_ctx c; |
512 | octet hash[RMD160_HASHSZ]; |
513 | rmd160_init(&c); |
514 | rmd160_hash(&c, optarg, strlen(optarg)); |
515 | rmd160_done(&c, hash); |
516 | r->ops->misc(r, RAND_KEY, hash, sizeof(hash)); |
517 | } break; |
518 | case 't': |
519 | r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg)); |
520 | break; |
521 | case 'H': { |
522 | char *p; |
523 | DRESET(&d); |
524 | unhex(optarg, &p, &d); |
525 | if (*p) |
526 | die(EXIT_FAILURE, "bad hex key `%s'", optarg); |
527 | r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len); |
528 | } break; |
529 | case 'n': |
530 | r->ops->misc(r, RAND_NOISESRC, &noise_source); |
531 | break; |
532 | } |
533 | } |
534 | |
535 | dstr_destroy(&d); |
536 | return (r); |
537 | } |
538 | |
539 | /* --- RC4 output --- */ |
540 | |
541 | static grand *gen_rc4(unsigned i) |
542 | { |
543 | grand *r; |
544 | dstr d = DSTR_INIT; |
545 | |
546 | static struct option opts[] = { |
547 | { "key", OPTF_ARGREQ, 0, 'k' }, |
548 | { "hex", OPTF_ARGREQ, 0, 'H' }, |
549 | { 0, 0, 0, 0 } |
550 | }; |
551 | |
552 | addopts("k:H:", opts); |
553 | |
554 | for (;;) { |
555 | int o = opt(); |
556 | if (o < 0) |
557 | break; |
558 | switch (o) { |
559 | case 'k': { |
560 | rmd160_ctx c; |
561 | dstr_ensure(&d, RMD160_HASHSZ); |
562 | rmd160_init(&c); |
563 | rmd160_hash(&c, optarg, strlen(optarg)); |
564 | rmd160_done(&c, d.buf); |
565 | d.len += RMD160_HASHSZ; |
566 | } break; |
567 | case 'H': { |
568 | char *p; |
569 | unhex(optarg, &p, &d); |
570 | if (*p) |
571 | die(EXIT_FAILURE, "bad hex key `%s'", optarg); |
572 | } break; |
573 | default: |
574 | return (0); |
575 | } |
576 | } |
577 | |
578 | if (!d.len) { |
579 | dstr_ensure(&d, 16); |
580 | d.len = 16; |
581 | rand_getgood(RAND_GLOBAL, d.buf, d.len); |
582 | } |
583 | r = rc4_rand(d.buf, d.len); |
584 | dstr_destroy(&d); |
585 | return (r); |
586 | } |
587 | |
588 | /* --- Output feedback generators --- */ |
589 | |
590 | #define OFBTAB \ |
591 | E(OFB_DES, DES_KEYSZ, DES_BLKSZ, des_ofbrand), \ |
592 | E(OFB_DES3, DES3_KEYSZ, DES3_BLKSZ, des3_ofbrand), \ |
593 | E(OFB_RC5, RC5_KEYSZ, RC5_BLKSZ, rc5_ofbrand), \ |
594 | E(OFB_BLOWFISH, BLOWFISH_KEYSZ, BLOWFISH_BLKSZ, blowfish_ofbrand), \ |
595 | E(OFB_IDEA, IDEA_KEYSZ, IDEA_BLKSZ, idea_ofbrand) |
596 | |
597 | static struct { |
598 | size_t keysz; |
599 | size_t blksz; |
600 | grand *(*rand)(const void */*k*/, size_t /*sz*/); |
601 | } ofbtab[] = { |
602 | #define E(c, x, y, z) { x, y, z } |
603 | OFBTAB |
604 | #undef E |
605 | }; |
606 | |
607 | enum { |
608 | #define E(c, x, y, z) c |
609 | OFBTAB |
610 | #undef E |
611 | }; |
612 | |
613 | #undef OFBTAB |
614 | |
615 | static grand *gen_ofb(unsigned i) |
616 | { |
617 | grand *r; |
618 | dstr d = DSTR_INIT; |
619 | dstr iv = DSTR_INIT; |
620 | |
621 | static struct option opts[] = { |
622 | { "key", OPTF_ARGREQ, 0, 'k' }, |
623 | { "hex", OPTF_ARGREQ, 0, 'H' }, |
624 | { "iv", OPTF_ARGREQ, 0, 'i' }, |
625 | { 0, 0, 0, 0 } |
626 | }; |
627 | |
628 | addopts("k:H:i:", opts); |
629 | |
630 | for (;;) { |
631 | int o = opt(); |
632 | if (o < 0) |
633 | break; |
634 | switch (o) { |
635 | case 'k': { |
636 | rmd160_ctx c; |
637 | dstr_ensure(&d, RMD160_HASHSZ); |
638 | rmd160_init(&c); |
639 | rmd160_hash(&c, optarg, strlen(optarg)); |
640 | rmd160_done(&c, d.buf); |
641 | d.len += RMD160_HASHSZ; |
642 | } break; |
643 | case 'H': { |
644 | char *p; |
645 | unhex(optarg, &p, &d); |
646 | if (*p) |
647 | die(EXIT_FAILURE, "bad hex key `%s'", optarg); |
648 | } break; |
649 | case 'i': { |
650 | char *p; |
651 | unhex(optarg, &p, &iv); |
652 | if (*p) |
653 | die(EXIT_FAILURE, "bad hex IV `%s'", optarg); |
654 | } break; |
655 | default: |
656 | return (0); |
657 | } |
658 | } |
659 | |
660 | if (!d.len) { |
661 | size_t n = ofbtab[i].keysz; |
662 | if (!n) |
663 | n = 16; |
664 | dstr_ensure(&d, n); |
665 | d.len = n; |
666 | rand_getgood(RAND_GLOBAL, d.buf, d.len); |
667 | } |
668 | |
669 | while (d.len < ofbtab[i].keysz) |
670 | DPUTD(&d, &d); |
671 | if (ofbtab[i].keysz && d.len > ofbtab[i].keysz) |
672 | d.len = ofbtab[i].keysz; |
673 | |
674 | r = ofbtab[i].rand(d.buf, d.len); |
675 | if (iv.len) { |
676 | while (iv.len < ofbtab[i].blksz) |
677 | DPUTD(&iv, &iv); |
678 | r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf); |
679 | } |
680 | |
681 | dstr_destroy(&d); |
682 | dstr_destroy(&iv); |
683 | return (r); |
684 | } |
685 | |
686 | /* --- Fibonacci generator --- */ |
687 | |
688 | static grand *gen_fib(unsigned i) |
689 | { |
690 | grand *r; |
691 | uint32 s = 0; |
692 | char *p; |
693 | unsigned set = 0; |
694 | |
695 | static struct option opts[] = { |
696 | { "seed", OPTF_ARGREQ, 0, 's' }, |
697 | { 0, 0, 0, 0 } |
698 | }; |
699 | |
700 | addopts("s:", opts); |
701 | |
702 | for (;;) { |
703 | int o = opt(); |
704 | if (o < 0) |
705 | break; |
706 | switch (o) { |
707 | case 's': |
708 | s = strtoul(optarg, &p, 0); |
709 | if (*p) |
710 | die(EXIT_FAILURE, "bad integer `%s'", optarg); |
711 | set = 1; |
712 | break; |
713 | default: |
714 | return (0); |
715 | } |
716 | } |
717 | r = fibrand_create(s); |
718 | if (!set) |
719 | r->ops->misc(r, GRAND_SEEDRAND, &rand_global); |
720 | return (r); |
721 | } |
722 | |
723 | /* --- LC generator --- */ |
724 | |
725 | static grand *gen_lc(unsigned i) |
726 | { |
727 | uint32 s = 0; |
728 | char *p; |
729 | unsigned set = 0; |
730 | |
731 | static struct option opts[] = { |
732 | { "seed", OPTF_ARGREQ, 0, 's' }, |
733 | { 0, 0, 0, 0 } |
734 | }; |
735 | |
736 | addopts("s:", opts); |
737 | |
738 | for (;;) { |
739 | int o = opt(); |
740 | if (o < 0) |
741 | break; |
742 | switch (o) { |
743 | case 's': |
744 | s = strtoul(optarg, &p, 0); |
745 | if (*p) |
746 | die(EXIT_FAILURE, "bad integer `%s'", optarg); |
747 | set = 1; |
748 | break; |
749 | default: |
750 | return (0); |
751 | } |
752 | } |
753 | if (!set) { |
754 | do |
755 | s = rand_global.ops->range(&rand_global, LCRAND_P); |
756 | while (s == LCRAND_FIXEDPT); |
757 | } |
758 | return (lcrand_create(s)); |
759 | } |
760 | |
761 | /* --- Basic options parser -- can't generate output --- */ |
762 | |
763 | static grand *gen_opts(unsigned i) |
764 | { |
765 | while (opt() >= 0) |
766 | ; |
767 | return (0); |
768 | } |
769 | |
770 | /*----- Generators table --------------------------------------------------*/ |
771 | |
772 | static gen generators[] = { |
773 | { "fibonacci", gen_fib, 0, |
774 | "[-s SEED]" }, |
775 | { "lc", gen_lc, 0, |
776 | "[-s SEED]" }, |
777 | { "des-ofb", gen_ofb, OFB_DES, |
778 | "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" }, |
779 | { "3des-ofb", gen_ofb, OFB_DES3, |
780 | "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" }, |
781 | { "rc5-ofb", gen_ofb, OFB_RC5, |
782 | "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" }, |
783 | { "blowfish-ofb", gen_ofb, OFB_BLOWFISH, |
784 | "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" }, |
785 | { "idea-ofb", gen_ofb, OFB_IDEA, |
786 | "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" }, |
787 | { "rc4", gen_rc4, 0, |
788 | "[-k KEY-PHRASE] [-H HEX-KEY]" }, |
789 | { "rand", gen_rand, 0, |
790 | "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" }, |
791 | { "bbs", gen_bbs, 0, |
87de7c73 |
792 | "[-gS] [-s SEED] [-m MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]" |
793 | }, |
ee33470f |
794 | { 0, 0, 0, 0 }, |
795 | }; |
796 | |
797 | static gen optsg = { "options", gen_opts, 0, |
798 | "This message shouldn't be printed." }; |
799 | |
800 | /*----- Main code ---------------------------------------------------------*/ |
801 | |
802 | int main(int ac, char *av[]) |
803 | { |
804 | gen *g = &optsg; |
805 | grand *r; |
806 | unsigned percent = -1; |
807 | size_t kb = 0; |
808 | time_t last; |
809 | static char baton[] = "|/-\\"; |
810 | char *bp; |
811 | |
812 | /* --- Initialize mLib --- */ |
813 | |
814 | ego(av[0]); |
815 | sub_init(); |
816 | |
817 | /* --- Set up the main Catacomb generator --- */ |
818 | |
819 | rand_noisesrc(RAND_GLOBAL, &noise_source); |
820 | |
821 | /* --- Initialize the options table --- */ |
822 | |
823 | addopts(sopts, opts); |
824 | argc = ac; |
825 | argv = av; |
826 | |
827 | /* --- Read the generator out of the first argument --- */ |
828 | |
829 | if (argc > 1 && *argv[1] != '-') { |
830 | const char *arg = av[1]; |
831 | size_t sz = strlen(arg); |
832 | gen *gg; |
833 | |
834 | g = 0; |
835 | for (gg = generators; gg->name; gg++) { |
836 | if (strncmp(arg, gg->name, sz) == 0) { |
837 | if (gg->name[sz] == 0) { |
838 | g = gg; |
839 | break; |
840 | } else if (g) |
841 | die(EXIT_FAILURE, "ambiguous generator name `%s'", arg); |
842 | else |
843 | g = gg; |
844 | } |
845 | } |
846 | if (!g) |
847 | die(EXIT_FAILURE, "unknown generator name `%s'", arg); |
848 | argc--; |
849 | argv++; |
850 | } |
851 | |
852 | /* --- Get a generic random number generator --- */ |
853 | |
854 | r = g->seed(g->i); |
855 | if (!r || optind != ac - 1) { |
856 | usage(stderr); |
857 | exit(EXIT_FAILURE); |
858 | } |
859 | |
860 | #ifndef PORTABLE |
861 | if (!(flags & f_file) && isatty(STDOUT_FILENO)) |
862 | die(EXIT_FAILURE, "writing output to a terminal is a bad idea"); |
863 | #endif |
864 | |
865 | /* --- Spit out random data --- */ |
866 | |
867 | last = time(0); |
868 | bp = baton; |
869 | if (flags & f_progress) { |
870 | char *errbuf = xmalloc(BUFSIZ); |
871 | setvbuf(stderr, errbuf, _IOLBF, BUFSIZ); |
872 | fputc('[', stderr); |
873 | fflush(stderr); |
874 | } |
875 | |
876 | #ifdef SIGPIPE |
877 | signal(SIGPIPE, SIG_IGN); |
878 | #endif |
879 | |
880 | for (;;) { |
881 | octet buf[BUFSIZ]; |
882 | size_t sz = sizeof(buf); |
883 | |
884 | /* --- Emit a bufferful (or less) of data --- */ |
885 | |
886 | if (outsz) { |
887 | if (sz > outsz - kb) |
888 | sz = outsz - kb; |
889 | } |
890 | r->ops->fill(r, buf, sz); |
891 | if (fwrite(buf, 1, sz, outfp) != sz) { |
892 | if (flags & f_progress) |
893 | fputc('\n', stderr); |
894 | die(EXIT_FAILURE, "error writing data: %s", strerror(errno)); |
895 | } |
896 | kb += sz; |
897 | |
898 | /* --- Update the display --- */ |
899 | |
900 | if (flags & f_progress) { |
901 | time_t t = time(0); |
902 | unsigned up = 0; |
903 | |
904 | if (percent > 100) |
905 | up = 1; |
906 | |
907 | if (!outsz) { |
908 | if (difftime(t, last) > 1.0) { |
909 | up = 1; |
910 | } |
911 | if (up) |
912 | fputs(" ] ", stderr); |
913 | } else { |
914 | unsigned pc = kb * 100.0 / outsz; |
915 | if (pc > percent || percent > 100 || difftime(t, last) > 1.0) { |
916 | if (percent > 100) |
917 | percent = 0; |
918 | percent &= ~1; |
919 | for (; percent < (pc & ~1); percent += 2) |
920 | putc('.', stderr); |
921 | percent = pc; |
922 | for (; pc < 100; pc += 2) |
923 | putc(' ', stderr); |
924 | fprintf(stderr, "] %3i%% ", percent); |
925 | up = 1; |
926 | } |
927 | } |
928 | |
929 | if (up) { |
930 | size_t q = kb; |
931 | char *suff = " KMG"; |
932 | while (q > 8192 && suff[1]) { |
933 | q >>= 10; |
934 | suff++; |
935 | } |
936 | fprintf(stderr, "%4i%c\r[", q, *suff); |
937 | if (outsz) { |
938 | unsigned pc; |
939 | for (pc = 0; pc < (percent & ~1); pc += 2) |
940 | putc('.', stderr); |
941 | } |
942 | last = t; |
943 | } |
944 | |
945 | if (percent > 100) |
946 | percent = 0; |
947 | |
948 | if (percent < 100) { |
949 | putc(*bp++, stderr); |
950 | putc('\b', stderr); |
951 | if (!*bp) |
952 | bp = baton; |
953 | } |
954 | fflush(stderr); |
955 | } |
956 | |
957 | /* --- Terminate the loop --- */ |
958 | |
959 | if (outsz && kb >= outsz) |
960 | break; |
961 | } |
962 | |
963 | /* --- Done --- */ |
964 | |
965 | r->ops->destroy(r); |
966 | if (flags & f_progress) |
967 | fputc('\n', stderr); |
968 | return (0); |
969 | } |
970 | |
971 | /*----- That's all, folks -------------------------------------------------*/ |