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