chiark / gitweb /
Initial support for BSD tunnel devices.
[tripe] / keyset.c
CommitLineData
410c8acf 1/* -*-c-*-
2 *
3 * $Id: keyset.c,v 1.1 2001/02/03 20:26:37 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.1 2001/02/03 20:26:37 mdw
33 * Initial checkin.
34 *
35 */
36
37/*----- Header files ------------------------------------------------------*/
38
39#include "tripe.h"
40
41/*----- Tunable parameters ------------------------------------------------*/
42
43#define KEY_EXPTIME MIN(60) /* Expiry time for a key */
44#define KEY_REGENTIME MIN(45) /* Regeneration time for a key */
45#define KEY_EXPSZ MEG(512) /* Expiry data size for a key */
46#define KEY_REGENSZ MEG(256) /* Data size threshold for regen */
47
48/*----- Handy macros ------------------------------------------------------*/
49
50#define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now)
51
52/*----- Main code ---------------------------------------------------------*/
53
54/* --- @freeks@ --- *
55 *
56 * Arguments: @keyset *ks@ = pointer to a keyset
57 *
58 * Returns: ---
59 *
60 * Use: Frees a keyset.
61 */
62
63static void freeks(keyset *ks)
64{
65 ks->c->ops->destroy(ks->c);
66 ks->m->ops->destroy(ks->m);
67 DESTROY(ks);
68}
69
70/* --- @ks_free@ --- *
71 *
72 * Arguments: @keyset **ksroot@ = pointer to keyset list head
73 *
74 * Returns: ---
75 *
76 * Use: Frees all of the keys in a keyset.
77 */
78
79void ks_free(keyset **ksroot)
80{
81 keyset *ks, *ksn;
82 for (ks = *ksroot; ks; ks = ksn) {
83 ksn = ks->next;
84 freeks(ks);
85 }
86}
87
88/* --- @ks_prune@ --- *
89 *
90 * Arguments: @keyset **ksroot@ = pointer to keyset list head
91 *
92 * Returns: ---
93 *
94 * Use: Prunes the keyset list by removing keys which mustn't be used
95 * any more.
96 */
97
98void ks_prune(keyset **ksroot)
99{
100 time_t now = time(0);
101
102 while (*ksroot) {
103 keyset *ks = *ksroot;
104 if (ks->t_exp <= now) {
105 T( trace(T_KEYSET, "keyset: expiring keyset %u (time limit reached)",
106 ks->seq); )
107 *ksroot = ks->next;
108 freeks(ks);
109 } else if (ks->sz_exp == 0) {
110 T( trace(T_KEYSET, "keyset: expiring keyset %u (data limit reached)",
111 ks->seq); )
112 *ksroot = ks->next;
113 freeks(ks);
114 } else
115 ksroot = &ks->next;
116 }
117}
118
119/* --- @ks_gen@ --- *
120 *
121 * Arguments: @keyset **ksroot@ = pointer to keyset list head
122 * @const void *k@ = pointer to key material
123 * @size_t sz@ = size of the key material
124 *
125 * Returns: The regeneration time for the new key.
126 *
127 * Use: Derives a keyset from the given key material and adds it to
128 * the list.
129 */
130
131time_t ks_gen(keyset **ksroot, const void *k, size_t sz)
132{
133 rmd160_ctx r;
134 octet buf[RMD160_HASHSZ];
135 keyset *ks = CREATE(keyset);
136 time_t now = time(0);
137 T( static unsigned seq = 0; )
138
139 T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
140
141#define GETHASH(str) do { \
142 rmd160_init(&r); \
143 rmd160_hash(&r, str, sizeof(str) - 1); \
144 rmd160_hash(&r, k, sz); \
145 rmd160_done(&r, buf); \
146 IF_TRACING(T_KEYSET, { \
147 trace_block(T_CRYPTO, "crypto: key " str, buf, sizeof(buf)); \
148 }) \
149} while (0)
150
151 GETHASH("tripe-encryption "); ks->c = blowfish_cbc.init(buf, sizeof(buf));
152 GETHASH("tripe-integrity "); ks->m = rmd160_hmac.key(buf, sizeof(buf));
153
154#undef GETHASH
155
156 T( ks->seq = seq++; )
157 ks->t_exp = now + KEY_EXPTIME;
158 ks->sz_exp = KEY_EXPSZ;
159 ks->next = *ksroot;
160 *ksroot = ks;
161 BURN(buf);
162 return (now + KEY_REGENTIME);
163}
164
165/* --- @ks_encrypt@ --- *
166 *
167 * Arguments: @keyset **ksroot@ = pointer to keyset list head
168 * @buf *b@ = pointer to input buffer
169 * @buf *bb@ = pointer to output buffer
170 *
171 * Returns: Nonzero if a new key is needed.
172 *
173 * Use: Encrypts a packet.
174 */
175
176int ks_encrypt(keyset **ksroot, buf *b, buf *bb)
177{
178 time_t now = time(0);
179 keyset *ks;
180 ghash *h;
181 gcipher *c;
182 size_t ivsz;
183 const octet *p = BCUR(b);
184 octet *q = BCUR(bb);
185 size_t sz = BLEFT(b);
186 size_t osz, nsz;
187 int rc = 0;
188
189 /* --- Get the latest valid key --- */
190
191 ks = *ksroot;
192 for (;;) {
193 if (!ks) {
194 T( trace(T_KEYSET, "keyset: no active keys -- forcing exchange"); )
195 buf_break(bb);
196 return (-1);
197 }
198 if (KEYOK(ks, now))
199 break;
200 ks = ks->next;
201 }
202
203 /* --- MAC and encrypt the packet --- */
204
205 c = ks->c;
206 ivsz = c->ops->c->blksz;
207 if (buf_ensure(bb, ivsz + sz))
208 return (0);
209 h = ks->m->ops->init(ks->m);
210 h->ops->hash(h, p, sz);
211 h->ops->done(h, q);
212 IF_TRACING(T_KEYSET, {
213 trace(T_KEYSET, "keyset: encrypting using keyset %u", ks->seq);
214 trace_block(T_CRYPTO, "crypto: computed MAC", q, ivsz);
215 })
216 c->ops->setiv(c, q);
217 h->ops->destroy(h);
218
219 if (buf_ensure(bb, sz))
220 return (0);
221 c->ops->encrypt(c, p, q + ivsz, sz);
222 IF_TRACING(T_KEYSET, {
223 trace_block(T_CRYPTO, "crypto: encrypted packet", q + ivsz, sz);
224 })
225 BSTEP(bb, ivsz + sz);
226
227 /* --- Deduct the packet size from the key's data life --- */
228
229 osz = ks->sz_exp;
230 if (osz > sz)
231 nsz = osz - sz;
232 else
233 nsz = 0;
234 if (osz >= KEY_REGENSZ && nsz < KEY_REGENSZ) {
235 T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
236 "forcing exchange", ks->seq); )
237 rc = -1;
238 }
239 ks->sz_exp = nsz;
240 return (rc);
241}
242
243/* --- @ks_decrypt@ --- *
244 *
245 * Arguments: @keyset **ksroot@ = pointer to keyset list head
246 * @buf *b@ = pointer to input buffer
247 * @buf *bb@ = pointer to output buffer
248 *
249 * Returns: Nonzero if the packet couldn't be decrypted.
250 *
251 * Use: Decrypts a packet.
252 */
253
254int ks_decrypt(keyset **ksroot, buf *b, buf *bb)
255{
256 time_t now = time(0);
257 const octet *pp = BCUR(b);
258 const octet *p;
259 size_t sz = BLEFT(b);
260 octet *q = BCUR(bb);
261 keyset *ks;
262
263 T( trace(T_KEYSET, "keyset: attempting to decrypt packet"); )
264 if (buf_ensure(bb, sz))
265 return (-1);
266 for (ks = *ksroot; ks; ks = ks->next) {
267 ghash *h;
268 gcipher *c = ks->c;
269 size_t ivsz = c->ops->c->blksz;
270 octet *mac;
271 int eq;
272
273 if (!KEYOK(ks, now))
274 continue;
275 if (sz < ivsz) {
276 T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
277 continue;
278 }
279 p = pp + ivsz;
280 c->ops->setiv(c, pp);
281 c->ops->decrypt(c, p, q, sz - ivsz);
282 h = ks->m->ops->init(ks->m);
283 h->ops->hash(h, q, sz - ivsz);
284 mac = h->ops->done(h, 0);
285 eq = !memcmp(mac, pp, ivsz);
286 IF_TRACING(T_KEYSET, {
287 trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq);
288 trace_block(T_CRYPTO, "crypto: computed MAC", mac, ivsz);
289 })
290 h->ops->destroy(h);
291 if (eq) {
292 BSTEP(bb, sz - ivsz);
293 IF_TRACING(T_KEYSET, {
294 trace(T_KEYSET, "keyset: decrypted OK");
295 trace_block(T_CRYPTO, "crypto: decrypted packet", q, sz - ivsz);
296 })
297 return (0);
298 }
299 IF_TRACING(T_KEYSET, {
300 trace(T_KEYSET, "keyset: decryption failed");
301 trace_block(T_CRYPTO, "crypto: expected MAC", pp, ivsz);
302 })
303 }
304 T( trace(T_KEYSET, "keyset: no matching keys"); )
305 return (-1);
306}
307
308/*----- That's all, folks -------------------------------------------------*/