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