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