algorithms.c: Add bindings for STROBE.
[catacomb-python] / algorithms.c
index be07fb7..de8fcd6 100644 (file)
@@ -3578,6 +3578,365 @@ static const PyTypeObject kmac256_pytype_skel = {
   0                                    /* @tp_is_gc@ */
 };
 
+static PyTypeObject *strobe_pytype;
+
+typedef struct strobe_pyobj {
+  PyObject_HEAD
+  strobe_ctx ctx;
+} strobe_pyobj;
+#define STROBE_CTX(o) (&((strobe_pyobj *)(o))->ctx)
+
+static int convstrbf(PyObject *x, void *p)
+{
+  unsigned *ff = p, f;
+  const char *q;
+  size_t sz;
+  int rc = 0;
+
+  if (TEXT_CHECK(x)) {
+    TEXT_PTRLEN(x, q, sz); f = 0;
+    while (sz--) switch (*q++) {
+      case 'I': f |= STRBF_I; break;
+      case 'A': f |= STRBF_A; break;
+      case 'C': f |= STRBF_C; break;
+      case 'T': f |= STRBF_T; break;
+      case 'M': f |= STRBF_M; break;
+      default: if (!ISSPACE(q[-1])) VALERR("unknown flag character");
+    }
+    *ff = f; rc = 1;
+  } else if (convuint(x, ff))
+    rc = 1;
+  else {
+    PyErr_Clear();
+    TYERR("expected string or int");
+  }
+end:
+  return (rc);
+}
+
+
+static PyObject *strobe_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+  strobe_pyobj *rc = 0;
+  unsigned lambda = 128;
+  static const char *const kwlist[] = { "l", 0 };
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST,
+                                  convuint, &lambda))
+    goto end;
+  if (lambda%32 || lambda > 704) VALERR("invalid security parameter");
+  rc = (strobe_pyobj *)ty->tp_alloc(ty, 0);
+  strobe_init(&rc->ctx, lambda);
+end:
+  return ((PyObject *)rc);
+}
+
+static PyObject *strobemeth_copy(PyObject *me)
+{
+  strobe_pyobj *strobe = (strobe_pyobj *)me, *rc;
+
+  rc = PyObject_NEW(strobe_pyobj, me->ob_type);
+  rc->ctx = strobe->ctx;
+  return ((PyObject *)rc);
+}
+
+static int strobe_checkinactive(PyObject *me)
+{
+  int rc = -1;
+
+  if (STROBE_CTX(me)->f&STRBF_ACTIVE) VALERR("operation already active");
+  rc = 0;
+end:
+  return (rc);
+}
+
+static int strobe_checkactive(PyObject *me)
+{
+  int rc = -1;
+
+  if (!(STROBE_CTX(me)->f&STRBF_ACTIVE)) VALERR("operation not active");
+  rc = 0;
+end:
+  return (rc);
+}
+
+static PyObject *strobemeth_begin(PyObject *me, PyObject *arg)
+{
+  unsigned f;
+
+  if (!PyArg_ParseTuple(arg, "O&:begin", convstrbf, &f)) goto end;
+  if (strobe_checkinactive(me)) goto end;
+  if (f&~STRBF_VALIDMASK) VALERR("bad flags");
+  strobe_begin(STROBE_CTX(me), f);
+  RETURN_ME;
+end:
+  return (0);
+}
+
+static PyObject *strobe_pyprocess(PyObject *me,
+                                 const void *p0, size_t sz0,
+                                 const void *p1, size_t sz1)
+{
+  char *q;
+  PyObject *rc = 0;
+
+  if (strobe_checkactive(me)) goto end;
+  if (!(STROBE_CTX(me)->f&STRBF_WANTIN) && p0)
+    VALERR("no input expected for current operation");
+  if (!(STROBE_CTX(me)->f&STRBF_WANTOUT)) q = 0;
+  else { rc = bytestring_pywrap(0, sz0 + sz1); q = BIN_PTR(rc); }
+  strobe_process(STROBE_CTX(me), p0, q, sz0);
+  if (sz1) strobe_process(STROBE_CTX(me), p1, q ? q + sz0 : 0, sz1);
+  if (!q) RETURN_ME;
+end:
+  return (rc);
+}
+
+static PyObject *strobemeth_process(PyObject *me, PyObject *arg)
+{
+  PyObject *inobj;
+  struct bin in;
+  PyObject *rc = 0;
+
+  in.p = 0;
+  if (!PyArg_ParseTuple(arg, "O:process", &inobj)) goto end;
+  if (!convszt(inobj, &in.sz) && (PyErr_Clear(), !convbin(inobj, &in))) {
+    PyErr_Clear();
+    TYERR("expected integer, string, unicode, or single-segment buffer");
+  }
+  rc = strobe_pyprocess(me, in.p, in.sz, 0, 0);
+end:
+  return (rc);
+}
+
+static PyObject *strobemeth_done(PyObject *me)
+{
+  unsigned f;
+  int rc;
+
+  if (strobe_checkactive(me)) return (0);
+  f = STROBE_CTX(me)->f; rc = strobe_done(STROBE_CTX(me));
+  if (f&STRBF_VRFOUT) return (getbool(!rc));
+  else RETURN_ME;
+}
+
+#define STROBEMETH_PROCESSU_(n, W, w)                                  \
+  static PyObject *strobemeth_processu##w(PyObject *me, PyObject *arg) \
+  {                                                                    \
+    uint##n x;                                                         \
+    octet b[SZ_##W];                                                   \
+    if (!PyArg_ParseTuple(arg, "O&:processu" #w, convu##n, &x)) return (0); \
+    STORE##W(b, x); return (strobe_pyprocess(me, b, sizeof(b), 0, 0)); \
+  }
+DOUINTCONV(STROBEMETH_PROCESSU_)
+
+#define STROBEMETH_PROCESSBUF_(n, W, w)                                        \
+  static PyObject *strobemeth_processbuf##w(PyObject *me, PyObject *arg) \
+  {                                                                    \
+    struct bin in;                                                     \
+    octet b[SZ_##W];                                                   \
+    if (!PyArg_ParseTuple(arg, "O&:processbuf" #w, convbin, &in)) goto end; \
+    if (in.sz > MASK##n) VALERR("too large");                          \
+    STORE##W(b, in.sz);                                                        \
+    return (strobe_pyprocess(me, b, sizeof(b), in.p, in.sz));          \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+DOUINTCONV(STROBEMETH_PROCESSBUF_)
+
+static PyObject *strobemeth_processstrz(PyObject *me, PyObject *arg)
+{
+  char *p;
+  if (!PyArg_ParseTuple(arg, "s:processstrz", &p)) return (0);
+  return (strobe_pyprocess(me, p, strlen(p) + 1, 0, 0));
+}
+
+#define STROBEMETH_INONLY_(meth, arg)                                  \
+  static PyObject *strobemeth_##meth(PyObject *me,                     \
+                                    PyObject *arg, PyObject *kw)       \
+  {                                                                    \
+    struct bin in; unsigned f = 0;                                     \
+    static const char *const kwlist[] = { #arg, "f", 0 };              \
+    if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:" #meth, KWLIST,  \
+                                    convbin, &in, convstrbf, &f))      \
+      goto end;                                                                \
+    if (f&~STRBF_M) VALERR("bad flags");                               \
+    if (strobe_checkinactive(me)) goto end;                            \
+    strobe_##meth(STROBE_CTX(me), f, in.p, in.sz);                     \
+    RETURN_ME;                                                         \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+
+#define STROBEMETH_OUTONLY_(meth)                                      \
+  static PyObject *strobemeth_##meth(PyObject *me,                     \
+                                    PyObject *arg, PyObject *kw)       \
+  {                                                                    \
+    size_t sz; unsigned f = 0; PyObject *rc;                           \
+    static const char *const kwlist[] = { "sz", "f", 0 };              \
+    if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:" #meth, KWLIST,  \
+                         convszt, &sz, convstrbf, &f))                 \
+      goto end;                                                                \
+    if (f&~STRBF_M) VALERR("bad flags");                               \
+    if (strobe_checkinactive(me)) goto end;                            \
+    rc = bytestring_pywrap(0, sz);                                     \
+    strobe_##meth(STROBE_CTX(me), f, BIN_PTR(rc), sz);                 \
+    return (rc);                                                       \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+
+#define STROBEMETH_INOUT_(meth, arg)                                   \
+  static PyObject *strobemeth_##meth(PyObject *me,                     \
+                                    PyObject *arg, PyObject *kw)       \
+  {                                                                    \
+    struct bin in; unsigned f = 0; PyObject *rc;                       \
+    static const char *const kwlist[] = { #arg, "f", 0 };              \
+    if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:" #meth, KWLIST,  \
+                                    convbin, &in, convstrbf, &f))      \
+      goto end;                                                                \
+    if (f&~STRBF_M) VALERR("bad flags");                               \
+    if (strobe_checkinactive(me)) goto end;                            \
+    rc = bytestring_pywrap(0, in.sz);                                  \
+    strobe_##meth(STROBE_CTX(me), f, in.p, BIN_PTR(rc), in.sz);                \
+    return (rc);                                                       \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+
+STROBEMETH_INONLY_(key, key)
+STROBEMETH_INONLY_(ad, msg)
+STROBEMETH_OUTONLY_(prf)
+STROBEMETH_INONLY_(clrout, msg)
+STROBEMETH_INONLY_(clrin, msg)
+STROBEMETH_INOUT_(encout, msg)
+STROBEMETH_INOUT_(encin, ct)
+STROBEMETH_OUTONLY_(macout)
+
+static PyObject *strobemeth_macin(PyObject *me, PyObject *arg, PyObject *kw)
+{
+  struct bin in; unsigned f = 0;
+  static const char *const kwlist[] = { "tag", "f", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:macin", KWLIST,
+                                  convbin, &in, convstrbf, &f))
+    goto end;
+  if (f&~STRBF_M) VALERR("bad flags");
+  if (strobe_checkinactive(me)) goto end;
+  return (getbool(!strobe_macin(STROBE_CTX(me), f, in.p, in.sz)));
+end:
+  return (0);
+}
+
+static PyObject *strobemeth_ratchet(PyObject *me,
+                                   PyObject *arg, PyObject *kw)
+{
+  size_t sz; unsigned f = 0;
+  static const char *const kwlist[] = { "sz", "f", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:ratchet", KWLIST,
+                                  convszt, &sz, convstrbf, &f))
+    goto end;
+  if (f&~STRBF_M) VALERR("bad flags");
+  if (strobe_checkinactive(me)) goto end;
+  strobe_ratchet(STROBE_CTX(me), f, sz); RETURN_ME;
+end:
+  return (0);
+}
+
+static PyObject *strobeget_l(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(4*(200 - STROBE_CTX(me)->r))); }
+
+static PyObject *strobeget_role(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(STROBE_CTX(me)->f&STROBE_ROLEMASK)); }
+
+static PyObject *strobeget_activep(PyObject *me, void *hunoz)
+  { return (getbool(STROBE_CTX(me)->f&STRBF_ACTIVE)); }
+
+static const PyGetSetDef strobe_pygetset[] = {
+#define GETSETNAME(op, name) strobe##op##_##name
+  GET   (l,            "STROBE.l -> security parameter")
+  GET  (role,          "STROBE.role -> STRBRL_...")
+  GET   (activep,      "STROBE.activep -> operation active?")
+#undef GETSETNAME
+  { 0 }
+};
+
+static const PyMethodDef strobe_pymethods[] = {
+#define METHNAME(func) strobemeth_##func
+  NAMETH(copy,         "S.copy() -> SS")
+  METH (begin,         "S.begin(MSGTY)")
+  METH (process,       "S.process(MSG | SZ) [-> OUT]")
+#define METHU_(n, W, w)                                                        \
+    METH(processu##w,  "S.processu" #w "(WORD) [-> OUT]")
+  DOUINTCONV(METHU_)
+#undef METHU_
+#define METHBUF_(n, W, w)                                              \
+    METH(processbuf##w,        "S.processbuf" #w "(BYTES) [-> OUT]")
+  DOUINTCONV(METHBUF_)
+#undef METHBUF_
+  METH (processstrz,   "S.processstrz(STRING) [-> OUT]")
+  NAMETH(done,         "S.done() [-> OK?]")
+  KWMETH(key,          "S.key(KEY, [f = 0])")
+  KWMETH(ad,           "S.ad(MSG, [f = 0])")
+  KWMETH(prf,          "S.prf(SZ, [f = 0]) -> BYTES")
+  KWMETH(clrout,       "S.clrout(MSG, [f = 0])")
+  KWMETH(clrin,                "S.clrin(MSG, [f = 0])")
+  KWMETH(encout,       "S.encout(MSG, [f = 0]) -> CT")
+  KWMETH(encin,                "S.encin(CT, [f = 0]) -> MSG")
+  KWMETH(macout,       "S.macout(SZ, [f = 0]) -> TAG")
+  KWMETH(macin,                "S.macin(TAG, [f = 0]) -> OK?")
+  KWMETH(ratchet,      "S.ratchet(SZ, [f = 0])")
+#undef METHNAME
+  { 0 }
+};
+
+static const PyTypeObject strobe_pytype_skel = {
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
+  "Strobe",                            /* @tp_name@ */
+  sizeof(strobe_pyobj),                        /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  0,                                   /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"STROBE symmetric-crypto framework.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  PYMETHODS(strobe),                   /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  PYGETSET(strobe),                    /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  strobe_pynew,                                /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
 /*----- Pseudorandom permutations -----------------------------------------*/
 
 static PyTypeObject *gcprp_pytype, *gprp_pytype;
@@ -3824,6 +4183,11 @@ static const PyTypeObject gprp_pytype_skel = {
 static const struct nameval consts[] = {
   CONST(AEADF_PCHSZ), CONST(AEADF_PCMSZ), CONST(AEADF_PCTSZ),
   CONST(AEADF_AADNDEP), CONST(AEADF_AADFIRST), CONST(AEADF_NOAAD),
+  CONST(STRBF_I), CONST(STRBF_A), CONST(STRBF_C), CONST(STRBF_T),
+  CONST(STRBF_M), CONST(STROBE_KEY), CONST(STROBE_AD), CONST(STROBE_PRF),
+  CONST(STROBE_CLROUT), CONST(STROBE_CLRIN), CONST(STROBE_ENCOUT),
+  CONST(STROBE_ENCIN), CONST(STRBRL_UNDCD), CONST(STRBRL_INIT),
+  CONST(STRBRL_RESP),
   { 0 }
 };
 
@@ -3873,6 +4237,7 @@ void algorithms_pyinit(void)
   INITTYPE(kmac, shake);
   INITTYPE(kmac128, kmac);
   INITTYPE(kmac256, kmac);
+  INITTYPE(strobe, root);
   INITTYPE(gcprp, type);
   INITTYPE(gprp, root);
   addmethods(methods);
@@ -3929,6 +4294,7 @@ void algorithms_pyinsert(PyObject *mod)
   INSERT("KMAC", kmac_pytype);
   INSERT("KMAC128", kmac128_pytype);
   INSERT("KMAC256", kmac256_pytype);
+  INSERT("Strobe", strobe_pytype);
   INSERT("GCPRP", gcprp_pytype);
   INSERT("GPRP", gprp_pytype);
   INSERT("gcprps", make_algtab(gprptab, sizeof(gcprp *),