3 * Spit out random numbers
5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
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.
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.
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,
28 /*----- Header files ------------------------------------------------------*/
30 #define _FILE_OFFSET_BITS 64
45 # include <sys/time.h>
48 #include <mLib/darray.h>
49 #include <mLib/dstr.h>
50 #include <mLib/mdwopt.h>
51 #include <mLib/quis.h>
52 #include <mLib/report.h>
76 #include "salsa20-core.h"
85 #include "skipjack-ofb.h"
88 #include "blowfish-ofb.h"
89 #include "twofish-ofb.h"
91 #include "cast128-ofb.h"
92 #include "cast256-ofb.h"
93 #include "noekeon-ofb.h"
94 #include "rijndael-ofb.h"
95 #include "rijndael192-ofb.h"
96 #include "rijndael256-ofb.h"
97 #include "safer-ofb.h"
98 #include "safersk-ofb.h"
99 #include "square-ofb.h"
100 #include "serpent-ofb.h"
102 #include "des-counter.h"
103 #include "des3-counter.h"
104 #include "rc2-counter.h"
105 #include "rc5-counter.h"
106 #include "mars-counter.h"
107 #include "skipjack-counter.h"
108 #include "tea-counter.h"
109 #include "xtea-counter.h"
110 #include "blowfish-counter.h"
111 #include "twofish-counter.h"
112 #include "idea-counter.h"
113 #include "cast128-counter.h"
114 #include "cast256-counter.h"
115 #include "noekeon-counter.h"
116 #include "rijndael-counter.h"
117 #include "rijndael192-counter.h"
118 #include "rijndael256-counter.h"
119 #include "safer-counter.h"
120 #include "safersk-counter.h"
121 #include "square-counter.h"
122 #include "serpent-counter.h"
128 #include "tiger-mgf.h"
129 #include "rmd128-mgf.h"
130 #include "rmd160-mgf.h"
131 #include "rmd256-mgf.h"
132 #include "rmd320-mgf.h"
136 /*----- Data structures ---------------------------------------------------*/
140 grand *(*seed)(unsigned /*i*/);
145 extern gen generators[];
153 E(SKIPJACK, skipjack) \
156 E(BLOWFISH, blowfish) \
157 E(TWOFISH, twofish) \
159 E(CAST128, cast128) \
160 E(CAST256, cast256) \
163 E(SAFERSK, safersk) \
164 E(NOEKEON, noekeon) \
165 E(RIJNDAEL, rijndael) \
166 E(RIJNDAEL192, rijndael192) \
167 E(RIJNDAEL256, rijndael256) \
181 #define E(PRE, pre) CIPHER_##PRE,
182 enum { CIPHERS CIPHER__bogus };
185 #define E(PRE, pre) HASH_##PRE,
186 enum { HASHES HASH__bogus };
189 static const struct {
192 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
193 grand *(*counter)(const void */*k*/, size_t /*sz*/);
195 #define E(PRE, pre) \
196 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
201 static const struct {
204 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
206 #define E(PRE, pre) \
207 { &pre, pre##_mgfkeysz, pre##_mgfrand },
213 E(salsa20, 20,, SALSA20) \
214 E(salsa20, 12,, SALSA20) \
215 E(salsa20, 8,, SALSA20) \
216 E(xsalsa20, 20, X, SALSA20) \
217 E(xsalsa20, 12, X, SALSA20) \
218 E(xsalsa20, 8, X, SALSA20) \
219 E(chacha, 20,, CHACHA) \
220 E(chacha, 12,, CHACHA) \
221 E(chacha, 8,, CHACHA) \
222 E(xchacha, 20, X, CHACHA) \
223 E(xchacha, 12, X, CHACHA) \
224 E(xchacha, 8, X, CHACHA)
226 #define E(pre, r, x, BASE) pre##_##r##_INDEX,
227 enum { SALSAE BOGUS_SALSA };
230 #define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
231 #define CHACHA_GEN(pre, r) pre##r##_rand
233 #define SALSA20_NAME(r) SALSA20_NAME_##r
234 #define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
235 #define CHACHA_NAME(r) "chacha" #r
236 #define XCHACHA_NAME(r) "xchacha" #r
238 static const struct {
240 grand *(*gen)(const void *, size_t, const void *);
242 #define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
247 #define SHAKES E(128) E(256)
250 #define E(sz) SHAKE##sz##_INDEX,
256 static const struct {
258 grand *(*shake)(const void *, size_t, const void *, size_t,
259 const void *, size_t);
260 grand *(*kmac)(const void *, size_t,
261 const void *, size_t);
263 #define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
268 /*----- Miscellaneous static data -----------------------------------------*/
271 static mp *outsz = 0;
272 static unsigned maurer_lo = 5, maurer_hi = 8;
277 static unsigned flags = 0;
279 #define f_progress 1u
284 #define f_discard 32u
286 /*----- Help options ------------------------------------------------------*/
288 static void usage(FILE *fp)
290 pquis(fp, "Usage: $ generator [options]\n");
293 static void version(FILE *fp)
295 pquis(fp, "$, Catacomb version " VERSION "\n");
298 static void help(FILE *fp)
304 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
305 The primary objective is to be able to generate streams of input for\n\
306 statistical tests, such as Diehard.\n\
308 Options are specific to the particular generator, although there's a\n\
311 -h, --help Display this help message.\n\
312 -v, --version Display the program's version number.\n\
313 -u, --usage Display a useless usage message.\n\
315 -l, --list Show a list of the supported generators, with\n\
317 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
318 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
319 -o, --output FILE Write output to FILE, not stdout.\n\
320 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
321 -p, --progress Show a little progress meter (on stderr).\n\
322 -T, --timer Keep track of the CPU time used by the generator.\n\
323 -d, --discard Discard the generated output.\n\
325 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
326 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
330 /*----- Main options parser -----------------------------------------------*/
332 static struct option opts[] = {
334 /* --- Standard GNU help options --- */
336 { "help", 0, 0, 'h' },
337 { "version", 0, 0, 'v' },
338 { "usage", 0, 0, 'u' },
340 /* --- Other useful things --- */
342 { "list", 0, 0, 'l' },
343 { "fipstest", 0, 0, 'f' },
344 { "maurer", OPTF_ARGOPT, 0, 'm' },
345 { "output", OPTF_ARGREQ, 0, 'o' },
346 { "size", OPTF_ARGREQ, 0, 'z' },
347 { "progress", 0, 0, 'p' },
348 { "timer", 0, 0, 'T' },
349 { "discard", 0, 0, 'd' },
351 /* --- End of main table --- */
356 static const char *sopts = "hvu lfm::o:z:pTd";
359 DA_DECL(option_v, struct option);
363 static option_v optv = DA_INIT;
364 static dstr optd = DSTR_INIT;
366 /* --- @addopts@ --- *
368 * Arguments: @const char *s@ = pointer to short options
369 * @struct option *l@ = pointer to long options
373 * Use: Adds a collection of options to the table.
376 static void addopts(const char *s, struct option *l)
382 DA_PUSH(&optv, *l++);
390 * Returns: Next option from argument array.
392 * Use: Fetches options, handling the standard ones.
398 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
411 puts("Generators supported:");
412 for (g = generators; g->name; g++)
413 printf(" %s %s\n", g->name, g->help);
423 unsigned long lo, hi;
424 lo = strtoul(optarg, &p, 0);
425 if (*p == '-' || *p == ',')
426 hi = strtoul(p + 1, &p, 0);
429 if (*p != 0 || hi < lo || lo == 0)
430 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
437 die(EXIT_FAILURE, "already set an output file");
438 if (strcmp(optarg, "-") == 0)
441 outfp = fopen(optarg, "w");
443 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
444 optarg, strerror(errno));
451 outsz = mp_readstring(outsz, optarg, &p, 0);
452 if (!outsz || MP_NEGP(outsz))
453 die(EXIT_FAILURE, "bad number `%s'", optarg);
455 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
456 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
457 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
461 die(EXIT_FAILURE, "bad suffix `%s'", p);
465 die(EXIT_FAILURE, "bad suffix `%s'", p);
482 /*----- Manglers for seed strings -----------------------------------------*/
486 * Arguments: @const char *p@ = pointer to input string
487 * @char **end@ = where the end goes
488 * @dstr *d@ = output buffer
492 * Use: Transforms a hex string into a chunk of binary data.
495 static void unhex(const char *p, char **end, dstr *d)
497 while (p[0] && p[1]) {
498 int x = p[0], y = p[1];
499 if ('0' <= x && x <= '9') x -= '0';
500 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
501 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
503 if ('0' <= y && y <= '9') y -= '0';
504 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
505 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
507 DPUTC(d, (x << 4) + y);
513 /* --- Generate a key --- */
515 static void textkey(dstr *d, const char *p, const octet *ksz)
517 size_t sz = strlen(p);
520 die(EXIT_FAILURE, "zero-length key string");
521 if (keysz(sz, ksz) != sz)
525 rmd160_mgfinit(&g, p, sz);
528 rmd160_mgfencrypt(&g, 0, d->buf, sz);
531 assert(((void)"I can't seem to choose a good key size",
532 keysz(d->len, ksz) == d->len));
535 static void hexkey(dstr *d, const char *p, const octet *ksz)
538 unhex(optarg, &q, d);
540 die(EXIT_FAILURE, "bad hex key `%s'", p);
541 if (keysz(d->len, ksz) != d->len)
542 die(EXIT_FAILURE, "bad key length");
545 static void randkey(dstr *d, const octet *ksz)
547 size_t sz = keysz(0, ksz);
549 rand_get(RAND_GLOBAL, d->buf, sz);
553 /*----- Generators --------------------------------------------------------*/
555 /* --- Blum-Blum-Shub strong generator --- */
557 static grand *gen_bbs(unsigned i)
559 /* --- Default modulus --- *
561 * The factors of this number are
563 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
564 * @7754313537966036459299022912838407755462506416274551744201653277@
565 * @313130311731673973886822067@
567 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
568 * @5374320073594018817245784145742769603334292182227671519041431067@
569 * @61344781426317516045890159@
571 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
572 * common factors. They were found using this program, with random
575 * I hope that, by publishing these factors, I'll dissuade people from
576 * actually using this modulus in an attempt to attain real security. The
577 * program is quite quick at finding Blum numbers, so there's no excuse for
578 * not generating your own.
582 "12051128439013574251357214209433471144307319411973256935382082"
583 "84356405274180923922403660880355098909699130818163691602989614"
584 "90135716255689660470370755013177656905237112577648090277537209"
585 "93607817155427455344810369808478266925293635284364998010510985"
586 "0503830397166360721262431179505917248447259735253684659338653";
588 /* --- Other things --- */
592 unsigned bits = 1024;
595 const char *kfile = 0, *id = 0, *ktype = 0;
597 /* --- Parse options --- */
599 static struct option opts[] = {
600 { "modulus", OPTF_ARGREQ, 0, 'M' },
601 { "generate", 0, 0, 'g' },
602 { "seed", OPTF_ARGREQ, 0, 's' },
603 { "bits", OPTF_ARGREQ, 0, 'b' },
604 { "show", 0, 0, 'S' },
605 { "keyring", OPTF_ARGREQ, 0, 'k' },
606 { "id", OPTF_ARGREQ, 0, 'i' },
607 { "type", OPTF_ARGREQ, 0, 't' },
611 addopts("M:gs:b:Sk:i:t:", opts);
628 bits = strtoul(optarg, 0, 0);
630 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
652 /* --- Generate a modulus if one is requested --- */
656 m = mp_readstring(MP_NEW, mt, &p, 0);
657 if (!m || *p || (m->v[0] & 3) != 1)
658 die(EXIT_FAILURE, "bad modulus `%s'", mt);
659 /* Unfortunately I don't know how to test for a Blum integer */
660 } else if (kfile || id || ktype) {
665 /* --- Open the key file --- */
669 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
670 die(EXIT_FAILURE, "error opening key file `%s': %s",
671 kfile, strerror(errno));
674 /* --- Find the key --- */
677 if ((kk = key_bytag(&kf, id)) == 0)
678 die(EXIT_FAILURE, "key `%s' not found", id);
682 if ((kk = key_bytype(&kf, ktype)) == 0)
683 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
686 /* --- Read the key data --- */
688 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
689 die(EXIT_FAILURE, "key is not structured");
690 if ((kd = key_structfind(kk->k, "n")) == 0)
691 die(EXIT_FAILURE, "key has no subkey `n'");
692 if ((kd->e & KF_ENCMASK) != KENC_MP)
693 die(EXIT_FAILURE, "incompatible subkey encoding");
694 m = MP_COPY(kd->u.m);
699 if (bbs_gen(&bp, bits, &rand_global, 0,
700 (flags & f_progress) ? pgen_ev : 0, 0))
701 die(EXIT_FAILURE, "modulus generation failed");
705 fputs("p = ", stderr);
706 mp_writefile(bp.p, stderr, 10);
707 fputs("\nq = ", stderr);
708 mp_writefile(bp.q, stderr, 10);
709 fputs("\nn = ", stderr);
710 mp_writefile(bp.n, stderr, 10);
718 /* --- Set up a seed --- */
721 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
724 x = mp_readstring(MP_NEW, xt, &p, 0);
726 die(EXIT_FAILURE, "bad modulus `%s'", xt);
738 /* --- Catacomb's random number generator --- */
740 static grand *gen_rand(unsigned i)
742 grand *r = rand_create();
745 static struct option opts[] = {
746 { "key", OPTF_ARGREQ, 0, 'k' },
747 { "text", OPTF_ARGREQ, 0, 't' },
748 { "hex", OPTF_ARGREQ, 0, 'H' },
752 addopts("k:t:H:n", opts);
754 r->ops->misc(r, RAND_NOISESRC, &noise_source);
755 r->ops->misc(r, RAND_SEED, 160);
764 textkey(&d, optarg, rmd160_hmackeysz);
765 r->ops->misc(r, RAND_KEY, d.buf, d.len);
768 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
772 hexkey(&d, optarg, rmd160_hmackeysz);
773 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
782 /* --- RC4 output --- */
784 static grand *gen_rc4(unsigned i)
789 static struct option opts[] = {
790 { "key", OPTF_ARGREQ, 0, 'k' },
791 { "hex", OPTF_ARGREQ, 0, 'H' },
795 addopts("k:H:", opts);
804 textkey(&d, optarg, rc4_keysz);
808 hexkey(&d, optarg, rc4_keysz);
816 randkey(&d, rc4_keysz);
817 r = rc4_rand(d.buf, d.len);
822 /* --- SEAL output --- */
824 static grand *gen_seal(unsigned i)
830 static struct option opts[] = {
831 { "key", OPTF_ARGREQ, 0, 'k' },
832 { "hex", OPTF_ARGREQ, 0, 'H' },
833 { "sequence", OPTF_ARGREQ, 0, 'n' },
837 addopts("k:H:n:", opts);
846 textkey(&d, optarg, seal_keysz);
850 hexkey(&d, optarg, seal_keysz);
854 n = strtoul(optarg, &p, 0);
856 die(EXIT_FAILURE, "bad number `%s'", optarg);
864 randkey(&d, seal_keysz);
865 r = seal_rand(d.buf, d.len, n);
870 /* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
872 static grand *gen_salsae(unsigned i)
878 kludge64 pos = { 0 };
882 static struct option opts[] = {
883 { "key", OPTF_ARGREQ, 0, 'k' },
884 { "hex", OPTF_ARGREQ, 0, 'H' },
885 { "nonce", OPTF_ARGREQ, 0, 'n' },
886 { "seek", OPTF_ARGREQ, 0, 's' },
890 addopts("k:H:n:s:", opts);
899 textkey(&d, optarg, salsa20_keysz);
903 hexkey(&d, optarg, salsa20_keysz);
907 unhex(optarg, &p, &n);
909 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
910 if (n.len != salsatab[i].noncesz) {
911 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
912 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
916 x = mp_readstring(MP_NEW, optarg, &p, 0);
917 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
918 die(EXIT_FAILURE, "bad position `%s'", optarg);
919 mp_storeb(x, posbuf, sizeof(posbuf));
921 LOAD64_(pos, posbuf);
929 randkey(&d, salsa20_keysz);
930 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
931 r->ops->misc(r, SALSA20_SEEKU64, pos);
939 /* --- Output feedback generators --- */
941 static grand *gen_ofb(unsigned i)
947 static struct option opts[] = {
948 { "key", OPTF_ARGREQ, 0, 'k' },
949 { "hex", OPTF_ARGREQ, 0, 'H' },
950 { "iv", OPTF_ARGREQ, 0, 'i' },
954 addopts("k:H:i:", opts);
963 textkey(&d, optarg, ciphertab[i].keysz);
967 hexkey(&d, optarg, ciphertab[i].keysz);
972 unhex(optarg, &p, &iv);
974 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
975 if (iv.len != ciphertab[i].blksz) {
976 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
977 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
986 randkey(&d, ciphertab[i].keysz);
987 r = ciphertab[i].ofb(d.buf, d.len);
989 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
996 /* --- Counter generators --- */
998 static grand *gen_counter(unsigned i)
1002 dstr iv = DSTR_INIT;
1004 static struct option opts[] = {
1005 { "key", OPTF_ARGREQ, 0, 'k' },
1006 { "hex", OPTF_ARGREQ, 0, 'H' },
1007 { "iv", OPTF_ARGREQ, 0, 'i' },
1011 addopts("k:H:i:", opts);
1020 textkey(&d, optarg, ciphertab[i].keysz);
1024 hexkey(&d, optarg, ciphertab[i].keysz);
1029 unhex(optarg, &p, &iv);
1031 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1032 if (iv.len != ciphertab[i].blksz) {
1033 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1034 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1043 randkey(&d, ciphertab[i].keysz);
1044 r = ciphertab[i].counter(d.buf, d.len);
1046 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
1053 /* --- Mask generators --- */
1055 static grand *gen_mgf(unsigned i)
1061 static struct option opts[] = {
1062 { "key", OPTF_ARGREQ, 0, 'k' },
1063 { "hex", OPTF_ARGREQ, 0, 'H' },
1064 { "index", OPTF_ARGREQ, 0, 'i' },
1068 addopts("k:H:i:", opts);
1077 textkey(&d, optarg, hashtab[i].keysz);
1081 hexkey(&d, optarg, hashtab[i].keysz);
1085 c = strtoul(optarg, &p, 0);
1087 die(EXIT_FAILURE, "bad index `%s'", optarg);
1095 randkey(&d, hashtab[i].keysz);
1097 r = hashtab[i].mgf(d.buf, d.len);
1099 r->ops->misc(r, GRAND_SEEDUINT32, c);
1105 /* --- SHAKE generators --- */
1107 static grand *gen_shake(unsigned i)
1110 const char *func = 0, *perso = 0;
1113 static struct option opts[] = {
1114 { "function", OPTF_ARGREQ, 0, 'F' },
1115 { "personalization", OPTF_ARGREQ, 0, 'P' },
1116 { "key", OPTF_ARGREQ, 0, 'k' },
1117 { "hex", OPTF_ARGREQ, 0, 'H' },
1121 addopts("F:P:k:H:", opts);
1136 textkey(&d, optarg, shaketab[i].ksz);
1140 hexkey(&d, optarg, shaketab[i].ksz);
1147 if (!d.len) randkey(&d, shaketab[i].ksz);
1148 r = shaketab[i].shake(func, func ? strlen(func) : 0,
1149 perso, perso ? strlen(perso) : 0,
1155 /* --- KMAC generators --- */
1157 static grand *gen_kmac(unsigned i)
1159 dstr d = DSTR_INIT, m = DSTR_INIT;
1160 const char *perso = 0;
1164 static struct option opts[] = {
1165 { "personalization", OPTF_ARGREQ, 0, 'P' },
1166 { "key", OPTF_ARGREQ, 0, 'k' },
1167 { "hex", OPTF_ARGREQ, 0, 'H' },
1168 { "message", OPTF_ARGREQ, 0, 'M' },
1169 { "msghex", OPTF_ARGREQ, 0, 'N' },
1173 addopts("P:k:H:M:N:", opts);
1185 textkey(&d, optarg, shaketab[i].ksz);
1189 hexkey(&d, optarg, shaketab[i].ksz);
1197 unhex(optarg, &q, &m);
1198 if (*q) die(EXIT_FAILURE, "bad hex");
1205 if (!d.len) randkey(&d, shaketab[i].ksz);
1206 r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
1207 r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
1208 dstr_destroy(&d); dstr_destroy(&m);
1212 /* --- Fibonacci generator --- */
1214 static grand *gen_fib(unsigned i)
1221 static struct option opts[] = {
1222 { "seed", OPTF_ARGREQ, 0, 's' },
1226 addopts("s:", opts);
1234 s = strtoul(optarg, &p, 0);
1236 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1243 r = fibrand_create(s);
1245 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1249 /* --- LC generator --- */
1251 static grand *gen_lc(unsigned i)
1257 static struct option opts[] = {
1258 { "seed", OPTF_ARGREQ, 0, 's' },
1262 addopts("s:", opts);
1270 s = strtoul(optarg, &p, 0);
1272 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1281 s = rand_global.ops->range(&rand_global, LCRAND_P);
1282 while (s == LCRAND_FIXEDPT);
1284 return (lcrand_create(s));
1287 /* --- Basic options parser -- can't generate output --- */
1289 static grand *gen_opts(unsigned i)
1296 /*----- Generators table --------------------------------------------------*/
1298 gen generators[] = {
1299 { "fibonacci", gen_fib, 0,
1303 #define E(PRE, pre) \
1304 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1305 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1308 #define E(PRE, pre) \
1309 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1310 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1313 #define E(PRE, pre) \
1314 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1315 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1318 #define E(pre, r, x, BASE) \
1319 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1320 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1324 { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
1325 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1329 { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
1330 "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
1333 { "rc4", gen_rc4, 0,
1334 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1335 { "seal", gen_seal, 0,
1336 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1337 { "rand", gen_rand, 0,
1338 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1339 { "bbs", gen_bbs, 0,
1340 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1345 static gen optsg = { "options", gen_opts, 0,
1346 "This message shouldn't be printed." };
1348 /*----- Random number generation ------------------------------------------*/
1350 static int genfile(const void *buf, size_t sz, void *p)
1353 if (fwrite(buf, 1, sz, fp) != sz)
1354 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1358 static int genbuf(const void *buf, size_t sz, void *p)
1361 memcpy(*pp, buf, sz);
1366 typedef struct genmaurer_ctx {
1371 static int genmaurer(const void *buf, size_t sz, void *p)
1373 genmaurer_ctx *g = p;
1376 for (i = 0; i < g->n; i++)
1377 maurer_test(&g->m[i], buf, sz);
1381 static double doubletime(void)
1384 static time_t start = (time_t)-1;
1385 time_t now = time(0);
1387 if (start == (time_t)-1) start = now;
1388 return difftime(now, start);
1392 gettimeofday(&tv, 0);
1393 return (tv.tv_sec + tv.tv_usec/1000000.0);
1397 static int generate(grand *r, mp *outsz,
1398 int (*func)(const void *buf, size_t sz, void *p),
1401 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1403 unsigned percent = 0;
1404 mp *kb = MP_ZERO, *t = MP_NEW;
1407 static char baton[] = "-\\|/";
1412 /* --- Spit out random data --- */
1414 last = doubletime();
1416 if (flags & f_progress) {
1417 char *errbuf = xmalloc(BUFSIZ);
1418 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1420 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1422 fputs("[ ] 0\r[/\b", stderr);
1427 signal(SIGPIPE, SIG_IGN);
1430 while (!outsz || MP_CMP(kb, <, outsz)) {
1432 size_t sz = sizeof(buf), left;
1433 clock_t c_start, c_stop;
1435 /* --- Emit a bufferful (or less) of data --- */
1438 t = mp_sub(t, outsz, kb);
1439 assert(!MP_NEGP(t));
1440 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1441 left = mp_tosizet(t);
1442 if (sz > left) sz = left;
1446 r->ops->fill(r, buf, sz);
1448 clk += c_stop - c_start;
1449 if (func && (rc = func(buf, sz, p)) != 0)
1451 t = mp_fromsizet(t, sz);
1452 kb = mp_add(kb, kb, t);
1454 /* --- Update the display --- */
1456 if (flags & f_progress) {
1465 if (now - last > 0.1) {
1469 fputs(" ] ", stderr);
1472 t = mp_fromulong(t, 100);
1473 t = mp_mul(t, t, kb);
1474 mp_div(&t, 0, t, outsz);
1475 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1477 if (pc > percent || percent > 100 || now - last > 0.1) {
1481 for (; percent < (pc & ~1); percent += 2)
1484 for (; pc < 100; pc += 2)
1486 fprintf(stderr, "] %3i%% ", percent);
1493 t = mp_add(t, kb, MP_ZERO);
1494 while (mp_bits(t) >= 14) {
1495 t = mp_lsr(t, t, 10);
1499 mp_writedstr(t, &d, 10);
1500 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1503 for (pc = 0; pc < (percent & ~1); pc += 2)
1512 if (percent < 100 && up) {
1513 putc(*bp++, stderr);
1522 if (flags & f_progress)
1523 fputc('\n', stderr);
1524 if (flags & f_timer) {
1526 dstr_puts(&d, "generated ");
1527 mp_writedstr(kb, &d, 10);
1528 dstr_puts(&d, " bytes ");
1530 dstr_puts(&d, "too quickly to measure\n");
1534 double sec = (double)clk/CLOCKS_PER_SEC;
1539 switch (MP_LEN(kb)) {
1540 case 0: out = 0; break;
1541 case 1: out = kb->v[0]; break;
1543 sh = mp_bits(kb) - MPW_BITS;
1544 t = mp_lsr(t, kb, sh);
1545 out = ldexp(t->v[0], sh);
1549 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1551 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1552 fwrite(d.buf, 1, d.len, stderr);
1561 /*----- Main code ---------------------------------------------------------*/
1563 int main(int ac, char *av[])
1568 /* --- Initialize mLib --- */
1573 /* --- Set up the main Catacomb generator --- */
1575 rand_noisesrc(RAND_GLOBAL, &noise_source);
1576 rand_seed(RAND_GLOBAL, 160);
1578 /* --- Initialize the options table --- */
1580 addopts(sopts, opts);
1585 /* --- Read the generator out of the first argument --- */
1587 if (argc > 1 && *argv[1] != '-') {
1588 const char *arg = av[1];
1589 size_t sz = strlen(arg);
1593 for (gg = generators; gg->name; gg++) {
1594 if (strncmp(arg, gg->name, sz) == 0) {
1595 if (gg->name[sz] == 0) {
1599 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1605 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1610 /* --- Get a generic random number generator --- */
1613 if (!r || optind != ac - 1) {
1618 /* --- Do the FIPS test --- */
1620 if (flags & f_fips) {
1621 octet buf[FIPSTEST_BUFSZ];
1626 t = mp_fromsizet(MP_NEW, sizeof(buf));
1627 generate(r, t, genbuf, &p);
1630 if (rc & FIPSTEST_MONOBIT)
1631 moan("failed monobit test");
1632 if (rc & FIPSTEST_POKER)
1633 moan("failed poker test");
1634 if (rc & FIPSTEST_RUNS)
1635 moan("failed runs test");
1636 if (rc & FIPSTEST_LONGRUNS)
1637 moan("failed long runs test");
1638 if (!rc && (flags & f_progress))
1639 fputs("test passed\n", stderr);
1640 return (rc ? EXIT_FAILURE : 0);
1643 /* --- Do Maurer's test --- */
1645 if (flags & f_maurer) {
1652 static struct { double x; const char *sig; } sigtab[] = {
1660 g.n = maurer_hi - maurer_lo + 1;
1661 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1662 for (i = 0; i < g.n; i++)
1663 maurer_init(&g.m[i], i + maurer_lo);
1664 bufsz = (100 * maurer_hi) << maurer_hi;
1666 t = mp_fromsizet(MP_NEW, bufsz);
1667 generate(r, t, genmaurer, &g);
1670 for (i = maurer_lo; i <= maurer_hi; i++) {
1671 double z = maurer_done(&g.m[i - maurer_lo]);
1672 double zz = fabs(z);
1675 for (j = 0; sigtab[j].sig; j++) {
1676 if (zz > sigtab[j].x) {
1678 moan("failed, bits = %u, sig = %s, Z_u = %g",
1679 i, sigtab[j].sig, z);
1683 if (flags & f_progress)
1684 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1691 /* --- Discard --- */
1693 if (flags & f_discard) {
1694 generate(r, outsz, 0, 0);
1698 /* --- Write to a file --- */
1701 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1702 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1705 generate(r, outsz, genfile, outfp);
1713 /*----- That's all, folks -------------------------------------------------*/