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