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 -------------------------------------------------*/