X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/cbef819a1a9286e0cffbb3783a1467eab85824bd..HEAD:/progs/rspit.c diff --git a/progs/rspit.c b/progs/rspit.c index 7ca1cce8..812525fc 100644 --- a/progs/rspit.c +++ b/progs/rspit.c @@ -27,6 +27,8 @@ /*----- Header files ------------------------------------------------------*/ +#define _FILE_OFFSET_BITS 64 + #include "config.h" #include @@ -40,15 +42,22 @@ #ifndef PORTABLE # include +# include #endif #include #include +#include #include #include #include #include +#include "mp.h" +#include "mpint.h" +#include "mplimits.h" +#include "mptext.h" + #include "fipstest.h" #include "grand.h" #include "maurer.h" @@ -62,8 +71,12 @@ #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" @@ -197,10 +210,66 @@ static const struct { #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; @@ -367,7 +436,7 @@ static int opt(void) 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"); @@ -380,13 +449,13 @@ static int opt(void) 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: @@ -799,6 +868,75 @@ static grand *gen_seal(unsigned i) 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) @@ -831,9 +969,14 @@ 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); @@ -843,13 +986,8 @@ static grand *gen_ofb(unsigned i) 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); @@ -888,9 +1026,14 @@ static grand *gen_counter(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); @@ -900,13 +1043,8 @@ static grand *gen_counter(unsigned i) 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); @@ -965,6 +1103,113 @@ static grand *gen_mgf(unsigned i) 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) @@ -1071,6 +1316,21 @@ gen generators[] = { "[-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, @@ -1119,15 +1379,32 @@ static int genmaurer(const void *buf, size_t sz, void *p) 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; @@ -1135,7 +1412,7 @@ static int generate(grand *r, size_t outsz, /* --- Spit out random data --- */ - last = time(0); + last = doubletime(); bp = baton; if (flags & f_progress) { char *errbuf = xmalloc(BUFSIZ); @@ -1151,16 +1428,20 @@ static int generate(grand *r, size_t outsz, 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); @@ -1168,26 +1449,33 @@ static int generate(grand *r, size_t outsz, 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; @@ -1202,25 +1490,27 @@ static int generate(grand *r, size_t outsz, } 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[", (int)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) @@ -1228,26 +1518,44 @@ static int generate(grand *r, size_t outsz, } 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); } @@ -1284,7 +1592,7 @@ int main(int ac, char *av[]) 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; @@ -1313,9 +1621,12 @@ int main(int ac, char *av[]) 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"); @@ -1336,6 +1647,7 @@ int main(int ac, char *av[]) size_t bufsz; unsigned i; unsigned rc = 0; + mp *t; genmaurer_ctx g; static struct { double x; const char *sig; } sigtab[] = { @@ -1352,7 +1664,9 @@ int main(int ac, char *av[]) 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]);