chiark / gitweb /
server/bulkcrypto.c: Abstract out MAC-failure tracing.
[tripe] / server / bulkcrypto.c
CommitLineData
a93aacce
MW
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
9a361a98
MW
48#define TRACE_MACERR(pmac, tagsz) do { IF_TRACING(T_KEYSET, { \
49 trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); \
50 trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz)); \
51}) } while (0)
52
a93aacce
MW
53#define CHECK_MAC(h, pmac, tagsz) do { \
54 ghash *_h = (h); \
55 const octet *_pmac = (pmac); \
56 size_t _tagsz = (tagsz); \
57 octet *_mac = GH_DONE(_h, 0); \
58 int _eq = ct_memeq(_mac, _pmac, _tagsz); \
59 TRACE_MAC(_mac, _tagsz); \
60 GH_DESTROY(_h); \
61 if (!_eq) { \
9a361a98 62 TRACE_MACERR(_pmac, _tagsz); \
a93aacce
MW
63 return (KSERR_DECRYPT); \
64 } \
65} while (0)
66
67/*----- The original transform --------------------------------------------*
68 *
69 * We generate a random initialization vector (if the cipher needs one). We
70 * encrypt the input message with the cipher, and format the type, sequence
71 * number, IV, and ciphertext as follows.
72 *
73 * +------+ +------+---...---+------...------+
74 * | type | | seq | iv | ciphertext |
75 * +------+ +------+---...---+------...------+
76 * 32 32 blksz sz
77 *
78 * All of this is fed into the MAC to compute a tag. The type is not
79 * transmitted: the other end knows what type of message it expects, and the
80 * type is only here to prevent us from being confused because some other
81 * kind of ciphertext has been substituted. The tag is prepended to the
82 * remainder, to yield the finished cryptogram, as follows.
83 *
84 * +---...---+------+---...---+------...------+
85 * | tag | seq | iv | ciphertext |
86 * +---...---+------+---...---+------...------+
87 * tagsz 32 blksz sz
88 *
89 * Decryption: checks the overall size, verifies the tag, then decrypts the
90 * ciphertext and extracts the sequence number.
91 */
92
93static int v0_check(const algswitch *a, dstr *e)
94 { return (0); }
95
96static size_t v0_overhead(const algswitch *a)
97 { return a->tagsz + SEQSZ + a->c->blksz; }
98
99static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
100{
101 ghash *h;
102 gcipher *c = ks->out.c;
103 const octet *p = BCUR(b);
104 size_t sz = BLEFT(b);
105 octet *qmac, *qseq, *qiv, *qpk;
106 uint32 oseq;
107 size_t ivsz = GC_CLASS(c)->blksz;
108 size_t tagsz = ks->tagsz;
109 octet t[4];
110
111 /* --- Determine the ciphertext layout --- */
112
113 if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
114 qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
115 BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
116
117 /* --- Store the type --- *
118 *
119 * This isn't transmitted, but it's covered by the MAC.
120 */
121
122 STORE32(t, ty);
123
124 /* --- Store the sequence number --- */
125
126 oseq = ks->oseq++;
127 STORE32(qseq, oseq);
128
129 /* --- Establish an initialization vector if necessary --- */
130
131 if (ivsz) {
132 rand_get(RAND_GLOBAL, qiv, ivsz);
133 GC_SETIV(c, qiv);
134 TRACE_IV(qiv, ivsz);
135 }
136
137 /* --- Encrypt the packet --- */
138
139 GC_ENCRYPT(c, p, qpk, sz);
140 TRACE_CT(qpk, sz);
141
142 /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
143
144 if (tagsz) {
145 h = GM_INIT(ks->out.m);
146 GH_HASH(h, t, sizeof(t));
147 GH_HASH(h, qseq, SEQSZ + ivsz + sz);
148 memcpy(qmac, GH_DONE(h, 0), tagsz);
149 GH_DESTROY(h);
150 TRACE_MAC(qmac, tagsz);
151 }
152
153 /* --- We're done --- */
154
155 return (0);
156}
157
158static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
159{
160 const octet *pmac, *piv, *pseq, *ppk;
161 size_t psz = BLEFT(b);
162 size_t sz;
163 octet *q = BCUR(bb);
164 ghash *h;
165 gcipher *c = ks->in.c;
166 size_t ivsz = GC_CLASS(c)->blksz;
167 size_t tagsz = ks->tagsz;
168 octet t[4];
169
170 /* --- Break up the packet into its components --- */
171
172 if (psz < ivsz + SEQSZ + tagsz) {
173 T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
174 return (KSERR_MALFORMED);
175 }
176 sz = psz - ivsz - SEQSZ - tagsz;
177 pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
178 STORE32(t, ty);
179
180 /* --- Verify the MAC on the packet --- */
181
182 if (tagsz) {
183 h = GM_INIT(ks->in.m);
184 GH_HASH(h, t, sizeof(t));
185 GH_HASH(h, pseq, SEQSZ + ivsz + sz);
186 CHECK_MAC(h, pmac, tagsz);
187 }
188
189 /* --- Decrypt the packet --- */
190
191 if (ivsz) {
192 TRACE_IV(piv, ivsz);
193 GC_SETIV(c, piv);
194 }
195 GC_DECRYPT(c, ppk, q, sz);
196
197 /* --- Finished --- */
198
199 *seq = LOAD32(pseq);
200 BSTEP(bb, sz);
201 return (0);
202}
203
b87bffcb
MW
204/*----- The implicit-IV transform -----------------------------------------*
205 *
206 * The v0 transform makes everything explicit. There's an IV because the
207 * cipher needs an IV; there's a sequence number because replay prevention
208 * needs a sequence number.
209 *
210 * This new transform works rather differently. We make use of a block
211 * cipher to encrypt the sequence number, and use that as the IV. We
212 * transmit the sequence number in the clear, as before. This reduces
213 * overhead; and it's not a significant privacy leak because the adversary
214 * can see the order in which the messages are transmitted -- i.e., the
215 * sequence numbers are almost completely predictable anyway.
216 *
217 * So, a MAC is computed over
218 *
219 * +------+ +------+------...------+
220 * | type | | seq | ciphertext |
221 * +------+ +------+------...------+
222 * 32 32 sz
223 *
224 * and we actually transmit the following as the cryptogram.
225 *
226 * +---...---+------+------...------+
227 * | tag | seq | ciphertext |
228 * +---...---+------+------...------+
229 * tagsz 32 sz
230 */
231
232static int iiv_check(const algswitch *a, dstr *e)
233{
234 if (a->b->blksz < a->c->blksz) {
235 a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
236 "blksz-insufficient", A_END);
237 return (-1);
238 }
239 return (0);
240}
241
242static size_t iiv_overhead(const algswitch *a)
243 { return a->tagsz + SEQSZ; }
244
245#define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, { \
246 trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \
247}) } while (0)
248
249static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
250{
251 ghash *h;
252 gcipher *c = ks->out.c, *blkc = ks->out.b;
253 const octet *p = BCUR(b);
254 size_t sz = BLEFT(b);
255 octet *qmac, *qseq, *qpk;
256 uint32 oseq;
257 size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
258 size_t tagsz = ks->tagsz;
259 octet t[4];
260
261 /* --- Determine the ciphertext layout --- */
262
263 if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0);
264 qmac = BCUR(bb); qseq = qmac + tagsz; qpk = qseq + SEQSZ;
265 BSTEP(bb, tagsz + SEQSZ + sz);
266
267 /* --- Store the type --- *
268 *
269 * This isn't transmitted, but it's covered by the MAC.
270 */
271
272 STORE32(t, ty);
273
274 /* --- Store the sequence number --- */
275
276 oseq = ks->oseq++;
277 STORE32(qseq, oseq);
278
279 /* --- Establish an initialization vector if necessary --- */
280
281 if (ivsz) {
282 memset(buf_u, 0, blkcsz - SEQSZ);
283 memcpy(buf_u + blkcsz - SEQSZ, qseq, SEQSZ);
284 TRACE_PRESEQ(buf_u, ivsz);
285 GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
286 GC_SETIV(c, buf_u);
287 TRACE_IV(buf_u, ivsz);
288 }
289
290 /* --- Encrypt the packet --- */
291
292 GC_ENCRYPT(c, p, qpk, sz);
293 TRACE_CT(qpk, sz);
294
295 /* --- Compute a MAC over type, sequence number, and ciphertext --- */
296
297 if (tagsz) {
298 h = GM_INIT(ks->out.m);
299 GH_HASH(h, t, sizeof(t));
300 GH_HASH(h, qseq, SEQSZ + sz);
301 memcpy(qmac, GH_DONE(h, 0), tagsz);
302 GH_DESTROY(h);
303 TRACE_MAC(qmac, tagsz);
304 }
305
306 /* --- We're done --- */
307
308 return (0);
309}
310
311static int iiv_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
312{
313 const octet *pmac, *pseq, *ppk;
314 size_t psz = BLEFT(b);
315 size_t sz;
316 octet *q = BCUR(bb);
317 ghash *h;
318 gcipher *c = ks->in.c, *blkc = ks->in.b;
319 size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
320 size_t tagsz = ks->tagsz;
321 octet t[4];
322
323 /* --- Break up the packet into its components --- */
324
325 if (psz < SEQSZ + tagsz) {
326 T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
327 return (KSERR_MALFORMED);
328 }
329 sz = psz - SEQSZ - tagsz;
330 pmac = BCUR(b); pseq = pmac + tagsz; ppk = pseq + SEQSZ;
331 STORE32(t, ty);
332
333 /* --- Verify the MAC on the packet --- */
334
335 if (tagsz) {
336 h = GM_INIT(ks->in.m);
337 GH_HASH(h, t, sizeof(t));
338 GH_HASH(h, pseq, SEQSZ + sz);
339 CHECK_MAC(h, pmac, tagsz);
340 }
341
342 /* --- Decrypt the packet --- */
343
344 if (ivsz) {
345 memset(buf_u, 0, blkcsz - SEQSZ);
346 memcpy(buf_u + blkcsz - SEQSZ, pseq, SEQSZ);
347 TRACE_PRESEQ(buf_u, ivsz);
348 GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
349 GC_SETIV(c, buf_u);
350 TRACE_IV(buf_u, ivsz);
351 }
352 GC_DECRYPT(c, ppk, q, sz);
353
354 /* --- Finished --- */
355
356 *seq = LOAD32(pseq);
357 BSTEP(bb, sz);
358 return (0);
359}
360
a93aacce
MW
361/*----- Bulk crypto transform table ---------------------------------------*/
362
fddd7fb7 363const bulkops bulktab[] = {
a93aacce
MW
364
365#define BULK(name, pre, prim) \
366 { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt }
367
368 BULK("v0", v0, BCP_CIPHER | BCP_MAC),
b87bffcb 369 BULK("iiv", iiv, BCP_CIPHER | BCP_MAC | BCP_BLKC),
a93aacce
MW
370
371#undef BULK
372 { 0 }
373};
374
375/*----- That's all, folks -------------------------------------------------*/