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