chiark / gitweb /
Fix stupid bug.
[tripe] / keyset.c
1 /* -*-c-*-
2  *
3  * $Id: keyset.c,v 1.6 2003/04/06 10:26:35 mdw Exp $
4  *
5  * Handling of symmetric keysets
6  *
7  * (c) 2001 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Trivial IP Encryption (TrIPE).
13  *
14  * TrIPE is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * TrIPE is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with TrIPE; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: keyset.c,v $
32  * Revision 1.6  2003/04/06 10:26:35  mdw
33  * Report peer name on decrypt errors.
34  *
35  * Revision 1.5  2001/06/19 22:07:43  mdw
36  * Change the encrypted packet format to be non-malleable.
37  *
38  * Revision 1.4  2001/06/16 14:06:40  mdw
39  * Quantify collision probabilities for the stated data volume bounds.
40  *
41  * Revision 1.3  2001/02/16 21:39:55  mdw
42  * Major overhaul.  Separate functions for manipulating keysets from
43  * functions for manipulating keyset lists.  Introduce a concept of
44  * listening-only keys.
45  *
46  * Revision 1.2  2001/02/05 19:53:23  mdw
47  * Add sequence number protection.
48  *
49  * Revision 1.1  2001/02/03 20:26:37  mdw
50  * Initial checkin.
51  *
52  */
53
54 /*----- Header files ------------------------------------------------------*/
55
56 #include "tripe.h"
57
58 /*----- Tunable parameters ------------------------------------------------*/
59
60 /* --- Note on size limits --- *
61  *
62  * For a 64-bit block cipher (e.g., Blowfish), the probability of a collision
63  * occurring after 32 MB is less than %$2^{-21}$%, and the probability of a
64  * collision occurring after 64 MB is less than %$2^{-19}$%.
65  */
66
67 #define T_EXP MIN(60)                   /* Expiry time for a key */
68 #define T_REGEN MIN(45)                 /* Regeneration time for a key */
69 #define SZ_EXP MEG(64)                  /* Expiry data size for a key */
70 #define SZ_REGEN MEG(32)                /* Data size threshold for regen */
71
72 /*----- Handy macros ------------------------------------------------------*/
73
74 #define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now)
75
76 /*----- Low-level packet encryption and decryption ------------------------*/
77
78 /* --- Encrypted data format --- *
79  *
80  * Let %$p_i$% be the %$i$%-th plaintext message.  We first compute
81  *
82  *   %$c_i = \mathcal{E}\textrm{-CBC}_{K_{\text{E}}}(p_i)$%
83  *
84  * as the CBC-ciphertext of %$p_i$%, and then
85  *
86  *   %$\sigma_i = \mathcal{T}_{K_{\text{M}}}(i, c_i)$%
87  *
88  * as a MAC on the %%\emph{ciphertext}%%.  The message sent is then the pair
89  * %$(\sigma_i, c_i)$%.  This construction is provably secure in the NM-CCA
90  * sense (assuming that the cipher is IND-CPA, and the MAC is SUF-CMA)
91  * [Bellare and Namprempre].
92  *
93  * This also ensures that, assuming the key is good, we have a secure channel
94  * [Krawczyk].  Actually, [Krawczyk] shows that, if the cipher is either a
95  * simple stream cipher or a block cipher in CBC mode, we can use the MAC-
96  * then-encrypt scheme and still have a secure channel.  However, I like the
97  * NM-CCA guarantee from [Bellare and Namprempre].  I'm less worried about
98  * the Horton Principle [Wagner and Schneier].
99  */
100
101 /* --- @doencrypt@ --- *
102  *
103  * Arguments:   @keyset *ks@ = pointer to keyset to use
104  *              @buf *b@ = pointer to an input buffer
105  *              @buf *bb@ = pointer to an output buffer
106  *
107  * Returns:     Zero if OK, nonzero if a new key is required.
108  *
109  * Use:         Encrypts a message with the given key.  We assume that the
110  *              keyset is OK to use.
111  */
112
113 static int doencrypt(keyset *ks, buf *b, buf *bb)
114 {
115   ghash *h;
116   gcipher *c;
117   const octet *p = BCUR(b);
118   size_t sz = BLEFT(b);
119   octet *qmac, *qseq, *qiv, *qpk;
120   uint32 oseq;
121   size_t osz, nsz;
122   int rc = 0;
123
124   /* --- Allocate the required buffer space --- */
125
126   c = ks->cout;
127   if (buf_ensure(bb, MACSZ + SEQSZ + IVSZ + sz))
128     return (0); /* Caution! */
129   qmac = BCUR(bb); qseq = qmac + MACSZ; qiv = qseq + SEQSZ; qpk = qiv + IVSZ;
130   BSTEP(bb, MACSZ + SEQSZ + IVSZ + sz);
131
132   /* --- Encrypt the packet --- */
133
134   oseq = ks->oseq++; STORE32(qseq, oseq);
135   rand_get(RAND_GLOBAL, qiv, IVSZ);
136   c->ops->setiv(c, qiv);
137   c->ops->encrypt(c, p, qpk, sz);
138   IF_TRACING(T_KEYSET, {
139     trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u",
140           (unsigned long)oseq, ks->seq);
141     trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz);
142   })
143
144   /* --- Now compute the MAC --- */
145
146   h = ks->mout->ops->init(ks->mout);
147   h->ops->hash(h, qseq, SEQSZ + IVSZ + sz);
148   memcpy(qmac, h->ops->done(h, 0), MACSZ);
149   h->ops->destroy(h);
150   IF_TRACING(T_KEYSET, {
151     trace_block(T_CRYPTO, "crypto: computed MAC", qmac, MACSZ);
152   })
153
154   /* --- Deduct the packet size from the key's data life --- */
155
156   osz = ks->sz_exp;
157   if (osz > sz)
158     nsz = osz - sz;
159   else
160     nsz = 0;
161   if (osz >= SZ_REGEN && nsz < SZ_REGEN) {
162     T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
163              "forcing exchange", ks->seq); )
164     rc = -1;
165   }
166   ks->sz_exp = nsz;
167   return (rc);  
168 }
169
170 /* --- @dodecrypt@ --- *
171  *
172  * Arguments:   @keyset *ks@ = pointer to keyset to use
173  *              @buf *b@ = pointer to an input buffer
174  *              @buf *bb@ = pointer to an output buffer
175  *              @uint32 *seq@ = where to store the sequence number
176  *
177  * Returns:     Zero if OK, nonzero if it failed.
178  *
179  * Use:         Attempts to decrypt a message with the given key.  No other
180  *              checking (e.g., sequence number checks) is performed.  We
181  *              assume that the keyset is OK to use, and that there is
182  *              sufficient output buffer space reserved.  If the decryption
183  *              is successful, the buffer pointer is moved past the decrypted
184  *              packet, and the packet's sequence number is stored in @*seq@.
185  */
186
187 static int dodecrypt(keyset *ks, buf *b, buf *bb, uint32 *seq)
188 {
189   const octet *pmac, *piv, *pseq, *ppk;
190   size_t psz = BLEFT(b);
191   size_t sz;
192   octet *q = BCUR(bb);
193   ghash *h;
194   gcipher *c = ks->cin;
195   size_t ivsz = c->ops->c->blksz;
196   octet *mac;
197   int eq;
198
199   /* --- Break up the packet into its components --- */
200
201   if (psz < ivsz + 4) {
202     T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
203     return (-1);
204   }
205   sz = psz - IVSZ - SEQSZ - MACSZ;
206   pmac = BCUR(b); pseq = pmac + MACSZ; piv = pseq + SEQSZ; ppk = piv + IVSZ;
207
208   /* --- Verify the MAC on the packet --- */
209
210   h = ks->min->ops->init(ks->min);
211   h->ops->hash(h, pseq, SEQSZ + IVSZ + sz);
212   mac = h->ops->done(h, 0);
213   eq = !memcmp(mac, pmac, MACSZ);
214   IF_TRACING(T_KEYSET, {
215     trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq);
216     trace_block(T_CRYPTO, "crypto: computed MAC", mac, MACSZ);
217   })
218   h->ops->destroy(h);
219   if (!eq) {
220     a_warn("incorrect MAC on packet from `%s'", p_name(ks->p));
221     IF_TRACING(T_KEYSET, {
222       trace(T_KEYSET, "keyset: decryption failed");
223       trace_block(T_CRYPTO, "crypto: expected MAC", pmac, MACSZ);
224     })
225     return (-1);
226   }
227
228   /* --- Decrypt the packet --- */
229
230   c->ops->setiv(c, piv);
231   c->ops->decrypt(c, ppk, q, sz);
232   if (seq)
233     *seq = LOAD32(pseq);
234   IF_TRACING(T_KEYSET, {
235     trace(T_KEYSET, "keyset: decrypted OK (sequence = %lu)",
236           (unsigned long)LOAD32(pseq));
237     trace_block(T_CRYPTO, "crypto: decrypted packet", q, sz);
238   })
239   BSTEP(bb, sz);
240   return (0);
241 }
242
243 /* --- @dosequence@ --- *
244  *
245  * Arguments:   @keyset *ks@ = pointer to a keyset
246  *              @uint32 seq@ = a sequence number from a packet
247  *
248  * Returns:     Zero if the sequence number is OK, nonzero if it's not.
249  *
250  * Use:         Checks a sequence number.  The data in the keyset which keeps
251  *              track of valid sequence numbers is updated if the sequence
252  *              number given is good.  It's assumed that the sequence number
253  *              has already been checked for authenticity.
254  */
255
256 static int dosequence(keyset *ks, uint32 seq)
257 {
258   uint32 seqbit;
259   uint32 n;
260
261   if (seq < ks->iseq) {
262     a_warn("received packet has old sequence number (possible replay)");
263     return (-1);
264   }
265   if (seq >= ks->iseq + KS_SEQWINSZ) {
266     n = seq - (ks->iseq + KS_SEQWINSZ - 1);
267     if (n < KS_SEQWINSZ)
268       ks->iwin >>= n;
269     else
270       ks->iwin = 0;
271     ks->iseq += n;
272   }
273   seqbit = 1 << (seq - ks->iseq);
274   if (ks->iwin & seqbit) {
275     a_warn("received packet repeats old sequence number");
276     return (-1);
277   }
278   ks->iwin |= seqbit;
279   return (0);
280 }
281
282 /*----- Operations on a single keyset -------------------------------------*/
283
284 /* --- @ks_drop@ --- *
285  *
286  * Arguments:   @keyset *ks@ = pointer to a keyset
287  *
288  * Returns:     ---
289  *
290  * Use:         Decrements a keyset's reference counter.  If the counter hits
291  *              zero, the keyset is freed.
292  */
293
294 void ks_drop(keyset *ks)
295 {
296   if (--ks->ref)
297     return;
298   ks->cin->ops->destroy(ks->cin);
299   ks->cout->ops->destroy(ks->cout);
300   ks->min->ops->destroy(ks->min);
301   ks->mout->ops->destroy(ks->mout);
302   DESTROY(ks);
303 }
304
305 /* --- @ks_gen@ --- *
306  *
307  * Arguments:   @const void *k@ = pointer to key material
308  *              @size_t x, y, z@ = offsets into key material (see below)
309  *              @peer *p@ = pointer to peer information 
310  *
311  * Returns:     A pointer to the new keyset.
312  *
313  * Use:         Derives a new keyset from the given key material.  The
314  *              offsets @x@, @y@ and @z@ separate the key material into three
315  *              parts.  Between the @k@ and @k + x@ is `my' contribution to
316  *              the key material; between @k + x@ and @k + y@ is `your'
317  *              contribution; and between @k + y@ and @k + z@ is a shared
318  *              value we made together.  These are used to construct two
319  *              pairs of symmetric keys.  Each pair consists of an encryption
320  *              key and a message authentication key.  One pair is used for
321  *              outgoing messages, the other for incoming messages.
322  *
323  *              The new key is marked so that it won't be selected for output
324  *              by @ksl_encrypt@.  You can still encrypt data with it by
325  *              calling @ks_encrypt@ directly.
326  */
327
328 keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
329 {
330   HASH_CTX h;
331   octet buf[HASHSZ];
332   keyset *ks = CREATE(keyset);
333   time_t now = time(0);
334   const octet *pp = k;
335   T( static unsigned seq = 0; )
336
337   T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
338
339   /* --- Construct the various keys --- *
340    *
341    * This is done with macros, because it's quite tedious.
342    */
343
344 #define MINE HASH(&h, pp, x)
345 #define YOURS HASH(&h, pp + x, y - x)
346 #define OURS HASH(&h, pp + y, z - y)
347
348 #define IN MINE; YOURS; OURS
349 #define OUT YOURS; MINE; OURS
350 #define STR_IN "incoming"
351 #define STR_OUT "outgoing"
352
353 #define GETHASH(str, dir) do {                                          \
354   HASH_INIT(&h);                                                        \
355   HASH_STRING(&h, "tripe-" str);                                        \
356   dir;                                                                  \
357   HASH_DONE(&h, buf);                                                   \
358   IF_TRACING(T_KEYSET, {                                                \
359     trace_block(T_CRYPTO, "crypto: " STR_##dir " key " str,             \
360                 buf, sizeof(buf));                                      \
361   })                                                                    \
362 } while (0)
363
364   GETHASH("encryption", IN); ks->cin = CIPHER->init(buf, sizeof(buf));
365   GETHASH("integrity", IN); ks->min = MAC->key(buf, sizeof(buf));
366   GETHASH("encryption", OUT); ks->cout = CIPHER->init(buf, sizeof(buf));
367   GETHASH("integrity", OUT); ks->mout = MAC->key(buf, sizeof(buf));
368
369 #undef MINE
370 #undef YOURS
371 #undef OURS
372 #undef IN
373 #undef OUT
374 #undef STR_IN
375 #undef STR_OUT
376 #undef GETHASH
377
378   T( ks->seq = seq++; )
379   ks->t_exp = now + T_EXP;
380   ks->sz_exp = SZ_EXP;
381   ks->oseq = ks->iseq = 0;
382   ks->iwin = 0;
383   ks->next = 0;
384   ks->p = p;
385   ks->f = KSF_LISTEN;
386   BURN(buf);
387   return (ks);
388 }
389
390 /* --- @ks_tregen@ --- *
391  *
392  * Arguments:   @keyset *ks@ = pointer to a keyset
393  *
394  * Returns:     The time at which moves ought to be made to replace this key.
395  */
396
397 time_t ks_tregen(keyset *ks) { return (ks->t_exp - T_EXP + T_REGEN); }
398
399 /* --- @ks_activate@ --- *
400  *
401  * Arguments:   @keyset *ks@ = pointer to a keyset
402  *
403  * Returns:     ---
404  *
405  * Use:         Activates a keyset, so that it can be used for encrypting
406  *              outgoing messages.
407  */
408
409 void ks_activate(keyset *ks)
410 {
411   if (ks->f & KSF_LISTEN) {
412     T( trace(T_KEYSET, "keyset: activating keyset %u", ks->seq); )
413     ks->f &= ~KSF_LISTEN;
414   }
415 }
416
417 /* --- @ks_encrypt@ --- *
418  *
419  * Arguments:   @keyset *ks@ = pointer to a keyset
420  *              @buf *b@ = pointer to input buffer
421  *              @buf *bb@ = pointer to output buffer
422  *
423  * Returns:     Zero if OK, nonzero if the key needs replacing.  If the
424  *              encryption failed, the output buffer is broken and zero is
425  *              returned.
426  *
427  * Use:         Encrypts a block of data using the key.  Note that the `key
428  *              ought to be replaced' notification is only ever given once
429  *              for each key.  Also note that this call forces a keyset to be
430  *              used even if it's marked as not for data output.
431  */
432
433 int ks_encrypt(keyset *ks, buf *b, buf *bb)
434 {
435   time_t now = time(0);
436
437   if (!KEYOK(ks, now)) {
438     buf_break(bb);
439     return (0);
440   }
441   return (doencrypt(ks, b, bb));
442 }
443
444 /* --- @ks_decrypt@ --- *
445  *
446  * Arguments:   @keyset *ks@ = pointer to a keyset
447  *              @buf *b@ = pointer to an input buffer
448  *              @buf *bb@ = pointer to an output buffer
449  *
450  * Returns:     Zero on success, or nonzero if there was some problem.
451  *
452  * Use:         Attempts to decrypt a message using a given key.  Note that
453  *              requesting decryption with a key directly won't clear a
454  *              marking that it's not for encryption.
455  */
456
457 int ks_decrypt(keyset *ks, buf *b, buf *bb)
458 {
459   time_t now = time(0);
460   uint32 seq;
461
462   if (!KEYOK(ks, now) ||
463       buf_ensure(bb, BLEN(b)) ||
464       dodecrypt(ks, b, bb, &seq) ||
465       dosequence(ks, seq))
466     return (-1);
467   return (0);
468 }
469
470 /*----- Keyset list handling ----------------------------------------------*/
471
472 /* --- @ksl_free@ --- *
473  *
474  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
475  *
476  * Returns:     ---
477  *
478  * Use:         Frees (releases references to) all of the keys in a keyset.
479  */
480
481 void ksl_free(keyset **ksroot)
482 {
483   keyset *ks, *ksn;
484   for (ks = *ksroot; ks; ks = ksn) {
485     ksn = ks->next;
486     ks->f &= ~KSF_LINK;
487     ks_drop(ks);
488   }
489 }
490
491 /* --- @ksl_link@ --- *
492  *
493  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
494  *              @keyset *ks@ = pointer to a keyset
495  *
496  * Returns:     ---
497  *
498  * Use:         Links a keyset into a list.  A keyset can only be on one list
499  *              at a time.  Bad things happen otherwise.
500  */
501
502 void ksl_link(keyset **ksroot, keyset *ks)
503 {
504   assert(!(ks->f & KSF_LINK));
505   ks->next = *ksroot;
506   *ksroot = ks;
507   ks->f |= KSF_LINK;
508   ks->ref++;
509 }
510
511 /* --- @ksl_prune@ --- *
512  *
513  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
514  *
515  * Returns:     ---
516  *
517  * Use:         Prunes the keyset list by removing keys which mustn't be used
518  *              any more.
519  */
520
521 void ksl_prune(keyset **ksroot)
522 {
523   time_t now = time(0);
524
525   while (*ksroot) {
526     keyset *ks = *ksroot;
527
528     if (ks->t_exp <= now) {
529       T( trace(T_KEYSET, "keyset: expiring keyset %u (time limit reached)",
530                ks->seq); )
531       goto kill;
532     } else if (ks->sz_exp == 0) {
533       T( trace(T_KEYSET, "keyset: expiring keyset %u (data limit reached)",
534                ks->seq); )
535       goto kill;
536     } else {
537       ksroot = &ks->next;
538       continue;
539     }
540
541   kill:
542     *ksroot = ks->next;
543     ks->f &= ~KSF_LINK;
544     ks_drop(ks);
545   }
546 }
547
548 /* --- @ksl_encrypt@ --- *
549  *
550  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
551  *              @buf *b@ = pointer to input buffer
552  *              @buf *bb@ = pointer to output buffer
553  *
554  * Returns:     Nonzero if a new key is needed.
555  *
556  * Use:         Encrypts a packet.
557  */
558
559 int ksl_encrypt(keyset **ksroot, buf *b, buf *bb)
560 {
561   time_t now = time(0);
562   keyset *ks = *ksroot;
563
564   for (;;) {
565     if (!ks) {
566       T( trace(T_KEYSET, "keyset: no suitable keysets found"); )
567       buf_break(bb);
568       return (-1);
569     }
570     if (KEYOK(ks, now) && !(ks->f & KSF_LISTEN))
571       break;
572     ks = ks->next;
573   }
574
575   return (doencrypt(ks, b, bb));
576 }
577
578 /* --- @ksl_decrypt@ --- *
579  *
580  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
581  *              @buf *b@ = pointer to input buffer
582  *              @buf *bb@ = pointer to output buffer
583  *
584  * Returns:     Nonzero if the packet couldn't be decrypted.
585  *
586  * Use:         Decrypts a packet.
587  */
588
589 int ksl_decrypt(keyset **ksroot, buf *b, buf *bb)
590 {
591   time_t now = time(0);
592   keyset *ks;
593   uint32 seq;
594
595   if (buf_ensure(bb, BLEN(b)))
596     return (-1);
597
598   for (ks = *ksroot; ks; ks = ks->next) {
599     if (!KEYOK(ks, now))
600       continue;
601     if (!dodecrypt(ks, b, bb, &seq)) {
602       if (ks->f & KSF_LISTEN) {
603         T( trace(T_KEYSET, "keyset: implicitly activating keyset %u",
604                  ks->seq); )
605         ks->f &= ~KSF_LISTEN;
606       }
607       return (dosequence(ks, seq));
608     }
609   }
610   T( trace(T_KEYSET, "keyset: no matching keys"); )
611   return (-1);
612 }
613
614 /*----- That's all, folks -------------------------------------------------*/