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