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