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