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