progs/key.c: Use the mLib generic codec interface instead of base64_*.
[catacomb] / progs / rspit.c
CommitLineData
ee33470f 1/* -*-c-*-
2 *
ee33470f 3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
ee33470f 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
ee33470f 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
ee33470f 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
ee33470f 28/*----- Header files ------------------------------------------------------*/
29
30#include "config.h"
31
bb78535e 32#include <assert.h>
ee33470f 33#include <errno.h>
bb78535e 34#include <math.h>
ee33470f 35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40
41#ifndef PORTABLE
42# include <unistd.h>
15df46bc 43# include <sys/time.h>
ee33470f 44#endif
45
46#include <mLib/darray.h>
47#include <mLib/dstr.h>
48#include <mLib/mdwopt.h>
49#include <mLib/quis.h>
50#include <mLib/report.h>
51#include <mLib/sub.h>
52
bafe8a7b
MW
53#include "mp.h"
54#include "mpint.h"
55#include "mplimits.h"
56#include "mptext.h"
57
bb78535e 58#include "fipstest.h"
ee33470f 59#include "grand.h"
bb78535e 60#include "maurer.h"
87de7c73 61#include "key.h"
ee33470f 62
63#include "lcrand.h"
64#include "fibrand.h"
65#include "rand.h"
66#include "noise.h"
67
68#include "bbs.h"
69#include "mprand.h"
70
71#include "rc4.h"
bb78535e 72#include "seal.h"
ee33470f 73
74#include "des-ofb.h"
75#include "des3-ofb.h"
bb78535e 76#include "rc2-ofb.h"
ee33470f 77#include "rc5-ofb.h"
b17f4ed5 78#include "mars-ofb.h"
265fb162 79#include "skipjack-ofb.h"
80#include "tea-ofb.h"
81#include "xtea-ofb.h"
ee33470f 82#include "blowfish-ofb.h"
bb78535e 83#include "twofish-ofb.h"
ee33470f 84#include "idea-ofb.h"
bb78535e 85#include "cast128-ofb.h"
86#include "cast256-ofb.h"
0ba18b90 87#include "noekeon-ofb.h"
bb78535e 88#include "rijndael-ofb.h"
2e8eb64a 89#include "rijndael192-ofb.h"
90#include "rijndael256-ofb.h"
b17f4ed5 91#include "safer-ofb.h"
92#include "safersk-ofb.h"
265fb162 93#include "square-ofb.h"
bb78535e 94#include "serpent-ofb.h"
95
96#include "des-counter.h"
97#include "des3-counter.h"
98#include "rc2-counter.h"
99#include "rc5-counter.h"
b17f4ed5 100#include "mars-counter.h"
265fb162 101#include "skipjack-counter.h"
102#include "tea-counter.h"
103#include "xtea-counter.h"
bb78535e 104#include "blowfish-counter.h"
105#include "twofish-counter.h"
106#include "idea-counter.h"
107#include "cast128-counter.h"
108#include "cast256-counter.h"
0ba18b90 109#include "noekeon-counter.h"
bb78535e 110#include "rijndael-counter.h"
2e8eb64a 111#include "rijndael192-counter.h"
112#include "rijndael256-counter.h"
b17f4ed5 113#include "safer-counter.h"
114#include "safersk-counter.h"
265fb162 115#include "square-counter.h"
bb78535e 116#include "serpent-counter.h"
117
d3187d77 118#include "md2-mgf.h"
bb78535e 119#include "md4-mgf.h"
120#include "md5-mgf.h"
121#include "sha-mgf.h"
265fb162 122#include "tiger-mgf.h"
123#include "rmd128-mgf.h"
bb78535e 124#include "rmd160-mgf.h"
265fb162 125#include "rmd256-mgf.h"
126#include "rmd320-mgf.h"
ee33470f 127
128#include "rmd160.h"
129
130/*----- Data structures ---------------------------------------------------*/
131
132typedef struct gen {
133 const char *name;
134 grand *(*seed)(unsigned /*i*/);
135 unsigned i;
136 const char *help;
137} gen;
138
f57c6d85 139extern gen generators[];
ee33470f 140
bb78535e 141#define CIPHERS \
142 E(DES, des) \
143 E(DES3, des3) \
144 E(RC2, rc2) \
145 E(RC5, rc5) \
b17f4ed5 146 E(MARS, mars) \
265fb162 147 E(SKIPJACK, skipjack) \
148 E(TEA, tea) \
149 E(XTEA, xtea) \
bb78535e 150 E(BLOWFISH, blowfish) \
151 E(TWOFISH, twofish) \
152 E(IDEA, idea) \
153 E(CAST128, cast128) \
154 E(CAST256, cast256) \
265fb162 155 E(SQUARE, square) \
b17f4ed5 156 E(SAFER, safer) \
157 E(SAFERSK, safersk) \
0ba18b90 158 E(NOEKEON, noekeon) \
bb78535e 159 E(RIJNDAEL, rijndael) \
2e8eb64a 160 E(RIJNDAEL192, rijndael192) \
161 E(RIJNDAEL256, rijndael256) \
bb78535e 162 E(SERPENT, serpent)
163
164#define HASHES \
d3187d77 165 E(MD2, md2) \
bb78535e 166 E(MD4, md4) \
167 E(MD5, md5) \
168 E(SHA, sha) \
265fb162 169 E(TIGER, tiger) \
170 E(RMD128, rmd128) \
171 E(RMD160, rmd160) \
172 E(RMD256, rmd256) \
173 E(RMD320, rmd320)
bb78535e 174
175#define E(PRE, pre) CIPHER_##PRE,
176enum { CIPHERS CIPHER__bogus };
177#undef E
178
179#define E(PRE, pre) HASH_##PRE,
180enum { HASHES HASH__bogus };
181#undef E
182
cbef819a 183static const struct {
bb78535e 184 const octet *keysz;
185 size_t blksz;
186 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
187 grand *(*counter)(const void */*k*/, size_t /*sz*/);
188} ciphertab[] = {
189#define E(PRE, pre) \
190 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
191 CIPHERS
192#undef E
193};
194
cbef819a 195static const struct {
bb78535e 196 const gchash *h;
197 const octet *keysz;
198 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
199} hashtab[] = {
200#define E(PRE, pre) \
201 { &pre, pre##_mgfkeysz, pre##_mgfrand },
202 HASHES
203#undef E
204};
205
ee33470f 206/*----- Miscellaneous static data -----------------------------------------*/
207
c2181593 208static FILE *outfp;
bafe8a7b 209static mp *outsz = 0;
f0675f8a 210static unsigned maurer_lo = 5, maurer_hi = 8;
ee33470f 211
212static int argc;
213static char **argv;
214
215static unsigned flags = 0;
216
16efd15b 217#define f_progress 1u
218#define f_file 2u
219#define f_fips 4u
220#define f_maurer 8u
221#define f_timer 16u
222#define f_discard 32u
ee33470f 223
224/*----- Help options ------------------------------------------------------*/
225
226static void usage(FILE *fp)
227{
228 pquis(fp, "Usage: $ generator [options]\n");
229}
230
231static void version(FILE *fp)
232{
233 pquis(fp, "$, Catacomb version " VERSION "\n");
234}
235
236static void help(FILE *fp)
237{
238 version(fp);
239 fputc('\n', fp);
240 usage(fp);
241 pquis(fp, "\n\
242Emits a stream of random bytes suitable for, well, all sorts of things.\n\
243The primary objective is to be able to generate streams of input for\n\
244statistical tests, such as Diehard.\n\
245\n\
246Options are specific to the particular generator, although there's a\n\
247common core set:\n\
248\n\
249-h, --help Display this help message.\n\
250-v, --version Display the program's version number.\n\
251-u, --usage Display a useless usage message.\n\
252\n\
253-l, --list Show a list of the supported generators, with\n\
254 their options.\n\
bb78535e 255-f, --fipstest Run the FIPS 140-1 randomness test.\n\
33efa0ae 256-m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
ee33470f 257-o, --output FILE Write output to FILE, not stdout.\n\
258-z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
259-p, --progress Show a little progress meter (on stderr).\n\
04d45209 260-T, --timer Keep track of the CPU time used by the generator.\n\
261-d, --discard Discard the generated output.\n\
ee33470f 262\n\
263(A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
264`k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
265");
266}
267
268/*----- Main options parser -----------------------------------------------*/
269
270static struct option opts[] = {
271
272 /* --- Standard GNU help options --- */
273
274 { "help", 0, 0, 'h' },
275 { "version", 0, 0, 'v' },
276 { "usage", 0, 0, 'u' },
277
278 /* --- Other useful things --- */
279
280 { "list", 0, 0, 'l' },
bb78535e 281 { "fipstest", 0, 0, 'f' },
f0675f8a 282 { "maurer", OPTF_ARGOPT, 0, 'm' },
ee33470f 283 { "output", OPTF_ARGREQ, 0, 'o' },
284 { "size", OPTF_ARGREQ, 0, 'z' },
285 { "progress", 0, 0, 'p' },
04d45209 286 { "timer", 0, 0, 'T' },
287 { "discard", 0, 0, 'd' },
ee33470f 288
289 /* --- End of main table --- */
290
291 { 0, 0, 0, 0 }
292};
293
04d45209 294static const char *sopts = "hvu lfm::o:z:pTd";
ee33470f 295
296#ifndef OPTION_V
297 DA_DECL(option_v, struct option);
298# define OPTION_V
299#endif
300
301static option_v optv = DA_INIT;
302static dstr optd = DSTR_INIT;
303
304/* --- @addopts@ --- *
305 *
306 * Arguments: @const char *s@ = pointer to short options
307 * @struct option *l@ = pointer to long options
308 *
309 * Returns: ---
310 *
311 * Use: Adds a collection of options to the table.
312 */
313
314static void addopts(const char *s, struct option *l)
315{
316 dstr_puts(&optd, s);
317 if (DA_LEN(&optv))
318 DA_SHRINK(&optv, 1);
319 while (l->name)
320 DA_PUSH(&optv, *l++);
321 DA_PUSH(&optv, *l);
322}
323
324/* --- @opt@ --- *
325 *
326 * Arguments: ---
327 *
328 * Returns: Next option from argument array.
329 *
330 * Use: Fetches options, handling the standard ones.
331 */
332
333static int opt(void)
334{
335 for (;;) {
336 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
337 switch (i) {
338 case 'h':
339 help(stdout);
340 exit(0);
341 case 'v':
342 version(stdout);
343 exit(0);
344 case 'u':
345 usage(stdout);
346 exit(0);
347 case 'l': {
348 gen *g;
349 puts("Generators supported:");
350 for (g = generators; g->name; g++)
351 printf(" %s %s\n", g->name, g->help);
352 exit(0);
353 } break;
bb78535e 354 case 'f':
355 flags |= f_fips;
356 break;
357 case 'm':
358 flags |= f_maurer;
f0675f8a 359 if (optarg) {
360 char *p;
361 unsigned long lo, hi;
362 lo = strtoul(optarg, &p, 0);
e3dc2d22 363 if (*p == '-' || *p == ',')
f0675f8a 364 hi = strtoul(p + 1, &p, 0);
365 else
366 hi = lo;
367 if (*p != 0 || hi < lo || lo == 0)
368 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
369 maurer_lo = lo;
370 maurer_hi = hi;
371 }
bb78535e 372 break;
ee33470f 373 case 'o':
374 if (flags & f_file)
375 die(EXIT_FAILURE, "already set an output file");
376 if (strcmp(optarg, "-") == 0)
377 outfp = stdout;
378 else {
379 outfp = fopen(optarg, "w");
380 if (!outfp) {
381 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
bb78535e 382 optarg, strerror(errno));
ee33470f 383 }
384 }
385 flags |= f_file;
386 break;
387 case 'z': {
388 char *p;
bafe8a7b
MW
389 outsz = mp_readstring(outsz, optarg, &p, 0);
390 if (!outsz || MP_NEGP(outsz))
ee33470f 391 die(EXIT_FAILURE, "bad number `%s'", optarg);
392 switch (*p) {
bafe8a7b
MW
393 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
394 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
395 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
ee33470f 396 case 0:
397 break;
398 default:
399 die(EXIT_FAILURE, "bad suffix `%s'", p);
400 break;
401 }
402 if (*p && p[1] != 0)
403 die(EXIT_FAILURE, "bad suffix `%s'", p);
404 } break;
405 case 'p':
406 flags |= f_progress;
407 break;
04d45209 408 case 'T':
409 flags |= f_timer;
410 break;
411 case 'd':
412 flags |= f_discard;
413 break;
ee33470f 414 default:
415 return (i);
416 }
417 }
418}
419
420/*----- Manglers for seed strings -----------------------------------------*/
421
422/* --- @unhex@ --- *
423 *
424 * Arguments: @const char *p@ = pointer to input string
425 * @char **end@ = where the end goes
426 * @dstr *d@ = output buffer
427 *
428 * Returns: ---
429 *
430 * Use: Transforms a hex string into a chunk of binary data.
431 */
432
433static void unhex(const char *p, char **end, dstr *d)
434{
435 while (p[0] && p[1]) {
436 int x = p[0], y = p[1];
437 if ('0' <= x && x <= '9') x -= '0';
438 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
439 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
440 else x = 0;
441 if ('0' <= y && y <= '9') y -= '0';
442 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
443 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
444 else y = 0;
445 DPUTC(d, (x << 4) + y);
446 p += 2;
447 }
448 *end = (char *)p;
449}
450
bb78535e 451/* --- Generate a key --- */
452
453static void textkey(dstr *d, const char *p, const octet *ksz)
454{
455 size_t sz = strlen(p);
456
457 if (!sz)
458 die(EXIT_FAILURE, "zero-length key string");
459 if (keysz(sz, ksz) != sz)
460 DPUTM(d, p, sz);
461 else {
462 rmd160_mgfctx g;
463 rmd160_mgfinit(&g, p, sz);
464 sz = keysz(0, ksz);
465 dstr_ensure(d, sz);
466 rmd160_mgfencrypt(&g, 0, d->buf, sz);
467 d->len += sz;
468 }
469 assert(((void)"I can't seem to choose a good key size",
470 keysz(d->len, ksz) == d->len));
471}
472
473static void hexkey(dstr *d, const char *p, const octet *ksz)
474{
475 char *q;
476 unhex(optarg, &q, d);
477 if (*q)
478 die(EXIT_FAILURE, "bad hex key `%s'", p);
479 if (keysz(d->len, ksz) != d->len)
480 die(EXIT_FAILURE, "bad key length");
481}
482
483static void randkey(dstr *d, const octet *ksz)
484{
485 size_t sz = keysz(0, ksz);
486 dstr_ensure(d, sz);
487 rand_get(RAND_GLOBAL, d->buf, sz);
488 d->len += sz;
489}
490
ee33470f 491/*----- Generators --------------------------------------------------------*/
492
493/* --- Blum-Blum-Shub strong generator --- */
494
ee33470f 495static grand *gen_bbs(unsigned i)
496{
497 /* --- Default modulus --- *
498 *
499 * The factors of this number are
500 *
501 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
45c0fd36 502 * @7754313537966036459299022912838407755462506416274551744201653277@
ee33470f 503 * @313130311731673973886822067@
504 *
505 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
506 * @5374320073594018817245784145742769603334292182227671519041431067@
507 * @61344781426317516045890159@
508 *
bb78535e 509 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
ee33470f 510 * common factors. They were found using this program, with random
511 * starting points.
512 *
513 * I hope that, by publishing these factors, I'll dissuade people from
bb78535e 514 * actually using this modulus in an attempt to attain real security. The
515 * program is quite quick at finding Blum numbers, so there's no excuse for
516 * not generating your own.
ee33470f 517 */
518
519 const char *mt =
eaa515d8 520 "12051128439013574251357214209433471144307319411973256935382082"
521 "84356405274180923922403660880355098909699130818163691602989614"
522 "90135716255689660470370755013177656905237112577648090277537209"
523 "93607817155427455344810369808478266925293635284364998010510985"
524 "0503830397166360721262431179505917248447259735253684659338653";
ee33470f 525
526 /* --- Other things --- */
527
528 grand *r;
529 const char *xt = 0;
87de7c73 530 unsigned bits = 1024;
ee33470f 531 mp *m, *x;
532 unsigned show = 0;
87de7c73 533 const char *kfile = 0, *id = 0, *ktype = 0;
ee33470f 534
535 /* --- Parse options --- */
536
537 static struct option opts[] = {
bb78535e 538 { "modulus", OPTF_ARGREQ, 0, 'M' },
ee33470f 539 { "generate", 0, 0, 'g' },
540 { "seed", OPTF_ARGREQ, 0, 's' },
541 { "bits", OPTF_ARGREQ, 0, 'b' },
542 { "show", 0, 0, 'S' },
87de7c73 543 { "keyring", OPTF_ARGREQ, 0, 'k' },
544 { "id", OPTF_ARGREQ, 0, 'i' },
545 { "type", OPTF_ARGREQ, 0, 't' },
ee33470f 546 { 0, 0, 0, 0 }
547 };
548
bb78535e 549 addopts("M:gs:b:Sk:i:t:", opts);
ee33470f 550
551 for (;;) {
552 int o = opt();
553 if (o < 0)
554 break;
555 switch (o) {
bb78535e 556 case 'M':
ee33470f 557 mt = optarg;
558 break;
559 case 'g':
560 mt = 0;
561 break;
562 case 's':
563 xt = optarg;
564 break;
565 case 'b':
566 bits = strtoul(optarg, 0, 0);
567 if (bits == 0)
568 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
569 break;
570 case 'S':
571 show = 1;
572 break;
87de7c73 573 case 'k':
574 kfile = optarg;
575 mt = 0;
576 break;
577 case 'i':
578 id = optarg;
579 mt = 0;
580 break;
581 case 't':
582 ktype = optarg;
583 mt = 0;
584 break;
ee33470f 585 default:
586 return (0);
587 }
588 }
589
590 /* --- Generate a modulus if one is requested --- */
591
592 if (mt) {
593 char *p;
594 m = mp_readstring(MP_NEW, mt, &p, 0);
87de7c73 595 if (!m || *p || (m->v[0] & 3) != 1)
ee33470f 596 die(EXIT_FAILURE, "bad modulus `%s'", mt);
597 /* Unfortunately I don't know how to test for a Blum integer */
87de7c73 598 } else if (kfile || id || ktype) {
599 key_file kf;
600 key *kk;
601 key_data *kd;
602
603 /* --- Open the key file --- */
604
605 if (!kfile)
606 kfile = "keyring";
607 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
608 die(EXIT_FAILURE, "error opening key file `%s': %s",
609 kfile, strerror(errno));
610 }
611
612 /* --- Find the key --- */
613
614 if (id) {
615 if ((kk = key_bytag(&kf, id)) == 0)
616 die(EXIT_FAILURE, "key `%s' not found", id);
617 } else {
618 if (!ktype)
619 ktype = "bbs";
620 if ((kk = key_bytype(&kf, ktype)) == 0)
621 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
622 }
623
624 /* --- Read the key data --- */
625
ef13e9a4 626 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
87de7c73 627 die(EXIT_FAILURE, "key is not structured");
ef13e9a4 628 if ((kd = key_structfind(kk->k, "n")) == 0)
87de7c73 629 die(EXIT_FAILURE, "key has no subkey `n'");
630 if ((kd->e & KF_ENCMASK) != KENC_MP)
e2edda68 631 die(EXIT_FAILURE, "incompatible subkey encoding");
87de7c73 632 m = MP_COPY(kd->u.m);
633 key_close(&kf);
ee33470f 634 } else {
c2181593 635 bbs_priv bp;
ee33470f 636
052b36d0 637 if (bbs_gen(&bp, bits, &rand_global, 0,
638 (flags & f_progress) ? pgen_ev : 0, 0))
87de7c73 639 die(EXIT_FAILURE, "modulus generation failed");
ee33470f 640 m = bp.n;
641
642 if (show) {
643 fputs("p = ", stderr);
644 mp_writefile(bp.p, stderr, 10);
645 fputs("\nq = ", stderr);
646 mp_writefile(bp.q, stderr, 10);
647 fputs("\nn = ", stderr);
648 mp_writefile(bp.n, stderr, 10);
649 fputc('\n', stderr);
650 }
651
ee33470f 652 mp_drop(bp.p);
653 mp_drop(bp.q);
654 }
655
656 /* --- Set up a seed --- */
657
658 if (!xt)
659 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
660 else {
661 char *p;
662 x = mp_readstring(MP_NEW, xt, &p, 0);
663 if (*p)
664 die(EXIT_FAILURE, "bad modulus `%s'", xt);
665 }
666
667 /* --- Right --- */
668
669 r = bbs_rand(m, x);
670
671 mp_drop(m);
672 mp_drop(x);
673 return (r);
674}
675
676/* --- Catacomb's random number generator --- */
677
678static grand *gen_rand(unsigned i)
679{
680 grand *r = rand_create();
681 dstr d = DSTR_INIT;
682
683 static struct option opts[] = {
684 { "key", OPTF_ARGREQ, 0, 'k' },
685 { "text", OPTF_ARGREQ, 0, 't' },
686 { "hex", OPTF_ARGREQ, 0, 'H' },
ee33470f 687 { 0, 0, 0, 0 }
688 };
689
690 addopts("k:t:H:n", opts);
691
bb78535e 692 r->ops->misc(r, RAND_NOISESRC, &noise_source);
693 r->ops->misc(r, RAND_SEED, 160);
694
ee33470f 695 for (;;) {
696 int o = opt();
697 if (o < 0)
698 break;
699 switch (o) {
bb78535e 700 case 'k':
701 DRESET(&d);
1d9ac42f 702 textkey(&d, optarg, rmd160_hmackeysz);
bb78535e 703 r->ops->misc(r, RAND_KEY, d.buf, d.len);
704 break;
ee33470f 705 case 't':
706 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
707 break;
bb78535e 708 case 'H':
ee33470f 709 DRESET(&d);
1d9ac42f 710 hexkey(&d, optarg, rmd160_hmackeysz);
ee33470f 711 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
ee33470f 712 break;
713 }
714 }
715
716 dstr_destroy(&d);
717 return (r);
718}
719
720/* --- RC4 output --- */
721
722static grand *gen_rc4(unsigned i)
723{
724 grand *r;
725 dstr d = DSTR_INIT;
726
727 static struct option opts[] = {
728 { "key", OPTF_ARGREQ, 0, 'k' },
729 { "hex", OPTF_ARGREQ, 0, 'H' },
730 { 0, 0, 0, 0 }
731 };
732
733 addopts("k:H:", opts);
734
735 for (;;) {
736 int o = opt();
737 if (o < 0)
738 break;
739 switch (o) {
bb78535e 740 case 'k':
741 DRESET(&d);
742 textkey(&d, optarg, rc4_keysz);
743 break;
744 case 'H':
745 DRESET(&d);
746 hexkey(&d, optarg, rc4_keysz);
747 break;
ee33470f 748 default:
749 return (0);
750 }
751 }
752
bb78535e 753 if (!d.len)
754 randkey(&d, rc4_keysz);
ee33470f 755 r = rc4_rand(d.buf, d.len);
756 dstr_destroy(&d);
757 return (r);
758}
759
bb78535e 760/* --- SEAL output --- */
ee33470f 761
bb78535e 762static grand *gen_seal(unsigned i)
763{
764 grand *r;
765 dstr d = DSTR_INIT;
766 uint32 n = 0;
ee33470f 767
bb78535e 768 static struct option opts[] = {
769 { "key", OPTF_ARGREQ, 0, 'k' },
770 { "hex", OPTF_ARGREQ, 0, 'H' },
771 { "sequence", OPTF_ARGREQ, 0, 'n' },
772 { 0, 0, 0, 0 }
773 };
ee33470f 774
bb78535e 775 addopts("k:H:n:", opts);
ee33470f 776
bb78535e 777 for (;;) {
778 int o = opt();
779 if (o < 0)
780 break;
781 switch (o) {
782 case 'k':
783 DRESET(&d);
784 textkey(&d, optarg, seal_keysz);
785 break;
786 case 'H':
787 DRESET(&d);
788 hexkey(&d, optarg, seal_keysz);
789 break;
790 case 'n': {
791 char *p;
792 n = strtoul(optarg, &p, 0);
793 if (*p)
794 die(EXIT_FAILURE, "bad number `%s'", optarg);
795 } break;
796 default:
797 return (0);
798 }
799 }
800
801 if (!d.len)
802 randkey(&d, seal_keysz);
803 r = seal_rand(d.buf, d.len, n);
804 dstr_destroy(&d);
805 return (r);
806}
807
808/* --- Output feedback generators --- */
ee33470f 809
810static grand *gen_ofb(unsigned i)
811{
812 grand *r;
813 dstr d = DSTR_INIT;
814 dstr iv = DSTR_INIT;
815
816 static struct option opts[] = {
817 { "key", OPTF_ARGREQ, 0, 'k' },
818 { "hex", OPTF_ARGREQ, 0, 'H' },
819 { "iv", OPTF_ARGREQ, 0, 'i' },
820 { 0, 0, 0, 0 }
821 };
822
823 addopts("k:H:i:", opts);
824
825 for (;;) {
826 int o = opt();
827 if (o < 0)
828 break;
829 switch (o) {
bb78535e 830 case 'k':
831 DRESET(&d);
832 textkey(&d, optarg, ciphertab[i].keysz);
833 break;
834 case 'H':
835 DRESET(&d);
836 hexkey(&d, optarg, ciphertab[i].keysz);
837 break;
ee33470f 838 case 'i': {
839 char *p;
1cdc3a62 840 DRESET(&iv);
ee33470f 841 unhex(optarg, &p, &iv);
842 if (*p)
843 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
844 if (iv.len != ciphertab[i].blksz) {
845 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
846 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
847 }
ee33470f 848 } break;
849 default:
850 return (0);
851 }
852 }
853
bb78535e 854 if (!d.len)
855 randkey(&d, ciphertab[i].keysz);
856 r = ciphertab[i].ofb(d.buf, d.len);
1cdc3a62 857 if (iv.len)
bb78535e 858 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 859
bb78535e 860 dstr_destroy(&d);
861 dstr_destroy(&iv);
862 return (r);
863}
864
865/* --- Counter generators --- */
866
867static grand *gen_counter(unsigned i)
868{
869 grand *r;
870 dstr d = DSTR_INIT;
871 dstr iv = DSTR_INIT;
ee33470f 872
bb78535e 873 static struct option opts[] = {
874 { "key", OPTF_ARGREQ, 0, 'k' },
875 { "hex", OPTF_ARGREQ, 0, 'H' },
876 { "iv", OPTF_ARGREQ, 0, 'i' },
877 { 0, 0, 0, 0 }
878 };
879
880 addopts("k:H:i:", opts);
881
882 for (;;) {
883 int o = opt();
884 if (o < 0)
885 break;
886 switch (o) {
887 case 'k':
888 DRESET(&d);
889 textkey(&d, optarg, ciphertab[i].keysz);
890 break;
891 case 'H':
892 DRESET(&d);
893 hexkey(&d, optarg, ciphertab[i].keysz);
894 break;
895 case 'i': {
896 char *p;
1cdc3a62 897 DRESET(&iv);
bb78535e 898 unhex(optarg, &p, &iv);
899 if (*p)
900 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
901 if (iv.len != ciphertab[i].blksz) {
902 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
903 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
904 }
bb78535e 905 } break;
906 default:
907 return (0);
908 }
909 }
910
911 if (!d.len)
912 randkey(&d, ciphertab[i].keysz);
913 r = ciphertab[i].counter(d.buf, d.len);
1cdc3a62 914 if (iv.len)
ee33470f 915 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 916
917 dstr_destroy(&d);
918 dstr_destroy(&iv);
919 return (r);
920}
921
bb78535e 922/* --- Mask generators --- */
923
924static grand *gen_mgf(unsigned i)
925{
926 grand *r;
927 dstr d = DSTR_INIT;
928 uint32 c = 0;
929
930 static struct option opts[] = {
931 { "key", OPTF_ARGREQ, 0, 'k' },
932 { "hex", OPTF_ARGREQ, 0, 'H' },
933 { "index", OPTF_ARGREQ, 0, 'i' },
934 { 0, 0, 0, 0 }
935 };
936
937 addopts("k:H:i:", opts);
938
939 for (;;) {
940 int o = opt();
941 if (o < 0)
942 break;
943 switch (o) {
944 case 'k':
945 DRESET(&d);
946 textkey(&d, optarg, hashtab[i].keysz);
947 break;
948 case 'H':
949 DRESET(&d);
950 hexkey(&d, optarg, hashtab[i].keysz);
951 break;
952 case 'i': {
953 char *p;
954 c = strtoul(optarg, &p, 0);
955 if (*p)
956 die(EXIT_FAILURE, "bad index `%s'", optarg);
957 } break;
958 default:
959 return (0);
960 }
961 }
962
963 if (!d.len)
964 randkey(&d, hashtab[i].keysz);
965
966 r = hashtab[i].mgf(d.buf, d.len);
967 if (c)
968 r->ops->misc(r, GRAND_SEEDUINT32, c);
969
970 dstr_destroy(&d);
971 return (r);
972}
973
ee33470f 974/* --- Fibonacci generator --- */
975
976static grand *gen_fib(unsigned i)
977{
978 grand *r;
979 uint32 s = 0;
980 char *p;
981 unsigned set = 0;
982
983 static struct option opts[] = {
984 { "seed", OPTF_ARGREQ, 0, 's' },
985 { 0, 0, 0, 0 }
986 };
987
988 addopts("s:", opts);
989
990 for (;;) {
991 int o = opt();
992 if (o < 0)
993 break;
994 switch (o) {
995 case 's':
996 s = strtoul(optarg, &p, 0);
997 if (*p)
998 die(EXIT_FAILURE, "bad integer `%s'", optarg);
999 set = 1;
1000 break;
1001 default:
1002 return (0);
1003 }
1004 }
1005 r = fibrand_create(s);
1006 if (!set)
1007 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1008 return (r);
1009}
1010
1011/* --- LC generator --- */
1012
1013static grand *gen_lc(unsigned i)
1014{
1015 uint32 s = 0;
1016 char *p;
1017 unsigned set = 0;
1018
1019 static struct option opts[] = {
1020 { "seed", OPTF_ARGREQ, 0, 's' },
1021 { 0, 0, 0, 0 }
1022 };
1023
1024 addopts("s:", opts);
1025
1026 for (;;) {
1027 int o = opt();
1028 if (o < 0)
1029 break;
1030 switch (o) {
1031 case 's':
1032 s = strtoul(optarg, &p, 0);
1033 if (*p)
1034 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1035 set = 1;
1036 break;
1037 default:
1038 return (0);
1039 }
1040 }
1041 if (!set) {
1042 do
1043 s = rand_global.ops->range(&rand_global, LCRAND_P);
1044 while (s == LCRAND_FIXEDPT);
1045 }
1046 return (lcrand_create(s));
1047}
1048
1049/* --- Basic options parser -- can't generate output --- */
1050
1051static grand *gen_opts(unsigned i)
1052{
1053 while (opt() >= 0)
1054 ;
1055 return (0);
1056}
1057
1058/*----- Generators table --------------------------------------------------*/
1059
f57c6d85 1060gen generators[] = {
ee33470f 1061 { "fibonacci", gen_fib, 0,
1062 "[-s SEED]" },
1063 { "lc", gen_lc, 0,
1064 "[-s SEED]" },
bb78535e 1065#define E(PRE, pre) \
1066 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
ee33470f 1067 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1068 CIPHERS
1069#undef E
1070#define E(PRE, pre) \
1071 { #pre "-counter", gen_counter, CIPHER_##PRE, \
ee33470f 1072 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1073 CIPHERS
f57c6d85 1074#undef E
bb78535e 1075#define E(PRE, pre) \
1076 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1077 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1078 HASHES
f57c6d85 1079#undef E
ee33470f 1080 { "rc4", gen_rc4, 0,
1081 "[-k KEY-PHRASE] [-H HEX-KEY]" },
bb78535e 1082 { "seal", gen_seal, 0,
1083 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
ee33470f 1084 { "rand", gen_rand, 0,
1085 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1086 { "bbs", gen_bbs, 0,
bb78535e 1087 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
87de7c73 1088 },
ee33470f 1089 { 0, 0, 0, 0 },
1090};
1091
1092static gen optsg = { "options", gen_opts, 0,
1093 "This message shouldn't be printed." };
1094
f0675f8a 1095/*----- Random number generation ------------------------------------------*/
ee33470f 1096
f0675f8a 1097static int genfile(const void *buf, size_t sz, void *p)
1098{
1099 FILE *fp = p;
1100 if (fwrite(buf, 1, sz, fp) != sz)
1101 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1102 return (0);
1103}
1104
1105static int genbuf(const void *buf, size_t sz, void *p)
1106{
1107 octet **pp = p;
1108 memcpy(*pp, buf, sz);
1109 *pp += sz;
1110 return (0);
1111}
1112
e3dc2d22 1113typedef struct genmaurer_ctx {
1114 size_t n;
1115 maurer_ctx *m;
1116} genmaurer_ctx;
1117
1118static int genmaurer(const void *buf, size_t sz, void *p)
1119{
1120 genmaurer_ctx *g = p;
1121 size_t i;
1122
1123 for (i = 0; i < g->n; i++)
1124 maurer_test(&g->m[i], buf, sz);
1125 return (0);
1126}
1127
15df46bc
MW
1128static double doubletime(void)
1129{
1130#ifdef PORTABLE
1131 static time_t start = (time_t)-1;
1132 time_t now = time(0);
1133
1134 if (start == (time_t)-1) start = now;
1135 return difftime(now, start);
1136#else
1137 struct timeval tv;
1138
1139 gettimeofday(&tv, 0);
1140 return (tv.tv_sec + tv.tv_usec/1000000.0);
1141#endif
1142}
1143
bafe8a7b 1144static int generate(grand *r, mp *outsz,
f0675f8a 1145 int (*func)(const void *buf, size_t sz, void *p),
1146 void *p)
ee33470f 1147{
04d45209 1148 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1149
bb78535e 1150 unsigned percent = 0;
bafe8a7b
MW
1151 mp *kb = MP_ZERO, *t = MP_NEW;
1152 dstr d = DSTR_INIT;
15df46bc 1153 double now, last;
bb78535e 1154 static char baton[] = "-\\|/";
ee33470f 1155 char *bp;
f0675f8a 1156 int rc;
04d45209 1157 clock_t clk = 0;
f0675f8a 1158
1159 /* --- Spit out random data --- */
1160
15df46bc 1161 last = doubletime();
f0675f8a 1162 bp = baton;
1163 if (flags & f_progress) {
1164 char *errbuf = xmalloc(BUFSIZ);
1165 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1166 if (outsz)
1167 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1168 else
1169 fputs("[ ] 0\r[/\b", stderr);
1170 fflush(stderr);
1171 }
1172
1173#ifdef SIGPIPE
1174 signal(SIGPIPE, SIG_IGN);
1175#endif
1176
bafe8a7b 1177 while (!outsz || MP_CMP(kb, <, outsz)) {
f0675f8a 1178 octet buf[BUFSIZ];
bafe8a7b 1179 size_t sz = sizeof(buf), left;
04d45209 1180 clock_t c_start, c_stop;
f0675f8a 1181
1182 /* --- Emit a bufferful (or less) of data --- */
1183
1184 if (outsz) {
bafe8a7b
MW
1185 t = mp_sub(t, outsz, kb);
1186 assert(!MP_NEGP(t));
1187 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1188 left = mp_tosizet(t);
1189 if (sz > left) sz = left;
1190 }
f0675f8a 1191 }
04d45209 1192 c_start = clock();
f0675f8a 1193 r->ops->fill(r, buf, sz);
04d45209 1194 c_stop = clock();
1195 clk += c_stop - c_start;
1196 if (func && (rc = func(buf, sz, p)) != 0)
f0675f8a 1197 return (rc);
bafe8a7b
MW
1198 t = mp_fromsizet(t, sz);
1199 kb = mp_add(kb, kb, t);
f0675f8a 1200
1201 /* --- Update the display --- */
1202
1203 if (flags & f_progress) {
f0675f8a 1204 unsigned up = 0;
1205
15df46bc
MW
1206 now = doubletime();
1207
f0675f8a 1208 if (percent > 100)
1209 up = 1;
1210
1211 if (!outsz) {
bbde884a 1212 if (now - last > 0.1) {
f0675f8a 1213 up = 1;
1214 }
1215 if (up)
1216 fputs(" ] ", stderr);
1217 } else {
bafe8a7b
MW
1218 unsigned pc;
1219 t = mp_fromulong(t, 100);
1220 t = mp_mul(t, t, kb);
1221 mp_div(&t, 0, t, outsz);
1222 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1223 pc = mp_touint(t);
bbde884a 1224 if (pc > percent || percent > 100 || now - last > 0.1) {
f0675f8a 1225 if (percent > 100)
1226 percent = 0;
1227 percent &= ~1;
1228 for (; percent < (pc & ~1); percent += 2)
1229 putc('.', stderr);
1230 percent = pc;
1231 for (; pc < 100; pc += 2)
1232 putc(' ', stderr);
1233 fprintf(stderr, "] %3i%% ", percent);
1234 up = 1;
1235 }
1236 }
1237
1238 if (up) {
04d45209 1239 char *kk = kmg;
bafe8a7b
MW
1240 t = mp_add(t, kb, MP_ZERO);
1241 while (mp_bits(t) >= 14) {
1242 t = mp_lsr(t, t, 10);
04d45209 1243 kk++;
f0675f8a 1244 }
bafe8a7b
MW
1245 DRESET(&d);
1246 mp_writedstr(t, &d, 10);
1247 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
f0675f8a 1248 if (outsz) {
1249 unsigned pc;
1250 for (pc = 0; pc < (percent & ~1); pc += 2)
1251 putc('.', stderr);
1252 }
bafe8a7b 1253 last = now;
f0675f8a 1254 }
1255
1256 if (percent > 100)
1257 percent = 0;
1258
bbde884a 1259 if (percent < 100 && up) {
f0675f8a 1260 putc(*bp++, stderr);
1261 putc('\b', stderr);
1262 if (!*bp)
1263 bp = baton;
1264 }
1265 fflush(stderr);
1266 }
bafe8a7b 1267 }
f0675f8a 1268
1269 if (flags & f_progress)
1270 fputc('\n', stderr);
04d45209 1271 if (flags & f_timer) {
bafe8a7b
MW
1272 DRESET(&d);
1273 dstr_puts(&d, "generated ");
1274 mp_writedstr(kb, &d, 10);
1275 dstr_puts(&d, " bytes ");
e3dc2d22 1276 if (!clk)
bafe8a7b 1277 dstr_puts(&d, "too quickly to measure\n");
e3dc2d22 1278 else {
1279 char *kk;
bafe8a7b 1280 double out;
e3dc2d22 1281 double sec = (double)clk/CLOCKS_PER_SEC;
bafe8a7b
MW
1282 unsigned long sh;
1283 double bps;
1284
1285 MP_SHRINK(kb);
1286 switch (MP_LEN(kb)) {
1287 case 0: out = 0; break;
1288 case 1: out = kb->v[0]; break;
1289 default:
1290 sh = mp_bits(kb) - MPW_BITS;
1291 t = mp_lsr(t, kb, sh);
1292 out = ldexp(t->v[0], sh);
1293 break;
1294 }
1295 bps = (8*out)/sec;
e3dc2d22 1296 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1297 ;
bafe8a7b
MW
1298 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1299 fwrite(d.buf, 1, d.len, stderr);
e3dc2d22 1300 }
04d45209 1301 }
bafe8a7b
MW
1302
1303 mp_drop(t);
1304 DDESTROY(&d);
f0675f8a 1305 return (0);
1306}
1307
1308/*----- Main code ---------------------------------------------------------*/
1309
1310int main(int ac, char *av[])
1311{
1312 gen *g = &optsg;
1313 grand *r;
ee33470f 1314
1315 /* --- Initialize mLib --- */
1316
1317 ego(av[0]);
1318 sub_init();
1319
1320 /* --- Set up the main Catacomb generator --- */
1321
1322 rand_noisesrc(RAND_GLOBAL, &noise_source);
bb78535e 1323 rand_seed(RAND_GLOBAL, 160);
ee33470f 1324
1325 /* --- Initialize the options table --- */
1326
1327 addopts(sopts, opts);
1328 argc = ac;
1329 argv = av;
c2181593 1330 outfp = stdout;
ee33470f 1331
1332 /* --- Read the generator out of the first argument --- */
1333
1334 if (argc > 1 && *argv[1] != '-') {
1335 const char *arg = av[1];
1336 size_t sz = strlen(arg);
bc97f84c 1337 gen *gg;
ee33470f 1338
1339 g = 0;
1340 for (gg = generators; gg->name; gg++) {
1341 if (strncmp(arg, gg->name, sz) == 0) {
1342 if (gg->name[sz] == 0) {
1343 g = gg;
1344 break;
1345 } else if (g)
1346 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1347 else
1348 g = gg;
1349 }
1350 }
1351 if (!g)
1352 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1353 argc--;
1354 argv++;
1355 }
1356
1357 /* --- Get a generic random number generator --- */
1358
1359 r = g->seed(g->i);
1360 if (!r || optind != ac - 1) {
1361 usage(stderr);
1362 exit(EXIT_FAILURE);
1363 }
1364
bb78535e 1365 /* --- Do the FIPS test --- */
1366
1367 if (flags & f_fips) {
1368 octet buf[FIPSTEST_BUFSZ];
1369 unsigned rc;
bafe8a7b 1370 mp *t;
f0675f8a 1371 octet *p = buf;
bb78535e 1372
bafe8a7b
MW
1373 t = mp_fromsizet(MP_NEW, sizeof(buf));
1374 generate(r, t, genbuf, &p);
1375 mp_drop(t);
bb78535e 1376 rc = fipstest(buf);
1377 if (rc & FIPSTEST_MONOBIT)
1378 moan("failed monobit test");
1379 if (rc & FIPSTEST_POKER)
1380 moan("failed poker test");
1381 if (rc & FIPSTEST_RUNS)
1382 moan("failed runs test");
1383 if (rc & FIPSTEST_LONGRUNS)
1384 moan("failed long runs test");
1385 if (!rc && (flags & f_progress))
04d45209 1386 fputs("test passed\n", stderr);
bb78535e 1387 return (rc ? EXIT_FAILURE : 0);
1388 }
1389
1390 /* --- Do Maurer's test --- */
1391
1392 if (flags & f_maurer) {
f0675f8a 1393 size_t bufsz;
bb78535e 1394 unsigned i;
1395 unsigned rc = 0;
bafe8a7b 1396 mp *t;
e3dc2d22 1397 genmaurer_ctx g;
bb78535e 1398
1399 static struct { double x; const char *sig; } sigtab[] = {
1400 { 3.2905, "1e-3" },
1401 { 3.0902, "2e-3" },
1402 { 2.8070, "5e-3" },
1403 { 2.5758, "1e-2" },
1404 { 0 , 0 }
1405 };
1406
e3dc2d22 1407 g.n = maurer_hi - maurer_lo + 1;
1408 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1409 for (i = 0; i < g.n; i++)
1410 maurer_init(&g.m[i], i + maurer_lo);
f0675f8a 1411 bufsz = (100 * maurer_hi) << maurer_hi;
e3dc2d22 1412
bafe8a7b
MW
1413 t = mp_fromsizet(MP_NEW, bufsz);
1414 generate(r, t, genmaurer, &g);
1415 mp_drop(t);
f0675f8a 1416
1417 for (i = maurer_lo; i <= maurer_hi; i++) {
e3dc2d22 1418 double z = maurer_done(&g.m[i - maurer_lo]);
bb78535e 1419 double zz = fabs(z);
1420 unsigned j;
1421
1422 for (j = 0; sigtab[j].sig; j++) {
1423 if (zz > sigtab[j].x) {
bb78535e 1424 rc = EXIT_FAILURE;
1425 moan("failed, bits = %u, sig = %s, Z_u = %g",
f0675f8a 1426 i, sigtab[j].sig, z);
bb78535e 1427 break;
1428 }
1429 }
1430 if (flags & f_progress)
04d45209 1431 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
bb78535e 1432 }
1433
e3dc2d22 1434 xfree(g.m);
bb78535e 1435 return (rc);
1436 }
1437
04d45209 1438 /* --- Discard --- */
1439
1440 if (flags & f_discard) {
1441 generate(r, outsz, 0, 0);
1442 return (0);
1443 }
1444
f0675f8a 1445 /* --- Write to a file --- */
bb78535e 1446
ee33470f 1447#ifndef PORTABLE
1448 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1449 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1450#endif
1451
f0675f8a 1452 generate(r, outsz, genfile, outfp);
ee33470f 1453
1454 /* --- Done --- */
1455
1456 r->ops->destroy(r);
ee33470f 1457 return (0);
1458}
1459
1460/*----- That's all, folks -------------------------------------------------*/