X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/494a7ac04de2a38bf6aade234602f831be314c55..a93aacce200e0d68b614d8bfb05d9cbeba850b12:/server/bulkcrypto.c diff --git a/server/bulkcrypto.c b/server/bulkcrypto.c new file mode 100644 index 00000000..faaf8d71 --- /dev/null +++ b/server/bulkcrypto.c @@ -0,0 +1,215 @@ +/* -*-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 -------------------------------------------------*/