chiark / gitweb /
svc/tripe-ifup.in: Trim prefix length from IPv6 address used as gateway.
[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
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
91static int v0_check(const algswitch *a, dstr *e)
92 { return (0); }
93
94static size_t v0_overhead(const algswitch *a)
95 { return a->tagsz + SEQSZ + a->c->blksz; }
96
97static 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
156static 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
b87bffcb
MW
202/*----- The implicit-IV transform -----------------------------------------*
203 *
204 * The v0 transform makes everything explicit. There's an IV because the
205 * cipher needs an IV; there's a sequence number because replay prevention
206 * needs a sequence number.
207 *
208 * This new transform works rather differently. We make use of a block
209 * cipher to encrypt the sequence number, and use that as the IV. We
210 * transmit the sequence number in the clear, as before. This reduces
211 * overhead; and it's not a significant privacy leak because the adversary
212 * can see the order in which the messages are transmitted -- i.e., the
213 * sequence numbers are almost completely predictable anyway.
214 *
215 * So, a MAC is computed over
216 *
217 * +------+ +------+------...------+
218 * | type | | seq | ciphertext |
219 * +------+ +------+------...------+
220 * 32 32 sz
221 *
222 * and we actually transmit the following as the cryptogram.
223 *
224 * +---...---+------+------...------+
225 * | tag | seq | ciphertext |
226 * +---...---+------+------...------+
227 * tagsz 32 sz
228 */
229
230static int iiv_check(const algswitch *a, dstr *e)
231{
232 if (a->b->blksz < a->c->blksz) {
233 a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
234 "blksz-insufficient", A_END);
235 return (-1);
236 }
237 return (0);
238}
239
240static size_t iiv_overhead(const algswitch *a)
241 { return a->tagsz + SEQSZ; }
242
243#define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, { \
244 trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \
245}) } while (0)
246
247static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
248{
249 ghash *h;
250 gcipher *c = ks->out.c, *blkc = ks->out.b;
251 const octet *p = BCUR(b);
252 size_t sz = BLEFT(b);
253 octet *qmac, *qseq, *qpk;
254 uint32 oseq;
255 size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
256 size_t tagsz = ks->tagsz;
257 octet t[4];
258
259 /* --- Determine the ciphertext layout --- */
260
261 if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0);
262 qmac = BCUR(bb); qseq = qmac + tagsz; qpk = qseq + SEQSZ;
263 BSTEP(bb, tagsz + SEQSZ + sz);
264
265 /* --- Store the type --- *
266 *
267 * This isn't transmitted, but it's covered by the MAC.
268 */
269
270 STORE32(t, ty);
271
272 /* --- Store the sequence number --- */
273
274 oseq = ks->oseq++;
275 STORE32(qseq, oseq);
276
277 /* --- Establish an initialization vector if necessary --- */
278
279 if (ivsz) {
280 memset(buf_u, 0, blkcsz - SEQSZ);
281 memcpy(buf_u + blkcsz - SEQSZ, qseq, SEQSZ);
282 TRACE_PRESEQ(buf_u, ivsz);
283 GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
284 GC_SETIV(c, buf_u);
285 TRACE_IV(buf_u, ivsz);
286 }
287
288 /* --- Encrypt the packet --- */
289
290 GC_ENCRYPT(c, p, qpk, sz);
291 TRACE_CT(qpk, sz);
292
293 /* --- Compute a MAC over type, sequence number, and ciphertext --- */
294
295 if (tagsz) {
296 h = GM_INIT(ks->out.m);
297 GH_HASH(h, t, sizeof(t));
298 GH_HASH(h, qseq, SEQSZ + sz);
299 memcpy(qmac, GH_DONE(h, 0), tagsz);
300 GH_DESTROY(h);
301 TRACE_MAC(qmac, tagsz);
302 }
303
304 /* --- We're done --- */
305
306 return (0);
307}
308
309static int iiv_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
310{
311 const octet *pmac, *pseq, *ppk;
312 size_t psz = BLEFT(b);
313 size_t sz;
314 octet *q = BCUR(bb);
315 ghash *h;
316 gcipher *c = ks->in.c, *blkc = ks->in.b;
317 size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
318 size_t tagsz = ks->tagsz;
319 octet t[4];
320
321 /* --- Break up the packet into its components --- */
322
323 if (psz < SEQSZ + tagsz) {
324 T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
325 return (KSERR_MALFORMED);
326 }
327 sz = psz - SEQSZ - tagsz;
328 pmac = BCUR(b); pseq = pmac + tagsz; ppk = pseq + SEQSZ;
329 STORE32(t, ty);
330
331 /* --- Verify the MAC on the packet --- */
332
333 if (tagsz) {
334 h = GM_INIT(ks->in.m);
335 GH_HASH(h, t, sizeof(t));
336 GH_HASH(h, pseq, SEQSZ + sz);
337 CHECK_MAC(h, pmac, tagsz);
338 }
339
340 /* --- Decrypt the packet --- */
341
342 if (ivsz) {
343 memset(buf_u, 0, blkcsz - SEQSZ);
344 memcpy(buf_u + blkcsz - SEQSZ, pseq, SEQSZ);
345 TRACE_PRESEQ(buf_u, ivsz);
346 GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
347 GC_SETIV(c, buf_u);
348 TRACE_IV(buf_u, ivsz);
349 }
350 GC_DECRYPT(c, ppk, q, sz);
351
352 /* --- Finished --- */
353
354 *seq = LOAD32(pseq);
355 BSTEP(bb, sz);
356 return (0);
357}
358
a93aacce
MW
359/*----- Bulk crypto transform table ---------------------------------------*/
360
361const bulkcrypto bulktab[] = {
362
363#define BULK(name, pre, prim) \
364 { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt }
365
366 BULK("v0", v0, BCP_CIPHER | BCP_MAC),
b87bffcb 367 BULK("iiv", iiv, BCP_CIPHER | BCP_MAC | BCP_BLKC),
a93aacce
MW
368
369#undef BULK
370 { 0 }
371};
372
373/*----- That's all, folks -------------------------------------------------*/