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