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