3 * $Id: rspit.c,v 1.17 2001/05/07 17:33:19 mdw Exp $
5 * Spit out random numbers
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.17 2001/05/07 17:33:19 mdw
34 * New Rijndael block sizes.
36 * Revision 1.16 2001/04/29 18:11:32 mdw
39 * Revision 1.15 2001/04/19 18:26:13 mdw
40 * Use the new MAC keysize names.
42 * Revision 1.14 2001/02/21 20:03:22 mdw
43 * Added support for MD2 hash function.
45 * Revision 1.13 2000/12/06 20:33:27 mdw
46 * Make flags be macros rather than enumerations, to ensure that they're
49 * Revision 1.12 2000/10/08 15:49:18 mdw
50 * Remove failed kludge for shutting up a warning.
52 * Revision 1.11 2000/10/08 12:10:32 mdw
53 * Make table have external linkage to bodge around deficiency in C. The
54 * problem is that @static gen generators[];@ is considered to be a
55 * `tentative definition', and therefore mustn't have incomplete type,
56 * which it obviously has.
58 * Revision 1.10 2000/08/11 21:34:59 mdw
59 * New restartable interface to Maurer testing.
61 * Revision 1.9 2000/08/04 23:24:15 mdw
62 * Add a timer and a discard option.
64 * Revision 1.8 2000/07/29 22:05:47 mdw
65 * Fix error in help message about Maurer test syntax.
67 * Revision 1.7 2000/07/18 23:01:26 mdw
68 * Improve progress indications, and allow user to choose chunk sizes for
71 * Revision 1.6 2000/07/15 20:53:35 mdw
72 * Add a load of new ciphers and hashes.
74 * Revision 1.5 2000/07/01 11:27:03 mdw
75 * Portability fix: don't assume that `stdout' is a constant expression.
76 * Remove old type name `bbs_param'.
78 * Revision 1.4 2000/06/17 12:08:28 mdw
79 * Restructure handling of cipher-based generators. Add counter-mode
80 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
82 * Revision 1.3 2000/02/12 18:21:03 mdw
83 * Overhaul of key management (again).
85 * Revision 1.2 1999/12/22 15:59:51 mdw
86 * New prime-search system. Read BBS keys from key files.
88 * Revision 1.1 1999/12/10 23:29:13 mdw
89 * Emit random numbers for statistical tests.
93 /*----- Header files ------------------------------------------------------*/
110 #include <mLib/darray.h>
111 #include <mLib/dstr.h>
112 #include <mLib/mdwopt.h>
113 #include <mLib/quis.h>
114 #include <mLib/report.h>
115 #include <mLib/sub.h>
117 #include "fipstest.h"
134 #include "des3-ofb.h"
137 #include "mars-ofb.h"
138 #include "skipjack-ofb.h"
140 #include "xtea-ofb.h"
141 #include "blowfish-ofb.h"
142 #include "twofish-ofb.h"
143 #include "idea-ofb.h"
144 #include "cast128-ofb.h"
145 #include "cast256-ofb.h"
146 #include "rijndael-ofb.h"
147 #include "rijndael192-ofb.h"
148 #include "rijndael256-ofb.h"
149 #include "safer-ofb.h"
150 #include "safersk-ofb.h"
151 #include "square-ofb.h"
152 #include "serpent-ofb.h"
154 #include "des-counter.h"
155 #include "des3-counter.h"
156 #include "rc2-counter.h"
157 #include "rc5-counter.h"
158 #include "mars-counter.h"
159 #include "skipjack-counter.h"
160 #include "tea-counter.h"
161 #include "xtea-counter.h"
162 #include "blowfish-counter.h"
163 #include "twofish-counter.h"
164 #include "idea-counter.h"
165 #include "cast128-counter.h"
166 #include "cast256-counter.h"
167 #include "rijndael-counter.h"
168 #include "rijndael192-counter.h"
169 #include "rijndael256-counter.h"
170 #include "safer-counter.h"
171 #include "safersk-counter.h"
172 #include "square-counter.h"
173 #include "serpent-counter.h"
179 #include "tiger-mgf.h"
180 #include "rmd128-mgf.h"
181 #include "rmd160-mgf.h"
182 #include "rmd256-mgf.h"
183 #include "rmd320-mgf.h"
187 /*----- Data structures ---------------------------------------------------*/
191 grand
*(*seed
)(unsigned /*i*/);
196 extern gen generators
[];
204 E(SKIPJACK, skipjack) \
207 E(BLOWFISH, blowfish) \
208 E(TWOFISH, twofish) \
210 E(CAST128, cast128) \
211 E(CAST256, cast256) \
214 E(SAFERSK, safersk) \
215 E(RIJNDAEL, rijndael) \
216 E(RIJNDAEL192, rijndael192) \
217 E(RIJNDAEL256, rijndael256) \
231 #define E(PRE, pre) CIPHER_##PRE,
232 enum { CIPHERS CIPHER__bogus
};
235 #define E(PRE, pre) HASH_##PRE,
236 enum { HASHES HASH__bogus
};
242 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
243 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
245 #define E(PRE, pre) \
246 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
254 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
256 #define E(PRE, pre) \
257 { &pre, pre##_mgfkeysz, pre##_mgfrand },
262 /*----- Miscellaneous static data -----------------------------------------*/
265 static size_t outsz
= 0;
266 static unsigned maurer_lo
= 5, maurer_hi
= 8;
271 static unsigned flags
= 0;
273 #define f_progress 1u
278 #define f_discard 32u
280 /*----- Help options ------------------------------------------------------*/
282 static void usage(FILE *fp
)
284 pquis(fp
, "Usage: $ generator [options]\n");
287 static void version(FILE *fp
)
289 pquis(fp
, "$, Catacomb version " VERSION
"\n");
292 static void help(FILE *fp
)
298 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
299 The primary objective is to be able to generate streams of input for\n\
300 statistical tests, such as Diehard.\n\
302 Options are specific to the particular generator, although there's a\n\
305 -h, --help Display this help message.\n\
306 -v, --version Display the program's version number.\n\
307 -u, --usage Display a useless usage message.\n\
309 -l, --list Show a list of the supported generators, with\n\
311 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
312 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
313 -o, --output FILE Write output to FILE, not stdout.\n\
314 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
315 -p, --progress Show a little progress meter (on stderr).\n\
316 -T, --timer Keep track of the CPU time used by the generator.\n\
317 -d, --discard Discard the generated output.\n\
319 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
320 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
324 /*----- Main options parser -----------------------------------------------*/
326 static struct option opts
[] = {
328 /* --- Standard GNU help options --- */
330 { "help", 0, 0, 'h' },
331 { "version", 0, 0, 'v' },
332 { "usage", 0, 0, 'u' },
334 /* --- Other useful things --- */
336 { "list", 0, 0, 'l' },
337 { "fipstest", 0, 0, 'f' },
338 { "maurer", OPTF_ARGOPT
, 0, 'm' },
339 { "output", OPTF_ARGREQ
, 0, 'o' },
340 { "size", OPTF_ARGREQ
, 0, 'z' },
341 { "progress", 0, 0, 'p' },
342 { "timer", 0, 0, 'T' },
343 { "discard", 0, 0, 'd' },
345 /* --- End of main table --- */
350 static const char *sopts
= "hvu lfm::o:z:pTd";
353 DA_DECL(option_v
, struct option
);
357 static option_v optv
= DA_INIT
;
358 static dstr optd
= DSTR_INIT
;
360 /* --- @addopts@ --- *
362 * Arguments: @const char *s@ = pointer to short options
363 * @struct option *l@ = pointer to long options
367 * Use: Adds a collection of options to the table.
370 static void addopts(const char *s
, struct option
*l
)
376 DA_PUSH(&optv
, *l
++);
384 * Returns: Next option from argument array.
386 * Use: Fetches options, handling the standard ones.
392 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
405 puts("Generators supported:");
406 for (g
= generators
; g
->name
; g
++)
407 printf(" %s %s\n", g
->name
, g
->help
);
417 unsigned long lo
, hi
;
418 lo
= strtoul(optarg
, &p
, 0);
419 if (*p
== '-' || *p
== ',')
420 hi
= strtoul(p
+ 1, &p
, 0);
423 if (*p
!= 0 || hi
< lo
|| lo
== 0)
424 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
431 die(EXIT_FAILURE
, "already set an output file");
432 if (strcmp(optarg
, "-") == 0)
435 outfp
= fopen(optarg
, "w");
437 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
438 optarg
, strerror(errno
));
445 outsz
= strtoul(optarg
, &p
, 0);
447 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
449 case 'G': case 'g': outsz
*= 1024;
450 case 'M': case 'm': outsz
*= 1024;
451 case 'K': case 'k': outsz
*= 1024;
455 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
459 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
476 /*----- Manglers for seed strings -----------------------------------------*/
480 * Arguments: @const char *p@ = pointer to input string
481 * @char **end@ = where the end goes
482 * @dstr *d@ = output buffer
486 * Use: Transforms a hex string into a chunk of binary data.
489 static void unhex(const char *p
, char **end
, dstr
*d
)
491 while (p
[0] && p
[1]) {
492 int x
= p
[0], y
= p
[1];
493 if ('0' <= x
&& x
<= '9') x
-= '0';
494 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
495 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
497 if ('0' <= y
&& y
<= '9') y
-= '0';
498 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
499 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
501 DPUTC(d
, (x
<< 4) + y
);
507 /* --- Generate a key --- */
509 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
511 size_t sz
= strlen(p
);
514 die(EXIT_FAILURE
, "zero-length key string");
515 if (keysz(sz
, ksz
) != sz
)
519 rmd160_mgfinit(&g
, p
, sz
);
522 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
525 assert(((void)"I can't seem to choose a good key size",
526 keysz(d
->len
, ksz
) == d
->len
));
529 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
532 unhex(optarg
, &q
, d
);
534 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
535 if (keysz(d
->len
, ksz
) != d
->len
)
536 die(EXIT_FAILURE
, "bad key length");
539 static void randkey(dstr
*d
, const octet
*ksz
)
541 size_t sz
= keysz(0, ksz
);
543 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
547 /*----- Generators --------------------------------------------------------*/
549 /* --- Blum-Blum-Shub strong generator --- */
551 static grand
*gen_bbs(unsigned i
)
553 /* --- Default modulus --- *
555 * The factors of this number are
557 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
558 * @7754313537966036459299022912838407755462506416274551744201653277@
559 * @313130311731673973886822067@
561 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
562 * @5374320073594018817245784145742769603334292182227671519041431067@
563 * @61344781426317516045890159@
565 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
566 * common factors. They were found using this program, with random
569 * I hope that, by publishing these factors, I'll dissuade people from
570 * actually using this modulus in an attempt to attain real security. The
571 * program is quite quick at finding Blum numbers, so there's no excuse for
572 * not generating your own.
576 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
578 /* --- Other things --- */
582 unsigned bits
= 1024;
585 const char *kfile
= 0, *id
= 0, *ktype
= 0;
587 /* --- Parse options --- */
589 static struct option opts
[] = {
590 { "modulus", OPTF_ARGREQ
, 0, 'M' },
591 { "generate", 0, 0, 'g' },
592 { "seed", OPTF_ARGREQ
, 0, 's' },
593 { "bits", OPTF_ARGREQ
, 0, 'b' },
594 { "show", 0, 0, 'S' },
595 { "keyring", OPTF_ARGREQ
, 0, 'k' },
596 { "id", OPTF_ARGREQ
, 0, 'i' },
597 { "type", OPTF_ARGREQ
, 0, 't' },
601 addopts("M:gs:b:Sk:i:t:", opts
);
618 bits
= strtoul(optarg
, 0, 0);
620 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
642 /* --- Generate a modulus if one is requested --- */
646 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
647 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
648 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
649 /* Unfortunately I don't know how to test for a Blum integer */
650 } else if (kfile
|| id
|| ktype
) {
655 /* --- Open the key file --- */
659 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
660 die(EXIT_FAILURE
, "error opening key file `%s': %s",
661 kfile
, strerror(errno
));
664 /* --- Find the key --- */
667 if ((kk
= key_bytag(&kf
, id
)) == 0)
668 die(EXIT_FAILURE
, "key `%s' not found", id
);
672 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
673 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
676 /* --- Read the key data --- */
678 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
679 die(EXIT_FAILURE
, "key is not structured");
680 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
681 die(EXIT_FAILURE
, "key has no subkey `n'");
682 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
683 die(EXIT_FAILURE
, "incomatible subkey encoding");
684 m
= MP_COPY(kd
->u
.m
);
689 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
690 (flags
& f_progress
) ? pgen_ev
: 0, 0))
691 die(EXIT_FAILURE
, "modulus generation failed");
695 fputs("p = ", stderr
);
696 mp_writefile(bp
.p
, stderr
, 10);
697 fputs("\nq = ", stderr
);
698 mp_writefile(bp
.q
, stderr
, 10);
699 fputs("\nn = ", stderr
);
700 mp_writefile(bp
.n
, stderr
, 10);
708 /* --- Set up a seed --- */
711 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
714 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
716 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
728 /* --- Catacomb's random number generator --- */
730 static grand
*gen_rand(unsigned i
)
732 grand
*r
= rand_create();
735 static struct option opts
[] = {
736 { "key", OPTF_ARGREQ
, 0, 'k' },
737 { "text", OPTF_ARGREQ
, 0, 't' },
738 { "hex", OPTF_ARGREQ
, 0, 'H' },
742 addopts("k:t:H:n", opts
);
744 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
745 r
->ops
->misc(r
, RAND_SEED
, 160);
754 textkey(&d
, optarg
, rmd160_hmackeysz
);
755 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
758 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
762 hexkey(&d
, optarg
, rmd160_hmackeysz
);
763 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
772 /* --- RC4 output --- */
774 static grand
*gen_rc4(unsigned i
)
779 static struct option opts
[] = {
780 { "key", OPTF_ARGREQ
, 0, 'k' },
781 { "hex", OPTF_ARGREQ
, 0, 'H' },
785 addopts("k:H:", opts
);
794 textkey(&d
, optarg
, rc4_keysz
);
798 hexkey(&d
, optarg
, rc4_keysz
);
806 randkey(&d
, rc4_keysz
);
807 r
= rc4_rand(d
.buf
, d
.len
);
812 /* --- SEAL output --- */
814 static grand
*gen_seal(unsigned i
)
820 static struct option opts
[] = {
821 { "key", OPTF_ARGREQ
, 0, 'k' },
822 { "hex", OPTF_ARGREQ
, 0, 'H' },
823 { "sequence", OPTF_ARGREQ
, 0, 'n' },
827 addopts("k:H:n:", opts
);
836 textkey(&d
, optarg
, seal_keysz
);
840 hexkey(&d
, optarg
, seal_keysz
);
844 n
= strtoul(optarg
, &p
, 0);
846 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
854 randkey(&d
, seal_keysz
);
855 r
= seal_rand(d
.buf
, d
.len
, n
);
860 /* --- Output feedback generators --- */
862 static grand
*gen_ofb(unsigned i
)
868 static struct option opts
[] = {
869 { "key", OPTF_ARGREQ
, 0, 'k' },
870 { "hex", OPTF_ARGREQ
, 0, 'H' },
871 { "iv", OPTF_ARGREQ
, 0, 'i' },
875 addopts("k:H:i:", opts
);
884 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
888 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
892 unhex(optarg
, &p
, &iv
);
894 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
902 randkey(&d
, ciphertab
[i
].keysz
);
903 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
905 if (iv
.len
!= ciphertab
[i
].blksz
) {
906 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
907 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
909 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
917 /* --- Counter generators --- */
919 static grand
*gen_counter(unsigned i
)
925 static struct option opts
[] = {
926 { "key", OPTF_ARGREQ
, 0, 'k' },
927 { "hex", OPTF_ARGREQ
, 0, 'H' },
928 { "iv", OPTF_ARGREQ
, 0, 'i' },
932 addopts("k:H:i:", opts
);
941 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
945 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
949 unhex(optarg
, &p
, &iv
);
951 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
959 randkey(&d
, ciphertab
[i
].keysz
);
960 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
962 if (iv
.len
!= ciphertab
[i
].blksz
) {
963 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
964 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
966 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
974 /* --- Mask generators --- */
976 static grand
*gen_mgf(unsigned i
)
982 static struct option opts
[] = {
983 { "key", OPTF_ARGREQ
, 0, 'k' },
984 { "hex", OPTF_ARGREQ
, 0, 'H' },
985 { "index", OPTF_ARGREQ
, 0, 'i' },
989 addopts("k:H:i:", opts
);
998 textkey(&d
, optarg
, hashtab
[i
].keysz
);
1002 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
1006 c
= strtoul(optarg
, &p
, 0);
1008 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
1016 randkey(&d
, hashtab
[i
].keysz
);
1018 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
1020 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
1026 /* --- Fibonacci generator --- */
1028 static grand
*gen_fib(unsigned i
)
1035 static struct option opts
[] = {
1036 { "seed", OPTF_ARGREQ
, 0, 's' },
1040 addopts("s:", opts
);
1048 s
= strtoul(optarg
, &p
, 0);
1050 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1057 r
= fibrand_create(s
);
1059 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1063 /* --- LC generator --- */
1065 static grand
*gen_lc(unsigned i
)
1071 static struct option opts
[] = {
1072 { "seed", OPTF_ARGREQ
, 0, 's' },
1076 addopts("s:", opts
);
1084 s
= strtoul(optarg
, &p
, 0);
1086 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1095 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1096 while (s
== LCRAND_FIXEDPT
);
1098 return (lcrand_create(s
));
1101 /* --- Basic options parser -- can't generate output --- */
1103 static grand
*gen_opts(unsigned i
)
1110 /*----- Generators table --------------------------------------------------*/
1112 gen generators
[] = {
1113 { "fibonacci", gen_fib
, 0,
1117 #define E(PRE, pre) \
1118 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1119 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1122 #define E(PRE, pre) \
1123 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1124 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1127 #define E(PRE, pre) \
1128 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1129 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1132 { "rc4", gen_rc4
, 0,
1133 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1134 { "seal", gen_seal
, 0,
1135 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1136 { "rand", gen_rand
, 0,
1137 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1138 { "bbs", gen_bbs
, 0,
1139 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1144 static gen optsg
= { "options", gen_opts
, 0,
1145 "This message shouldn't be printed." };
1147 /*----- Random number generation ------------------------------------------*/
1149 static int genfile(const void *buf
, size_t sz
, void *p
)
1152 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1153 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1157 static int genbuf(const void *buf
, size_t sz
, void *p
)
1160 memcpy(*pp
, buf
, sz
);
1165 typedef struct genmaurer_ctx
{
1170 static int genmaurer(const void *buf
, size_t sz
, void *p
)
1172 genmaurer_ctx
*g
= p
;
1175 for (i
= 0; i
< g
->n
; i
++)
1176 maurer_test(&g
->m
[i
], buf
, sz
);
1180 static int generate(grand
*r
, size_t outsz
,
1181 int (*func
)(const void *buf
, size_t sz
, void *p
),
1184 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1186 unsigned percent
= 0;
1189 static char baton
[] = "-\\|/";
1194 /* --- Spit out random data --- */
1198 if (flags
& f_progress
) {
1199 char *errbuf
= xmalloc(BUFSIZ
);
1200 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1202 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1204 fputs("[ ] 0\r[/\b", stderr
);
1209 signal(SIGPIPE
, SIG_IGN
);
1214 size_t sz
= sizeof(buf
);
1215 clock_t c_start
, c_stop
;
1217 /* --- Emit a bufferful (or less) of data --- */
1220 if (sz
> outsz
- kb
)
1224 r
->ops
->fill(r
, buf
, sz
);
1226 clk
+= c_stop
- c_start
;
1227 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1231 /* --- Update the display --- */
1233 if (flags
& f_progress
) {
1241 if (difftime(t
, last
) > 1.0) {
1245 fputs(" ] ", stderr
);
1247 unsigned pc
= kb
* 100.0 / outsz
;
1248 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1252 for (; percent
< (pc
& ~1); percent
+= 2)
1255 for (; pc
< 100; pc
+= 2)
1257 fprintf(stderr
, "] %3i%% ", percent
);
1265 while (q
> 8192 && kk
[1]) {
1269 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1272 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1281 if (percent
< 100) {
1282 putc(*bp
++, stderr
);
1290 /* --- Terminate the loop --- */
1292 } while (!outsz
|| kb
< outsz
);
1294 if (flags
& f_progress
)
1295 fputc('\n', stderr
);
1296 if (flags
& f_timer
) {
1297 fprintf(stderr
, "generated %lu bytes ", (unsigned long)outsz
);
1299 fputs("too quickly to measure\n", stderr
);
1302 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1303 double bps
= (outsz
<< 3)/sec
;
1304 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1306 fprintf(stderr
, "in %g secs (%g %cb/s)\n", sec
, bps
, *kk
);
1312 /*----- Main code ---------------------------------------------------------*/
1314 int main(int ac
, char *av
[])
1319 /* --- Initialize mLib --- */
1324 /* --- Set up the main Catacomb generator --- */
1326 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1327 rand_seed(RAND_GLOBAL
, 160);
1329 /* --- Initialize the options table --- */
1331 addopts(sopts
, opts
);
1336 /* --- Read the generator out of the first argument --- */
1338 if (argc
> 1 && *argv
[1] != '-') {
1339 const char *arg
= av
[1];
1340 size_t sz
= strlen(arg
);
1344 for (gg
= generators
; gg
->name
; gg
++) {
1345 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1346 if (gg
->name
[sz
] == 0) {
1350 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1356 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1361 /* --- Get a generic random number generator --- */
1364 if (!r
|| optind
!= ac
- 1) {
1369 /* --- Do the FIPS test --- */
1371 if (flags
& f_fips
) {
1372 octet buf
[FIPSTEST_BUFSZ
];
1376 generate(r
, sizeof(buf
), genbuf
, &p
);
1378 if (rc
& FIPSTEST_MONOBIT
)
1379 moan("failed monobit test");
1380 if (rc
& FIPSTEST_POKER
)
1381 moan("failed poker test");
1382 if (rc
& FIPSTEST_RUNS
)
1383 moan("failed runs test");
1384 if (rc
& FIPSTEST_LONGRUNS
)
1385 moan("failed long runs test");
1386 if (!rc
&& (flags
& f_progress
))
1387 fputs("test passed\n", stderr
);
1388 return (rc ? EXIT_FAILURE
: 0);
1391 /* --- Do Maurer's test --- */
1393 if (flags
& f_maurer
) {
1399 static struct { double x
; const char *sig
; } sigtab
[] = {
1407 g
.n
= maurer_hi
- maurer_lo
+ 1;
1408 g
.m
= xmalloc(g
.n
* sizeof(maurer_ctx
));
1409 for (i
= 0; i
< g
.n
; i
++)
1410 maurer_init(&g
.m
[i
], i
+ maurer_lo
);
1411 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1413 generate(r
, bufsz
, genmaurer
, &g
);
1415 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1416 double z
= maurer_done(&g
.m
[i
- maurer_lo
]);
1417 double zz
= fabs(z
);
1420 for (j
= 0; sigtab
[j
].sig
; j
++) {
1421 if (zz
> sigtab
[j
].x
) {
1423 moan("failed, bits = %u, sig = %s, Z_u = %g",
1424 i
, sigtab
[j
].sig
, z
);
1428 if (flags
& f_progress
)
1429 fprintf(stderr
, "bits = %u, Z_u = %g\n", i
, z
);
1436 /* --- Discard --- */
1438 if (flags
& f_discard
) {
1439 generate(r
, outsz
, 0, 0);
1443 /* --- Write to a file --- */
1446 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1447 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1450 generate(r
, outsz
, genfile
, outfp
);
1458 /*----- That's all, folks -------------------------------------------------*/