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