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