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