chiark / gitweb /
server/bulkcrypto.c: Abstract out MAC-failure tracing.
[tripe] / server / bulkcrypto.c
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 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
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) {                                                           \
62     TRACE_MACERR(_pmac, _tagsz);                                        \
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
93 static int v0_check(const algswitch *a, dstr *e)
94   { return (0); }
95
96 static size_t v0_overhead(const algswitch *a)
97   { return a->tagsz + SEQSZ + a->c->blksz; }
98
99 static 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
158 static 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
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
232 static 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
242 static 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
249 static 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
311 static 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
361 /*----- Bulk crypto transform table ---------------------------------------*/
362
363 const bulkops bulktab[] = {
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),
369   BULK("iiv", iiv, BCP_CIPHER | BCP_MAC | BCP_BLKC),
370
371 #undef BULK
372   { 0 }
373 };
374
375 /*----- That's all, folks -------------------------------------------------*/