--- /dev/null
+/* -*-c-*-
+ *
+ * Various unit-level tests
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Trivial IP Encryption (TrIPE).
+ *
+ * TrIPE is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * TrIPE is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "tripe.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+/*----- Global variables --------------------------------------------------*/
+
+sel_state sel;
+
+/*----- Static variables --------------------------------------------------*/
+
+static char **args;
+
+/*----- Main code ---------------------------------------------------------*/
+
+static void usage(FILE *fp)
+{
+ pquis(fp,
+"Usage: $ [-k FILE] [-t KEYTAG] [-T TRACE-OPTS] COMMAND [ARGS...]\n");
+}
+
+static void version(FILE *fp)
+ { pquis(fp, "$, TrIPE version " VERSION "\n"); }
+
+static void help(FILE *fp)
+{
+ version(fp); fputc('\n', fp);
+ usage(fp); fputc('\n', fp);
+ fputs("\
+Options in full:\n\
+\n\
+-h, --help Show this help text.\n\
+-v, --version Show version number.\n\
+-u, --usage Show brief usage message.\n\
+\n\
+-k, --keyring=FILE Get keys from FILE.\n\
+-t, --tag=KEYTAG Use KEYTAG as master private key.\n\
+-T, --trace=TRACE-OPTS Turn on tracing options.\n\
+\n\
+Commands:\n\
+\n\
+ies-encrypt TY MESSAGE\n\
+ies-decrypt TY CIPHERTEXT\n\
+", fp);
+}
+
+static uint32 parseu32(const char *p)
+{
+ int e = errno;
+ unsigned long i;
+ char *q;
+
+ errno = 0;
+ i = strtoul(p, &q, 0);
+ while (*q && isspace((unsigned char)*q)) q++;
+ if (errno || *q || i > 0xffffffffu) die(2, "bad 32-bit integer `%s'", p);
+ errno = e;
+ return (i);
+}
+
+static const char *getarg(void)
+ { if (!*args) die(2, "missing argument"); else return (*args++); }
+
+static void lastarg(void)
+ { if (*args) die(2, "unexpected argument `%s'", *args); }
+
+int main(int argc, char *argv[])
+{
+ const char *kr = "keyring";
+ const char *tag = "tripe";
+ const char *arg;
+ codec *b64;
+ int i, err;
+ uint32 ty;
+ buf b, bb;
+ dstr d = DSTR_INIT;
+ unsigned f = 0;
+#define f_bogus 1u
+
+ ego(argv[0]);
+ for (;;) {
+ static const struct option opts[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "usage", 0, 0, 'u' },
+ { "keyring", OPTF_ARGREQ, 0, 'k' },
+ { "tag", OPTF_ARGREQ, 0, 't' },
+ { "trace", OPTF_ARGREQ, 0, 'T' },
+ { 0, 0, 0, 0 }
+ };
+
+ i = mdwopt(argc, argv, "hvuk:t:T:", opts, 0, 0, 0); if (i < 0) break;
+ switch (i) {
+ case 'h': help(stdout); exit(0);
+ case 'v': version(stdout); exit(0);
+ case 'u': usage(stdout); exit(0);
+ case 'k': kr = optarg; break;
+ case 't': tag = optarg; break;
+ case 'T':
+ tr_flags = traceopt(tr_opts, optarg, tr_flags, 0);
+ break;
+ default: f |= f_bogus; break;
+ }
+ }
+ if (f&f_bogus) { usage(stderr); exit(2); }
+ args = argv + optind;
+
+ km_init(kr, kr, tag);
+ trace_on(stderr, tr_flags);
+
+ arg = getarg();
+ if (strcmp(arg, "ies-encrypt") == 0) {
+ arg = getarg(); ty = parseu32(arg);
+ arg = getarg(); buf_init(&b, (/*unconst*/ octet *)arg, strlen(arg));
+ buf_init(&bb, buf_t, sizeof(buf_t));
+ lastarg();
+ if ((err = ies_encrypt(master, ty, &b, &bb)) != 0)
+ die(3, "ies_encrypt failed: err = %d", err);
+ b64 = base64_class.encoder(0, "\n", 72);
+ if ((err = b64->ops->code(b64, BBASE(&bb), BLEN(&bb), &d)) != 0 ||
+ (err = b64->ops->code(b64, 0, 0, &d)) != 0)
+ die(3, "base64 encoding failed: %s", codec_strerror(err));
+ b64->ops->destroy(b64);
+ DPUTC(&d, '\n');
+ fwrite(d.buf, 1, d.len, stdout);
+ dstr_destroy(&d);
+ } else if (strcmp(arg, "ies-decrypt") == 0) {
+ arg = getarg(); ty = parseu32(arg);
+ arg = getarg();
+ b64 = base64_class.decoder(CDCF_IGNSPC | CDCF_IGNNEWL);
+ if ((err = b64->ops->code(b64, arg, strlen(arg), &d)) != 0 ||
+ (err = b64->ops->code(b64, 0, 0, &d)) != 0)
+ die(3, "base64 decoding failed: %s", codec_strerror(err));
+ b64->ops->destroy(b64);
+ lastarg();
+ buf_init(&b, d.buf, d.len); buf_init(&bb, buf_t, sizeof(buf_t));
+ if ((err = ies_decrypt(master, ty, &b, &bb)) != 0)
+ die(3, "ies_decrypt failed: err = %d", err);
+ fwrite(BBASE(&bb), 1, BLEN(&bb), stdout);
+ dstr_destroy(&d);
+ } else
+ die(2, "unknown command `%s'", arg);
+
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/