Renamed from `rsa-decrypt', since the name was no longer appropriate.
[u/mdw/catacomb] / rspit.c
CommitLineData
ee33470f 1/* -*-c-*-
2 *
bb78535e 3 * $Id: rspit.c,v 1.4 2000/06/17 12:08:28 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 $
bb78535e 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 *
052b36d0 37 * Revision 1.3 2000/02/12 18:21:03 mdw
38 * Overhaul of key management (again).
39 *
87de7c73 40 * Revision 1.2 1999/12/22 15:59:51 mdw
41 * New prime-search system. Read BBS keys from key files.
42 *
ee33470f 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
bb78535e 52#include <assert.h>
ee33470f 53#include <errno.h>
bb78535e 54#include <math.h>
ee33470f 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
bb78535e 72#include "fipstest.h"
ee33470f 73#include "grand.h"
bb78535e 74#include "maurer.h"
87de7c73 75#include "key.h"
ee33470f 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"
bb78535e 86#include "seal.h"
ee33470f 87
88#include "des-ofb.h"
89#include "des3-ofb.h"
bb78535e 90#include "rc2-ofb.h"
ee33470f 91#include "rc5-ofb.h"
92#include "blowfish-ofb.h"
bb78535e 93#include "twofish-ofb.h"
ee33470f 94#include "idea-ofb.h"
bb78535e 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"
ee33470f 116
117#include "rmd160.h"
118
119/*----- Data structures ---------------------------------------------------*/
120
121typedef struct gen {
122 const char *name;
123 grand *(*seed)(unsigned /*i*/);
124 unsigned i;
125 const char *help;
126} gen;
127
128static gen generators[];
129
bb78535e 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,
150enum { CIPHERS CIPHER__bogus };
151#undef E
152
153#define E(PRE, pre) HASH_##PRE,
154enum { HASHES HASH__bogus };
155#undef E
156
157static 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
169static 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
ee33470f 180/*----- Miscellaneous static data -----------------------------------------*/
181
182static FILE *outfp = stdout;
183static size_t outsz = 0;
184
185static int argc;
186static char **argv;
187
188static unsigned flags = 0;
189
190enum {
191 f_progress = 1,
bb78535e 192 f_file = 2,
193 f_fips = 4,
194 f_maurer = 8
ee33470f 195};
196
197/*----- Help options ------------------------------------------------------*/
198
199static void usage(FILE *fp)
200{
201 pquis(fp, "Usage: $ generator [options]\n");
202}
203
204static void version(FILE *fp)
205{
206 pquis(fp, "$, Catacomb version " VERSION "\n");
207}
208
209static void help(FILE *fp)
210{
211 version(fp);
212 fputc('\n', fp);
213 usage(fp);
214 pquis(fp, "\n\
215Emits a stream of random bytes suitable for, well, all sorts of things.\n\
216The primary objective is to be able to generate streams of input for\n\
217statistical tests, such as Diehard.\n\
218\n\
219Options are specific to the particular generator, although there's a\n\
220common 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\
bb78535e 228-f, --fipstest Run the FIPS 140-1 randomness test.\n\
229-m, --maurer Run Maurer's universal statistical test.\n\
ee33470f 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
241static 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' },
bb78535e 252 { "fipstest", 0, 0, 'f' },
253 { "maurer", 0, 0, 'm' },
ee33470f 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
bb78535e 263static const char *sopts = "hvu lfmo:z:p";
ee33470f 264
265#ifndef OPTION_V
266 DA_DECL(option_v, struct option);
267# define OPTION_V
268#endif
269
270static option_v optv = DA_INIT;
271static 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
283static 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
302static 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;
bb78535e 323 case 'f':
324 flags |= f_fips;
325 break;
326 case 'm':
327 flags |= f_maurer;
328 break;
ee33470f 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",
bb78535e 338 optarg, strerror(errno));
ee33470f 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
383static 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
bb78535e 401/* --- Generate a key --- */
402
403static 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
423static 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
433static 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
ee33470f 441/*----- Generators --------------------------------------------------------*/
442
443/* --- Blum-Blum-Shub strong generator --- */
444
ee33470f 445static 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 *
bb78535e 459 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
ee33470f 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
bb78535e 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.
ee33470f 467 */
468
469 const char *mt =
470 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
471
472 /* --- Other things --- */
473
474 grand *r;
475 const char *xt = 0;
87de7c73 476 unsigned bits = 1024;
ee33470f 477 mp *m, *x;
478 unsigned show = 0;
87de7c73 479 const char *kfile = 0, *id = 0, *ktype = 0;
ee33470f 480
481 /* --- Parse options --- */
482
483 static struct option opts[] = {
bb78535e 484 { "modulus", OPTF_ARGREQ, 0, 'M' },
ee33470f 485 { "generate", 0, 0, 'g' },
486 { "seed", OPTF_ARGREQ, 0, 's' },
487 { "bits", OPTF_ARGREQ, 0, 'b' },
488 { "show", 0, 0, 'S' },
87de7c73 489 { "keyring", OPTF_ARGREQ, 0, 'k' },
490 { "id", OPTF_ARGREQ, 0, 'i' },
491 { "type", OPTF_ARGREQ, 0, 't' },
ee33470f 492 { 0, 0, 0, 0 }
493 };
494
bb78535e 495 addopts("M:gs:b:Sk:i:t:", opts);
ee33470f 496
497 for (;;) {
498 int o = opt();
499 if (o < 0)
500 break;
501 switch (o) {
bb78535e 502 case 'M':
ee33470f 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;
87de7c73 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;
ee33470f 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);
87de7c73 541 if (!m || *p || (m->v[0] & 3) != 1)
ee33470f 542 die(EXIT_FAILURE, "bad modulus `%s'", mt);
543 /* Unfortunately I don't know how to test for a Blum integer */
87de7c73 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);
ee33470f 580 } else {
87de7c73 581 bbs_param bp;
ee33470f 582
052b36d0 583 if (bbs_gen(&bp, bits, &rand_global, 0,
584 (flags & f_progress) ? pgen_ev : 0, 0))
87de7c73 585 die(EXIT_FAILURE, "modulus generation failed");
ee33470f 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
ee33470f 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
624static 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' },
ee33470f 633 { 0, 0, 0, 0 }
634 };
635
636 addopts("k:t:H:n", opts);
637
bb78535e 638 r->ops->misc(r, RAND_NOISESRC, &noise_source);
639 r->ops->misc(r, RAND_SEED, 160);
640
ee33470f 641 for (;;) {
642 int o = opt();
643 if (o < 0)
644 break;
645 switch (o) {
bb78535e 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;
ee33470f 651 case 't':
652 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
653 break;
bb78535e 654 case 'H':
ee33470f 655 DRESET(&d);
bb78535e 656 hexkey(&d, optarg, rmd160_mackeysz);
ee33470f 657 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
ee33470f 658 break;
659 }
660 }
661
662 dstr_destroy(&d);
663 return (r);
664}
665
666/* --- RC4 output --- */
667
668static 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) {
bb78535e 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;
ee33470f 694 default:
695 return (0);
696 }
697 }
698
bb78535e 699 if (!d.len)
700 randkey(&d, rc4_keysz);
ee33470f 701 r = rc4_rand(d.buf, d.len);
702 dstr_destroy(&d);
703 return (r);
704}
705
bb78535e 706/* --- SEAL output --- */
ee33470f 707
bb78535e 708static grand *gen_seal(unsigned i)
709{
710 grand *r;
711 dstr d = DSTR_INIT;
712 uint32 n = 0;
ee33470f 713
bb78535e 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 };
ee33470f 720
bb78535e 721 addopts("k:H:n:", opts);
ee33470f 722
bb78535e 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 --- */
ee33470f 755
756static 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) {
bb78535e 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;
ee33470f 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
bb78535e 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);
ee33470f 804 }
805
bb78535e 806 dstr_destroy(&d);
807 dstr_destroy(&iv);
808 return (r);
809}
810
811/* --- Counter generators --- */
812
813static grand *gen_counter(unsigned i)
814{
815 grand *r;
816 dstr d = DSTR_INIT;
817 dstr iv = DSTR_INIT;
ee33470f 818
bb78535e 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);
ee33470f 855 if (iv.len) {
bb78535e 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 }
ee33470f 860 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
861 }
862
863 dstr_destroy(&d);
864 dstr_destroy(&iv);
865 return (r);
866}
867
bb78535e 868/* --- Mask generators --- */
869
870static 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
ee33470f 920/* --- Fibonacci generator --- */
921
922static 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
959static 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
997static grand *gen_opts(unsigned i)
998{
999 while (opt() >= 0)
1000 ;
1001 return (0);
1002}
1003
1004/*----- Generators table --------------------------------------------------*/
1005
1006static gen generators[] = {
1007 { "fibonacci", gen_fib, 0,
1008 "[-s SEED]" },
1009 { "lc", gen_lc, 0,
1010 "[-s SEED]" },
bb78535e 1011#define E(PRE, pre) \
1012 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
ee33470f 1013 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1014 CIPHERS
1015#undef E
1016#define E(PRE, pre) \
1017 { #pre "-counter", gen_counter, CIPHER_##PRE, \
ee33470f 1018 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 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)
ee33470f 1026 { "rc4", gen_rc4, 0,
1027 "[-k KEY-PHRASE] [-H HEX-KEY]" },
bb78535e 1028 { "seal", gen_seal, 0,
1029 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
ee33470f 1030 { "rand", gen_rand, 0,
1031 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1032 { "bbs", gen_bbs, 0,
bb78535e 1033 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
87de7c73 1034 },
ee33470f 1035 { 0, 0, 0, 0 },
1036};
1037
1038static gen optsg = { "options", gen_opts, 0,
1039 "This message shouldn't be printed." };
1040
1041/*----- Main code ---------------------------------------------------------*/
1042
1043int main(int ac, char *av[])
1044{
1045 gen *g = &optsg;
1046 grand *r;
bb78535e 1047 unsigned percent = 0;
ee33470f 1048 size_t kb = 0;
1049 time_t last;
bb78535e 1050 static char baton[] = "-\\|/";
ee33470f 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);
bb78535e 1061 rand_seed(RAND_GLOBAL, 160);
ee33470f 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
bb78535e 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
ee33470f 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);
bb78535e 1180 if (outsz)
1181 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1182 else
1183 fputs("[ ] 0\r[/\b", stderr);
ee33470f 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 -------------------------------------------------*/