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/macros.h>
51 #include <mLib/mdwopt.h>
52 #include <mLib/quis.h>
53 #include <mLib/report.h>
77 #include "salsa20-core.h"
86 #include "skipjack-ofb.h"
89 #include "blowfish-ofb.h"
90 #include "twofish-ofb.h"
92 #include "cast128-ofb.h"
93 #include "cast256-ofb.h"
94 #include "noekeon-ofb.h"
95 #include "rijndael-ofb.h"
96 #include "rijndael192-ofb.h"
97 #include "rijndael256-ofb.h"
98 #include "safer-ofb.h"
99 #include "safersk-ofb.h"
100 #include "square-ofb.h"
101 #include "serpent-ofb.h"
103 #include "des-counter.h"
104 #include "des3-counter.h"
105 #include "rc2-counter.h"
106 #include "rc5-counter.h"
107 #include "mars-counter.h"
108 #include "skipjack-counter.h"
109 #include "tea-counter.h"
110 #include "xtea-counter.h"
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"
116 #include "noekeon-counter.h"
117 #include "rijndael-counter.h"
118 #include "rijndael192-counter.h"
119 #include "rijndael256-counter.h"
120 #include "safer-counter.h"
121 #include "safersk-counter.h"
122 #include "square-counter.h"
123 #include "serpent-counter.h"
129 #include "tiger-mgf.h"
130 #include "rmd128-mgf.h"
131 #include "rmd160-mgf.h"
132 #include "rmd256-mgf.h"
133 #include "rmd320-mgf.h"
137 /*----- Data structures ---------------------------------------------------*/
141 grand *(*seed)(unsigned /*i*/);
146 extern gen generators[];
154 E(SKIPJACK, skipjack) \
157 E(BLOWFISH, blowfish) \
158 E(TWOFISH, twofish) \
160 E(CAST128, cast128) \
161 E(CAST256, cast256) \
164 E(SAFERSK, safersk) \
165 E(NOEKEON, noekeon) \
166 E(RIJNDAEL, rijndael) \
167 E(RIJNDAEL192, rijndael192) \
168 E(RIJNDAEL256, rijndael256) \
182 #define E(PRE, pre) CIPHER_##PRE,
183 enum { CIPHERS CIPHER__bogus };
186 #define E(PRE, pre) HASH_##PRE,
187 enum { HASHES HASH__bogus };
190 static const struct {
193 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
194 grand *(*counter)(const void */*k*/, size_t /*sz*/);
196 #define E(PRE, pre) \
197 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
202 static const struct {
205 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
207 #define E(PRE, pre) \
208 { &pre, pre##_mgfkeysz, pre##_mgfrand },
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)
227 #define E(pre, r, x, BASE) pre##_##r##_INDEX,
228 enum { SALSAE BOGUS_SALSA };
231 #define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
232 #define CHACHA_GEN(pre, r) pre##r##_rand
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
239 static const struct {
241 grand *(*gen)(const void *, size_t, const void *);
243 #define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
248 #define SHAKES E(128) E(256)
251 #define E(sz) SHAKE##sz##_INDEX,
257 static const struct {
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);
264 #define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
269 /*----- Miscellaneous static data -----------------------------------------*/
272 static mp *outsz = 0;
273 static unsigned maurer_lo = 5, maurer_hi = 8;
278 static unsigned flags = 0;
280 #define f_progress 1u
285 #define f_discard 32u
287 /*----- Help options ------------------------------------------------------*/
289 static void usage(FILE *fp)
291 pquis(fp, "Usage: $ generator [options]\n");
294 static void version(FILE *fp)
296 pquis(fp, "$, Catacomb version " VERSION "\n");
299 static void help(FILE *fp)
305 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
306 The primary objective is to be able to generate streams of input for\n\
307 statistical tests, such as Diehard.\n\
309 Options are specific to the particular generator, although there's a\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\
316 -l, --list Show a list of the supported generators, with\n\
318 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
319 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
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\
323 -T, --timer Keep track of the CPU time used by the generator.\n\
324 -d, --discard Discard the generated output.\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\
331 /*----- Main options parser -----------------------------------------------*/
333 static struct option opts[] = {
335 /* --- Standard GNU help options --- */
337 { "help", 0, 0, 'h' },
338 { "version", 0, 0, 'v' },
339 { "usage", 0, 0, 'u' },
341 /* --- Other useful things --- */
343 { "list", 0, 0, 'l' },
344 { "fipstest", 0, 0, 'f' },
345 { "maurer", OPTF_ARGOPT, 0, 'm' },
346 { "output", OPTF_ARGREQ, 0, 'o' },
347 { "size", OPTF_ARGREQ, 0, 'z' },
348 { "progress", 0, 0, 'p' },
349 { "timer", 0, 0, 'T' },
350 { "discard", 0, 0, 'd' },
352 /* --- End of main table --- */
357 static const char *sopts = "hvu lfm::o:z:pTd";
360 DA_DECL(option_v, struct option);
364 static option_v optv = DA_INIT;
365 static dstr optd = DSTR_INIT;
367 /* --- @addopts@ --- *
369 * Arguments: @const char *s@ = pointer to short options
370 * @struct option *l@ = pointer to long options
374 * Use: Adds a collection of options to the table.
377 static void addopts(const char *s, struct option *l)
383 DA_PUSH(&optv, *l++);
391 * Returns: Next option from argument array.
393 * Use: Fetches options, handling the standard ones.
399 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
412 puts("Generators supported:");
413 for (g = generators; g->name; g++)
414 printf(" %s %s\n", g->name, g->help);
424 unsigned long lo, hi;
425 lo = strtoul(optarg, &p, 0);
426 if (*p == '-' || *p == ',')
427 hi = strtoul(p + 1, &p, 0);
430 if (*p != 0 || hi < lo || lo == 0)
431 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
438 die(EXIT_FAILURE, "already set an output file");
439 if (STRCMP(optarg, ==, "-"))
442 outfp = fopen(optarg, "w");
444 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
445 optarg, strerror(errno));
452 outsz = mp_readstring(outsz, optarg, &p, 0);
453 if (!outsz || MP_NEGP(outsz))
454 die(EXIT_FAILURE, "bad number `%s'", optarg);
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);
462 die(EXIT_FAILURE, "bad suffix `%s'", p);
466 die(EXIT_FAILURE, "bad suffix `%s'", p);
483 /*----- Manglers for seed strings -----------------------------------------*/
487 * Arguments: @const char *p@ = pointer to input string
488 * @char **end@ = where the end goes
489 * @dstr *d@ = output buffer
493 * Use: Transforms a hex string into a chunk of binary data.
496 static void unhex(const char *p, char **end, dstr *d)
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;
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;
508 DPUTC(d, (x << 4) + y);
514 /* --- Generate a key --- */
516 static void textkey(dstr *d, const char *p, const octet *ksz)
518 size_t sz = strlen(p);
521 die(EXIT_FAILURE, "zero-length key string");
522 if (keysz(sz, ksz) != sz)
526 rmd160_mgfinit(&g, p, sz);
529 rmd160_mgfencrypt(&g, 0, d->buf, sz);
532 assert(((void)"I can't seem to choose a good key size",
533 keysz(d->len, ksz) == d->len));
536 static void hexkey(dstr *d, const char *p, const octet *ksz)
539 unhex(optarg, &q, d);
541 die(EXIT_FAILURE, "bad hex key `%s'", p);
542 if (keysz(d->len, ksz) != d->len)
543 die(EXIT_FAILURE, "bad key length");
546 static void randkey(dstr *d, const octet *ksz)
548 size_t sz = keysz(0, ksz);
550 rand_get(RAND_GLOBAL, d->buf, sz);
554 /*----- Generators --------------------------------------------------------*/
556 /* --- Blum-Blum-Shub strong generator --- */
558 static grand *gen_bbs(unsigned i)
560 /* --- Default modulus --- *
562 * The factors of this number are
564 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
565 * @7754313537966036459299022912838407755462506416274551744201653277@
566 * @313130311731673973886822067@
568 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
569 * @5374320073594018817245784145742769603334292182227671519041431067@
570 * @61344781426317516045890159@
572 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
573 * common factors. They were found using this program, with random
576 * I hope that, by publishing these factors, I'll dissuade people from
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.
583 "12051128439013574251357214209433471144307319411973256935382082"
584 "84356405274180923922403660880355098909699130818163691602989614"
585 "90135716255689660470370755013177656905237112577648090277537209"
586 "93607817155427455344810369808478266925293635284364998010510985"
587 "0503830397166360721262431179505917248447259735253684659338653";
589 /* --- Other things --- */
593 unsigned bits = 1024;
596 const char *kfile = 0, *id = 0, *ktype = 0;
598 /* --- Parse options --- */
600 static struct option opts[] = {
601 { "modulus", OPTF_ARGREQ, 0, 'M' },
602 { "generate", 0, 0, 'g' },
603 { "seed", OPTF_ARGREQ, 0, 's' },
604 { "bits", OPTF_ARGREQ, 0, 'b' },
605 { "show", 0, 0, 'S' },
606 { "keyring", OPTF_ARGREQ, 0, 'k' },
607 { "id", OPTF_ARGREQ, 0, 'i' },
608 { "type", OPTF_ARGREQ, 0, 't' },
612 addopts("M:gs:b:Sk:i:t:", opts);
629 bits = strtoul(optarg, 0, 0);
631 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
653 /* --- Generate a modulus if one is requested --- */
657 m = mp_readstring(MP_NEW, mt, &p, 0);
658 if (!m || *p || (m->v[0] & 3) != 1)
659 die(EXIT_FAILURE, "bad modulus `%s'", mt);
660 /* Unfortunately I don't know how to test for a Blum integer */
661 } else if (kfile || id || ktype) {
666 /* --- Open the key file --- */
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));
675 /* --- Find the key --- */
678 if ((kk = key_bytag(&kf, id)) == 0)
679 die(EXIT_FAILURE, "key `%s' not found", id);
683 if ((kk = key_bytype(&kf, ktype)) == 0)
684 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
687 /* --- Read the key data --- */
689 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
690 die(EXIT_FAILURE, "key is not structured");
691 if ((kd = key_structfind(kk->k, "n")) == 0)
692 die(EXIT_FAILURE, "key has no subkey `n'");
693 if ((kd->e & KF_ENCMASK) != KENC_MP)
694 die(EXIT_FAILURE, "incompatible subkey encoding");
695 m = MP_COPY(kd->u.m);
700 if (bbs_gen(&bp, bits, &rand_global, 0,
701 (flags & f_progress) ? pgen_ev : 0, 0))
702 die(EXIT_FAILURE, "modulus generation failed");
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);
719 /* --- Set up a seed --- */
722 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
725 x = mp_readstring(MP_NEW, xt, &p, 0);
727 die(EXIT_FAILURE, "bad modulus `%s'", xt);
739 /* --- Catacomb's random number generator --- */
741 static grand *gen_rand(unsigned i)
743 grand *r = rand_create();
746 static struct option opts[] = {
747 { "key", OPTF_ARGREQ, 0, 'k' },
748 { "text", OPTF_ARGREQ, 0, 't' },
749 { "hex", OPTF_ARGREQ, 0, 'H' },
753 addopts("k:t:H:n", opts);
755 r->ops->misc(r, RAND_NOISESRC, &noise_source);
756 r->ops->misc(r, RAND_SEED, 160);
765 textkey(&d, optarg, rmd160_hmackeysz);
766 r->ops->misc(r, RAND_KEY, d.buf, d.len);
769 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
773 hexkey(&d, optarg, rmd160_hmackeysz);
774 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
783 /* --- RC4 output --- */
785 static grand *gen_rc4(unsigned i)
790 static struct option opts[] = {
791 { "key", OPTF_ARGREQ, 0, 'k' },
792 { "hex", OPTF_ARGREQ, 0, 'H' },
796 addopts("k:H:", opts);
805 textkey(&d, optarg, rc4_keysz);
809 hexkey(&d, optarg, rc4_keysz);
817 randkey(&d, rc4_keysz);
818 r = rc4_rand(d.buf, d.len);
823 /* --- SEAL output --- */
825 static grand *gen_seal(unsigned i)
831 static struct option opts[] = {
832 { "key", OPTF_ARGREQ, 0, 'k' },
833 { "hex", OPTF_ARGREQ, 0, 'H' },
834 { "sequence", OPTF_ARGREQ, 0, 'n' },
838 addopts("k:H:n:", opts);
847 textkey(&d, optarg, seal_keysz);
851 hexkey(&d, optarg, seal_keysz);
855 n = strtoul(optarg, &p, 0);
857 die(EXIT_FAILURE, "bad number `%s'", optarg);
865 randkey(&d, seal_keysz);
866 r = seal_rand(d.buf, d.len, n);
871 /* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
873 static grand *gen_salsae(unsigned i)
879 kludge64 pos = { 0 };
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' },
891 addopts("k:H:n:s:", opts);
900 textkey(&d, optarg, salsa20_keysz);
904 hexkey(&d, optarg, salsa20_keysz);
908 unhex(optarg, &p, &n);
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);
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));
922 LOAD64_(pos, posbuf);
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);
940 /* --- Output feedback generators --- */
942 static grand *gen_ofb(unsigned i)
948 static struct option opts[] = {
949 { "key", OPTF_ARGREQ, 0, 'k' },
950 { "hex", OPTF_ARGREQ, 0, 'H' },
951 { "iv", OPTF_ARGREQ, 0, 'i' },
955 addopts("k:H:i:", opts);
964 textkey(&d, optarg, ciphertab[i].keysz);
968 hexkey(&d, optarg, ciphertab[i].keysz);
973 unhex(optarg, &p, &iv);
975 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
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);
987 randkey(&d, ciphertab[i].keysz);
988 r = ciphertab[i].ofb(d.buf, d.len);
990 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
997 /* --- Counter generators --- */
999 static grand *gen_counter(unsigned i)
1003 dstr iv = DSTR_INIT;
1005 static struct option opts[] = {
1006 { "key", OPTF_ARGREQ, 0, 'k' },
1007 { "hex", OPTF_ARGREQ, 0, 'H' },
1008 { "iv", OPTF_ARGREQ, 0, 'i' },
1012 addopts("k:H:i:", opts);
1021 textkey(&d, optarg, ciphertab[i].keysz);
1025 hexkey(&d, optarg, ciphertab[i].keysz);
1030 unhex(optarg, &p, &iv);
1032 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
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);
1044 randkey(&d, ciphertab[i].keysz);
1045 r = ciphertab[i].counter(d.buf, d.len);
1047 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
1054 /* --- Mask generators --- */
1056 static grand *gen_mgf(unsigned i)
1062 static struct option opts[] = {
1063 { "key", OPTF_ARGREQ, 0, 'k' },
1064 { "hex", OPTF_ARGREQ, 0, 'H' },
1065 { "index", OPTF_ARGREQ, 0, 'i' },
1069 addopts("k:H:i:", opts);
1078 textkey(&d, optarg, hashtab[i].keysz);
1082 hexkey(&d, optarg, hashtab[i].keysz);
1086 c = strtoul(optarg, &p, 0);
1088 die(EXIT_FAILURE, "bad index `%s'", optarg);
1096 randkey(&d, hashtab[i].keysz);
1098 r = hashtab[i].mgf(d.buf, d.len);
1100 r->ops->misc(r, GRAND_SEEDUINT32, c);
1106 /* --- SHAKE generators --- */
1108 static grand *gen_shake(unsigned i)
1111 const char *func = 0, *perso = 0;
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' },
1122 addopts("F:P:k:H:", opts);
1137 textkey(&d, optarg, shaketab[i].ksz);
1141 hexkey(&d, optarg, shaketab[i].ksz);
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,
1156 /* --- KMAC generators --- */
1158 static grand *gen_kmac(unsigned i)
1160 dstr d = DSTR_INIT, m = DSTR_INIT;
1161 const char *perso = 0;
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' },
1174 addopts("P:k:H:M:N:", opts);
1186 textkey(&d, optarg, shaketab[i].ksz);
1190 hexkey(&d, optarg, shaketab[i].ksz);
1198 unhex(optarg, &q, &m);
1199 if (*q) die(EXIT_FAILURE, "bad hex");
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);
1213 /* --- Fibonacci generator --- */
1215 static grand *gen_fib(unsigned i)
1222 static struct option opts[] = {
1223 { "seed", OPTF_ARGREQ, 0, 's' },
1227 addopts("s:", opts);
1235 s = strtoul(optarg, &p, 0);
1237 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1244 r = fibrand_create(s);
1246 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1250 /* --- LC generator --- */
1252 static grand *gen_lc(unsigned i)
1258 static struct option opts[] = {
1259 { "seed", OPTF_ARGREQ, 0, 's' },
1263 addopts("s:", opts);
1271 s = strtoul(optarg, &p, 0);
1273 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1282 s = rand_global.ops->range(&rand_global, LCRAND_P);
1283 while (s == LCRAND_FIXEDPT);
1285 return (lcrand_create(s));
1288 /* --- Basic options parser -- can't generate output --- */
1290 static grand *gen_opts(unsigned i)
1297 /*----- Generators table --------------------------------------------------*/
1299 gen generators[] = {
1300 { "fibonacci", gen_fib, 0,
1304 #define E(PRE, pre) \
1305 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1306 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1309 #define E(PRE, pre) \
1310 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1311 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1314 #define E(PRE, pre) \
1315 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1316 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
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]" },
1325 { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
1326 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1330 { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
1331 "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
1334 { "rc4", gen_rc4, 0,
1335 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1336 { "seal", gen_seal, 0,
1337 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1338 { "rand", gen_rand, 0,
1339 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1340 { "bbs", gen_bbs, 0,
1341 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1346 static gen optsg = { "options", gen_opts, 0,
1347 "This message shouldn't be printed." };
1349 /*----- Random number generation ------------------------------------------*/
1351 static int genfile(const void *buf, size_t sz, void *p)
1354 if (fwrite(buf, 1, sz, fp) != sz)
1355 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1359 static int genbuf(const void *buf, size_t sz, void *p)
1362 memcpy(*pp, buf, sz);
1367 typedef struct genmaurer_ctx {
1372 static int genmaurer(const void *buf, size_t sz, void *p)
1374 genmaurer_ctx *g = p;
1377 for (i = 0; i < g->n; i++)
1378 maurer_test(&g->m[i], buf, sz);
1382 static double doubletime(void)
1385 static time_t start = (time_t)-1;
1386 time_t now = time(0);
1388 if (start == (time_t)-1) start = now;
1389 return difftime(now, start);
1393 gettimeofday(&tv, 0);
1394 return (tv.tv_sec + tv.tv_usec/1000000.0);
1398 static int generate(grand *r, mp *outsz,
1399 int (*func)(const void *buf, size_t sz, void *p),
1402 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1404 unsigned percent = 0;
1405 mp *kb = MP_ZERO, *t = MP_NEW;
1408 static char baton[] = "-\\|/";
1413 /* --- Spit out random data --- */
1415 last = doubletime();
1417 if (flags & f_progress) {
1418 char *errbuf = xmalloc(BUFSIZ);
1419 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1421 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1423 fputs("[ ] 0\r[/\b", stderr);
1428 signal(SIGPIPE, SIG_IGN);
1431 while (!outsz || MP_CMP(kb, <, outsz)) {
1433 size_t sz = sizeof(buf), left;
1434 clock_t c_start, c_stop;
1436 /* --- Emit a bufferful (or less) of data --- */
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;
1447 r->ops->fill(r, buf, sz);
1449 clk += c_stop - c_start;
1450 if (func && (rc = func(buf, sz, p)) != 0)
1452 t = mp_fromsizet(t, sz);
1453 kb = mp_add(kb, kb, t);
1455 /* --- Update the display --- */
1457 if (flags & f_progress) {
1466 if (now - last > 0.1) {
1470 fputs(" ] ", stderr);
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));
1478 if (pc > percent || percent > 100 || now - last > 0.1) {
1482 for (; percent < (pc & ~1); percent += 2)
1485 for (; pc < 100; pc += 2)
1487 fprintf(stderr, "] %3i%% ", percent);
1494 t = mp_add(t, kb, MP_ZERO);
1495 while (mp_bits(t) >= 14) {
1496 t = mp_lsr(t, t, 10);
1500 mp_writedstr(t, &d, 10);
1501 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1504 for (pc = 0; pc < (percent & ~1); pc += 2)
1513 if (percent < 100 && up) {
1514 putc(*bp++, stderr);
1523 if (flags & f_progress)
1524 fputc('\n', stderr);
1525 if (flags & f_timer) {
1527 dstr_puts(&d, "generated ");
1528 mp_writedstr(kb, &d, 10);
1529 dstr_puts(&d, " bytes ");
1531 dstr_puts(&d, "too quickly to measure\n");
1535 double sec = (double)clk/CLOCKS_PER_SEC;
1540 switch (MP_LEN(kb)) {
1541 case 0: out = 0; break;
1542 case 1: out = kb->v[0]; break;
1544 sh = mp_bits(kb) - MPW_BITS;
1545 t = mp_lsr(t, kb, sh);
1546 out = ldexp(t->v[0], sh);
1550 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1552 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1553 fwrite(d.buf, 1, d.len, stderr);
1562 /*----- Main code ---------------------------------------------------------*/
1564 int main(int ac, char *av[])
1569 /* --- Initialize mLib --- */
1574 /* --- Set up the main Catacomb generator --- */
1576 rand_noisesrc(RAND_GLOBAL, &noise_source);
1577 rand_seed(RAND_GLOBAL, 160);
1579 /* --- Initialize the options table --- */
1581 addopts(sopts, opts);
1586 /* --- Read the generator out of the first argument --- */
1588 if (argc > 1 && *argv[1] != '-') {
1589 const char *arg = av[1];
1590 size_t sz = strlen(arg);
1594 for (gg = generators; gg->name; gg++) {
1595 if (STRNCMP(arg, ==, gg->name, sz)) {
1596 if (gg->name[sz] == 0) {
1600 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1606 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1611 /* --- Get a generic random number generator --- */
1614 if (!r || optind != ac - 1) {
1619 /* --- Do the FIPS test --- */
1621 if (flags & f_fips) {
1622 octet buf[FIPSTEST_BUFSZ];
1627 t = mp_fromsizet(MP_NEW, sizeof(buf));
1628 generate(r, t, genbuf, &p);
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))
1640 fputs("test passed\n", stderr);
1641 return (rc ? EXIT_FAILURE : 0);
1644 /* --- Do Maurer's test --- */
1646 if (flags & f_maurer) {
1653 static struct { double x; const char *sig; } sigtab[] = {
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);
1665 bufsz = (100 * maurer_hi) << maurer_hi;
1667 t = mp_fromsizet(MP_NEW, bufsz);
1668 generate(r, t, genmaurer, &g);
1671 for (i = maurer_lo; i <= maurer_hi; i++) {
1672 double z = maurer_done(&g.m[i - maurer_lo]);
1673 double zz = fabs(z);
1676 for (j = 0; sigtab[j].sig; j++) {
1677 if (zz > sigtab[j].x) {
1679 moan("failed, bits = %u, sig = %s, Z_u = %g",
1680 i, sigtab[j].sig, z);
1684 if (flags & f_progress)
1685 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1692 /* --- Discard --- */
1694 if (flags & f_discard) {
1695 generate(r, outsz, 0, 0);
1699 /* --- Write to a file --- */
1702 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1703 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1706 generate(r, outsz, genfile, outfp);
1714 /*----- That's all, folks -------------------------------------------------*/