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