Merge branch '2.5.x'
[catacomb] / progs / rspit.c
index 67913d5..66a0538 100644 (file)
@@ -27,6 +27,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <assert.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"
@@ -203,6 +209,62 @@ 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;
@@ -805,6 +867,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)
@@ -971,6 +1102,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)
@@ -1077,6 +1315,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,