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