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