/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <assert.h>
#ifndef PORTABLE
# include <unistd.h>
+# include <sys/time.h>
#endif
#include <mLib/darray.h>
#include <mLib/dstr.h>
+#include <mLib/macros.h>
#include <mLib/mdwopt.h>
#include <mLib/quis.h>
#include <mLib/report.h>
#include <mLib/sub.h>
+#include "mp.h"
+#include "mpint.h"
+#include "mplimits.h"
+#include "mptext.h"
+
#include "fipstest.h"
#include "grand.h"
#include "maurer.h"
#include "bbs.h"
#include "mprand.h"
+#include "chacha.h"
#include "rc4.h"
+#include "salsa20.h"
+#include "salsa20-core.h"
#include "seal.h"
+#include "sha3.h"
#include "des-ofb.h"
#include "des3-ofb.h"
enum { HASHES HASH__bogus };
#undef E
-static struct {
+static const struct {
const octet *keysz;
size_t blksz;
grand *(*ofb)(const void */*k*/, size_t /*sz*/);
#undef E
};
-static struct {
+static const struct {
const gchash *h;
const octet *keysz;
grand *(*mgf)(const void */*k*/, size_t /*sz*/);
#undef E
};
+#define SALSAE \
+ E(salsa20, 20,, SALSA20) \
+ E(salsa20, 12,, SALSA20) \
+ E(salsa20, 8,, SALSA20) \
+ E(xsalsa20, 20, X, SALSA20) \
+ E(xsalsa20, 12, X, SALSA20) \
+ E(xsalsa20, 8, X, SALSA20) \
+ E(chacha, 20,, CHACHA) \
+ E(chacha, 12,, CHACHA) \
+ E(chacha, 8,, CHACHA) \
+ E(xchacha, 20, X, CHACHA) \
+ E(xchacha, 12, X, CHACHA) \
+ E(xchacha, 8, X, CHACHA)
+
+#define E(pre, r, x, BASE) pre##_##r##_INDEX,
+enum { SALSAE BOGUS_SALSA };
+#undef E
+
+#define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
+#define CHACHA_GEN(pre, r) pre##r##_rand
+
+#define SALSA20_NAME(r) SALSA20_NAME_##r
+#define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
+#define CHACHA_NAME(r) "chacha" #r
+#define XCHACHA_NAME(r) "xchacha" #r
+
+static const struct {
+ size_t noncesz;
+ grand *(*gen)(const void *, size_t, const void *);
+} salsatab[] = {
+#define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
+ SALSAE
+#undef E
+};
+
+#define SHAKES E(128) E(256)
+
+enum {
+#define E(sz) SHAKE##sz##_INDEX,
+ SHAKES
+#undef E
+ SHAKE__LIMIT
+};
+
+static const struct {
+ const octet *ksz;
+ grand *(*shake)(const void *, size_t, const void *, size_t,
+ const void *, size_t);
+ grand *(*kmac)(const void *, size_t,
+ const void *, size_t);
+} shaketab[] = {
+#define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
+ SHAKES
+#undef E
+};
+
/*----- Miscellaneous static data -----------------------------------------*/
static FILE *outfp;
-static size_t outsz = 0;
+static mp *outsz = 0;
static unsigned maurer_lo = 5, maurer_hi = 8;
static int argc;
case 'o':
if (flags & f_file)
die(EXIT_FAILURE, "already set an output file");
- if (strcmp(optarg, "-") == 0)
+ if (STRCMP(optarg, ==, "-"))
outfp = stdout;
else {
outfp = fopen(optarg, "w");
break;
case 'z': {
char *p;
- outsz = strtoul(optarg, &p, 0);
- if (!outsz)
+ outsz = mp_readstring(outsz, optarg, &p, 0);
+ if (!outsz || MP_NEGP(outsz))
die(EXIT_FAILURE, "bad number `%s'", optarg);
switch (*p) {
- case 'G': case 'g': outsz *= 1024;
- case 'M': case 'm': outsz *= 1024;
- case 'K': case 'k': outsz *= 1024;
+ case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
+ case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
+ case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
case 0:
break;
default:
return (r);
}
+/* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
+
+static grand *gen_salsae(unsigned i)
+{
+ grand *r;
+ char *p;
+ dstr d = DSTR_INIT;
+ dstr n = DSTR_INIT;
+ kludge64 pos = { 0 };
+ octet posbuf[8];
+ mp *x;
+
+ static struct option opts[] = {
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { "hex", OPTF_ARGREQ, 0, 'H' },
+ { "nonce", OPTF_ARGREQ, 0, 'n' },
+ { "seek", OPTF_ARGREQ, 0, 's' },
+ { 0, 0, 0, 0 }
+ };
+
+ addopts("k:H:n:s:", opts);
+
+ for (;;) {
+ int o = opt();
+ if (o < 0)
+ break;
+ switch (o) {
+ case 'k':
+ DRESET(&d);
+ textkey(&d, optarg, salsa20_keysz);
+ break;
+ case 'H':
+ DRESET(&d);
+ hexkey(&d, optarg, salsa20_keysz);
+ break;
+ case 'n':
+ DRESET(&n);
+ unhex(optarg, &p, &n);
+ if (*p)
+ die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
+ if (n.len != salsatab[i].noncesz) {
+ die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
+ (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
+ }
+ break;
+ case 's':
+ x = mp_readstring(MP_NEW, optarg, &p, 0);
+ if (*p || MP_NEGP(x) || mp_bits(x) > 64)
+ die(EXIT_FAILURE, "bad position `%s'", optarg);
+ mp_storeb(x, posbuf, sizeof(posbuf));
+ mp_drop(x);
+ LOAD64_(pos, posbuf);
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ if (!d.len)
+ randkey(&d, salsa20_keysz);
+ r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
+ r->ops->misc(r, SALSA20_SEEKU64, pos);
+
+ dstr_destroy(&d);
+ dstr_destroy(&n);
+
+ return (r);
+}
+
/* --- Output feedback generators --- */
static grand *gen_ofb(unsigned i)
break;
case 'i': {
char *p;
+ DRESET(&iv);
unhex(optarg, &p, &iv);
if (*p)
die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
+ if (iv.len != ciphertab[i].blksz) {
+ die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
+ (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
+ }
} break;
default:
return (0);
if (!d.len)
randkey(&d, ciphertab[i].keysz);
r = ciphertab[i].ofb(d.buf, d.len);
- if (iv.len) {
- if (iv.len != ciphertab[i].blksz) {
- die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
- (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
- }
+ if (iv.len)
r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
- }
dstr_destroy(&d);
dstr_destroy(&iv);
break;
case 'i': {
char *p;
+ DRESET(&iv);
unhex(optarg, &p, &iv);
if (*p)
die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
+ if (iv.len != ciphertab[i].blksz) {
+ die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
+ (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
+ }
} break;
default:
return (0);
if (!d.len)
randkey(&d, ciphertab[i].keysz);
r = ciphertab[i].counter(d.buf, d.len);
- if (iv.len) {
- if (iv.len != ciphertab[i].blksz) {
- die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
- (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
- }
+ if (iv.len)
r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
- }
dstr_destroy(&d);
dstr_destroy(&iv);
return (r);
}
+/* --- SHAKE generators --- */
+
+static grand *gen_shake(unsigned i)
+{
+ dstr d = DSTR_INIT;
+ const char *func = 0, *perso = 0;
+ grand *r;
+
+ static struct option opts[] = {
+ { "function", OPTF_ARGREQ, 0, 'F' },
+ { "personalization", OPTF_ARGREQ, 0, 'P' },
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { "hex", OPTF_ARGREQ, 0, 'H' },
+ { 0, 0, 0, 0 }
+ };
+
+ addopts("F:P:k:H:", opts);
+
+ for (;;) {
+ int o = opt();
+ if (o < 0)
+ break;
+ switch (o) {
+ case 'F':
+ func = optarg;
+ break;
+ case 'P':
+ perso = optarg;
+ break;
+ case 'k':
+ DRESET(&d);
+ textkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'H':
+ DRESET(&d);
+ hexkey(&d, optarg, shaketab[i].ksz);
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ if (!d.len) randkey(&d, shaketab[i].ksz);
+ r = shaketab[i].shake(func, func ? strlen(func) : 0,
+ perso, perso ? strlen(perso) : 0,
+ d.buf, d.len);
+ dstr_destroy(&d);
+ return (r);
+}
+
+/* --- KMAC generators --- */
+
+static grand *gen_kmac(unsigned i)
+{
+ dstr d = DSTR_INIT, m = DSTR_INIT;
+ const char *perso = 0;
+ char *q;
+ grand *r;
+
+ static struct option opts[] = {
+ { "personalization", OPTF_ARGREQ, 0, 'P' },
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { "hex", OPTF_ARGREQ, 0, 'H' },
+ { "message", OPTF_ARGREQ, 0, 'M' },
+ { "msghex", OPTF_ARGREQ, 0, 'N' },
+ { 0, 0, 0, 0 }
+ };
+
+ addopts("P:k:H:M:N:", opts);
+
+ for (;;) {
+ int o = opt();
+ if (o < 0)
+ break;
+ switch (o) {
+ case 'P':
+ perso = optarg;
+ break;
+ case 'k':
+ DRESET(&d);
+ textkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'H':
+ DRESET(&d);
+ hexkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'M':
+ DRESET(&m);
+ DPUTS(&d, optarg);
+ break;
+ case 'N':
+ DRESET(&m);
+ unhex(optarg, &q, &m);
+ if (*q) die(EXIT_FAILURE, "bad hex");
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ if (!d.len) randkey(&d, shaketab[i].ksz);
+ r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
+ r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
+ dstr_destroy(&d); dstr_destroy(&m);
+ return (r);
+}
+
/* --- Fibonacci generator --- */
static grand *gen_fib(unsigned i)
"[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
HASHES
#undef E
+#define E(pre, r, x, BASE) \
+ { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
+ "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
+ SALSAE
+#undef E
+#define E(sz) \
+ { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
+ "[-k KEY-PHRASE] [-H HEX-KEY]" },
+ SHAKES
+#undef E
+#define E(sz) \
+ { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
+ "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
+ SHAKES
+#undef E
{ "rc4", gen_rc4, 0,
"[-k KEY-PHRASE] [-H HEX-KEY]" },
{ "seal", gen_seal, 0,
return (0);
}
-static int generate(grand *r, size_t outsz,
+static double doubletime(void)
+{
+#ifdef PORTABLE
+ static time_t start = (time_t)-1;
+ time_t now = time(0);
+
+ if (start == (time_t)-1) start = now;
+ return difftime(now, start);
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, 0);
+ return (tv.tv_sec + tv.tv_usec/1000000.0);
+#endif
+}
+
+static int generate(grand *r, mp *outsz,
int (*func)(const void *buf, size_t sz, void *p),
void *p)
{
static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
unsigned percent = 0;
- size_t kb = 0;
- time_t last;
+ mp *kb = MP_ZERO, *t = MP_NEW;
+ dstr d = DSTR_INIT;
+ double now, last;
static char baton[] = "-\\|/";
char *bp;
int rc;
/* --- Spit out random data --- */
- last = time(0);
+ last = doubletime();
bp = baton;
if (flags & f_progress) {
char *errbuf = xmalloc(BUFSIZ);
signal(SIGPIPE, SIG_IGN);
#endif
- do {
+ while (!outsz || MP_CMP(kb, <, outsz)) {
octet buf[BUFSIZ];
- size_t sz = sizeof(buf);
+ size_t sz = sizeof(buf), left;
clock_t c_start, c_stop;
/* --- Emit a bufferful (or less) of data --- */
if (outsz) {
- if (sz > outsz - kb)
- sz = outsz - kb;
+ t = mp_sub(t, outsz, kb);
+ assert(!MP_NEGP(t));
+ if (MP_CMP(t, <=, MP_SIZET_MAX)) {
+ left = mp_tosizet(t);
+ if (sz > left) sz = left;
+ }
}
c_start = clock();
r->ops->fill(r, buf, sz);
clk += c_stop - c_start;
if (func && (rc = func(buf, sz, p)) != 0)
return (rc);
- kb += sz;
+ t = mp_fromsizet(t, sz);
+ kb = mp_add(kb, kb, t);
/* --- Update the display --- */
if (flags & f_progress) {
- time_t t = time(0);
unsigned up = 0;
+ now = doubletime();
+
if (percent > 100)
up = 1;
if (!outsz) {
- if (difftime(t, last) > 1.0) {
+ if (now - last > 0.1) {
up = 1;
}
if (up)
fputs(" ] ", stderr);
} else {
- unsigned pc = kb * 100.0 / outsz;
- if (pc > percent || percent > 100 || difftime(t, last) > 1.0) {
+ unsigned pc;
+ t = mp_fromulong(t, 100);
+ t = mp_mul(t, t, kb);
+ mp_div(&t, 0, t, outsz);
+ assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
+ pc = mp_touint(t);
+ if (pc > percent || percent > 100 || now - last > 0.1) {
if (percent > 100)
percent = 0;
percent &= ~1;
}
if (up) {
- size_t q = kb;
char *kk = kmg;
- while (q > 8192 && kk[1]) {
- q >>= 10;
+ t = mp_add(t, kb, MP_ZERO);
+ while (mp_bits(t) >= 14) {
+ t = mp_lsr(t, t, 10);
kk++;
}
- fprintf(stderr, "%4i%c\r[", q, *kk);
+ DRESET(&d);
+ mp_writedstr(t, &d, 10);
+ fprintf(stderr, "%4s%c\r[", d.buf, *kk);
if (outsz) {
unsigned pc;
for (pc = 0; pc < (percent & ~1); pc += 2)
putc('.', stderr);
}
- last = t;
+ last = now;
}
if (percent > 100)
percent = 0;
- if (percent < 100) {
+ if (percent < 100 && up) {
putc(*bp++, stderr);
putc('\b', stderr);
if (!*bp)
}
fflush(stderr);
}
-
- /* --- Terminate the loop --- */
-
- } while (!outsz || kb < outsz);
+ }
if (flags & f_progress)
fputc('\n', stderr);
if (flags & f_timer) {
- fprintf(stderr, "generated %lu bytes ", (unsigned long)outsz);
+ DRESET(&d);
+ dstr_puts(&d, "generated ");
+ mp_writedstr(kb, &d, 10);
+ dstr_puts(&d, " bytes ");
if (!clk)
- fputs("too quickly to measure\n", stderr);
+ dstr_puts(&d, "too quickly to measure\n");
else {
char *kk;
+ double out;
double sec = (double)clk/CLOCKS_PER_SEC;
- double bps = (outsz << 3)/sec;
+ unsigned long sh;
+ double bps;
+
+ MP_SHRINK(kb);
+ switch (MP_LEN(kb)) {
+ case 0: out = 0; break;
+ case 1: out = kb->v[0]; break;
+ default:
+ sh = mp_bits(kb) - MPW_BITS;
+ t = mp_lsr(t, kb, sh);
+ out = ldexp(t->v[0], sh);
+ break;
+ }
+ bps = (8*out)/sec;
for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
;
- fprintf(stderr, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
+ dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
+ fwrite(d.buf, 1, d.len, stderr);
}
}
+
+ mp_drop(t);
+ DDESTROY(&d);
return (0);
}
g = 0;
for (gg = generators; gg->name; gg++) {
- if (strncmp(arg, gg->name, sz) == 0) {
+ if (STRNCMP(arg, ==, gg->name, sz)) {
if (gg->name[sz] == 0) {
g = gg;
break;
if (flags & f_fips) {
octet buf[FIPSTEST_BUFSZ];
unsigned rc;
+ mp *t;
octet *p = buf;
- generate(r, sizeof(buf), genbuf, &p);
+ t = mp_fromsizet(MP_NEW, sizeof(buf));
+ generate(r, t, genbuf, &p);
+ mp_drop(t);
rc = fipstest(buf);
if (rc & FIPSTEST_MONOBIT)
moan("failed monobit test");
size_t bufsz;
unsigned i;
unsigned rc = 0;
+ mp *t;
genmaurer_ctx g;
static struct { double x; const char *sig; } sigtab[] = {
maurer_init(&g.m[i], i + maurer_lo);
bufsz = (100 * maurer_hi) << maurer_hi;
- generate(r, bufsz, genmaurer, &g);
+ t = mp_fromsizet(MP_NEW, bufsz);
+ generate(r, t, genmaurer, &g);
+ mp_drop(t);
for (i = maurer_lo; i <= maurer_hi; i++) {
double z = maurer_done(&g.m[i - maurer_lo]);