Deploy the new <ctype.h> and `foocmp' macros from mLib.
[catacomb] / progs / rspit.c
CommitLineData
ee33470f 1/* -*-c-*-
2 *
ee33470f 3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
ee33470f 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
ee33470f 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
ee33470f 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
ee33470f 28/*----- Header files ------------------------------------------------------*/
29
68ea1def
MW
30#define _FILE_OFFSET_BITS 64
31
ee33470f 32#include "config.h"
33
bb78535e 34#include <assert.h>
ee33470f 35#include <errno.h>
bb78535e 36#include <math.h>
ee33470f 37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42
43#ifndef PORTABLE
44# include <unistd.h>
15df46bc 45# include <sys/time.h>
ee33470f 46#endif
47
48#include <mLib/darray.h>
49#include <mLib/dstr.h>
141c1284 50#include <mLib/macros.h>
ee33470f 51#include <mLib/mdwopt.h>
52#include <mLib/quis.h>
53#include <mLib/report.h>
54#include <mLib/sub.h>
55
bafe8a7b
MW
56#include "mp.h"
57#include "mpint.h"
58#include "mplimits.h"
59#include "mptext.h"
60
bb78535e 61#include "fipstest.h"
ee33470f 62#include "grand.h"
bb78535e 63#include "maurer.h"
87de7c73 64#include "key.h"
ee33470f 65
66#include "lcrand.h"
67#include "fibrand.h"
68#include "rand.h"
69#include "noise.h"
70
71#include "bbs.h"
72#include "mprand.h"
73
965c4e75 74#include "chacha.h"
ee33470f 75#include "rc4.h"
965c4e75
MW
76#include "salsa20.h"
77#include "salsa20-core.h"
bb78535e 78#include "seal.h"
78b4ea88 79#include "sha3.h"
ee33470f 80
81#include "des-ofb.h"
82#include "des3-ofb.h"
bb78535e 83#include "rc2-ofb.h"
ee33470f 84#include "rc5-ofb.h"
b17f4ed5 85#include "mars-ofb.h"
265fb162 86#include "skipjack-ofb.h"
87#include "tea-ofb.h"
88#include "xtea-ofb.h"
ee33470f 89#include "blowfish-ofb.h"
bb78535e 90#include "twofish-ofb.h"
ee33470f 91#include "idea-ofb.h"
bb78535e 92#include "cast128-ofb.h"
93#include "cast256-ofb.h"
0ba18b90 94#include "noekeon-ofb.h"
bb78535e 95#include "rijndael-ofb.h"
2e8eb64a 96#include "rijndael192-ofb.h"
97#include "rijndael256-ofb.h"
b17f4ed5 98#include "safer-ofb.h"
99#include "safersk-ofb.h"
265fb162 100#include "square-ofb.h"
bb78535e 101#include "serpent-ofb.h"
102
103#include "des-counter.h"
104#include "des3-counter.h"
105#include "rc2-counter.h"
106#include "rc5-counter.h"
b17f4ed5 107#include "mars-counter.h"
265fb162 108#include "skipjack-counter.h"
109#include "tea-counter.h"
110#include "xtea-counter.h"
bb78535e 111#include "blowfish-counter.h"
112#include "twofish-counter.h"
113#include "idea-counter.h"
114#include "cast128-counter.h"
115#include "cast256-counter.h"
0ba18b90 116#include "noekeon-counter.h"
bb78535e 117#include "rijndael-counter.h"
2e8eb64a 118#include "rijndael192-counter.h"
119#include "rijndael256-counter.h"
b17f4ed5 120#include "safer-counter.h"
121#include "safersk-counter.h"
265fb162 122#include "square-counter.h"
bb78535e 123#include "serpent-counter.h"
124
d3187d77 125#include "md2-mgf.h"
bb78535e 126#include "md4-mgf.h"
127#include "md5-mgf.h"
128#include "sha-mgf.h"
265fb162 129#include "tiger-mgf.h"
130#include "rmd128-mgf.h"
bb78535e 131#include "rmd160-mgf.h"
265fb162 132#include "rmd256-mgf.h"
133#include "rmd320-mgf.h"
ee33470f 134
135#include "rmd160.h"
136
137/*----- Data structures ---------------------------------------------------*/
138
139typedef struct gen {
140 const char *name;
141 grand *(*seed)(unsigned /*i*/);
142 unsigned i;
143 const char *help;
144} gen;
145
f57c6d85 146extern gen generators[];
ee33470f 147
bb78535e 148#define CIPHERS \
149 E(DES, des) \
150 E(DES3, des3) \
151 E(RC2, rc2) \
152 E(RC5, rc5) \
b17f4ed5 153 E(MARS, mars) \
265fb162 154 E(SKIPJACK, skipjack) \
155 E(TEA, tea) \
156 E(XTEA, xtea) \
bb78535e 157 E(BLOWFISH, blowfish) \
158 E(TWOFISH, twofish) \
159 E(IDEA, idea) \
160 E(CAST128, cast128) \
161 E(CAST256, cast256) \
265fb162 162 E(SQUARE, square) \
b17f4ed5 163 E(SAFER, safer) \
164 E(SAFERSK, safersk) \
0ba18b90 165 E(NOEKEON, noekeon) \
bb78535e 166 E(RIJNDAEL, rijndael) \
2e8eb64a 167 E(RIJNDAEL192, rijndael192) \
168 E(RIJNDAEL256, rijndael256) \
bb78535e 169 E(SERPENT, serpent)
170
171#define HASHES \
d3187d77 172 E(MD2, md2) \
bb78535e 173 E(MD4, md4) \
174 E(MD5, md5) \
175 E(SHA, sha) \
265fb162 176 E(TIGER, tiger) \
177 E(RMD128, rmd128) \
178 E(RMD160, rmd160) \
179 E(RMD256, rmd256) \
180 E(RMD320, rmd320)
bb78535e 181
182#define E(PRE, pre) CIPHER_##PRE,
183enum { CIPHERS CIPHER__bogus };
184#undef E
185
186#define E(PRE, pre) HASH_##PRE,
187enum { HASHES HASH__bogus };
188#undef E
189
cbef819a 190static const struct {
bb78535e 191 const octet *keysz;
192 size_t blksz;
193 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
194 grand *(*counter)(const void */*k*/, size_t /*sz*/);
195} ciphertab[] = {
196#define E(PRE, pre) \
197 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
198 CIPHERS
199#undef E
200};
201
cbef819a 202static const struct {
bb78535e 203 const gchash *h;
204 const octet *keysz;
205 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
206} hashtab[] = {
207#define E(PRE, pre) \
208 { &pre, pre##_mgfkeysz, pre##_mgfrand },
209 HASHES
210#undef E
211};
212
965c4e75
MW
213#define SALSAE \
214 E(salsa20, 20,, SALSA20) \
215 E(salsa20, 12,, SALSA20) \
216 E(salsa20, 8,, SALSA20) \
217 E(xsalsa20, 20, X, SALSA20) \
218 E(xsalsa20, 12, X, SALSA20) \
219 E(xsalsa20, 8, X, SALSA20) \
220 E(chacha, 20,, CHACHA) \
221 E(chacha, 12,, CHACHA) \
222 E(chacha, 8,, CHACHA) \
223 E(xchacha, 20, X, CHACHA) \
224 E(xchacha, 12, X, CHACHA) \
225 E(xchacha, 8, X, CHACHA)
226
227#define E(pre, r, x, BASE) pre##_##r##_INDEX,
228enum { SALSAE BOGUS_SALSA };
229#undef E
230
231#define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
232#define CHACHA_GEN(pre, r) pre##r##_rand
233
234#define SALSA20_NAME(r) SALSA20_NAME_##r
235#define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
236#define CHACHA_NAME(r) "chacha" #r
237#define XCHACHA_NAME(r) "xchacha" #r
238
d58b0c17 239static const struct {
965c4e75
MW
240 size_t noncesz;
241 grand *(*gen)(const void *, size_t, const void *);
242} salsatab[] = {
243#define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
244 SALSAE
245#undef E
246};
247
78b4ea88
MW
248#define SHAKES E(128) E(256)
249
250enum {
251#define E(sz) SHAKE##sz##_INDEX,
252 SHAKES
253#undef E
254 SHAKE__LIMIT
255};
256
257static const struct {
258 const octet *ksz;
259 grand *(*shake)(const void *, size_t, const void *, size_t,
260 const void *, size_t);
261 grand *(*kmac)(const void *, size_t,
262 const void *, size_t);
263} shaketab[] = {
264#define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
265 SHAKES
266#undef E
267};
268
ee33470f 269/*----- Miscellaneous static data -----------------------------------------*/
270
c2181593 271static FILE *outfp;
bafe8a7b 272static mp *outsz = 0;
f0675f8a 273static unsigned maurer_lo = 5, maurer_hi = 8;
ee33470f 274
275static int argc;
276static char **argv;
277
278static unsigned flags = 0;
279
16efd15b 280#define f_progress 1u
281#define f_file 2u
282#define f_fips 4u
283#define f_maurer 8u
284#define f_timer 16u
285#define f_discard 32u
ee33470f 286
287/*----- Help options ------------------------------------------------------*/
288
289static void usage(FILE *fp)
290{
291 pquis(fp, "Usage: $ generator [options]\n");
292}
293
294static void version(FILE *fp)
295{
296 pquis(fp, "$, Catacomb version " VERSION "\n");
297}
298
299static void help(FILE *fp)
300{
301 version(fp);
302 fputc('\n', fp);
303 usage(fp);
304 pquis(fp, "\n\
305Emits a stream of random bytes suitable for, well, all sorts of things.\n\
306The primary objective is to be able to generate streams of input for\n\
307statistical tests, such as Diehard.\n\
308\n\
309Options are specific to the particular generator, although there's a\n\
310common core set:\n\
311\n\
312-h, --help Display this help message.\n\
313-v, --version Display the program's version number.\n\
314-u, --usage Display a useless usage message.\n\
315\n\
316-l, --list Show a list of the supported generators, with\n\
317 their options.\n\
bb78535e 318-f, --fipstest Run the FIPS 140-1 randomness test.\n\
33efa0ae 319-m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
ee33470f 320-o, --output FILE Write output to FILE, not stdout.\n\
321-z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
322-p, --progress Show a little progress meter (on stderr).\n\
04d45209 323-T, --timer Keep track of the CPU time used by the generator.\n\
324-d, --discard Discard the generated output.\n\
ee33470f 325\n\
326(A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
327`k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
328");
329}
330
331/*----- Main options parser -----------------------------------------------*/
332
333static struct option opts[] = {
334
335 /* --- Standard GNU help options --- */
336
337 { "help", 0, 0, 'h' },
338 { "version", 0, 0, 'v' },
339 { "usage", 0, 0, 'u' },
340
341 /* --- Other useful things --- */
342
343 { "list", 0, 0, 'l' },
bb78535e 344 { "fipstest", 0, 0, 'f' },
f0675f8a 345 { "maurer", OPTF_ARGOPT, 0, 'm' },
ee33470f 346 { "output", OPTF_ARGREQ, 0, 'o' },
347 { "size", OPTF_ARGREQ, 0, 'z' },
348 { "progress", 0, 0, 'p' },
04d45209 349 { "timer", 0, 0, 'T' },
350 { "discard", 0, 0, 'd' },
ee33470f 351
352 /* --- End of main table --- */
353
354 { 0, 0, 0, 0 }
355};
356
04d45209 357static const char *sopts = "hvu lfm::o:z:pTd";
ee33470f 358
359#ifndef OPTION_V
360 DA_DECL(option_v, struct option);
361# define OPTION_V
362#endif
363
364static option_v optv = DA_INIT;
365static dstr optd = DSTR_INIT;
366
367/* --- @addopts@ --- *
368 *
369 * Arguments: @const char *s@ = pointer to short options
370 * @struct option *l@ = pointer to long options
371 *
372 * Returns: ---
373 *
374 * Use: Adds a collection of options to the table.
375 */
376
377static void addopts(const char *s, struct option *l)
378{
379 dstr_puts(&optd, s);
380 if (DA_LEN(&optv))
381 DA_SHRINK(&optv, 1);
382 while (l->name)
383 DA_PUSH(&optv, *l++);
384 DA_PUSH(&optv, *l);
385}
386
387/* --- @opt@ --- *
388 *
389 * Arguments: ---
390 *
391 * Returns: Next option from argument array.
392 *
393 * Use: Fetches options, handling the standard ones.
394 */
395
396static int opt(void)
397{
398 for (;;) {
399 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
400 switch (i) {
401 case 'h':
402 help(stdout);
403 exit(0);
404 case 'v':
405 version(stdout);
406 exit(0);
407 case 'u':
408 usage(stdout);
409 exit(0);
410 case 'l': {
411 gen *g;
412 puts("Generators supported:");
413 for (g = generators; g->name; g++)
414 printf(" %s %s\n", g->name, g->help);
415 exit(0);
416 } break;
bb78535e 417 case 'f':
418 flags |= f_fips;
419 break;
420 case 'm':
421 flags |= f_maurer;
f0675f8a 422 if (optarg) {
423 char *p;
424 unsigned long lo, hi;
425 lo = strtoul(optarg, &p, 0);
e3dc2d22 426 if (*p == '-' || *p == ',')
f0675f8a 427 hi = strtoul(p + 1, &p, 0);
428 else
429 hi = lo;
430 if (*p != 0 || hi < lo || lo == 0)
431 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
432 maurer_lo = lo;
433 maurer_hi = hi;
434 }
bb78535e 435 break;
ee33470f 436 case 'o':
437 if (flags & f_file)
438 die(EXIT_FAILURE, "already set an output file");
141c1284 439 if (STRCMP(optarg, ==, "-"))
ee33470f 440 outfp = stdout;
441 else {
442 outfp = fopen(optarg, "w");
443 if (!outfp) {
444 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
bb78535e 445 optarg, strerror(errno));
ee33470f 446 }
447 }
448 flags |= f_file;
449 break;
450 case 'z': {
451 char *p;
bafe8a7b
MW
452 outsz = mp_readstring(outsz, optarg, &p, 0);
453 if (!outsz || MP_NEGP(outsz))
ee33470f 454 die(EXIT_FAILURE, "bad number `%s'", optarg);
455 switch (*p) {
bafe8a7b
MW
456 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
457 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
458 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
ee33470f 459 case 0:
460 break;
461 default:
462 die(EXIT_FAILURE, "bad suffix `%s'", p);
463 break;
464 }
465 if (*p && p[1] != 0)
466 die(EXIT_FAILURE, "bad suffix `%s'", p);
467 } break;
468 case 'p':
469 flags |= f_progress;
470 break;
04d45209 471 case 'T':
472 flags |= f_timer;
473 break;
474 case 'd':
475 flags |= f_discard;
476 break;
ee33470f 477 default:
478 return (i);
479 }
480 }
481}
482
483/*----- Manglers for seed strings -----------------------------------------*/
484
485/* --- @unhex@ --- *
486 *
487 * Arguments: @const char *p@ = pointer to input string
488 * @char **end@ = where the end goes
489 * @dstr *d@ = output buffer
490 *
491 * Returns: ---
492 *
493 * Use: Transforms a hex string into a chunk of binary data.
494 */
495
496static void unhex(const char *p, char **end, dstr *d)
497{
498 while (p[0] && p[1]) {
499 int x = p[0], y = p[1];
500 if ('0' <= x && x <= '9') x -= '0';
501 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
502 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
503 else x = 0;
504 if ('0' <= y && y <= '9') y -= '0';
505 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
506 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
507 else y = 0;
508 DPUTC(d, (x << 4) + y);
509 p += 2;
510 }
511 *end = (char *)p;
512}
513
bb78535e 514/* --- Generate a key --- */
515
516static void textkey(dstr *d, const char *p, const octet *ksz)
517{
518 size_t sz = strlen(p);
519
520 if (!sz)
521 die(EXIT_FAILURE, "zero-length key string");
522 if (keysz(sz, ksz) != sz)
523 DPUTM(d, p, sz);
524 else {
525 rmd160_mgfctx g;
526 rmd160_mgfinit(&g, p, sz);
527 sz = keysz(0, ksz);
528 dstr_ensure(d, sz);
529 rmd160_mgfencrypt(&g, 0, d->buf, sz);
530 d->len += sz;
531 }
532 assert(((void)"I can't seem to choose a good key size",
533 keysz(d->len, ksz) == d->len));
534}
535
536static void hexkey(dstr *d, const char *p, const octet *ksz)
537{
538 char *q;
539 unhex(optarg, &q, d);
540 if (*q)
541 die(EXIT_FAILURE, "bad hex key `%s'", p);
542 if (keysz(d->len, ksz) != d->len)
543 die(EXIT_FAILURE, "bad key length");
544}
545
546static void randkey(dstr *d, const octet *ksz)
547{
548 size_t sz = keysz(0, ksz);
549 dstr_ensure(d, sz);
550 rand_get(RAND_GLOBAL, d->buf, sz);
551 d->len += sz;
552}
553
ee33470f 554/*----- Generators --------------------------------------------------------*/
555
556/* --- Blum-Blum-Shub strong generator --- */
557
ee33470f 558static grand *gen_bbs(unsigned i)
559{
560 /* --- Default modulus --- *
561 *
562 * The factors of this number are
563 *
564 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
45c0fd36 565 * @7754313537966036459299022912838407755462506416274551744201653277@
ee33470f 566 * @313130311731673973886822067@
567 *
568 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
569 * @5374320073594018817245784145742769603334292182227671519041431067@
570 * @61344781426317516045890159@
571 *
bb78535e 572 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
ee33470f 573 * common factors. They were found using this program, with random
574 * starting points.
575 *
576 * I hope that, by publishing these factors, I'll dissuade people from
bb78535e 577 * actually using this modulus in an attempt to attain real security. The
578 * program is quite quick at finding Blum numbers, so there's no excuse for
579 * not generating your own.
ee33470f 580 */
581
582 const char *mt =
eaa515d8 583 "12051128439013574251357214209433471144307319411973256935382082"
584 "84356405274180923922403660880355098909699130818163691602989614"
585 "90135716255689660470370755013177656905237112577648090277537209"
586 "93607817155427455344810369808478266925293635284364998010510985"
587 "0503830397166360721262431179505917248447259735253684659338653";
ee33470f 588
589 /* --- Other things --- */
590
591 grand *r;
592 const char *xt = 0;
87de7c73 593 unsigned bits = 1024;
ee33470f 594 mp *m, *x;
595 unsigned show = 0;
87de7c73 596 const char *kfile = 0, *id = 0, *ktype = 0;
ee33470f 597
598 /* --- Parse options --- */
599
600 static struct option opts[] = {
bb78535e 601 { "modulus", OPTF_ARGREQ, 0, 'M' },
ee33470f 602 { "generate", 0, 0, 'g' },
603 { "seed", OPTF_ARGREQ, 0, 's' },
604 { "bits", OPTF_ARGREQ, 0, 'b' },
605 { "show", 0, 0, 'S' },
87de7c73 606 { "keyring", OPTF_ARGREQ, 0, 'k' },
607 { "id", OPTF_ARGREQ, 0, 'i' },
608 { "type", OPTF_ARGREQ, 0, 't' },
ee33470f 609 { 0, 0, 0, 0 }
610 };
611
bb78535e 612 addopts("M:gs:b:Sk:i:t:", opts);
ee33470f 613
614 for (;;) {
615 int o = opt();
616 if (o < 0)
617 break;
618 switch (o) {
bb78535e 619 case 'M':
ee33470f 620 mt = optarg;
621 break;
622 case 'g':
623 mt = 0;
624 break;
625 case 's':
626 xt = optarg;
627 break;
628 case 'b':
629 bits = strtoul(optarg, 0, 0);
630 if (bits == 0)
631 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
632 break;
633 case 'S':
634 show = 1;
635 break;
87de7c73 636 case 'k':
637 kfile = optarg;
638 mt = 0;
639 break;
640 case 'i':
641 id = optarg;
642 mt = 0;
643 break;
644 case 't':
645 ktype = optarg;
646 mt = 0;
647 break;
ee33470f 648 default:
649 return (0);
650 }
651 }
652
653 /* --- Generate a modulus if one is requested --- */
654
655 if (mt) {
656 char *p;
657 m = mp_readstring(MP_NEW, mt, &p, 0);
87de7c73 658 if (!m || *p || (m->v[0] & 3) != 1)
ee33470f 659 die(EXIT_FAILURE, "bad modulus `%s'", mt);
660 /* Unfortunately I don't know how to test for a Blum integer */
87de7c73 661 } else if (kfile || id || ktype) {
662 key_file kf;
663 key *kk;
664 key_data *kd;
665
666 /* --- Open the key file --- */
667
668 if (!kfile)
669 kfile = "keyring";
670 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
671 die(EXIT_FAILURE, "error opening key file `%s': %s",
672 kfile, strerror(errno));
673 }
674
675 /* --- Find the key --- */
676
677 if (id) {
678 if ((kk = key_bytag(&kf, id)) == 0)
679 die(EXIT_FAILURE, "key `%s' not found", id);
680 } else {
681 if (!ktype)
682 ktype = "bbs";
683 if ((kk = key_bytype(&kf, ktype)) == 0)
684 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
685 }
686
687 /* --- Read the key data --- */
688
ef13e9a4 689 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
87de7c73 690 die(EXIT_FAILURE, "key is not structured");
ef13e9a4 691 if ((kd = key_structfind(kk->k, "n")) == 0)
87de7c73 692 die(EXIT_FAILURE, "key has no subkey `n'");
693 if ((kd->e & KF_ENCMASK) != KENC_MP)
e2edda68 694 die(EXIT_FAILURE, "incompatible subkey encoding");
87de7c73 695 m = MP_COPY(kd->u.m);
696 key_close(&kf);
ee33470f 697 } else {
c2181593 698 bbs_priv bp;
ee33470f 699
052b36d0 700 if (bbs_gen(&bp, bits, &rand_global, 0,
701 (flags & f_progress) ? pgen_ev : 0, 0))
87de7c73 702 die(EXIT_FAILURE, "modulus generation failed");
ee33470f 703 m = bp.n;
704
705 if (show) {
706 fputs("p = ", stderr);
707 mp_writefile(bp.p, stderr, 10);
708 fputs("\nq = ", stderr);
709 mp_writefile(bp.q, stderr, 10);
710 fputs("\nn = ", stderr);
711 mp_writefile(bp.n, stderr, 10);
712 fputc('\n', stderr);
713 }
714
ee33470f 715 mp_drop(bp.p);
716 mp_drop(bp.q);
717 }
718
719 /* --- Set up a seed --- */
720
721 if (!xt)
722 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
723 else {
724 char *p;
725 x = mp_readstring(MP_NEW, xt, &p, 0);
726 if (*p)
727 die(EXIT_FAILURE, "bad modulus `%s'", xt);
728 }
729
730 /* --- Right --- */
731
732 r = bbs_rand(m, x);
733
734 mp_drop(m);
735 mp_drop(x);
736 return (r);
737}
738
739/* --- Catacomb's random number generator --- */
740
741static grand *gen_rand(unsigned i)
742{
743 grand *r = rand_create();
744 dstr d = DSTR_INIT;
745
746 static struct option opts[] = {
747 { "key", OPTF_ARGREQ, 0, 'k' },
748 { "text", OPTF_ARGREQ, 0, 't' },
749 { "hex", OPTF_ARGREQ, 0, 'H' },
ee33470f 750 { 0, 0, 0, 0 }
751 };
752
753 addopts("k:t:H:n", opts);
754
bb78535e 755 r->ops->misc(r, RAND_NOISESRC, &noise_source);
756 r->ops->misc(r, RAND_SEED, 160);
757
ee33470f 758 for (;;) {
759 int o = opt();
760 if (o < 0)
761 break;
762 switch (o) {
bb78535e 763 case 'k':
764 DRESET(&d);
1d9ac42f 765 textkey(&d, optarg, rmd160_hmackeysz);
bb78535e 766 r->ops->misc(r, RAND_KEY, d.buf, d.len);
767 break;
ee33470f 768 case 't':
769 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
770 break;
bb78535e 771 case 'H':
ee33470f 772 DRESET(&d);
1d9ac42f 773 hexkey(&d, optarg, rmd160_hmackeysz);
ee33470f 774 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
ee33470f 775 break;
776 }
777 }
778
779 dstr_destroy(&d);
780 return (r);
781}
782
783/* --- RC4 output --- */
784
785static grand *gen_rc4(unsigned i)
786{
787 grand *r;
788 dstr d = DSTR_INIT;
789
790 static struct option opts[] = {
791 { "key", OPTF_ARGREQ, 0, 'k' },
792 { "hex", OPTF_ARGREQ, 0, 'H' },
793 { 0, 0, 0, 0 }
794 };
795
796 addopts("k:H:", opts);
797
798 for (;;) {
799 int o = opt();
800 if (o < 0)
801 break;
802 switch (o) {
bb78535e 803 case 'k':
804 DRESET(&d);
805 textkey(&d, optarg, rc4_keysz);
806 break;
807 case 'H':
808 DRESET(&d);
809 hexkey(&d, optarg, rc4_keysz);
810 break;
ee33470f 811 default:
812 return (0);
813 }
814 }
815
bb78535e 816 if (!d.len)
817 randkey(&d, rc4_keysz);
ee33470f 818 r = rc4_rand(d.buf, d.len);
819 dstr_destroy(&d);
820 return (r);
821}
822
bb78535e 823/* --- SEAL output --- */
ee33470f 824
bb78535e 825static grand *gen_seal(unsigned i)
826{
827 grand *r;
828 dstr d = DSTR_INIT;
829 uint32 n = 0;
ee33470f 830
bb78535e 831 static struct option opts[] = {
832 { "key", OPTF_ARGREQ, 0, 'k' },
833 { "hex", OPTF_ARGREQ, 0, 'H' },
834 { "sequence", OPTF_ARGREQ, 0, 'n' },
835 { 0, 0, 0, 0 }
836 };
ee33470f 837
bb78535e 838 addopts("k:H:n:", opts);
ee33470f 839
bb78535e 840 for (;;) {
841 int o = opt();
842 if (o < 0)
843 break;
844 switch (o) {
845 case 'k':
846 DRESET(&d);
847 textkey(&d, optarg, seal_keysz);
848 break;
849 case 'H':
850 DRESET(&d);
851 hexkey(&d, optarg, seal_keysz);
852 break;
853 case 'n': {
854 char *p;
855 n = strtoul(optarg, &p, 0);
856 if (*p)
857 die(EXIT_FAILURE, "bad number `%s'", optarg);
858 } break;
859 default:
860 return (0);
861 }
862 }
863
864 if (!d.len)
865 randkey(&d, seal_keysz);
866 r = seal_rand(d.buf, d.len, n);
867 dstr_destroy(&d);
868 return (r);
869}
870
965c4e75
MW
871/* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
872
873static grand *gen_salsae(unsigned i)
874{
875 grand *r;
876 char *p;
877 dstr d = DSTR_INIT;
878 dstr n = DSTR_INIT;
879 kludge64 pos = { 0 };
880 octet posbuf[8];
881 mp *x;
882
883 static struct option opts[] = {
884 { "key", OPTF_ARGREQ, 0, 'k' },
885 { "hex", OPTF_ARGREQ, 0, 'H' },
886 { "nonce", OPTF_ARGREQ, 0, 'n' },
887 { "seek", OPTF_ARGREQ, 0, 's' },
888 { 0, 0, 0, 0 }
889 };
890
891 addopts("k:H:n:s:", opts);
892
893 for (;;) {
894 int o = opt();
895 if (o < 0)
896 break;
897 switch (o) {
898 case 'k':
899 DRESET(&d);
900 textkey(&d, optarg, salsa20_keysz);
901 break;
902 case 'H':
903 DRESET(&d);
904 hexkey(&d, optarg, salsa20_keysz);
905 break;
906 case 'n':
907 DRESET(&n);
908 unhex(optarg, &p, &n);
909 if (*p)
910 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
911 if (n.len != salsatab[i].noncesz) {
912 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
913 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
914 }
915 break;
916 case 's':
917 x = mp_readstring(MP_NEW, optarg, &p, 0);
918 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
919 die(EXIT_FAILURE, "bad position `%s'", optarg);
920 mp_storeb(x, posbuf, sizeof(posbuf));
921 mp_drop(x);
922 LOAD64_(pos, posbuf);
923 break;
924 default:
925 return (0);
926 }
927 }
928
929 if (!d.len)
930 randkey(&d, salsa20_keysz);
931 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
932 r->ops->misc(r, SALSA20_SEEKU64, pos);
933
934 dstr_destroy(&d);
935 dstr_destroy(&n);
936
937 return (r);
938}
939
bb78535e 940/* --- Output feedback generators --- */
ee33470f 941
942static grand *gen_ofb(unsigned i)
943{
944 grand *r;
945 dstr d = DSTR_INIT;
946 dstr iv = DSTR_INIT;
947
948 static struct option opts[] = {
949 { "key", OPTF_ARGREQ, 0, 'k' },
950 { "hex", OPTF_ARGREQ, 0, 'H' },
951 { "iv", OPTF_ARGREQ, 0, 'i' },
952 { 0, 0, 0, 0 }
953 };
954
955 addopts("k:H:i:", opts);
956
957 for (;;) {
958 int o = opt();
959 if (o < 0)
960 break;
961 switch (o) {
bb78535e 962 case 'k':
963 DRESET(&d);
964 textkey(&d, optarg, ciphertab[i].keysz);
965 break;
966 case 'H':
967 DRESET(&d);
968 hexkey(&d, optarg, ciphertab[i].keysz);
969 break;
ee33470f 970 case 'i': {
971 char *p;
1cdc3a62 972 DRESET(&iv);
ee33470f 973 unhex(optarg, &p, &iv);
974 if (*p)
975 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
976 if (iv.len != ciphertab[i].blksz) {
977 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
978 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
979 }
ee33470f 980 } break;
981 default:
982 return (0);
983 }
984 }
985
bb78535e 986 if (!d.len)
987 randkey(&d, ciphertab[i].keysz);
988 r = ciphertab[i].ofb(d.buf, d.len);
1cdc3a62 989 if (iv.len)
bb78535e 990 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 991
bb78535e 992 dstr_destroy(&d);
993 dstr_destroy(&iv);
994 return (r);
995}
996
997/* --- Counter generators --- */
998
999static grand *gen_counter(unsigned i)
1000{
1001 grand *r;
1002 dstr d = DSTR_INIT;
1003 dstr iv = DSTR_INIT;
ee33470f 1004
bb78535e 1005 static struct option opts[] = {
1006 { "key", OPTF_ARGREQ, 0, 'k' },
1007 { "hex", OPTF_ARGREQ, 0, 'H' },
1008 { "iv", OPTF_ARGREQ, 0, 'i' },
1009 { 0, 0, 0, 0 }
1010 };
1011
1012 addopts("k:H:i:", opts);
1013
1014 for (;;) {
1015 int o = opt();
1016 if (o < 0)
1017 break;
1018 switch (o) {
1019 case 'k':
1020 DRESET(&d);
1021 textkey(&d, optarg, ciphertab[i].keysz);
1022 break;
1023 case 'H':
1024 DRESET(&d);
1025 hexkey(&d, optarg, ciphertab[i].keysz);
1026 break;
1027 case 'i': {
1028 char *p;
1cdc3a62 1029 DRESET(&iv);
bb78535e 1030 unhex(optarg, &p, &iv);
1031 if (*p)
1032 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
1033 if (iv.len != ciphertab[i].blksz) {
1034 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1035 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1036 }
bb78535e 1037 } break;
1038 default:
1039 return (0);
1040 }
1041 }
1042
1043 if (!d.len)
1044 randkey(&d, ciphertab[i].keysz);
1045 r = ciphertab[i].counter(d.buf, d.len);
1cdc3a62 1046 if (iv.len)
ee33470f 1047 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 1048
1049 dstr_destroy(&d);
1050 dstr_destroy(&iv);
1051 return (r);
1052}
1053
bb78535e 1054/* --- Mask generators --- */
1055
1056static grand *gen_mgf(unsigned i)
1057{
1058 grand *r;
1059 dstr d = DSTR_INIT;
1060 uint32 c = 0;
1061
1062 static struct option opts[] = {
1063 { "key", OPTF_ARGREQ, 0, 'k' },
1064 { "hex", OPTF_ARGREQ, 0, 'H' },
1065 { "index", OPTF_ARGREQ, 0, 'i' },
1066 { 0, 0, 0, 0 }
1067 };
1068
1069 addopts("k:H:i:", opts);
1070
1071 for (;;) {
1072 int o = opt();
1073 if (o < 0)
1074 break;
1075 switch (o) {
1076 case 'k':
1077 DRESET(&d);
1078 textkey(&d, optarg, hashtab[i].keysz);
1079 break;
1080 case 'H':
1081 DRESET(&d);
1082 hexkey(&d, optarg, hashtab[i].keysz);
1083 break;
1084 case 'i': {
1085 char *p;
1086 c = strtoul(optarg, &p, 0);
1087 if (*p)
1088 die(EXIT_FAILURE, "bad index `%s'", optarg);
1089 } break;
1090 default:
1091 return (0);
1092 }
1093 }
1094
1095 if (!d.len)
1096 randkey(&d, hashtab[i].keysz);
1097
1098 r = hashtab[i].mgf(d.buf, d.len);
1099 if (c)
1100 r->ops->misc(r, GRAND_SEEDUINT32, c);
1101
1102 dstr_destroy(&d);
1103 return (r);
1104}
1105
78b4ea88
MW
1106/* --- SHAKE generators --- */
1107
1108static grand *gen_shake(unsigned i)
1109{
1110 dstr d = DSTR_INIT;
1111 const char *func = 0, *perso = 0;
1112 grand *r;
1113
1114 static struct option opts[] = {
1115 { "function", OPTF_ARGREQ, 0, 'F' },
1116 { "personalization", OPTF_ARGREQ, 0, 'P' },
1117 { "key", OPTF_ARGREQ, 0, 'k' },
1118 { "hex", OPTF_ARGREQ, 0, 'H' },
1119 { 0, 0, 0, 0 }
1120 };
1121
1122 addopts("F:P:k:H:", opts);
1123
1124 for (;;) {
1125 int o = opt();
1126 if (o < 0)
1127 break;
1128 switch (o) {
1129 case 'F':
1130 func = optarg;
1131 break;
1132 case 'P':
1133 perso = optarg;
1134 break;
1135 case 'k':
1136 DRESET(&d);
1137 textkey(&d, optarg, shaketab[i].ksz);
1138 break;
1139 case 'H':
1140 DRESET(&d);
1141 hexkey(&d, optarg, shaketab[i].ksz);
1142 break;
1143 default:
1144 return (0);
1145 }
1146 }
1147
1148 if (!d.len) randkey(&d, shaketab[i].ksz);
1149 r = shaketab[i].shake(func, func ? strlen(func) : 0,
1150 perso, perso ? strlen(perso) : 0,
1151 d.buf, d.len);
1152 dstr_destroy(&d);
1153 return (r);
1154}
1155
1156/* --- KMAC generators --- */
1157
1158static grand *gen_kmac(unsigned i)
1159{
1160 dstr d = DSTR_INIT, m = DSTR_INIT;
1161 const char *perso = 0;
1162 char *q;
1163 grand *r;
1164
1165 static struct option opts[] = {
1166 { "personalization", OPTF_ARGREQ, 0, 'P' },
1167 { "key", OPTF_ARGREQ, 0, 'k' },
1168 { "hex", OPTF_ARGREQ, 0, 'H' },
1169 { "message", OPTF_ARGREQ, 0, 'M' },
1170 { "msghex", OPTF_ARGREQ, 0, 'N' },
1171 { 0, 0, 0, 0 }
1172 };
1173
1174 addopts("P:k:H:M:N:", opts);
1175
1176 for (;;) {
1177 int o = opt();
1178 if (o < 0)
1179 break;
1180 switch (o) {
1181 case 'P':
1182 perso = optarg;
1183 break;
1184 case 'k':
1185 DRESET(&d);
1186 textkey(&d, optarg, shaketab[i].ksz);
1187 break;
1188 case 'H':
1189 DRESET(&d);
1190 hexkey(&d, optarg, shaketab[i].ksz);
1191 break;
1192 case 'M':
1193 DRESET(&m);
1194 DPUTS(&d, optarg);
1195 break;
1196 case 'N':
1197 DRESET(&m);
1198 unhex(optarg, &q, &m);
1199 if (*q) die(EXIT_FAILURE, "bad hex");
1200 break;
1201 default:
1202 return (0);
1203 }
1204 }
1205
1206 if (!d.len) randkey(&d, shaketab[i].ksz);
1207 r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
1208 r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
1209 dstr_destroy(&d); dstr_destroy(&m);
1210 return (r);
1211}
1212
ee33470f 1213/* --- Fibonacci generator --- */
1214
1215static grand *gen_fib(unsigned i)
1216{
1217 grand *r;
1218 uint32 s = 0;
1219 char *p;
1220 unsigned set = 0;
1221
1222 static struct option opts[] = {
1223 { "seed", OPTF_ARGREQ, 0, 's' },
1224 { 0, 0, 0, 0 }
1225 };
1226
1227 addopts("s:", opts);
1228
1229 for (;;) {
1230 int o = opt();
1231 if (o < 0)
1232 break;
1233 switch (o) {
1234 case 's':
1235 s = strtoul(optarg, &p, 0);
1236 if (*p)
1237 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1238 set = 1;
1239 break;
1240 default:
1241 return (0);
1242 }
1243 }
1244 r = fibrand_create(s);
1245 if (!set)
1246 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1247 return (r);
1248}
1249
1250/* --- LC generator --- */
1251
1252static grand *gen_lc(unsigned i)
1253{
1254 uint32 s = 0;
1255 char *p;
1256 unsigned set = 0;
1257
1258 static struct option opts[] = {
1259 { "seed", OPTF_ARGREQ, 0, 's' },
1260 { 0, 0, 0, 0 }
1261 };
1262
1263 addopts("s:", opts);
1264
1265 for (;;) {
1266 int o = opt();
1267 if (o < 0)
1268 break;
1269 switch (o) {
1270 case 's':
1271 s = strtoul(optarg, &p, 0);
1272 if (*p)
1273 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1274 set = 1;
1275 break;
1276 default:
1277 return (0);
1278 }
1279 }
1280 if (!set) {
1281 do
1282 s = rand_global.ops->range(&rand_global, LCRAND_P);
1283 while (s == LCRAND_FIXEDPT);
1284 }
1285 return (lcrand_create(s));
1286}
1287
1288/* --- Basic options parser -- can't generate output --- */
1289
1290static grand *gen_opts(unsigned i)
1291{
1292 while (opt() >= 0)
1293 ;
1294 return (0);
1295}
1296
1297/*----- Generators table --------------------------------------------------*/
1298
f57c6d85 1299gen generators[] = {
ee33470f 1300 { "fibonacci", gen_fib, 0,
1301 "[-s SEED]" },
1302 { "lc", gen_lc, 0,
1303 "[-s SEED]" },
bb78535e 1304#define E(PRE, pre) \
1305 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
ee33470f 1306 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1307 CIPHERS
1308#undef E
1309#define E(PRE, pre) \
1310 { #pre "-counter", gen_counter, CIPHER_##PRE, \
ee33470f 1311 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1312 CIPHERS
f57c6d85 1313#undef E
bb78535e 1314#define E(PRE, pre) \
1315 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1316 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1317 HASHES
f57c6d85 1318#undef E
965c4e75
MW
1319#define E(pre, r, x, BASE) \
1320 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1321 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1322 SALSAE
1323#undef E
78b4ea88
MW
1324#define E(sz) \
1325 { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
1326 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1327 SHAKES
1328#undef E
1329#define E(sz) \
1330 { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
1331 "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
1332 SHAKES
1333#undef E
ee33470f 1334 { "rc4", gen_rc4, 0,
1335 "[-k KEY-PHRASE] [-H HEX-KEY]" },
bb78535e 1336 { "seal", gen_seal, 0,
1337 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
ee33470f 1338 { "rand", gen_rand, 0,
1339 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1340 { "bbs", gen_bbs, 0,
bb78535e 1341 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
87de7c73 1342 },
ee33470f 1343 { 0, 0, 0, 0 },
1344};
1345
1346static gen optsg = { "options", gen_opts, 0,
1347 "This message shouldn't be printed." };
1348
f0675f8a 1349/*----- Random number generation ------------------------------------------*/
ee33470f 1350
f0675f8a 1351static int genfile(const void *buf, size_t sz, void *p)
1352{
1353 FILE *fp = p;
1354 if (fwrite(buf, 1, sz, fp) != sz)
1355 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1356 return (0);
1357}
1358
1359static int genbuf(const void *buf, size_t sz, void *p)
1360{
1361 octet **pp = p;
1362 memcpy(*pp, buf, sz);
1363 *pp += sz;
1364 return (0);
1365}
1366
e3dc2d22 1367typedef struct genmaurer_ctx {
1368 size_t n;
1369 maurer_ctx *m;
1370} genmaurer_ctx;
1371
1372static int genmaurer(const void *buf, size_t sz, void *p)
1373{
1374 genmaurer_ctx *g = p;
1375 size_t i;
1376
1377 for (i = 0; i < g->n; i++)
1378 maurer_test(&g->m[i], buf, sz);
1379 return (0);
1380}
1381
15df46bc
MW
1382static double doubletime(void)
1383{
1384#ifdef PORTABLE
1385 static time_t start = (time_t)-1;
1386 time_t now = time(0);
1387
1388 if (start == (time_t)-1) start = now;
1389 return difftime(now, start);
1390#else
1391 struct timeval tv;
1392
1393 gettimeofday(&tv, 0);
1394 return (tv.tv_sec + tv.tv_usec/1000000.0);
1395#endif
1396}
1397
bafe8a7b 1398static int generate(grand *r, mp *outsz,
f0675f8a 1399 int (*func)(const void *buf, size_t sz, void *p),
1400 void *p)
ee33470f 1401{
04d45209 1402 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1403
bb78535e 1404 unsigned percent = 0;
bafe8a7b
MW
1405 mp *kb = MP_ZERO, *t = MP_NEW;
1406 dstr d = DSTR_INIT;
15df46bc 1407 double now, last;
bb78535e 1408 static char baton[] = "-\\|/";
ee33470f 1409 char *bp;
f0675f8a 1410 int rc;
04d45209 1411 clock_t clk = 0;
f0675f8a 1412
1413 /* --- Spit out random data --- */
1414
15df46bc 1415 last = doubletime();
f0675f8a 1416 bp = baton;
1417 if (flags & f_progress) {
1418 char *errbuf = xmalloc(BUFSIZ);
1419 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1420 if (outsz)
1421 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1422 else
1423 fputs("[ ] 0\r[/\b", stderr);
1424 fflush(stderr);
1425 }
1426
1427#ifdef SIGPIPE
1428 signal(SIGPIPE, SIG_IGN);
1429#endif
1430
bafe8a7b 1431 while (!outsz || MP_CMP(kb, <, outsz)) {
f0675f8a 1432 octet buf[BUFSIZ];
bafe8a7b 1433 size_t sz = sizeof(buf), left;
04d45209 1434 clock_t c_start, c_stop;
f0675f8a 1435
1436 /* --- Emit a bufferful (or less) of data --- */
1437
1438 if (outsz) {
bafe8a7b
MW
1439 t = mp_sub(t, outsz, kb);
1440 assert(!MP_NEGP(t));
1441 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1442 left = mp_tosizet(t);
1443 if (sz > left) sz = left;
1444 }
f0675f8a 1445 }
04d45209 1446 c_start = clock();
f0675f8a 1447 r->ops->fill(r, buf, sz);
04d45209 1448 c_stop = clock();
1449 clk += c_stop - c_start;
1450 if (func && (rc = func(buf, sz, p)) != 0)
f0675f8a 1451 return (rc);
bafe8a7b
MW
1452 t = mp_fromsizet(t, sz);
1453 kb = mp_add(kb, kb, t);
f0675f8a 1454
1455 /* --- Update the display --- */
1456
1457 if (flags & f_progress) {
f0675f8a 1458 unsigned up = 0;
1459
15df46bc
MW
1460 now = doubletime();
1461
f0675f8a 1462 if (percent > 100)
1463 up = 1;
1464
1465 if (!outsz) {
bbde884a 1466 if (now - last > 0.1) {
f0675f8a 1467 up = 1;
1468 }
1469 if (up)
1470 fputs(" ] ", stderr);
1471 } else {
bafe8a7b
MW
1472 unsigned pc;
1473 t = mp_fromulong(t, 100);
1474 t = mp_mul(t, t, kb);
1475 mp_div(&t, 0, t, outsz);
1476 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1477 pc = mp_touint(t);
bbde884a 1478 if (pc > percent || percent > 100 || now - last > 0.1) {
f0675f8a 1479 if (percent > 100)
1480 percent = 0;
1481 percent &= ~1;
1482 for (; percent < (pc & ~1); percent += 2)
1483 putc('.', stderr);
1484 percent = pc;
1485 for (; pc < 100; pc += 2)
1486 putc(' ', stderr);
1487 fprintf(stderr, "] %3i%% ", percent);
1488 up = 1;
1489 }
1490 }
1491
1492 if (up) {
04d45209 1493 char *kk = kmg;
bafe8a7b
MW
1494 t = mp_add(t, kb, MP_ZERO);
1495 while (mp_bits(t) >= 14) {
1496 t = mp_lsr(t, t, 10);
04d45209 1497 kk++;
f0675f8a 1498 }
bafe8a7b
MW
1499 DRESET(&d);
1500 mp_writedstr(t, &d, 10);
1501 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
f0675f8a 1502 if (outsz) {
1503 unsigned pc;
1504 for (pc = 0; pc < (percent & ~1); pc += 2)
1505 putc('.', stderr);
1506 }
bafe8a7b 1507 last = now;
f0675f8a 1508 }
1509
1510 if (percent > 100)
1511 percent = 0;
1512
bbde884a 1513 if (percent < 100 && up) {
f0675f8a 1514 putc(*bp++, stderr);
1515 putc('\b', stderr);
1516 if (!*bp)
1517 bp = baton;
1518 }
1519 fflush(stderr);
1520 }
bafe8a7b 1521 }
f0675f8a 1522
1523 if (flags & f_progress)
1524 fputc('\n', stderr);
04d45209 1525 if (flags & f_timer) {
bafe8a7b
MW
1526 DRESET(&d);
1527 dstr_puts(&d, "generated ");
1528 mp_writedstr(kb, &d, 10);
1529 dstr_puts(&d, " bytes ");
e3dc2d22 1530 if (!clk)
bafe8a7b 1531 dstr_puts(&d, "too quickly to measure\n");
e3dc2d22 1532 else {
1533 char *kk;
bafe8a7b 1534 double out;
e3dc2d22 1535 double sec = (double)clk/CLOCKS_PER_SEC;
bafe8a7b
MW
1536 unsigned long sh;
1537 double bps;
1538
1539 MP_SHRINK(kb);
1540 switch (MP_LEN(kb)) {
1541 case 0: out = 0; break;
1542 case 1: out = kb->v[0]; break;
1543 default:
1544 sh = mp_bits(kb) - MPW_BITS;
1545 t = mp_lsr(t, kb, sh);
1546 out = ldexp(t->v[0], sh);
1547 break;
1548 }
1549 bps = (8*out)/sec;
e3dc2d22 1550 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1551 ;
bafe8a7b
MW
1552 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1553 fwrite(d.buf, 1, d.len, stderr);
e3dc2d22 1554 }
04d45209 1555 }
bafe8a7b
MW
1556
1557 mp_drop(t);
1558 DDESTROY(&d);
f0675f8a 1559 return (0);
1560}
1561
1562/*----- Main code ---------------------------------------------------------*/
1563
1564int main(int ac, char *av[])
1565{
1566 gen *g = &optsg;
1567 grand *r;
ee33470f 1568
1569 /* --- Initialize mLib --- */
1570
1571 ego(av[0]);
1572 sub_init();
1573
1574 /* --- Set up the main Catacomb generator --- */
1575
1576 rand_noisesrc(RAND_GLOBAL, &noise_source);
bb78535e 1577 rand_seed(RAND_GLOBAL, 160);
ee33470f 1578
1579 /* --- Initialize the options table --- */
1580
1581 addopts(sopts, opts);
1582 argc = ac;
1583 argv = av;
c2181593 1584 outfp = stdout;
ee33470f 1585
1586 /* --- Read the generator out of the first argument --- */
1587
1588 if (argc > 1 && *argv[1] != '-') {
1589 const char *arg = av[1];
1590 size_t sz = strlen(arg);
bc97f84c 1591 gen *gg;
ee33470f 1592
1593 g = 0;
1594 for (gg = generators; gg->name; gg++) {
141c1284 1595 if (STRNCMP(arg, ==, gg->name, sz)) {
ee33470f 1596 if (gg->name[sz] == 0) {
1597 g = gg;
1598 break;
1599 } else if (g)
1600 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1601 else
1602 g = gg;
1603 }
1604 }
1605 if (!g)
1606 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1607 argc--;
1608 argv++;
1609 }
1610
1611 /* --- Get a generic random number generator --- */
1612
1613 r = g->seed(g->i);
1614 if (!r || optind != ac - 1) {
1615 usage(stderr);
1616 exit(EXIT_FAILURE);
1617 }
1618
bb78535e 1619 /* --- Do the FIPS test --- */
1620
1621 if (flags & f_fips) {
1622 octet buf[FIPSTEST_BUFSZ];
1623 unsigned rc;
bafe8a7b 1624 mp *t;
f0675f8a 1625 octet *p = buf;
bb78535e 1626
bafe8a7b
MW
1627 t = mp_fromsizet(MP_NEW, sizeof(buf));
1628 generate(r, t, genbuf, &p);
1629 mp_drop(t);
bb78535e 1630 rc = fipstest(buf);
1631 if (rc & FIPSTEST_MONOBIT)
1632 moan("failed monobit test");
1633 if (rc & FIPSTEST_POKER)
1634 moan("failed poker test");
1635 if (rc & FIPSTEST_RUNS)
1636 moan("failed runs test");
1637 if (rc & FIPSTEST_LONGRUNS)
1638 moan("failed long runs test");
1639 if (!rc && (flags & f_progress))
04d45209 1640 fputs("test passed\n", stderr);
bb78535e 1641 return (rc ? EXIT_FAILURE : 0);
1642 }
1643
1644 /* --- Do Maurer's test --- */
1645
1646 if (flags & f_maurer) {
f0675f8a 1647 size_t bufsz;
bb78535e 1648 unsigned i;
1649 unsigned rc = 0;
bafe8a7b 1650 mp *t;
e3dc2d22 1651 genmaurer_ctx g;
bb78535e 1652
1653 static struct { double x; const char *sig; } sigtab[] = {
1654 { 3.2905, "1e-3" },
1655 { 3.0902, "2e-3" },
1656 { 2.8070, "5e-3" },
1657 { 2.5758, "1e-2" },
1658 { 0 , 0 }
1659 };
1660
e3dc2d22 1661 g.n = maurer_hi - maurer_lo + 1;
1662 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1663 for (i = 0; i < g.n; i++)
1664 maurer_init(&g.m[i], i + maurer_lo);
f0675f8a 1665 bufsz = (100 * maurer_hi) << maurer_hi;
e3dc2d22 1666
bafe8a7b
MW
1667 t = mp_fromsizet(MP_NEW, bufsz);
1668 generate(r, t, genmaurer, &g);
1669 mp_drop(t);
f0675f8a 1670
1671 for (i = maurer_lo; i <= maurer_hi; i++) {
e3dc2d22 1672 double z = maurer_done(&g.m[i - maurer_lo]);
bb78535e 1673 double zz = fabs(z);
1674 unsigned j;
1675
1676 for (j = 0; sigtab[j].sig; j++) {
1677 if (zz > sigtab[j].x) {
bb78535e 1678 rc = EXIT_FAILURE;
1679 moan("failed, bits = %u, sig = %s, Z_u = %g",
f0675f8a 1680 i, sigtab[j].sig, z);
bb78535e 1681 break;
1682 }
1683 }
1684 if (flags & f_progress)
04d45209 1685 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
bb78535e 1686 }
1687
e3dc2d22 1688 xfree(g.m);
bb78535e 1689 return (rc);
1690 }
1691
04d45209 1692 /* --- Discard --- */
1693
1694 if (flags & f_discard) {
1695 generate(r, outsz, 0, 0);
1696 return (0);
1697 }
1698
f0675f8a 1699 /* --- Write to a file --- */
bb78535e 1700
ee33470f 1701#ifndef PORTABLE
1702 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1703 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1704#endif
1705
f0675f8a 1706 generate(r, outsz, genfile, outfp);
ee33470f 1707
1708 /* --- Done --- */
1709
1710 r->ops->destroy(r);
ee33470f 1711 return (0);
1712}
1713
1714/*----- That's all, folks -------------------------------------------------*/