tripe_SOURCES += servutil.c
tripe_SOURCES += addrmap.c
tripe_SOURCES += keymgmt.c
+tripe_SOURCES += bulkcrypto.c
tripe_SOURCES += keyset.c
tripe_SOURCES += keyexch.c
tripe_SOURCES += chal.c
"hash-sz=%lu", (unsigned long)algs->h->hashsz,
A_END);
a_info(a,
- "cipher=%s", algs->c->name,
- "cipher-keysz=%lu", (unsigned long)algs->cksz,
- "cipher-blksz=%lu", (unsigned long)algs->c->blksz,
+ "bulk-transform=%s", algs->bulk->name,
+ "bulk-overhead=%lu", (unsigned long)algs->bulk->overhead(algs),
A_END);
+ if (algs->c) {
+ a_info(a,
+ "cipher=%s", algs->c->name,
+ "cipher-keysz=%lu", (unsigned long)algs->cksz,
+ "cipher-blksz=%lu", (unsigned long)algs->c->blksz,
+ A_END);
+ }
a_info(a,
"cipher-data-limit=%lu", (unsigned long)algs->expsz,
A_END);
- a_info(a,
- "mac=%s", algs->m->name,
- "mac-keysz=%lu", (unsigned long)algs->mksz,
- "mac-tagsz=%lu", (unsigned long)algs->tagsz,
- A_END);
+ if (algs->m) {
+ a_info(a,
+ "mac=%s", algs->m->name,
+ "mac-keysz=%lu", (unsigned long)algs->mksz,
+ "mac-tagsz=%lu", (unsigned long)algs->tagsz,
+ A_END);
+ }
a_ok(a);
}
--- /dev/null
+/* -*-c-*-
+ *
+ * Bulk crypto transformations
+ *
+ * (c) 2014 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 2 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, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "tripe.h"
+
+/*----- Utilities ---------------------------------------------------------*/
+
+#define SEQSZ 4 /* Size of sequence number packet */
+
+#define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, { \
+ trace_block(T_CRYPTO, "crypto: initialization vector", \
+ (qiv), (ivsz)); \
+}) } while (0)
+
+#define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, { \
+ trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz)); \
+}) } while (0)
+
+#define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, { \
+ trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz)); \
+}) } while (0)
+
+#define CHECK_MAC(h, pmac, tagsz) do { \
+ ghash *_h = (h); \
+ const octet *_pmac = (pmac); \
+ size_t _tagsz = (tagsz); \
+ octet *_mac = GH_DONE(_h, 0); \
+ int _eq = ct_memeq(_mac, _pmac, _tagsz); \
+ TRACE_MAC(_mac, _tagsz); \
+ GH_DESTROY(_h); \
+ if (!_eq) { \
+ IF_TRACING(T_KEYSET, { \
+ trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); \
+ trace_block(T_CRYPTO, "crypto: expected MAC", _pmac, _tagsz); \
+ }) \
+ return (KSERR_DECRYPT); \
+ } \
+} while (0)
+
+/*----- The original transform --------------------------------------------*
+ *
+ * We generate a random initialization vector (if the cipher needs one). We
+ * encrypt the input message with the cipher, and format the type, sequence
+ * number, IV, and ciphertext as follows.
+ *
+ * +------+ +------+---...---+------...------+
+ * | type | | seq | iv | ciphertext |
+ * +------+ +------+---...---+------...------+
+ * 32 32 blksz sz
+ *
+ * All of this is fed into the MAC to compute a tag. The type is not
+ * transmitted: the other end knows what type of message it expects, and the
+ * type is only here to prevent us from being confused because some other
+ * kind of ciphertext has been substituted. The tag is prepended to the
+ * remainder, to yield the finished cryptogram, as follows.
+ *
+ * +---...---+------+---...---+------...------+
+ * | tag | seq | iv | ciphertext |
+ * +---...---+------+---...---+------...------+
+ * tagsz 32 blksz sz
+ *
+ * Decryption: checks the overall size, verifies the tag, then decrypts the
+ * ciphertext and extracts the sequence number.
+ */
+
+static int v0_check(const algswitch *a, dstr *e)
+ { return (0); }
+
+static size_t v0_overhead(const algswitch *a)
+ { return a->tagsz + SEQSZ + a->c->blksz; }
+
+static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
+{
+ ghash *h;
+ gcipher *c = ks->out.c;
+ const octet *p = BCUR(b);
+ size_t sz = BLEFT(b);
+ octet *qmac, *qseq, *qiv, *qpk;
+ uint32 oseq;
+ size_t ivsz = GC_CLASS(c)->blksz;
+ size_t tagsz = ks->tagsz;
+ octet t[4];
+
+ /* --- Determine the ciphertext layout --- */
+
+ if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
+ qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
+ BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
+
+ /* --- Store the type --- *
+ *
+ * This isn't transmitted, but it's covered by the MAC.
+ */
+
+ STORE32(t, ty);
+
+ /* --- Store the sequence number --- */
+
+ oseq = ks->oseq++;
+ STORE32(qseq, oseq);
+
+ /* --- Establish an initialization vector if necessary --- */
+
+ if (ivsz) {
+ rand_get(RAND_GLOBAL, qiv, ivsz);
+ GC_SETIV(c, qiv);
+ TRACE_IV(qiv, ivsz);
+ }
+
+ /* --- Encrypt the packet --- */
+
+ GC_ENCRYPT(c, p, qpk, sz);
+ TRACE_CT(qpk, sz);
+
+ /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
+
+ if (tagsz) {
+ h = GM_INIT(ks->out.m);
+ GH_HASH(h, t, sizeof(t));
+ GH_HASH(h, qseq, SEQSZ + ivsz + sz);
+ memcpy(qmac, GH_DONE(h, 0), tagsz);
+ GH_DESTROY(h);
+ TRACE_MAC(qmac, tagsz);
+ }
+
+ /* --- We're done --- */
+
+ return (0);
+}
+
+static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
+{
+ const octet *pmac, *piv, *pseq, *ppk;
+ size_t psz = BLEFT(b);
+ size_t sz;
+ octet *q = BCUR(bb);
+ ghash *h;
+ gcipher *c = ks->in.c;
+ size_t ivsz = GC_CLASS(c)->blksz;
+ size_t tagsz = ks->tagsz;
+ octet t[4];
+
+ /* --- Break up the packet into its components --- */
+
+ if (psz < ivsz + SEQSZ + tagsz) {
+ T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
+ return (KSERR_MALFORMED);
+ }
+ sz = psz - ivsz - SEQSZ - tagsz;
+ pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
+ STORE32(t, ty);
+
+ /* --- Verify the MAC on the packet --- */
+
+ if (tagsz) {
+ h = GM_INIT(ks->in.m);
+ GH_HASH(h, t, sizeof(t));
+ GH_HASH(h, pseq, SEQSZ + ivsz + sz);
+ CHECK_MAC(h, pmac, tagsz);
+ }
+
+ /* --- Decrypt the packet --- */
+
+ if (ivsz) {
+ TRACE_IV(piv, ivsz);
+ GC_SETIV(c, piv);
+ }
+ GC_DECRYPT(c, ppk, q, sz);
+
+ /* --- Finished --- */
+
+ *seq = LOAD32(pseq);
+ BSTEP(bb, sz);
+ return (0);
+}
+
+/*----- Bulk crypto transform table ---------------------------------------*/
+
+const bulkcrypto bulktab[] = {
+
+#define BULK(name, pre, prim) \
+ { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt }
+
+ BULK("v0", v0, BCP_CIPHER | BCP_MAC),
+
+#undef BULK
+ { 0 }
+};
+
+/*----- That's all, folks -------------------------------------------------*/
static int algs_get(algswitch *a, dstr *e, key_file *kf, key *k)
{
const char *p;
+ const bulkcrypto *bulk;
char *q, *qq;
dstr d = DSTR_INIT;
int rc = -1;
- /* --- Symmetric encryption for bulk data --- */
-
- if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc";
- if ((a->c = gcipher_byname(p)) == 0) {
- a_format(e, "unknown-cipher", "%s", p, A_END);
- goto done;
- }
-
/* --- Hash function --- */
if ((p = key_getattr(kf, k, "hash")) == 0) p = "rmd160";
goto done;
}
- /* --- Message authentication for bulk data --- */
+ /* --- Bulk crypto transform --- */
- if ((p = key_getattr(kf, k, "mac")) != 0) {
- dstr_reset(&d);
- dstr_puts(&d, p);
- if ((q = strchr(d.buf, '/')) != 0)
- *q++ = 0;
- if ((a->m = gmac_byname(d.buf)) == 0) {
- a_format(e, "unknown-mac", "%s", d.buf, A_END);
+ if ((p = key_getattr(kf, k, "bulk")) == 0) p = "v0";
+ for (bulk = bulktab; bulk->name && strcmp(p, bulk->name) != 0; bulk++);
+ if (!bulk->name) {
+ a_format(e, "unknown-bulk-transform", "%s", p, A_END);
+ goto done;
+ }
+ a->bulk = bulk;
+
+ /* --- Symmetric encryption for bulk data --- */
+
+ if (!(a->bulk->prim & BCP_CIPHER))
+ a->c = 0;
+ else {
+ if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc";
+ if ((a->c = gcipher_byname(p)) == 0) {
+ a_format(e, "unknown-cipher", "%s", p, A_END);
goto done;
}
- if (!q)
- a->tagsz = a->m->hashsz;
- else {
- unsigned long n = strtoul(q, &qq, 0);
- if (*qq) {
- a_format(e, "bad-tag-length-string", "%s", q, A_END);
+ }
+
+ /* --- Message authentication for bulk data --- */
+
+ if (!(a->bulk->prim & BCP_MAC)) {
+ a->m = 0;
+ a->tagsz = 0;
+ } else {
+ if ((p = key_getattr(kf, k, "mac")) != 0) {
+ dstr_reset(&d);
+ dstr_puts(&d, p);
+ if ((q = strchr(d.buf, '/')) != 0)
+ *q++ = 0;
+ if ((a->m = gmac_byname(d.buf)) == 0) {
+ a_format(e, "unknown-mac", "%s", d.buf, A_END);
goto done;
}
- if (n%8 || n/8 > a->m->hashsz) {
- a_format(e, "bad-tag-length", "%lu", n, A_END);
+ if (!q)
+ a->tagsz = a->m->hashsz;
+ else {
+ unsigned long n = strtoul(q, &qq, 0);
+ if (*qq) {
+ a_format(e, "bad-tag-length-string", "%s", q, A_END);
+ goto done;
+ }
+ if (n%8 || n/8 > a->m->hashsz) {
+ a_format(e, "bad-tag-length", "%lu", n, A_END);
+ goto done;
+ }
+ a->tagsz = n/8;
+ }
+ } else {
+ dstr_reset(&d);
+ dstr_putf(&d, "%s-hmac", a->h->name);
+ if ((a->m = gmac_byname(d.buf)) == 0) {
+ a_format(e, "no-hmac-for-hash", "%s", a->h->name, A_END);
goto done;
}
- a->tagsz = n/8;
+ a->tagsz = a->h->hashsz/2;
}
- } else {
- dstr_reset(&d);
- dstr_putf(&d, "%s-hmac", a->h->name);
- if ((a->m = gmac_byname(d.buf)) == 0) {
- a_format(e, "no-hmac-for-hash", "%s", a->h->name, A_END);
- goto done;
- }
- a->tagsz = a->h->hashsz/2;
}
+ /* --- All done --- */
+
rc = 0;
done:
dstr_destroy(&d);
static int algs_check(algswitch *a, dstr *e, const group *g)
{
+ /* --- Check the bulk crypto transform --- */
+
+ if (a->bulk->check(a, e)) return (-1);
+
/* --- Derive the key sizes --- *
*
* Must ensure that we have non-empty keys. This isn't ideal, but it
*/
a->hashsz = a->h->hashsz;
- if ((a->cksz = keysz(a->hashsz, a->c->keysz)) == 0) {
+ if (a->c && (a->cksz = keysz(a->hashsz, a->c->keysz)) == 0) {
a_format(e, "cipher", "%s", a->c->name,
"no-key-size", "%lu", (unsigned long)a->hashsz,
A_END);
return (-1);
}
- if ((a->mksz = keysz(a->hashsz, a->m->keysz)) == 0) {
+ if (a->m && (a->mksz = keysz(a->hashsz, a->m->keysz)) == 0) {
a_format(e, "mac", "%s", a->m->name,
"no-key-size", "%lu", (unsigned long)a->hashsz,
A_END);
/* --- Derive the data limit --- */
- if (a->c->blksz < 16) a->expsz = MEG(64);
+ if (a->c && a->c->blksz < 16) a->expsz = MEG(64);
else a->expsz = MEG(2048);
/* --- Ensure the MGF accepts hashes as keys --- */
#define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now)
-#define SEQSZ 4 /* Size of sequence number packet */
-
/*----- Low-level packet encryption and decryption ------------------------*/
/* --- Encrypted data format --- *
static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
{
- ghash *h;
- gcipher *c = ks->cout;
- const octet *p = BCUR(b);
+ int rc;
size_t sz = BLEFT(b);
- octet *qmac, *qseq, *qiv, *qpk;
- uint32 oseq;
- size_t ivsz = GC_CLASS(c)->blksz;
- size_t tagsz = ks->tagsz;
size_t osz, nsz;
- octet t[4];
- int rc = 0;
-
- /* --- Allocate the required buffer space --- */
- if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz))
- return (0); /* Caution! */
- qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
- BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
- STORE32(t, ty);
+ /* --- Initial tracing --- */
- oseq = ks->oseq++; STORE32(qseq, oseq);
IF_TRACING(T_KEYSET, {
- trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u",
- (unsigned long)oseq, ks->seq);
- trace_block(T_CRYPTO, "crypto: plaintext packet", p, sz);
+ trace(T_KEYSET,
+ "keyset: encrypting packet %lu (type %u) using keyset %u",
+ (unsigned long)ks->oseq, ty, ks->seq);
+ trace_block(T_CRYPTO, "crypto: plaintext packet", BCUR(b), sz);
})
- /* --- Encrypt the packet --- */
-
- if (ivsz) {
- rand_get(RAND_GLOBAL, qiv, ivsz);
- GC_SETIV(c, qiv);
- IF_TRACING(T_KEYSET, {
- trace_block(T_CRYPTO, "crypto: initialization vector", qiv, ivsz);
- })
- }
- GC_ENCRYPT(c, p, qpk, sz);
- IF_TRACING(T_KEYSET, {
- trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz);
- })
+ /* --- Apply the bulk-crypto transformation --- */
- /* --- Now compute the MAC --- */
-
- if (tagsz) {
- h = GM_INIT(ks->mout);
- GH_HASH(h, t, sizeof(t));
- GH_HASH(h, qseq, SEQSZ + ivsz + sz);
- memcpy(qmac, GH_DONE(h, 0), tagsz);
- GH_DESTROY(h);
- IF_TRACING(T_KEYSET, {
- trace_block(T_CRYPTO, "crypto: computed MAC", qmac, tagsz);
- })
- }
+ rc = ks->bulk->encrypt(ks, ty, b, bb);
+ if (rc || !BOK(bb)) return (rc);
- /* --- Deduct the packet size from the key's data life --- */
+ /* --- Do the necessary accounting for data volume --- */
osz = ks->sz_exp;
- if (osz > sz)
- nsz = osz - sz;
- else
- nsz = 0;
+ nsz = osz > sz ? osz - sz : 0;
if (osz >= ks->sz_regen && ks->sz_regen > nsz) {
T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
"forcing exchange", ks->seq); )
rc = KSERR_REGEN;
}
ks->sz_exp = nsz;
+
+ /* --- We're done --- */
+
return (rc);
}
static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
{
- const octet *pmac, *piv, *pseq, *ppk;
- size_t psz = BLEFT(b);
- size_t sz;
- octet *q = BCUR(bb);
- ghash *h;
- gcipher *c = ks->cin;
- size_t ivsz = GC_CLASS(c)->blksz;
- size_t tagsz = ks->tagsz;
- octet *mac;
- int eq;
- octet t[4];
-
- /* --- Break up the packet into its components --- */
-
- if (psz < ivsz + SEQSZ + tagsz) {
- T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
- return (KSERR_MALFORMED);
- }
- sz = psz - ivsz - SEQSZ - tagsz;
- pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
- STORE32(t, ty);
+ const octet *q = BCUR(bb);
+ int rc;
IF_TRACING(T_KEYSET, {
- trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq);
- trace_block(T_CRYPTO, "crypto: ciphertext packet", ppk, sz);
+ trace(T_KEYSET,
+ "keyset: try decrypting packet (type %u) using keyset %u",
+ ty, ks->seq);
+ trace_block(T_CRYPTO, "crypto: ciphertext packet", BCUR(b), BLEFT(b));
})
- /* --- Verify the MAC on the packet --- */
-
- if (tagsz) {
- h = GM_INIT(ks->min);
- GH_HASH(h, t, sizeof(t));
- GH_HASH(h, pseq, SEQSZ + ivsz + sz);
- mac = GH_DONE(h, 0);
- eq = ct_memeq(mac, pmac, tagsz);
- IF_TRACING(T_KEYSET, {
- trace_block(T_CRYPTO, "crypto: computed MAC", mac, tagsz);
- })
- GH_DESTROY(h);
- if (!eq) {
- IF_TRACING(T_KEYSET, {
- trace(T_KEYSET, "keyset: incorrect MAC: decryption failed");
- trace_block(T_CRYPTO, "crypto: expected MAC", pmac, tagsz);
- })
- return (KSERR_DECRYPT);
- }
- }
-
- /* --- Decrypt the packet --- */
+ rc = ks->bulk->decrypt(ks, ty, b, bb, seq);
+ if (rc) return (rc);
- if (ivsz) {
- GC_SETIV(c, piv);
- IF_TRACING(T_KEYSET, {
- trace_block(T_CRYPTO, "crypto: initialization vector", piv, ivsz);
- })
- }
- GC_DECRYPT(c, ppk, q, sz);
- if (seq)
- *seq = LOAD32(pseq);
IF_TRACING(T_KEYSET, {
trace(T_KEYSET, "keyset: decrypted OK (sequence = %lu)",
- (unsigned long)LOAD32(pseq));
- trace_block(T_CRYPTO, "crypto: decrypted packet", q, sz);
+ (unsigned long)*seq);
+ trace_block(T_CRYPTO, "crypto: decrypted packet", q, BCUR(bb) - q);
})
- BSTEP(bb, sz);
return (0);
}
{
if (--ks->ref)
return;
- GC_DESTROY(ks->cin);
- GC_DESTROY(ks->cout);
- GM_DESTROY(ks->min);
- GM_DESTROY(ks->mout);
+
+#define DROP(dir, a, drop) do { if (ks->dir.a) drop(ks->dir.a); } while (0)
+#define DROP_DIR(dir) do { \
+ DROP(dir, c, GC_DESTROY); \
+ DROP(dir, m, GM_DESTROY); \
+} while (0)
+
+ DROP_DIR(in);
+ DROP_DIR(out);
+
+#undef DROP
+#undef DROP_DIR
+
DESTROY(ks);
}
* calling @ks_encrypt@ directly.
*/
+static void gen_dir(const algswitch *algs, struct ksdir *ksd,
+ const char *whichdir,
+ const octet *from, size_t fromsz,
+ const octet *to, size_t tosz,
+ const octet *both, size_t bothsz)
+{
+#define SETKEY(what, a, init) do { \
+ ghash *_h; \
+ octet *_hh; \
+ \
+ if (!algs->a) \
+ ksd->a = 0; \
+ else { \
+ _h = GH_INIT(algs->h); \
+ HASH_STRING(_h, "tripe-" what); \
+ GH_HASH(_h, from, fromsz); \
+ GH_HASH(_h, to, tosz); \
+ GH_HASH(_h, both, bothsz); \
+ _hh = GH_DONE(_h, 0); \
+ IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, { \
+ char _buf[32]; \
+ sprintf(_buf, "crypto: %s key " what, whichdir); \
+ trace_block(T_CRYPTO, _buf, _hh, algs->a##ksz); \
+ }) }) \
+ ksd->a = init(algs->a, _hh, algs->a##ksz); \
+ GH_DESTROY(_h); \
+ } \
+} while (0)
+
+ SETKEY("encryption", c, GC_INIT);
+ SETKEY("integrity", m, GM_KEY);
+
+#undef SETKEY
+}
+
keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
{
- ghash *h;
- const octet *hh;
keyset *ks = CREATE(keyset);
time_t now = time(0);
const octet *pp = k;
T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
- /* --- Construct the various keys --- *
- *
- * This is done with macros, because it's quite tedious.
- */
-
-#define MINE GH_HASH(h, pp, x)
-#define YOURS GH_HASH(h, pp + x, y - x)
-#define OURS GH_HASH(h, pp + y, z - y)
-
-#define HASH_in MINE; YOURS; OURS
-#define HASH_out YOURS; MINE; OURS
-#define INIT_c(k) GC_INIT(algs->c, (k), algs->cksz)
-#define INIT_m(k) GM_KEY(algs->m, (k), algs->mksz)
-#define STR_c "encryption"
-#define STR_m "integrity"
-#define STR_in "incoming"
-#define STR_out "outgoing"
-
-#define SETKEY(a, dir) do { \
- h = GH_INIT(algs->h); \
- HASH_STRING(h, "tripe-" STR_##a); \
- HASH_##dir; \
- hh = GH_DONE(h, 0); \
- IF_TRACING(T_KEYSET, { \
- trace_block(T_CRYPTO, "crypto: " STR_##dir " key " STR_##a, \
- hh, algs->a##ksz); \
- }) \
- ks->a##dir = INIT_##a(hh); \
- GH_DESTROY(h); \
-} while (0)
-
- SETKEY(c, in); SETKEY(c, out);
- SETKEY(m, in); SETKEY(m, out);
-
-#undef MINE
-#undef YOURS
-#undef OURS
-#undef STR_c
-#undef STR_m
-#undef STR_in
-#undef STR_out
-#undef INIT_c
-#undef INIT_m
-#undef HASH_in
-#undef HASH_out
-#undef SETKEY
+ gen_dir(algs, &ks->in, "incoming", pp, x, pp + x, y - x, pp + y, z - y);
+ gen_dir(algs, &ks->out, "outgoing", pp + x, y - x, pp, x, pp + y, z - y);
T( ks->seq = seq++; )
+ ks->bulk = algs->bulk;
ks->ref = 1;
ks->t_exp = now + T_EXP;
ks->sz_exp = algs->expsz;
* ought to be replaced' notification is only ever given once
* for each key. Also note that this call forces a keyset to be
* used even if it's marked as not for data output.
+ *
+ * The encryption transform is permitted to corrupt @buf_u@ for
+ * its own purposes. Neither the source nor destination should
+ * be within @buf_u@; and callers mustn't expect anything stored
+ * in @buf_u@ to still
*/
int ks_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
* Use: Attempts to decrypt a message using a given key. Note that
* requesting decryption with a key directly won't clear a
* marking that it's not for encryption.
+ *
+ * The decryption transform is permitted to corrupt @buf_u@ for
+ * its own purposes. Neither the source nor destination should
+ * be within @buf_u@; and callers mustn't expect anything stored
+ * in @buf_u@ to still
*/
int ks_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
AT_DATA([algs-alpha], [dnl
kx-group=ec kx-group-order-bits=256 kx-group-elt-bits=512
hash=rmd160 mgf=rmd160-mgf hash-sz=20
+bulk-transform=v0 bulk-overhead=22
cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8
cipher-data-limit=67108864
mac=rmd160-hmac mac-keysz=20 mac-tagsz=10
AT_DATA([algs-beta-old], [dnl
kx-group=prime kx-group-order-bits=160 kx-group-elt-bits=1023
hash=rmd160 mgf=rmd160-mgf hash-sz=20
+bulk-transform=v0 bulk-overhead=22
cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8
cipher-data-limit=67108864
mac=rmd160-hmac mac-keysz=20 mac-tagsz=10
AT_DATA([algs-beta-new], [dnl
kx-group=ec kx-group-order-bits=161 kx-group-elt-bits=320
hash=rmd160 mgf=rmd160-mgf hash-sz=20
+bulk-transform=v0 bulk-overhead=22
cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8
cipher-data-limit=67108864
mac=rmd160-hmac mac-keysz=20 mac-tagsz=10
.B hashsz
The size of the hash function's output, in octets.
.TP
+.B bulk-transform
+The name of the bulk-crypto transform.
+.TP
+.B bulk-overhead
+The amount of overhead, in bytes, caused by the crypto transform.
+.TP
.B cipher
The name of the bulk data cipher in use, e.g.,
.BR blowfish-cbc .
is the MTU of the path to the peer, then the tunnel MTU should be
.IP
.I MTU
-\- 33 \-
-.I cipher-blksz
-\-
-.I mac-tagsz
+\- 29 \-
+.I bulk-overhead
.PP
allowing 20 bytes of IP header, 8 bytes of UDP header, a packet type
-octet, a four-octet sequence number, an IV, and a MAC tag.
+octet, and the bulk-crypto transform overhead (which includes the
+sequence number).
.RE
.SP
.BI "BGCANCEL " tag
.BI "KEYMGMT " which "-keyring " file " io-error " ecode " " message
A system error occurred while opening or reading the keyring file.
.SP
+.BI "KEYMGMT " which "-keyring " file " key " tag " unknown-bulk-transform " bulk
+The key specifies the use of an unknown bulk-crypto transform
+.IR bulk .
+Maybe the key was generated wrongly, or maybe the version of Catacomb
+installed is too old.
+.SP
.BI "KEYMGMT " which "-keyring " file " key " tag " unknown-cipher " cipher
The key specifies the use of an unknown symmetric encryption algorithm
.IR cipher .
mode, designed by Bellare, Canetti and Krawczyk). These can all be
overridden by setting attributes on your private key, as follows.
.TP
+.B bulk
+Names the bulk-crypto transform to use. Currently the only choice is
+.BR v0 .
+.TP
.B cipher
Names the symmetric encryption scheme to use. The default is
.BR blowfish\-cbc .
/*----- Cipher selections -------------------------------------------------*/
-typedef struct algswitch {
- const gccipher *c; /* Symmetric encryption scheme */
- const gccipher *mgf; /* Mask-generation function */
+typedef struct keyset keyset;
+typedef struct algswitch algswitch;
+
+typedef struct bulkcrypto {
+ const char *name;
+ unsigned prim;
+ int (*check)(const algswitch */*a*/, dstr */*e*/);
+ size_t (*overhead)(const algswitch */*a*/);
+ int (*encrypt)(keyset */*ks*/, unsigned /*ty*/, buf */*b*/, buf */*bb*/);
+ int (*decrypt)(keyset */*ks*/, unsigned /*ty*/,
+ buf */*b*/, buf */*bb*/, uint32 */*seq*/);
+} bulkcrypto;
+
+#define BCP_CIPHER 1
+#define BCP_MAC 2
+
+struct algswitch {
const gchash *h; /* Hash function */
+ const gccipher *mgf; /* Mask-generation function */
+ const struct bulkcrypto *bulk; /* Bulk crypto transformation */
+ const gccipher *c; /* Symmetric encryption scheme */
const gcmac *m; /* Message authentication code */
size_t hashsz; /* Hash output size */
size_t tagsz; /* Length to truncate MAC tags */
size_t expsz; /* Size of data to process */
size_t cksz, mksz; /* Key lengths for @c@ and @m@ */
-} algswitch;
+};
typedef struct kdata {
unsigned ref; /* Reference counter */
#define HASH_STRING(h, s) GH_HASH((h), (s), sizeof(s))
+extern const struct bulkcrypto bulktab[];
+
/*----- Data structures ---------------------------------------------------*/
/* --- Socket addresses --- *
* expiry.
*/
-typedef struct keyset {
+struct keyset {
struct keyset *next; /* Next active keyset in the list */
unsigned ref; /* Reference count for keyset */
struct peer *p; /* Pointer to peer structure */
unsigned long sz_exp, sz_regen; /* Data limits for the keyset */
T( unsigned seq; ) /* Sequence number for tracing */
unsigned f; /* Various useful flags */
- gcipher *cin, *cout; /* Keyset ciphers for encryption */
+ const bulkcrypto *bulk; /* Bulk crypto transform */
size_t tagsz; /* Length to truncate MAC tags */
- gmac *min, *mout; /* Keyset MACs for integrity */
+ struct ksdir {
+ gcipher *c; /* Keyset cipher for encryption */
+ gmac *m; /* Keyset MAC for integrity */
+ } in, out;
uint32 oseq; /* Outbound sequence number */
seqwin iseq; /* Inbound sequence number */
-} keyset;
+};
#define KSF_LISTEN 1u /* Don't encrypt packets yet */
#define KSF_LINK 2u /* Key is in a linked list */
* ought to be replaced' notification is only ever given once
* for each key. Also note that this call forces a keyset to be
* used even if it's marked as not for data output.
+ *
+ * The encryption transform is permitted to corrupt @buf_u@ for
+ * its own purposes. Neither the source nor destination should
+ * be within @buf_u@; and callers mustn't expect anything stored
+ * in @buf_u@ to still
*/
extern int ks_encrypt(keyset */*ks*/, unsigned /*ty*/,
* Use: Attempts to decrypt a message using a given key. Note that
* requesting decryption with a key directly won't clear a
* marking that it's not for encryption.
+ *
+ * The decryption transform is permitted to corrupt @buf_u@ for
+ * its own purposes. Neither the source nor destination should
+ * be within @buf_u@; and callers mustn't expect anything stored
+ * in @buf_u@ to still
*/
extern int ks_decrypt(keyset */*ks*/, unsigned /*ty*/,
mtu=$P_MTU;;
*)
pathmtu=$(pathmtu "$addr")
- mtu=$(expr "$pathmtu" - 33 - $A_CIPHER_BLKSZ - $A_MAC_TAGSZ)
+ mtu=$(expr "$pathmtu" - 29 - $A_BULK_OVERHEAD)
;;
esac
ip link set dev "$ifname" up mtu "$mtu"