X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/b4e566689f469cc1cffe99e50e16a346d0f9832d..b5c45da15703d85b506a1ea1eb38c318c3418ed3:/keyset.c diff --git a/keyset.c b/keyset.c index 0a320457..8893e606 100644 --- a/keyset.c +++ b/keyset.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyset.c,v 1.10 2004/04/08 01:36:17 mdw Exp $ + * $Id: keyset.c,v 1.11 2004/04/18 18:08:11 mdw Exp $ * * Handling of symmetric keysets * @@ -36,7 +36,8 @@ * * For a 64-bit block cipher (e.g., Blowfish), the probability of a collision * occurring after 32 MB is less than %$2^{-21}$%, and the probability of a - * collision occurring after 64 MB is less than %$2^{-19}$%. + * collision occurring after 64 MB is less than %$2^{-19}$%. These could be + * adjusted dependent on the encryption scheme, but it's too much pain. */ #define T_EXP MIN(60) /* Expiry time for a key */ @@ -48,6 +49,8 @@ #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 --- * @@ -90,47 +93,59 @@ static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb) { ghash *h; - gcipher *c; + gcipher *c = ks->cout; 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; size_t osz, nsz; octet t[4]; int rc = 0; /* --- Allocate the required buffer space --- */ - c = ks->cout; - if (buf_ensure(bb, MACSZ + SEQSZ + IVSZ + sz)) + if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0); /* Caution! */ - qmac = BCUR(bb); qseq = qmac + MACSZ; qiv = qseq + SEQSZ; qpk = qiv + IVSZ; - BSTEP(bb, MACSZ + SEQSZ + IVSZ + sz); + qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz; + BSTEP(bb, tagsz + SEQSZ + ivsz + sz); STORE32(t, ty); - /* --- Encrypt the packet --- */ - oseq = ks->oseq++; STORE32(qseq, oseq); - rand_get(RAND_GLOBAL, qiv, IVSZ); - c->ops->setiv(c, qiv); - c->ops->encrypt(c, p, qpk, sz); IF_TRACING(T_KEYSET, { trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u", (unsigned long)oseq, ks->seq); - trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz); + trace_block(T_CRYPTO, "crypto: plaintext packet", p, sz); }) - /* --- Now compute the MAC --- */ + /* --- Encrypt the packet --- */ - h = ks->mout->ops->init(ks->mout); - h->ops->hash(h, t, sizeof(t)); - h->ops->hash(h, qseq, SEQSZ + IVSZ + sz); - memcpy(qmac, h->ops->done(h, 0), MACSZ); - h->ops->destroy(h); + 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: computed MAC", qmac, MACSZ); + trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz); }) + /* --- 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); + }) + } + /* --- Deduct the packet size from the key's data life --- */ osz = ks->sz_exp; @@ -173,45 +188,57 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) octet *q = BCUR(bb); ghash *h; gcipher *c = ks->cin; - size_t ivsz = c->ops->c->blksz; + 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 + 4) { + if (psz < ivsz + SEQSZ + tagsz) { T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); ) return (-1); } - sz = psz - IVSZ - SEQSZ - MACSZ; - pmac = BCUR(b); pseq = pmac + MACSZ; piv = pseq + SEQSZ; ppk = piv + IVSZ; + 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 --- */ - - h = ks->min->ops->init(ks->min); - h->ops->hash(h, t, sizeof(t)); - h->ops->hash(h, pseq, SEQSZ + IVSZ + sz); - mac = h->ops->done(h, 0); - eq = !memcmp(mac, pmac, MACSZ); IF_TRACING(T_KEYSET, { trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq); - trace_block(T_CRYPTO, "crypto: computed MAC", mac, MACSZ); + trace_block(T_CRYPTO, "crypto: ciphertext packet", ppk, sz); }) - h->ops->destroy(h); - if (!eq) { + + /* --- 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 = !memcmp(mac, pmac, tagsz); IF_TRACING(T_KEYSET, { - trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); - trace_block(T_CRYPTO, "crypto: expected MAC", pmac, MACSZ); + trace_block(T_CRYPTO, "crypto: computed MAC", mac, tagsz); }) - return (-1); + 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 (-1); + } } /* --- Decrypt the packet --- */ - c->ops->setiv(c, piv); - c->ops->decrypt(c, ppk, q, sz); + 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, { @@ -278,10 +305,10 @@ void ks_drop(keyset *ks) { if (--ks->ref) return; - ks->cin->ops->destroy(ks->cin); - ks->cout->ops->destroy(ks->cout); - ks->min->ops->destroy(ks->min); - ks->mout->ops->destroy(ks->mout); + GC_DESTROY(ks->cin); + GC_DESTROY(ks->cout); + GM_DESTROY(ks->min); + GM_DESTROY(ks->mout); DESTROY(ks); } @@ -310,8 +337,8 @@ void ks_drop(keyset *ks) keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) { - HASH_CTX h; - octet buf[HASHSZ]; + ghash *h; + const octet *hh; keyset *ks = CREATE(keyset); time_t now = time(0); const octet *pp = k; @@ -324,39 +351,47 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) * This is done with macros, because it's quite tedious. */ -#define MINE HASH(&h, pp, x) -#define YOURS HASH(&h, pp + x, y - x) -#define OURS HASH(&h, pp + y, z - y) - -#define IN MINE; YOURS; OURS -#define OUT YOURS; MINE; OURS -#define STR_IN "incoming" -#define STR_OUT "outgoing" - -#define GETHASH(str, dir) do { \ - HASH_INIT(&h); \ - HASH_STRING(&h, "tripe-" str); \ - dir; \ - HASH_DONE(&h, buf); \ +#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, \ - buf, sizeof(buf)); \ + 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) - GETHASH("encryption", IN); ks->cin = CIPHER->init(buf, sizeof(buf)); - GETHASH("integrity", IN); ks->min = MAC->key(buf, sizeof(buf)); - GETHASH("encryption", OUT); ks->cout = CIPHER->init(buf, sizeof(buf)); - GETHASH("integrity", OUT); ks->mout = MAC->key(buf, sizeof(buf)); + SETKEY(c, in); SETKEY(c, out); + SETKEY(m, in); SETKEY(m, out); #undef MINE #undef YOURS #undef OURS -#undef IN -#undef OUT -#undef STR_IN -#undef STR_OUT -#undef GETHASH +#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 T( ks->seq = seq++; ) ks->ref = 1; @@ -367,7 +402,7 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) ks->next = 0; ks->p = p; ks->f = KSF_LISTEN; - BURN(buf); + ks->tagsz = algs.tagsz; return (ks); }