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