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