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