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