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