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