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