3 * $Id: rspit.c,v 1.18 2001/05/08 22:17:41 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.18 2001/05/08 22:17:41 mdw
34 * New cipher Noekeon added.
36 * Revision 1.17 2001/05/07 17:33:19 mdw
37 * New Rijndael block sizes.
39 * Revision 1.16 2001/04/29 18:11:32 mdw
42 * Revision 1.15 2001/04/19 18:26:13 mdw
43 * Use the new MAC keysize names.
45 * Revision 1.14 2001/02/21 20:03:22 mdw
46 * Added support for MD2 hash function.
48 * Revision 1.13 2000/12/06 20:33:27 mdw
49 * Make flags be macros rather than enumerations, to ensure that they're
52 * Revision 1.12 2000/10/08 15:49:18 mdw
53 * Remove failed kludge for shutting up a warning.
55 * Revision 1.11 2000/10/08 12:10:32 mdw
56 * Make table have external linkage to bodge around deficiency in C. The
57 * problem is that @static gen generators[];@ is considered to be a
58 * `tentative definition', and therefore mustn't have incomplete type,
59 * which it obviously has.
61 * Revision 1.10 2000/08/11 21:34:59 mdw
62 * New restartable interface to Maurer testing.
64 * Revision 1.9 2000/08/04 23:24:15 mdw
65 * Add a timer and a discard option.
67 * Revision 1.8 2000/07/29 22:05:47 mdw
68 * Fix error in help message about Maurer test syntax.
70 * Revision 1.7 2000/07/18 23:01:26 mdw
71 * Improve progress indications, and allow user to choose chunk sizes for
74 * Revision 1.6 2000/07/15 20:53:35 mdw
75 * Add a load of new ciphers and hashes.
77 * Revision 1.5 2000/07/01 11:27:03 mdw
78 * Portability fix: don't assume that `stdout' is a constant expression.
79 * Remove old type name `bbs_param'.
81 * Revision 1.4 2000/06/17 12:08:28 mdw
82 * Restructure handling of cipher-based generators. Add counter-mode
83 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
85 * Revision 1.3 2000/02/12 18:21:03 mdw
86 * Overhaul of key management (again).
88 * Revision 1.2 1999/12/22 15:59:51 mdw
89 * New prime-search system. Read BBS keys from key files.
91 * Revision 1.1 1999/12/10 23:29:13 mdw
92 * Emit random numbers for statistical tests.
96 /*----- Header files ------------------------------------------------------*/
113 #include <mLib/darray.h>
114 #include <mLib/dstr.h>
115 #include <mLib/mdwopt.h>
116 #include <mLib/quis.h>
117 #include <mLib/report.h>
118 #include <mLib/sub.h>
120 #include "fipstest.h"
137 #include "des3-ofb.h"
140 #include "mars-ofb.h"
141 #include "skipjack-ofb.h"
143 #include "xtea-ofb.h"
144 #include "blowfish-ofb.h"
145 #include "twofish-ofb.h"
146 #include "idea-ofb.h"
147 #include "cast128-ofb.h"
148 #include "cast256-ofb.h"
149 #include "noekeon-ofb.h"
150 #include "rijndael-ofb.h"
151 #include "rijndael192-ofb.h"
152 #include "rijndael256-ofb.h"
153 #include "safer-ofb.h"
154 #include "safersk-ofb.h"
155 #include "square-ofb.h"
156 #include "serpent-ofb.h"
158 #include "des-counter.h"
159 #include "des3-counter.h"
160 #include "rc2-counter.h"
161 #include "rc5-counter.h"
162 #include "mars-counter.h"
163 #include "skipjack-counter.h"
164 #include "tea-counter.h"
165 #include "xtea-counter.h"
166 #include "blowfish-counter.h"
167 #include "twofish-counter.h"
168 #include "idea-counter.h"
169 #include "cast128-counter.h"
170 #include "cast256-counter.h"
171 #include "noekeon-counter.h"
172 #include "rijndael-counter.h"
173 #include "rijndael192-counter.h"
174 #include "rijndael256-counter.h"
175 #include "safer-counter.h"
176 #include "safersk-counter.h"
177 #include "square-counter.h"
178 #include "serpent-counter.h"
184 #include "tiger-mgf.h"
185 #include "rmd128-mgf.h"
186 #include "rmd160-mgf.h"
187 #include "rmd256-mgf.h"
188 #include "rmd320-mgf.h"
192 /*----- Data structures ---------------------------------------------------*/
196 grand
*(*seed
)(unsigned /*i*/);
201 extern gen generators
[];
209 E(SKIPJACK, skipjack) \
212 E(BLOWFISH, blowfish) \
213 E(TWOFISH, twofish) \
215 E(CAST128, cast128) \
216 E(CAST256, cast256) \
219 E(SAFERSK, safersk) \
220 E(NOEKEON, noekeon) \
221 E(RIJNDAEL, rijndael) \
222 E(RIJNDAEL192, rijndael192) \
223 E(RIJNDAEL256, rijndael256) \
237 #define E(PRE, pre) CIPHER_##PRE,
238 enum { CIPHERS CIPHER__bogus
};
241 #define E(PRE, pre) HASH_##PRE,
242 enum { HASHES HASH__bogus
};
248 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
249 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
251 #define E(PRE, pre) \
252 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
260 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
262 #define E(PRE, pre) \
263 { &pre, pre##_mgfkeysz, pre##_mgfrand },
268 /*----- Miscellaneous static data -----------------------------------------*/
271 static size_t 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
= strtoul(optarg
, &p
, 0);
453 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
455 case 'G': case 'g': outsz
*= 1024;
456 case 'M': case 'm': outsz
*= 1024;
457 case 'K': case 'k': outsz
*= 1024;
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 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
584 /* --- Other things --- */
588 unsigned bits
= 1024;
591 const char *kfile
= 0, *id
= 0, *ktype
= 0;
593 /* --- Parse options --- */
595 static struct option opts
[] = {
596 { "modulus", OPTF_ARGREQ
, 0, 'M' },
597 { "generate", 0, 0, 'g' },
598 { "seed", OPTF_ARGREQ
, 0, 's' },
599 { "bits", OPTF_ARGREQ
, 0, 'b' },
600 { "show", 0, 0, 'S' },
601 { "keyring", OPTF_ARGREQ
, 0, 'k' },
602 { "id", OPTF_ARGREQ
, 0, 'i' },
603 { "type", OPTF_ARGREQ
, 0, 't' },
607 addopts("M:gs:b:Sk:i:t:", opts
);
624 bits
= strtoul(optarg
, 0, 0);
626 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
648 /* --- Generate a modulus if one is requested --- */
652 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
653 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
654 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
655 /* Unfortunately I don't know how to test for a Blum integer */
656 } else if (kfile
|| id
|| ktype
) {
661 /* --- Open the key file --- */
665 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
666 die(EXIT_FAILURE
, "error opening key file `%s': %s",
667 kfile
, strerror(errno
));
670 /* --- Find the key --- */
673 if ((kk
= key_bytag(&kf
, id
)) == 0)
674 die(EXIT_FAILURE
, "key `%s' not found", id
);
678 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
679 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
682 /* --- Read the key data --- */
684 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
685 die(EXIT_FAILURE
, "key is not structured");
686 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
687 die(EXIT_FAILURE
, "key has no subkey `n'");
688 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
689 die(EXIT_FAILURE
, "incomatible subkey encoding");
690 m
= MP_COPY(kd
->u
.m
);
695 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
696 (flags
& f_progress
) ? pgen_ev
: 0, 0))
697 die(EXIT_FAILURE
, "modulus generation failed");
701 fputs("p = ", stderr
);
702 mp_writefile(bp
.p
, stderr
, 10);
703 fputs("\nq = ", stderr
);
704 mp_writefile(bp
.q
, stderr
, 10);
705 fputs("\nn = ", stderr
);
706 mp_writefile(bp
.n
, stderr
, 10);
714 /* --- Set up a seed --- */
717 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
720 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
722 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
734 /* --- Catacomb's random number generator --- */
736 static grand
*gen_rand(unsigned i
)
738 grand
*r
= rand_create();
741 static struct option opts
[] = {
742 { "key", OPTF_ARGREQ
, 0, 'k' },
743 { "text", OPTF_ARGREQ
, 0, 't' },
744 { "hex", OPTF_ARGREQ
, 0, 'H' },
748 addopts("k:t:H:n", opts
);
750 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
751 r
->ops
->misc(r
, RAND_SEED
, 160);
760 textkey(&d
, optarg
, rmd160_hmackeysz
);
761 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
764 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
768 hexkey(&d
, optarg
, rmd160_hmackeysz
);
769 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
778 /* --- RC4 output --- */
780 static grand
*gen_rc4(unsigned i
)
785 static struct option opts
[] = {
786 { "key", OPTF_ARGREQ
, 0, 'k' },
787 { "hex", OPTF_ARGREQ
, 0, 'H' },
791 addopts("k:H:", opts
);
800 textkey(&d
, optarg
, rc4_keysz
);
804 hexkey(&d
, optarg
, rc4_keysz
);
812 randkey(&d
, rc4_keysz
);
813 r
= rc4_rand(d
.buf
, d
.len
);
818 /* --- SEAL output --- */
820 static grand
*gen_seal(unsigned i
)
826 static struct option opts
[] = {
827 { "key", OPTF_ARGREQ
, 0, 'k' },
828 { "hex", OPTF_ARGREQ
, 0, 'H' },
829 { "sequence", OPTF_ARGREQ
, 0, 'n' },
833 addopts("k:H:n:", opts
);
842 textkey(&d
, optarg
, seal_keysz
);
846 hexkey(&d
, optarg
, seal_keysz
);
850 n
= strtoul(optarg
, &p
, 0);
852 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
860 randkey(&d
, seal_keysz
);
861 r
= seal_rand(d
.buf
, d
.len
, n
);
866 /* --- Output feedback generators --- */
868 static grand
*gen_ofb(unsigned i
)
874 static struct option opts
[] = {
875 { "key", OPTF_ARGREQ
, 0, 'k' },
876 { "hex", OPTF_ARGREQ
, 0, 'H' },
877 { "iv", OPTF_ARGREQ
, 0, 'i' },
881 addopts("k:H:i:", opts
);
890 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
894 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
898 unhex(optarg
, &p
, &iv
);
900 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
908 randkey(&d
, ciphertab
[i
].keysz
);
909 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
911 if (iv
.len
!= ciphertab
[i
].blksz
) {
912 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
913 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
915 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
923 /* --- Counter generators --- */
925 static grand
*gen_counter(unsigned i
)
931 static struct option opts
[] = {
932 { "key", OPTF_ARGREQ
, 0, 'k' },
933 { "hex", OPTF_ARGREQ
, 0, 'H' },
934 { "iv", OPTF_ARGREQ
, 0, 'i' },
938 addopts("k:H:i:", opts
);
947 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
951 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
955 unhex(optarg
, &p
, &iv
);
957 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
965 randkey(&d
, ciphertab
[i
].keysz
);
966 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
968 if (iv
.len
!= ciphertab
[i
].blksz
) {
969 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
970 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
972 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
980 /* --- Mask generators --- */
982 static grand
*gen_mgf(unsigned i
)
988 static struct option opts
[] = {
989 { "key", OPTF_ARGREQ
, 0, 'k' },
990 { "hex", OPTF_ARGREQ
, 0, 'H' },
991 { "index", OPTF_ARGREQ
, 0, 'i' },
995 addopts("k:H:i:", opts
);
1004 textkey(&d
, optarg
, hashtab
[i
].keysz
);
1008 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
1012 c
= strtoul(optarg
, &p
, 0);
1014 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
1022 randkey(&d
, hashtab
[i
].keysz
);
1024 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
1026 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
1032 /* --- Fibonacci generator --- */
1034 static grand
*gen_fib(unsigned i
)
1041 static struct option opts
[] = {
1042 { "seed", OPTF_ARGREQ
, 0, 's' },
1046 addopts("s:", opts
);
1054 s
= strtoul(optarg
, &p
, 0);
1056 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1063 r
= fibrand_create(s
);
1065 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1069 /* --- LC generator --- */
1071 static grand
*gen_lc(unsigned i
)
1077 static struct option opts
[] = {
1078 { "seed", OPTF_ARGREQ
, 0, 's' },
1082 addopts("s:", opts
);
1090 s
= strtoul(optarg
, &p
, 0);
1092 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1101 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1102 while (s
== LCRAND_FIXEDPT
);
1104 return (lcrand_create(s
));
1107 /* --- Basic options parser -- can't generate output --- */
1109 static grand
*gen_opts(unsigned i
)
1116 /*----- Generators table --------------------------------------------------*/
1118 gen generators
[] = {
1119 { "fibonacci", gen_fib
, 0,
1123 #define E(PRE, pre) \
1124 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1125 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1128 #define E(PRE, pre) \
1129 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1130 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1133 #define E(PRE, pre) \
1134 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1135 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1138 { "rc4", gen_rc4
, 0,
1139 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1140 { "seal", gen_seal
, 0,
1141 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1142 { "rand", gen_rand
, 0,
1143 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1144 { "bbs", gen_bbs
, 0,
1145 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1150 static gen optsg
= { "options", gen_opts
, 0,
1151 "This message shouldn't be printed." };
1153 /*----- Random number generation ------------------------------------------*/
1155 static int genfile(const void *buf
, size_t sz
, void *p
)
1158 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1159 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1163 static int genbuf(const void *buf
, size_t sz
, void *p
)
1166 memcpy(*pp
, buf
, sz
);
1171 typedef struct genmaurer_ctx
{
1176 static int genmaurer(const void *buf
, size_t sz
, void *p
)
1178 genmaurer_ctx
*g
= p
;
1181 for (i
= 0; i
< g
->n
; i
++)
1182 maurer_test(&g
->m
[i
], buf
, sz
);
1186 static int generate(grand
*r
, size_t outsz
,
1187 int (*func
)(const void *buf
, size_t sz
, void *p
),
1190 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1192 unsigned percent
= 0;
1195 static char baton
[] = "-\\|/";
1200 /* --- Spit out random data --- */
1204 if (flags
& f_progress
) {
1205 char *errbuf
= xmalloc(BUFSIZ
);
1206 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1208 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1210 fputs("[ ] 0\r[/\b", stderr
);
1215 signal(SIGPIPE
, SIG_IGN
);
1220 size_t sz
= sizeof(buf
);
1221 clock_t c_start
, c_stop
;
1223 /* --- Emit a bufferful (or less) of data --- */
1226 if (sz
> outsz
- kb
)
1230 r
->ops
->fill(r
, buf
, sz
);
1232 clk
+= c_stop
- c_start
;
1233 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1237 /* --- Update the display --- */
1239 if (flags
& f_progress
) {
1247 if (difftime(t
, last
) > 1.0) {
1251 fputs(" ] ", stderr
);
1253 unsigned pc
= kb
* 100.0 / outsz
;
1254 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1258 for (; percent
< (pc
& ~1); percent
+= 2)
1261 for (; pc
< 100; pc
+= 2)
1263 fprintf(stderr
, "] %3i%% ", percent
);
1271 while (q
> 8192 && kk
[1]) {
1275 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1278 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1287 if (percent
< 100) {
1288 putc(*bp
++, stderr
);
1296 /* --- Terminate the loop --- */
1298 } while (!outsz
|| kb
< outsz
);
1300 if (flags
& f_progress
)
1301 fputc('\n', stderr
);
1302 if (flags
& f_timer
) {
1303 fprintf(stderr
, "generated %lu bytes ", (unsigned long)outsz
);
1305 fputs("too quickly to measure\n", stderr
);
1308 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1309 double bps
= (outsz
<< 3)/sec
;
1310 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1312 fprintf(stderr
, "in %g secs (%g %cb/s)\n", sec
, bps
, *kk
);
1318 /*----- Main code ---------------------------------------------------------*/
1320 int main(int ac
, char *av
[])
1325 /* --- Initialize mLib --- */
1330 /* --- Set up the main Catacomb generator --- */
1332 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1333 rand_seed(RAND_GLOBAL
, 160);
1335 /* --- Initialize the options table --- */
1337 addopts(sopts
, opts
);
1342 /* --- Read the generator out of the first argument --- */
1344 if (argc
> 1 && *argv
[1] != '-') {
1345 const char *arg
= av
[1];
1346 size_t sz
= strlen(arg
);
1350 for (gg
= generators
; gg
->name
; gg
++) {
1351 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1352 if (gg
->name
[sz
] == 0) {
1356 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1362 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1367 /* --- Get a generic random number generator --- */
1370 if (!r
|| optind
!= ac
- 1) {
1375 /* --- Do the FIPS test --- */
1377 if (flags
& f_fips
) {
1378 octet buf
[FIPSTEST_BUFSZ
];
1382 generate(r
, sizeof(buf
), genbuf
, &p
);
1384 if (rc
& FIPSTEST_MONOBIT
)
1385 moan("failed monobit test");
1386 if (rc
& FIPSTEST_POKER
)
1387 moan("failed poker test");
1388 if (rc
& FIPSTEST_RUNS
)
1389 moan("failed runs test");
1390 if (rc
& FIPSTEST_LONGRUNS
)
1391 moan("failed long runs test");
1392 if (!rc
&& (flags
& f_progress
))
1393 fputs("test passed\n", stderr
);
1394 return (rc ? EXIT_FAILURE
: 0);
1397 /* --- Do Maurer's test --- */
1399 if (flags
& f_maurer
) {
1405 static struct { double x
; const char *sig
; } sigtab
[] = {
1413 g
.n
= maurer_hi
- maurer_lo
+ 1;
1414 g
.m
= xmalloc(g
.n
* sizeof(maurer_ctx
));
1415 for (i
= 0; i
< g
.n
; i
++)
1416 maurer_init(&g
.m
[i
], i
+ maurer_lo
);
1417 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1419 generate(r
, bufsz
, genmaurer
, &g
);
1421 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1422 double z
= maurer_done(&g
.m
[i
- maurer_lo
]);
1423 double zz
= fabs(z
);
1426 for (j
= 0; sigtab
[j
].sig
; j
++) {
1427 if (zz
> sigtab
[j
].x
) {
1429 moan("failed, bits = %u, sig = %s, Z_u = %g",
1430 i
, sigtab
[j
].sig
, z
);
1434 if (flags
& f_progress
)
1435 fprintf(stderr
, "bits = %u, Z_u = %g\n", i
, z
);
1442 /* --- Discard --- */
1444 if (flags
& f_discard
) {
1445 generate(r
, outsz
, 0, 0);
1449 /* --- Write to a file --- */
1452 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1453 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1456 generate(r
, outsz
, genfile
, outfp
);
1464 /*----- That's all, folks -------------------------------------------------*/