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