math/mpreduce.h: Missing include files.
[u/mdw/catacomb] / progs / rspit.c
1 /* -*-c-*-
2 *
3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <math.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40
41 #ifndef PORTABLE
42 # include <unistd.h>
43 #endif
44
45 #include <mLib/darray.h>
46 #include <mLib/dstr.h>
47 #include <mLib/mdwopt.h>
48 #include <mLib/quis.h>
49 #include <mLib/report.h>
50 #include <mLib/sub.h>
51
52 #include "fipstest.h"
53 #include "grand.h"
54 #include "maurer.h"
55 #include "key.h"
56
57 #include "lcrand.h"
58 #include "fibrand.h"
59 #include "rand.h"
60 #include "noise.h"
61
62 #include "bbs.h"
63 #include "mprand.h"
64
65 #include "rc4.h"
66 #include "seal.h"
67
68 #include "des-ofb.h"
69 #include "des3-ofb.h"
70 #include "rc2-ofb.h"
71 #include "rc5-ofb.h"
72 #include "mars-ofb.h"
73 #include "skipjack-ofb.h"
74 #include "tea-ofb.h"
75 #include "xtea-ofb.h"
76 #include "blowfish-ofb.h"
77 #include "twofish-ofb.h"
78 #include "idea-ofb.h"
79 #include "cast128-ofb.h"
80 #include "cast256-ofb.h"
81 #include "noekeon-ofb.h"
82 #include "rijndael-ofb.h"
83 #include "rijndael192-ofb.h"
84 #include "rijndael256-ofb.h"
85 #include "safer-ofb.h"
86 #include "safersk-ofb.h"
87 #include "square-ofb.h"
88 #include "serpent-ofb.h"
89
90 #include "des-counter.h"
91 #include "des3-counter.h"
92 #include "rc2-counter.h"
93 #include "rc5-counter.h"
94 #include "mars-counter.h"
95 #include "skipjack-counter.h"
96 #include "tea-counter.h"
97 #include "xtea-counter.h"
98 #include "blowfish-counter.h"
99 #include "twofish-counter.h"
100 #include "idea-counter.h"
101 #include "cast128-counter.h"
102 #include "cast256-counter.h"
103 #include "noekeon-counter.h"
104 #include "rijndael-counter.h"
105 #include "rijndael192-counter.h"
106 #include "rijndael256-counter.h"
107 #include "safer-counter.h"
108 #include "safersk-counter.h"
109 #include "square-counter.h"
110 #include "serpent-counter.h"
111
112 #include "md2-mgf.h"
113 #include "md4-mgf.h"
114 #include "md5-mgf.h"
115 #include "sha-mgf.h"
116 #include "tiger-mgf.h"
117 #include "rmd128-mgf.h"
118 #include "rmd160-mgf.h"
119 #include "rmd256-mgf.h"
120 #include "rmd320-mgf.h"
121
122 #include "rmd160.h"
123
124 /*----- Data structures ---------------------------------------------------*/
125
126 typedef struct gen {
127 const char *name;
128 grand *(*seed)(unsigned /*i*/);
129 unsigned i;
130 const char *help;
131 } gen;
132
133 extern gen generators[];
134
135 #define CIPHERS \
136 E(DES, des) \
137 E(DES3, des3) \
138 E(RC2, rc2) \
139 E(RC5, rc5) \
140 E(MARS, mars) \
141 E(SKIPJACK, skipjack) \
142 E(TEA, tea) \
143 E(XTEA, xtea) \
144 E(BLOWFISH, blowfish) \
145 E(TWOFISH, twofish) \
146 E(IDEA, idea) \
147 E(CAST128, cast128) \
148 E(CAST256, cast256) \
149 E(SQUARE, square) \
150 E(SAFER, safer) \
151 E(SAFERSK, safersk) \
152 E(NOEKEON, noekeon) \
153 E(RIJNDAEL, rijndael) \
154 E(RIJNDAEL192, rijndael192) \
155 E(RIJNDAEL256, rijndael256) \
156 E(SERPENT, serpent)
157
158 #define HASHES \
159 E(MD2, md2) \
160 E(MD4, md4) \
161 E(MD5, md5) \
162 E(SHA, sha) \
163 E(TIGER, tiger) \
164 E(RMD128, rmd128) \
165 E(RMD160, rmd160) \
166 E(RMD256, rmd256) \
167 E(RMD320, rmd320)
168
169 #define E(PRE, pre) CIPHER_##PRE,
170 enum { CIPHERS CIPHER__bogus };
171 #undef E
172
173 #define E(PRE, pre) HASH_##PRE,
174 enum { HASHES HASH__bogus };
175 #undef E
176
177 static struct {
178 const octet *keysz;
179 size_t blksz;
180 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
181 grand *(*counter)(const void */*k*/, size_t /*sz*/);
182 } ciphertab[] = {
183 #define E(PRE, pre) \
184 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
185 CIPHERS
186 #undef E
187 };
188
189 static struct {
190 const gchash *h;
191 const octet *keysz;
192 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
193 } hashtab[] = {
194 #define E(PRE, pre) \
195 { &pre, pre##_mgfkeysz, pre##_mgfrand },
196 HASHES
197 #undef E
198 };
199
200 /*----- Miscellaneous static data -----------------------------------------*/
201
202 static FILE *outfp;
203 static size_t outsz = 0;
204 static unsigned maurer_lo = 5, maurer_hi = 8;
205
206 static int argc;
207 static char **argv;
208
209 static unsigned flags = 0;
210
211 #define f_progress 1u
212 #define f_file 2u
213 #define f_fips 4u
214 #define f_maurer 8u
215 #define f_timer 16u
216 #define f_discard 32u
217
218 /*----- Help options ------------------------------------------------------*/
219
220 static void usage(FILE *fp)
221 {
222 pquis(fp, "Usage: $ generator [options]\n");
223 }
224
225 static void version(FILE *fp)
226 {
227 pquis(fp, "$, Catacomb version " VERSION "\n");
228 }
229
230 static void help(FILE *fp)
231 {
232 version(fp);
233 fputc('\n', fp);
234 usage(fp);
235 pquis(fp, "\n\
236 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
237 The primary objective is to be able to generate streams of input for\n\
238 statistical tests, such as Diehard.\n\
239 \n\
240 Options are specific to the particular generator, although there's a\n\
241 common core set:\n\
242 \n\
243 -h, --help Display this help message.\n\
244 -v, --version Display the program's version number.\n\
245 -u, --usage Display a useless usage message.\n\
246 \n\
247 -l, --list Show a list of the supported generators, with\n\
248 their options.\n\
249 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
250 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
251 -o, --output FILE Write output to FILE, not stdout.\n\
252 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
253 -p, --progress Show a little progress meter (on stderr).\n\
254 -T, --timer Keep track of the CPU time used by the generator.\n\
255 -d, --discard Discard the generated output.\n\
256 \n\
257 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
258 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
259 ");
260 }
261
262 /*----- Main options parser -----------------------------------------------*/
263
264 static struct option opts[] = {
265
266 /* --- Standard GNU help options --- */
267
268 { "help", 0, 0, 'h' },
269 { "version", 0, 0, 'v' },
270 { "usage", 0, 0, 'u' },
271
272 /* --- Other useful things --- */
273
274 { "list", 0, 0, 'l' },
275 { "fipstest", 0, 0, 'f' },
276 { "maurer", OPTF_ARGOPT, 0, 'm' },
277 { "output", OPTF_ARGREQ, 0, 'o' },
278 { "size", OPTF_ARGREQ, 0, 'z' },
279 { "progress", 0, 0, 'p' },
280 { "timer", 0, 0, 'T' },
281 { "discard", 0, 0, 'd' },
282
283 /* --- End of main table --- */
284
285 { 0, 0, 0, 0 }
286 };
287
288 static const char *sopts = "hvu lfm::o:z:pTd";
289
290 #ifndef OPTION_V
291 DA_DECL(option_v, struct option);
292 # define OPTION_V
293 #endif
294
295 static option_v optv = DA_INIT;
296 static dstr optd = DSTR_INIT;
297
298 /* --- @addopts@ --- *
299 *
300 * Arguments: @const char *s@ = pointer to short options
301 * @struct option *l@ = pointer to long options
302 *
303 * Returns: ---
304 *
305 * Use: Adds a collection of options to the table.
306 */
307
308 static void addopts(const char *s, struct option *l)
309 {
310 dstr_puts(&optd, s);
311 if (DA_LEN(&optv))
312 DA_SHRINK(&optv, 1);
313 while (l->name)
314 DA_PUSH(&optv, *l++);
315 DA_PUSH(&optv, *l);
316 }
317
318 /* --- @opt@ --- *
319 *
320 * Arguments: ---
321 *
322 * Returns: Next option from argument array.
323 *
324 * Use: Fetches options, handling the standard ones.
325 */
326
327 static int opt(void)
328 {
329 for (;;) {
330 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
331 switch (i) {
332 case 'h':
333 help(stdout);
334 exit(0);
335 case 'v':
336 version(stdout);
337 exit(0);
338 case 'u':
339 usage(stdout);
340 exit(0);
341 case 'l': {
342 gen *g;
343 puts("Generators supported:");
344 for (g = generators; g->name; g++)
345 printf(" %s %s\n", g->name, g->help);
346 exit(0);
347 } break;
348 case 'f':
349 flags |= f_fips;
350 break;
351 case 'm':
352 flags |= f_maurer;
353 if (optarg) {
354 char *p;
355 unsigned long lo, hi;
356 lo = strtoul(optarg, &p, 0);
357 if (*p == '-' || *p == ',')
358 hi = strtoul(p + 1, &p, 0);
359 else
360 hi = lo;
361 if (*p != 0 || hi < lo || lo == 0)
362 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
363 maurer_lo = lo;
364 maurer_hi = hi;
365 }
366 break;
367 case 'o':
368 if (flags & f_file)
369 die(EXIT_FAILURE, "already set an output file");
370 if (strcmp(optarg, "-") == 0)
371 outfp = stdout;
372 else {
373 outfp = fopen(optarg, "w");
374 if (!outfp) {
375 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
376 optarg, strerror(errno));
377 }
378 }
379 flags |= f_file;
380 break;
381 case 'z': {
382 char *p;
383 outsz = strtoul(optarg, &p, 0);
384 if (!outsz)
385 die(EXIT_FAILURE, "bad number `%s'", optarg);
386 switch (*p) {
387 case 'G': case 'g': outsz *= 1024;
388 case 'M': case 'm': outsz *= 1024;
389 case 'K': case 'k': outsz *= 1024;
390 case 0:
391 break;
392 default:
393 die(EXIT_FAILURE, "bad suffix `%s'", p);
394 break;
395 }
396 if (*p && p[1] != 0)
397 die(EXIT_FAILURE, "bad suffix `%s'", p);
398 } break;
399 case 'p':
400 flags |= f_progress;
401 break;
402 case 'T':
403 flags |= f_timer;
404 break;
405 case 'd':
406 flags |= f_discard;
407 break;
408 default:
409 return (i);
410 }
411 }
412 }
413
414 /*----- Manglers for seed strings -----------------------------------------*/
415
416 /* --- @unhex@ --- *
417 *
418 * Arguments: @const char *p@ = pointer to input string
419 * @char **end@ = where the end goes
420 * @dstr *d@ = output buffer
421 *
422 * Returns: ---
423 *
424 * Use: Transforms a hex string into a chunk of binary data.
425 */
426
427 static void unhex(const char *p, char **end, dstr *d)
428 {
429 while (p[0] && p[1]) {
430 int x = p[0], y = p[1];
431 if ('0' <= x && x <= '9') x -= '0';
432 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
433 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
434 else x = 0;
435 if ('0' <= y && y <= '9') y -= '0';
436 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
437 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
438 else y = 0;
439 DPUTC(d, (x << 4) + y);
440 p += 2;
441 }
442 *end = (char *)p;
443 }
444
445 /* --- Generate a key --- */
446
447 static void textkey(dstr *d, const char *p, const octet *ksz)
448 {
449 size_t sz = strlen(p);
450
451 if (!sz)
452 die(EXIT_FAILURE, "zero-length key string");
453 if (keysz(sz, ksz) != sz)
454 DPUTM(d, p, sz);
455 else {
456 rmd160_mgfctx g;
457 rmd160_mgfinit(&g, p, sz);
458 sz = keysz(0, ksz);
459 dstr_ensure(d, sz);
460 rmd160_mgfencrypt(&g, 0, d->buf, sz);
461 d->len += sz;
462 }
463 assert(((void)"I can't seem to choose a good key size",
464 keysz(d->len, ksz) == d->len));
465 }
466
467 static void hexkey(dstr *d, const char *p, const octet *ksz)
468 {
469 char *q;
470 unhex(optarg, &q, d);
471 if (*q)
472 die(EXIT_FAILURE, "bad hex key `%s'", p);
473 if (keysz(d->len, ksz) != d->len)
474 die(EXIT_FAILURE, "bad key length");
475 }
476
477 static void randkey(dstr *d, const octet *ksz)
478 {
479 size_t sz = keysz(0, ksz);
480 dstr_ensure(d, sz);
481 rand_get(RAND_GLOBAL, d->buf, sz);
482 d->len += sz;
483 }
484
485 /*----- Generators --------------------------------------------------------*/
486
487 /* --- Blum-Blum-Shub strong generator --- */
488
489 static grand *gen_bbs(unsigned i)
490 {
491 /* --- Default modulus --- *
492 *
493 * The factors of this number are
494 *
495 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
496 * @7754313537966036459299022912838407755462506416274551744201653277@
497 * @313130311731673973886822067@
498 *
499 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
500 * @5374320073594018817245784145742769603334292182227671519041431067@
501 * @61344781426317516045890159@
502 *
503 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
504 * common factors. They were found using this program, with random
505 * starting points.
506 *
507 * I hope that, by publishing these factors, I'll dissuade people from
508 * actually using this modulus in an attempt to attain real security. The
509 * program is quite quick at finding Blum numbers, so there's no excuse for
510 * not generating your own.
511 */
512
513 const char *mt =
514 "12051128439013574251357214209433471144307319411973256935382082"
515 "84356405274180923922403660880355098909699130818163691602989614"
516 "90135716255689660470370755013177656905237112577648090277537209"
517 "93607817155427455344810369808478266925293635284364998010510985"
518 "0503830397166360721262431179505917248447259735253684659338653";
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, "incompatible 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_hmackeysz);
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_hmackeysz);
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 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
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
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 typedef struct genmaurer_ctx {
1108 size_t n;
1109 maurer_ctx *m;
1110 } genmaurer_ctx;
1111
1112 static int genmaurer(const void *buf, size_t sz, void *p)
1113 {
1114 genmaurer_ctx *g = p;
1115 size_t i;
1116
1117 for (i = 0; i < g->n; i++)
1118 maurer_test(&g->m[i], buf, sz);
1119 return (0);
1120 }
1121
1122 static int generate(grand *r, size_t outsz,
1123 int (*func)(const void *buf, size_t sz, void *p),
1124 void *p)
1125 {
1126 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1127
1128 unsigned percent = 0;
1129 size_t kb = 0;
1130 time_t last;
1131 static char baton[] = "-\\|/";
1132 char *bp;
1133 int rc;
1134 clock_t clk = 0;
1135
1136 /* --- Spit out random data --- */
1137
1138 last = time(0);
1139 bp = baton;
1140 if (flags & f_progress) {
1141 char *errbuf = xmalloc(BUFSIZ);
1142 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1143 if (outsz)
1144 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1145 else
1146 fputs("[ ] 0\r[/\b", stderr);
1147 fflush(stderr);
1148 }
1149
1150 #ifdef SIGPIPE
1151 signal(SIGPIPE, SIG_IGN);
1152 #endif
1153
1154 do {
1155 octet buf[BUFSIZ];
1156 size_t sz = sizeof(buf);
1157 clock_t c_start, c_stop;
1158
1159 /* --- Emit a bufferful (or less) of data --- */
1160
1161 if (outsz) {
1162 if (sz > outsz - kb)
1163 sz = outsz - kb;
1164 }
1165 c_start = clock();
1166 r->ops->fill(r, buf, sz);
1167 c_stop = clock();
1168 clk += c_stop - c_start;
1169 if (func && (rc = func(buf, sz, p)) != 0)
1170 return (rc);
1171 kb += sz;
1172
1173 /* --- Update the display --- */
1174
1175 if (flags & f_progress) {
1176 time_t t = time(0);
1177 unsigned up = 0;
1178
1179 if (percent > 100)
1180 up = 1;
1181
1182 if (!outsz) {
1183 if (difftime(t, last) > 1.0) {
1184 up = 1;
1185 }
1186 if (up)
1187 fputs(" ] ", stderr);
1188 } else {
1189 unsigned pc = kb * 100.0 / outsz;
1190 if (pc > percent || percent > 100 || difftime(t, last) > 1.0) {
1191 if (percent > 100)
1192 percent = 0;
1193 percent &= ~1;
1194 for (; percent < (pc & ~1); percent += 2)
1195 putc('.', stderr);
1196 percent = pc;
1197 for (; pc < 100; pc += 2)
1198 putc(' ', stderr);
1199 fprintf(stderr, "] %3i%% ", percent);
1200 up = 1;
1201 }
1202 }
1203
1204 if (up) {
1205 size_t q = kb;
1206 char *kk = kmg;
1207 while (q > 8192 && kk[1]) {
1208 q >>= 10;
1209 kk++;
1210 }
1211 fprintf(stderr, "%4i%c\r[", (int)q, *kk);
1212 if (outsz) {
1213 unsigned pc;
1214 for (pc = 0; pc < (percent & ~1); pc += 2)
1215 putc('.', stderr);
1216 }
1217 last = t;
1218 }
1219
1220 if (percent > 100)
1221 percent = 0;
1222
1223 if (percent < 100) {
1224 putc(*bp++, stderr);
1225 putc('\b', stderr);
1226 if (!*bp)
1227 bp = baton;
1228 }
1229 fflush(stderr);
1230 }
1231
1232 /* --- Terminate the loop --- */
1233
1234 } while (!outsz || kb < outsz);
1235
1236 if (flags & f_progress)
1237 fputc('\n', stderr);
1238 if (flags & f_timer) {
1239 fprintf(stderr, "generated %lu bytes ", (unsigned long)outsz);
1240 if (!clk)
1241 fputs("too quickly to measure\n", stderr);
1242 else {
1243 char *kk;
1244 double sec = (double)clk/CLOCKS_PER_SEC;
1245 double bps = (outsz << 3)/sec;
1246 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1247 ;
1248 fprintf(stderr, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1249 }
1250 }
1251 return (0);
1252 }
1253
1254 /*----- Main code ---------------------------------------------------------*/
1255
1256 int main(int ac, char *av[])
1257 {
1258 gen *g = &optsg;
1259 grand *r;
1260
1261 /* --- Initialize mLib --- */
1262
1263 ego(av[0]);
1264 sub_init();
1265
1266 /* --- Set up the main Catacomb generator --- */
1267
1268 rand_noisesrc(RAND_GLOBAL, &noise_source);
1269 rand_seed(RAND_GLOBAL, 160);
1270
1271 /* --- Initialize the options table --- */
1272
1273 addopts(sopts, opts);
1274 argc = ac;
1275 argv = av;
1276 outfp = stdout;
1277
1278 /* --- Read the generator out of the first argument --- */
1279
1280 if (argc > 1 && *argv[1] != '-') {
1281 const char *arg = av[1];
1282 size_t sz = strlen(arg);
1283 gen *gg;
1284
1285 g = 0;
1286 for (gg = generators; gg->name; gg++) {
1287 if (strncmp(arg, gg->name, sz) == 0) {
1288 if (gg->name[sz] == 0) {
1289 g = gg;
1290 break;
1291 } else if (g)
1292 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1293 else
1294 g = gg;
1295 }
1296 }
1297 if (!g)
1298 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1299 argc--;
1300 argv++;
1301 }
1302
1303 /* --- Get a generic random number generator --- */
1304
1305 r = g->seed(g->i);
1306 if (!r || optind != ac - 1) {
1307 usage(stderr);
1308 exit(EXIT_FAILURE);
1309 }
1310
1311 /* --- Do the FIPS test --- */
1312
1313 if (flags & f_fips) {
1314 octet buf[FIPSTEST_BUFSZ];
1315 unsigned rc;
1316 octet *p = buf;
1317
1318 generate(r, sizeof(buf), genbuf, &p);
1319 rc = fipstest(buf);
1320 if (rc & FIPSTEST_MONOBIT)
1321 moan("failed monobit test");
1322 if (rc & FIPSTEST_POKER)
1323 moan("failed poker test");
1324 if (rc & FIPSTEST_RUNS)
1325 moan("failed runs test");
1326 if (rc & FIPSTEST_LONGRUNS)
1327 moan("failed long runs test");
1328 if (!rc && (flags & f_progress))
1329 fputs("test passed\n", stderr);
1330 return (rc ? EXIT_FAILURE : 0);
1331 }
1332
1333 /* --- Do Maurer's test --- */
1334
1335 if (flags & f_maurer) {
1336 size_t bufsz;
1337 unsigned i;
1338 unsigned rc = 0;
1339 genmaurer_ctx g;
1340
1341 static struct { double x; const char *sig; } sigtab[] = {
1342 { 3.2905, "1e-3" },
1343 { 3.0902, "2e-3" },
1344 { 2.8070, "5e-3" },
1345 { 2.5758, "1e-2" },
1346 { 0 , 0 }
1347 };
1348
1349 g.n = maurer_hi - maurer_lo + 1;
1350 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1351 for (i = 0; i < g.n; i++)
1352 maurer_init(&g.m[i], i + maurer_lo);
1353 bufsz = (100 * maurer_hi) << maurer_hi;
1354
1355 generate(r, bufsz, genmaurer, &g);
1356
1357 for (i = maurer_lo; i <= maurer_hi; i++) {
1358 double z = maurer_done(&g.m[i - maurer_lo]);
1359 double zz = fabs(z);
1360 unsigned j;
1361
1362 for (j = 0; sigtab[j].sig; j++) {
1363 if (zz > sigtab[j].x) {
1364 rc = EXIT_FAILURE;
1365 moan("failed, bits = %u, sig = %s, Z_u = %g",
1366 i, sigtab[j].sig, z);
1367 break;
1368 }
1369 }
1370 if (flags & f_progress)
1371 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1372 }
1373
1374 xfree(g.m);
1375 return (rc);
1376 }
1377
1378 /* --- Discard --- */
1379
1380 if (flags & f_discard) {
1381 generate(r, outsz, 0, 0);
1382 return (0);
1383 }
1384
1385 /* --- Write to a file --- */
1386
1387 #ifndef PORTABLE
1388 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1389 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1390 #endif
1391
1392 generate(r, outsz, genfile, outfp);
1393
1394 /* --- Done --- */
1395
1396 r->ops->destroy(r);
1397 return (0);
1398 }
1399
1400 /*----- That's all, folks -------------------------------------------------*/