3 * $Id: keyset.c,v 1.2 2001/02/05 19:53:23 mdw Exp $
5 * Handling of symmetric keysets
7 * (c) 2001 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Trivial IP Encryption (TrIPE).
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.
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.
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.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.2 2001/02/05 19:53:23 mdw
33 * Add sequence number protection.
35 * Revision 1.1 2001/02/03 20:26:37 mdw
40 /*----- Header files ------------------------------------------------------*/
44 /*----- Tunable parameters ------------------------------------------------*/
46 #define KEY_EXPTIME MIN(60) /* Expiry time for a key */
47 #define KEY_REGENTIME MIN(45) /* Regeneration time for a key */
48 #define KEY_EXPSZ MEG(512) /* Expiry data size for a key */
49 #define KEY_REGENSZ MEG(256) /* Data size threshold for regen */
51 /*----- Handy macros ------------------------------------------------------*/
53 #define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now)
55 /*----- Main code ---------------------------------------------------------*/
59 * Arguments: @keyset *ks@ = pointer to a keyset
63 * Use: Frees a keyset.
66 static void freeks(keyset *ks)
68 ks->c->ops->destroy(ks->c);
69 ks->m->ops->destroy(ks->m);
73 /* --- @ks_free@ --- *
75 * Arguments: @keyset **ksroot@ = pointer to keyset list head
79 * Use: Frees all of the keys in a keyset.
82 void ks_free(keyset **ksroot)
85 for (ks = *ksroot; ks; ks = ksn) {
91 /* --- @ks_prune@ --- *
93 * Arguments: @keyset **ksroot@ = pointer to keyset list head
97 * Use: Prunes the keyset list by removing keys which mustn't be used
101 void ks_prune(keyset **ksroot)
103 time_t now = time(0);
106 keyset *ks = *ksroot;
107 if (ks->t_exp <= now) {
108 T( trace(T_KEYSET, "keyset: expiring keyset %u (time limit reached)",
112 } else if (ks->sz_exp == 0) {
113 T( trace(T_KEYSET, "keyset: expiring keyset %u (data limit reached)",
122 /* --- @ks_gen@ --- *
124 * Arguments: @keyset **ksroot@ = pointer to keyset list head
125 * @const void *k@ = pointer to key material
126 * @size_t sz@ = size of the key material
128 * Returns: The regeneration time for the new key.
130 * Use: Derives a keyset from the given key material and adds it to
134 time_t ks_gen(keyset **ksroot, const void *k, size_t sz)
137 octet buf[RMD160_HASHSZ];
138 keyset *ks = CREATE(keyset);
139 time_t now = time(0);
140 T( static unsigned seq = 0; )
142 T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
144 #define GETHASH(str) do { \
146 rmd160_hash(&r, str, sizeof(str) - 1); \
147 rmd160_hash(&r, k, sz); \
148 rmd160_done(&r, buf); \
149 IF_TRACING(T_KEYSET, { \
150 trace_block(T_CRYPTO, "crypto: key " str, buf, sizeof(buf)); \
154 GETHASH("tripe-encryption "); ks->c = blowfish_cbc.init(buf, sizeof(buf));
155 GETHASH("tripe-integrity "); ks->m = rmd160_hmac.key(buf, sizeof(buf));
159 T( ks->seq = seq++; )
160 ks->t_exp = now + KEY_EXPTIME;
161 ks->sz_exp = KEY_EXPSZ;
162 ks->oseq = ks->iseq = 0;
167 return (now + KEY_REGENTIME);
170 /* --- @ks_encrypt@ --- *
172 * Arguments: @keyset **ksroot@ = pointer to keyset list head
173 * @buf *b@ = pointer to input buffer
174 * @buf *bb@ = pointer to output buffer
176 * Returns: Nonzero if a new key is needed.
178 * Use: Encrypts a packet.
181 int ks_encrypt(keyset **ksroot, buf *b, buf *bb)
183 time_t now = time(0);
188 const octet *p = BCUR(b);
189 size_t sz = BLEFT(b);
190 octet *qiv, *qseq, *qpk;
195 /* --- Get the latest valid key --- */
200 T( trace(T_KEYSET, "keyset: no active keys -- forcing exchange"); )
209 /* --- Allocate the required buffer space --- */
212 ivsz = c->ops->c->blksz;
213 if (buf_ensure(bb, ivsz + 4 + sz)) return (0);
214 qiv = BCUR(bb); qseq = qiv + ivsz; qpk = qseq + 4;
215 BSTEP(bb, ivsz + 4 + sz);
217 /* --- MAC and encrypt the packet --- */
219 oseq = ks->oseq++; STORE32(qseq, oseq);
220 h = ks->m->ops->init(ks->m);
221 h->ops->hash(h, qseq, 4);
222 h->ops->hash(h, p, sz);
223 memcpy(qiv, h->ops->done(h, 0), ivsz);
225 IF_TRACING(T_KEYSET, {
226 trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u",
227 (unsigned long)oseq, ks->seq);
228 trace_block(T_CRYPTO, "crypto: computed MAC", qiv, ivsz);
230 c->ops->setiv(c, qiv);
231 c->ops->encrypt(c, p, qpk, sz);
232 IF_TRACING(T_KEYSET, {
233 trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz);
236 /* --- Deduct the packet size from the key's data life --- */
243 if (osz >= KEY_REGENSZ && nsz < KEY_REGENSZ) {
244 T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
245 "forcing exchange", ks->seq); )
252 /* --- @ks_decrypt@ --- *
254 * Arguments: @keyset **ksroot@ = pointer to keyset list head
255 * @buf *b@ = pointer to input buffer
256 * @buf *bb@ = pointer to output buffer
258 * Returns: Nonzero if the packet couldn't be decrypted.
260 * Use: Decrypts a packet.
263 int ks_decrypt(keyset **ksroot, buf *b, buf *bb)
265 time_t now = time(0);
266 const octet *piv, *pseq, *ppk;
267 size_t psz = BLEFT(b);
274 /* --- Allocate space in the output buffer --- */
276 T( trace(T_KEYSET, "keyset: attempting to decrypt packet"); )
277 if (buf_ensure(bb, psz))
280 /* --- Try all of the valid keys --- */
282 for (ks = *ksroot; ks; ks = ks->next) {
285 size_t ivsz = c->ops->c->blksz;
289 /* --- Break up the packet into its components --- */
293 if (psz < ivsz + 4) {
294 T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
298 piv = BCUR(b); pseq = piv + ivsz; ppk = pseq + 4;
300 /* --- Attempt to decrypt the packet --- */
302 c->ops->setiv(c, piv);
303 c->ops->decrypt(c, ppk, q, sz);
304 h = ks->m->ops->init(ks->m);
305 h->ops->hash(h, pseq, 4);
306 h->ops->hash(h, q, sz);
307 mac = h->ops->done(h, 0);
308 eq = !memcmp(mac, piv, ivsz);
309 IF_TRACING(T_KEYSET, {
310 trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq);
311 trace_block(T_CRYPTO, "crypto: computed MAC", mac, ivsz);
318 IF_TRACING(T_KEYSET, {
319 trace(T_KEYSET, "keyset: decryption failed");
320 trace_block(T_CRYPTO, "crypto: expected MAC", piv, ivsz);
321 trace_block(T_CRYPTO, "crypto: invalid packet", q, sz);
324 T( trace(T_KEYSET, "keyset: no matching keys"); )
327 /* --- We've found a match, so check the sequence number --- */
331 IF_TRACING(T_KEYSET, {
332 trace(T_KEYSET, "keyset: decrypted OK (sequence = %lu)",
333 (unsigned long)iseq);
334 trace_block(T_CRYPTO, "crypto: decrypted packet", q, sz);
336 if (iseq < ks->iseq) {
337 a_warn("received packet has old sequence number (possible replay)");
340 if (iseq >= ks->iseq + KS_SEQWINSZ) {
341 uint32 n = iseq - (ks->iseq + KS_SEQWINSZ - 1);
348 seqbit = 1 << (iseq - ks->iseq);
349 if (ks->iwin & seqbit) {
350 a_warn("received packet repeats old sequence number");
357 /*----- That's all, folks -------------------------------------------------*/