Reorganized, and removed `-sched' test set.
[u/mdw/catacomb] / rspit.c
CommitLineData
ee33470f 1/* -*-c-*-
2 *
1d9ac42f 3 * $Id: rspit.c,v 1.15 2001/04/19 18:26:13 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 $
1d9ac42f 33 * Revision 1.15 2001/04/19 18:26:13 mdw
34 * Use the new MAC keysize names.
35 *
d3187d77 36 * Revision 1.14 2001/02/21 20:03:22 mdw
37 * Added support for MD2 hash function.
38 *
16efd15b 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 *
bc97f84c 43 * Revision 1.12 2000/10/08 15:49:18 mdw
44 * Remove failed kludge for shutting up a warning.
45 *
f57c6d85 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 *
e3dc2d22 52 * Revision 1.10 2000/08/11 21:34:59 mdw
53 * New restartable interface to Maurer testing.
54 *
04d45209 55 * Revision 1.9 2000/08/04 23:24:15 mdw
56 * Add a timer and a discard option.
57 *
33efa0ae 58 * Revision 1.8 2000/07/29 22:05:47 mdw
59 * Fix error in help message about Maurer test syntax.
60 *
f0675f8a 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 *
265fb162 65 * Revision 1.6 2000/07/15 20:53:35 mdw
66 * Add a load of new ciphers and hashes.
67 *
c2181593 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 *
bb78535e 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 *
052b36d0 76 * Revision 1.3 2000/02/12 18:21:03 mdw
77 * Overhaul of key management (again).
78 *
87de7c73 79 * Revision 1.2 1999/12/22 15:59:51 mdw
80 * New prime-search system. Read BBS keys from key files.
81 *
ee33470f 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
bb78535e 91#include <assert.h>
ee33470f 92#include <errno.h>
bb78535e 93#include <math.h>
ee33470f 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
bb78535e 111#include "fipstest.h"
ee33470f 112#include "grand.h"
bb78535e 113#include "maurer.h"
87de7c73 114#include "key.h"
ee33470f 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"
bb78535e 125#include "seal.h"
ee33470f 126
127#include "des-ofb.h"
128#include "des3-ofb.h"
bb78535e 129#include "rc2-ofb.h"
ee33470f 130#include "rc5-ofb.h"
265fb162 131#include "skipjack-ofb.h"
132#include "tea-ofb.h"
133#include "xtea-ofb.h"
ee33470f 134#include "blowfish-ofb.h"
bb78535e 135#include "twofish-ofb.h"
ee33470f 136#include "idea-ofb.h"
bb78535e 137#include "cast128-ofb.h"
138#include "cast256-ofb.h"
139#include "rijndael-ofb.h"
265fb162 140#include "square-ofb.h"
bb78535e 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"
265fb162 147#include "skipjack-counter.h"
148#include "tea-counter.h"
149#include "xtea-counter.h"
bb78535e 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"
265fb162 156#include "square-counter.h"
bb78535e 157#include "serpent-counter.h"
158
d3187d77 159#include "md2-mgf.h"
bb78535e 160#include "md4-mgf.h"
161#include "md5-mgf.h"
162#include "sha-mgf.h"
265fb162 163#include "tiger-mgf.h"
164#include "rmd128-mgf.h"
bb78535e 165#include "rmd160-mgf.h"
265fb162 166#include "rmd256-mgf.h"
167#include "rmd320-mgf.h"
ee33470f 168
169#include "rmd160.h"
170
171/*----- Data structures ---------------------------------------------------*/
172
173typedef struct gen {
174 const char *name;
175 grand *(*seed)(unsigned /*i*/);
176 unsigned i;
177 const char *help;
178} gen;
179
f57c6d85 180extern gen generators[];
ee33470f 181
bb78535e 182#define CIPHERS \
183 E(DES, des) \
184 E(DES3, des3) \
185 E(RC2, rc2) \
186 E(RC5, rc5) \
265fb162 187 E(SKIPJACK, skipjack) \
188 E(TEA, tea) \
189 E(XTEA, xtea) \
bb78535e 190 E(BLOWFISH, blowfish) \
191 E(TWOFISH, twofish) \
192 E(IDEA, idea) \
193 E(CAST128, cast128) \
194 E(CAST256, cast256) \
265fb162 195 E(SQUARE, square) \
bb78535e 196 E(RIJNDAEL, rijndael) \
197 E(SERPENT, serpent)
198
199#define HASHES \
d3187d77 200 E(MD2, md2) \
bb78535e 201 E(MD4, md4) \
202 E(MD5, md5) \
203 E(SHA, sha) \
265fb162 204 E(TIGER, tiger) \
205 E(RMD128, rmd128) \
206 E(RMD160, rmd160) \
207 E(RMD256, rmd256) \
208 E(RMD320, rmd320)
bb78535e 209
210#define E(PRE, pre) CIPHER_##PRE,
211enum { CIPHERS CIPHER__bogus };
212#undef E
213
214#define E(PRE, pre) HASH_##PRE,
215enum { HASHES HASH__bogus };
216#undef E
217
218static 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
230static 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
ee33470f 241/*----- Miscellaneous static data -----------------------------------------*/
242
c2181593 243static FILE *outfp;
ee33470f 244static size_t outsz = 0;
f0675f8a 245static unsigned maurer_lo = 5, maurer_hi = 8;
ee33470f 246
247static int argc;
248static char **argv;
249
250static unsigned flags = 0;
251
16efd15b 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
ee33470f 258
259/*----- Help options ------------------------------------------------------*/
260
261static void usage(FILE *fp)
262{
263 pquis(fp, "Usage: $ generator [options]\n");
264}
265
266static void version(FILE *fp)
267{
268 pquis(fp, "$, Catacomb version " VERSION "\n");
269}
270
271static void help(FILE *fp)
272{
273 version(fp);
274 fputc('\n', fp);
275 usage(fp);
276 pquis(fp, "\n\
277Emits a stream of random bytes suitable for, well, all sorts of things.\n\
278The primary objective is to be able to generate streams of input for\n\
279statistical tests, such as Diehard.\n\
280\n\
281Options are specific to the particular generator, although there's a\n\
282common 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\
bb78535e 290-f, --fipstest Run the FIPS 140-1 randomness test.\n\
33efa0ae 291-m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
ee33470f 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\
04d45209 295-T, --timer Keep track of the CPU time used by the generator.\n\
296-d, --discard Discard the generated output.\n\
ee33470f 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
305static 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' },
bb78535e 316 { "fipstest", 0, 0, 'f' },
f0675f8a 317 { "maurer", OPTF_ARGOPT, 0, 'm' },
ee33470f 318 { "output", OPTF_ARGREQ, 0, 'o' },
319 { "size", OPTF_ARGREQ, 0, 'z' },
320 { "progress", 0, 0, 'p' },
04d45209 321 { "timer", 0, 0, 'T' },
322 { "discard", 0, 0, 'd' },
ee33470f 323
324 /* --- End of main table --- */
325
326 { 0, 0, 0, 0 }
327};
328
04d45209 329static const char *sopts = "hvu lfm::o:z:pTd";
ee33470f 330
331#ifndef OPTION_V
332 DA_DECL(option_v, struct option);
333# define OPTION_V
334#endif
335
336static option_v optv = DA_INIT;
337static 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
349static 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
368static 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;
bb78535e 389 case 'f':
390 flags |= f_fips;
391 break;
392 case 'm':
393 flags |= f_maurer;
f0675f8a 394 if (optarg) {
395 char *p;
396 unsigned long lo, hi;
397 lo = strtoul(optarg, &p, 0);
e3dc2d22 398 if (*p == '-' || *p == ',')
f0675f8a 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 }
bb78535e 407 break;
ee33470f 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",
bb78535e 417 optarg, strerror(errno));
ee33470f 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;
04d45209 443 case 'T':
444 flags |= f_timer;
445 break;
446 case 'd':
447 flags |= f_discard;
448 break;
ee33470f 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
468static 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
bb78535e 486/* --- Generate a key --- */
487
488static 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
508static 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
518static 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
ee33470f 526/*----- Generators --------------------------------------------------------*/
527
528/* --- Blum-Blum-Shub strong generator --- */
529
ee33470f 530static 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 *
bb78535e 544 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
ee33470f 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
bb78535e 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.
ee33470f 552 */
553
554 const char *mt =
555 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
556
557 /* --- Other things --- */
558
559 grand *r;
560 const char *xt = 0;
87de7c73 561 unsigned bits = 1024;
ee33470f 562 mp *m, *x;
563 unsigned show = 0;
87de7c73 564 const char *kfile = 0, *id = 0, *ktype = 0;
ee33470f 565
566 /* --- Parse options --- */
567
568 static struct option opts[] = {
bb78535e 569 { "modulus", OPTF_ARGREQ, 0, 'M' },
ee33470f 570 { "generate", 0, 0, 'g' },
571 { "seed", OPTF_ARGREQ, 0, 's' },
572 { "bits", OPTF_ARGREQ, 0, 'b' },
573 { "show", 0, 0, 'S' },
87de7c73 574 { "keyring", OPTF_ARGREQ, 0, 'k' },
575 { "id", OPTF_ARGREQ, 0, 'i' },
576 { "type", OPTF_ARGREQ, 0, 't' },
ee33470f 577 { 0, 0, 0, 0 }
578 };
579
bb78535e 580 addopts("M:gs:b:Sk:i:t:", opts);
ee33470f 581
582 for (;;) {
583 int o = opt();
584 if (o < 0)
585 break;
586 switch (o) {
bb78535e 587 case 'M':
ee33470f 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;
87de7c73 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;
ee33470f 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);
87de7c73 626 if (!m || *p || (m->v[0] & 3) != 1)
ee33470f 627 die(EXIT_FAILURE, "bad modulus `%s'", mt);
628 /* Unfortunately I don't know how to test for a Blum integer */
87de7c73 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);
ee33470f 665 } else {
c2181593 666 bbs_priv bp;
ee33470f 667
052b36d0 668 if (bbs_gen(&bp, bits, &rand_global, 0,
669 (flags & f_progress) ? pgen_ev : 0, 0))
87de7c73 670 die(EXIT_FAILURE, "modulus generation failed");
ee33470f 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
ee33470f 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
709static 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' },
ee33470f 718 { 0, 0, 0, 0 }
719 };
720
721 addopts("k:t:H:n", opts);
722
bb78535e 723 r->ops->misc(r, RAND_NOISESRC, &noise_source);
724 r->ops->misc(r, RAND_SEED, 160);
725
ee33470f 726 for (;;) {
727 int o = opt();
728 if (o < 0)
729 break;
730 switch (o) {
bb78535e 731 case 'k':
732 DRESET(&d);
1d9ac42f 733 textkey(&d, optarg, rmd160_hmackeysz);
bb78535e 734 r->ops->misc(r, RAND_KEY, d.buf, d.len);
735 break;
ee33470f 736 case 't':
737 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
738 break;
bb78535e 739 case 'H':
ee33470f 740 DRESET(&d);
1d9ac42f 741 hexkey(&d, optarg, rmd160_hmackeysz);
ee33470f 742 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
ee33470f 743 break;
744 }
745 }
746
747 dstr_destroy(&d);
748 return (r);
749}
750
751/* --- RC4 output --- */
752
753static 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) {
bb78535e 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;
ee33470f 779 default:
780 return (0);
781 }
782 }
783
bb78535e 784 if (!d.len)
785 randkey(&d, rc4_keysz);
ee33470f 786 r = rc4_rand(d.buf, d.len);
787 dstr_destroy(&d);
788 return (r);
789}
790
bb78535e 791/* --- SEAL output --- */
ee33470f 792
bb78535e 793static grand *gen_seal(unsigned i)
794{
795 grand *r;
796 dstr d = DSTR_INIT;
797 uint32 n = 0;
ee33470f 798
bb78535e 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 };
ee33470f 805
bb78535e 806 addopts("k:H:n:", opts);
ee33470f 807
bb78535e 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 --- */
ee33470f 840
841static 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) {
bb78535e 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;
ee33470f 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
bb78535e 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);
ee33470f 889 }
890
bb78535e 891 dstr_destroy(&d);
892 dstr_destroy(&iv);
893 return (r);
894}
895
896/* --- Counter generators --- */
897
898static grand *gen_counter(unsigned i)
899{
900 grand *r;
901 dstr d = DSTR_INIT;
902 dstr iv = DSTR_INIT;
ee33470f 903
bb78535e 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);
ee33470f 940 if (iv.len) {
bb78535e 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 }
ee33470f 945 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
946 }
947
948 dstr_destroy(&d);
949 dstr_destroy(&iv);
950 return (r);
951}
952
bb78535e 953/* --- Mask generators --- */
954
955static 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
ee33470f 1005/* --- Fibonacci generator --- */
1006
1007static 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
1044static 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
1082static grand *gen_opts(unsigned i)
1083{
1084 while (opt() >= 0)
1085 ;
1086 return (0);
1087}
1088
1089/*----- Generators table --------------------------------------------------*/
1090
f57c6d85 1091gen generators[] = {
ee33470f 1092 { "fibonacci", gen_fib, 0,
1093 "[-s SEED]" },
1094 { "lc", gen_lc, 0,
1095 "[-s SEED]" },
bb78535e 1096#define E(PRE, pre) \
1097 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
ee33470f 1098 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1099 CIPHERS
1100#undef E
1101#define E(PRE, pre) \
1102 { #pre "-counter", gen_counter, CIPHER_##PRE, \
ee33470f 1103 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1104 CIPHERS
f57c6d85 1105#undef E
bb78535e 1106#define E(PRE, pre) \
1107 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1108 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1109 HASHES
f57c6d85 1110#undef E
ee33470f 1111 { "rc4", gen_rc4, 0,
1112 "[-k KEY-PHRASE] [-H HEX-KEY]" },
bb78535e 1113 { "seal", gen_seal, 0,
1114 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
ee33470f 1115 { "rand", gen_rand, 0,
1116 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1117 { "bbs", gen_bbs, 0,
bb78535e 1118 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
87de7c73 1119 },
ee33470f 1120 { 0, 0, 0, 0 },
1121};
1122
1123static gen optsg = { "options", gen_opts, 0,
1124 "This message shouldn't be printed." };
1125
f0675f8a 1126/*----- Random number generation ------------------------------------------*/
ee33470f 1127
f0675f8a 1128static 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
1136static 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
e3dc2d22 1144typedef struct genmaurer_ctx {
1145 size_t n;
1146 maurer_ctx *m;
1147} genmaurer_ctx;
1148
1149static 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
f0675f8a 1159static int generate(grand *r, size_t outsz,
1160 int (*func)(const void *buf, size_t sz, void *p),
1161 void *p)
ee33470f 1162{
04d45209 1163 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1164
bb78535e 1165 unsigned percent = 0;
ee33470f 1166 size_t kb = 0;
1167 time_t last;
bb78535e 1168 static char baton[] = "-\\|/";
ee33470f 1169 char *bp;
f0675f8a 1170 int rc;
04d45209 1171 clock_t clk = 0;
f0675f8a 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
04d45209 1191 do {
f0675f8a 1192 octet buf[BUFSIZ];
1193 size_t sz = sizeof(buf);
04d45209 1194 clock_t c_start, c_stop;
f0675f8a 1195
1196 /* --- Emit a bufferful (or less) of data --- */
1197
1198 if (outsz) {
1199 if (sz > outsz - kb)
1200 sz = outsz - kb;
1201 }
04d45209 1202 c_start = clock();
f0675f8a 1203 r->ops->fill(r, buf, sz);
04d45209 1204 c_stop = clock();
1205 clk += c_stop - c_start;
1206 if (func && (rc = func(buf, sz, p)) != 0)
f0675f8a 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;
04d45209 1243 char *kk = kmg;
1244 while (q > 8192 && kk[1]) {
f0675f8a 1245 q >>= 10;
04d45209 1246 kk++;
f0675f8a 1247 }
04d45209 1248 fprintf(stderr, "%4i%c\r[", q, *kk);
f0675f8a 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
04d45209 1271 } while (!outsz || kb < outsz);
f0675f8a 1272
1273 if (flags & f_progress)
1274 fputc('\n', stderr);
04d45209 1275 if (flags & f_timer) {
e3dc2d22 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 }
04d45209 1287 }
f0675f8a 1288 return (0);
1289}
1290
1291/*----- Main code ---------------------------------------------------------*/
1292
1293int main(int ac, char *av[])
1294{
1295 gen *g = &optsg;
1296 grand *r;
ee33470f 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);
bb78535e 1306 rand_seed(RAND_GLOBAL, 160);
ee33470f 1307
1308 /* --- Initialize the options table --- */
1309
1310 addopts(sopts, opts);
1311 argc = ac;
1312 argv = av;
c2181593 1313 outfp = stdout;
ee33470f 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);
bc97f84c 1320 gen *gg;
ee33470f 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
bb78535e 1348 /* --- Do the FIPS test --- */
1349
1350 if (flags & f_fips) {
1351 octet buf[FIPSTEST_BUFSZ];
1352 unsigned rc;
f0675f8a 1353 octet *p = buf;
bb78535e 1354
f0675f8a 1355 generate(r, sizeof(buf), genbuf, &p);
bb78535e 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))
04d45209 1366 fputs("test passed\n", stderr);
bb78535e 1367 return (rc ? EXIT_FAILURE : 0);
1368 }
1369
1370 /* --- Do Maurer's test --- */
1371
1372 if (flags & f_maurer) {
f0675f8a 1373 size_t bufsz;
bb78535e 1374 unsigned i;
1375 unsigned rc = 0;
e3dc2d22 1376 genmaurer_ctx g;
bb78535e 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
e3dc2d22 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);
f0675f8a 1390 bufsz = (100 * maurer_hi) << maurer_hi;
e3dc2d22 1391
1392 generate(r, bufsz, genmaurer, &g);
f0675f8a 1393
1394 for (i = maurer_lo; i <= maurer_hi; i++) {
e3dc2d22 1395 double z = maurer_done(&g.m[i - maurer_lo]);
bb78535e 1396 double zz = fabs(z);
1397 unsigned j;
1398
1399 for (j = 0; sigtab[j].sig; j++) {
1400 if (zz > sigtab[j].x) {
bb78535e 1401 rc = EXIT_FAILURE;
1402 moan("failed, bits = %u, sig = %s, Z_u = %g",
f0675f8a 1403 i, sigtab[j].sig, z);
bb78535e 1404 break;
1405 }
1406 }
1407 if (flags & f_progress)
04d45209 1408 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
bb78535e 1409 }
1410
e3dc2d22 1411 xfree(g.m);
bb78535e 1412 return (rc);
1413 }
1414
04d45209 1415 /* --- Discard --- */
1416
1417 if (flags & f_discard) {
1418 generate(r, outsz, 0, 0);
1419 return (0);
1420 }
1421
f0675f8a 1422 /* --- Write to a file --- */
bb78535e 1423
ee33470f 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
f0675f8a 1429 generate(r, outsz, genfile, outfp);
ee33470f 1430
1431 /* --- Done --- */
1432
1433 r->ops->destroy(r);
ee33470f 1434 return (0);
1435}
1436
1437/*----- That's all, folks -------------------------------------------------*/