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