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