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