| 1 | /* -*-c-*- |
| 2 | * |
| 3 | * Bulk crypto transformations |
| 4 | * |
| 5 | * (c) 2014 Straylight/Edgeware |
| 6 | */ |
| 7 | |
| 8 | /*----- Licensing notice --------------------------------------------------* |
| 9 | * |
| 10 | * This file is part of Trivial IP Encryption (TrIPE). |
| 11 | * |
| 12 | * TrIPE is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation; either version 2 of the License, or |
| 15 | * (at your option) any later version. |
| 16 | * |
| 17 | * TrIPE is distributed in the hope that it will be useful, |
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU General Public License for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with TrIPE; if not, write to the Free Software Foundation, |
| 24 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 25 | */ |
| 26 | |
| 27 | /*----- Header files ------------------------------------------------------*/ |
| 28 | |
| 29 | #include "tripe.h" |
| 30 | |
| 31 | /*----- Utilities ---------------------------------------------------------*/ |
| 32 | |
| 33 | #define SEQSZ 4 /* Size of sequence number packet */ |
| 34 | |
| 35 | #define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, { \ |
| 36 | trace_block(T_CRYPTO, "crypto: initialization vector", \ |
| 37 | (qiv), (ivsz)); \ |
| 38 | }) } while (0) |
| 39 | |
| 40 | #define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, { \ |
| 41 | trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz)); \ |
| 42 | }) } while (0) |
| 43 | |
| 44 | #define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, { \ |
| 45 | trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz)); \ |
| 46 | }) } while (0) |
| 47 | |
| 48 | #define CHECK_MAC(h, pmac, tagsz) do { \ |
| 49 | ghash *_h = (h); \ |
| 50 | const octet *_pmac = (pmac); \ |
| 51 | size_t _tagsz = (tagsz); \ |
| 52 | octet *_mac = GH_DONE(_h, 0); \ |
| 53 | int _eq = ct_memeq(_mac, _pmac, _tagsz); \ |
| 54 | TRACE_MAC(_mac, _tagsz); \ |
| 55 | GH_DESTROY(_h); \ |
| 56 | if (!_eq) { \ |
| 57 | IF_TRACING(T_KEYSET, { \ |
| 58 | trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); \ |
| 59 | trace_block(T_CRYPTO, "crypto: expected MAC", _pmac, _tagsz); \ |
| 60 | }) \ |
| 61 | return (KSERR_DECRYPT); \ |
| 62 | } \ |
| 63 | } while (0) |
| 64 | |
| 65 | /*----- The original transform --------------------------------------------* |
| 66 | * |
| 67 | * We generate a random initialization vector (if the cipher needs one). We |
| 68 | * encrypt the input message with the cipher, and format the type, sequence |
| 69 | * number, IV, and ciphertext as follows. |
| 70 | * |
| 71 | * +------+ +------+---...---+------...------+ |
| 72 | * | type | | seq | iv | ciphertext | |
| 73 | * +------+ +------+---...---+------...------+ |
| 74 | * 32 32 blksz sz |
| 75 | * |
| 76 | * All of this is fed into the MAC to compute a tag. The type is not |
| 77 | * transmitted: the other end knows what type of message it expects, and the |
| 78 | * type is only here to prevent us from being confused because some other |
| 79 | * kind of ciphertext has been substituted. The tag is prepended to the |
| 80 | * remainder, to yield the finished cryptogram, as follows. |
| 81 | * |
| 82 | * +---...---+------+---...---+------...------+ |
| 83 | * | tag | seq | iv | ciphertext | |
| 84 | * +---...---+------+---...---+------...------+ |
| 85 | * tagsz 32 blksz sz |
| 86 | * |
| 87 | * Decryption: checks the overall size, verifies the tag, then decrypts the |
| 88 | * ciphertext and extracts the sequence number. |
| 89 | */ |
| 90 | |
| 91 | static int v0_check(const algswitch *a, dstr *e) |
| 92 | { return (0); } |
| 93 | |
| 94 | static size_t v0_overhead(const algswitch *a) |
| 95 | { return a->tagsz + SEQSZ + a->c->blksz; } |
| 96 | |
| 97 | static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) |
| 98 | { |
| 99 | ghash *h; |
| 100 | gcipher *c = ks->out.c; |
| 101 | const octet *p = BCUR(b); |
| 102 | size_t sz = BLEFT(b); |
| 103 | octet *qmac, *qseq, *qiv, *qpk; |
| 104 | uint32 oseq; |
| 105 | size_t ivsz = GC_CLASS(c)->blksz; |
| 106 | size_t tagsz = ks->tagsz; |
| 107 | octet t[4]; |
| 108 | |
| 109 | /* --- Determine the ciphertext layout --- */ |
| 110 | |
| 111 | if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0); |
| 112 | qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz; |
| 113 | BSTEP(bb, tagsz + SEQSZ + ivsz + sz); |
| 114 | |
| 115 | /* --- Store the type --- * |
| 116 | * |
| 117 | * This isn't transmitted, but it's covered by the MAC. |
| 118 | */ |
| 119 | |
| 120 | STORE32(t, ty); |
| 121 | |
| 122 | /* --- Store the sequence number --- */ |
| 123 | |
| 124 | oseq = ks->oseq++; |
| 125 | STORE32(qseq, oseq); |
| 126 | |
| 127 | /* --- Establish an initialization vector if necessary --- */ |
| 128 | |
| 129 | if (ivsz) { |
| 130 | rand_get(RAND_GLOBAL, qiv, ivsz); |
| 131 | GC_SETIV(c, qiv); |
| 132 | TRACE_IV(qiv, ivsz); |
| 133 | } |
| 134 | |
| 135 | /* --- Encrypt the packet --- */ |
| 136 | |
| 137 | GC_ENCRYPT(c, p, qpk, sz); |
| 138 | TRACE_CT(qpk, sz); |
| 139 | |
| 140 | /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */ |
| 141 | |
| 142 | if (tagsz) { |
| 143 | h = GM_INIT(ks->out.m); |
| 144 | GH_HASH(h, t, sizeof(t)); |
| 145 | GH_HASH(h, qseq, SEQSZ + ivsz + sz); |
| 146 | memcpy(qmac, GH_DONE(h, 0), tagsz); |
| 147 | GH_DESTROY(h); |
| 148 | TRACE_MAC(qmac, tagsz); |
| 149 | } |
| 150 | |
| 151 | /* --- We're done --- */ |
| 152 | |
| 153 | return (0); |
| 154 | } |
| 155 | |
| 156 | static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) |
| 157 | { |
| 158 | const octet *pmac, *piv, *pseq, *ppk; |
| 159 | size_t psz = BLEFT(b); |
| 160 | size_t sz; |
| 161 | octet *q = BCUR(bb); |
| 162 | ghash *h; |
| 163 | gcipher *c = ks->in.c; |
| 164 | size_t ivsz = GC_CLASS(c)->blksz; |
| 165 | size_t tagsz = ks->tagsz; |
| 166 | octet t[4]; |
| 167 | |
| 168 | /* --- Break up the packet into its components --- */ |
| 169 | |
| 170 | if (psz < ivsz + SEQSZ + tagsz) { |
| 171 | T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); ) |
| 172 | return (KSERR_MALFORMED); |
| 173 | } |
| 174 | sz = psz - ivsz - SEQSZ - tagsz; |
| 175 | pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz; |
| 176 | STORE32(t, ty); |
| 177 | |
| 178 | /* --- Verify the MAC on the packet --- */ |
| 179 | |
| 180 | if (tagsz) { |
| 181 | h = GM_INIT(ks->in.m); |
| 182 | GH_HASH(h, t, sizeof(t)); |
| 183 | GH_HASH(h, pseq, SEQSZ + ivsz + sz); |
| 184 | CHECK_MAC(h, pmac, tagsz); |
| 185 | } |
| 186 | |
| 187 | /* --- Decrypt the packet --- */ |
| 188 | |
| 189 | if (ivsz) { |
| 190 | TRACE_IV(piv, ivsz); |
| 191 | GC_SETIV(c, piv); |
| 192 | } |
| 193 | GC_DECRYPT(c, ppk, q, sz); |
| 194 | |
| 195 | /* --- Finished --- */ |
| 196 | |
| 197 | *seq = LOAD32(pseq); |
| 198 | BSTEP(bb, sz); |
| 199 | return (0); |
| 200 | } |
| 201 | |
| 202 | /*----- Bulk crypto transform table ---------------------------------------*/ |
| 203 | |
| 204 | const bulkcrypto bulktab[] = { |
| 205 | |
| 206 | #define BULK(name, pre, prim) \ |
| 207 | { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt } |
| 208 | |
| 209 | BULK("v0", v0, BCP_CIPHER | BCP_MAC), |
| 210 | |
| 211 | #undef BULK |
| 212 | { 0 } |
| 213 | }; |
| 214 | |
| 215 | /*----- That's all, folks -------------------------------------------------*/ |