Make flags be macros rather than enumerations, to ensure that they're
[u/mdw/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 -------------------------------------------------*/