1 /* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */
2
3 /*-
4 * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
38 #include <sys/syslog.h>
39 #include <sys/mbuf.h>
40
41 #include <net/if.h>
42 #include <net/route.h>
43
44 #include <netinet/in.h>
45
46 #include <netinet6/ipsec.h>
47 #include <netinet6/esp.h>
48 #include <netinet6/esp_aesctr.h>
49
50 #include <netproto/key/key.h>
51
52 #include <crypto/rijndael/rijndael.h>
53
54 #define AES_BLOCKSIZE 16
55
56 #define NONCESIZE 4
57 union cblock {
58 struct {
59 u_int8_t nonce[4];
60 u_int8_t iv[8];
61 u_int32_t ctr;
62 } __packed v;
63 u_int8_t cblock[16];
64 };
65
66 typedef struct {
67 u_int32_t r_ek[(RIJNDAEL_MAXNR+1)*4];
68 int r_nr; /* key-length-dependent number of rounds */
69 } aesctr_ctx;
70
71 int
72 esp_aesctr_mature(struct secasvar *sav)
73 {
74 int keylen;
75 const struct esp_algorithm *algo;
76
77 algo = esp_algorithm_lookup(sav->alg_enc);
78 if (!algo) {
79 ipseclog((LOG_ERR,
80 "esp_aeesctr_mature: unsupported algorithm %d\n",
81 sav->alg_enc));
82 return 1;
83 }
84
85 keylen = sav->key_enc->sadb_key_bits;
86 if (keylen < algo->keymin || algo->keymax < keylen) {
87 ipseclog((LOG_ERR,
88 "esp_aesctr_mature %s: invalid key length %d.\n",
89 algo->name, sav->key_enc->sadb_key_bits));
90 return 1;
91 }
92
93 /* rijndael key + nonce */
94 if (!(keylen == 128 + 32 || keylen == 192 + 32 || keylen == 256 + 32)) {
95 ipseclog((LOG_ERR,
96 "esp_aesctr_mature %s: invalid key length %d.\n",
97 algo->name, keylen));
98 return 1;
99 }
100
101 return 0;
102 }
103
104 size_t
105 esp_aesctr_schedlen(const struct esp_algorithm *algo)
106 {
107
108 return sizeof(aesctr_ctx);
109 }
110
111 int
112 esp_aesctr_schedule(const struct esp_algorithm *algo, struct secasvar *sav)
113 {
114 aesctr_ctx *ctx;
115 int keylen;
116
117 /* SA key = AES key + nonce */
118 keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8;
119
120 ctx = (aesctr_ctx *)sav->sched;
121 if ((ctx->r_nr = rijndaelKeySetupEnc(ctx->r_ek,
122 (char *)_KEYBUF(sav->key_enc), keylen)) == 0)
123 return -1;
124 return 0;
125 }
126
127 int
128 esp_aesctr_decrypt(struct mbuf *m, size_t off, struct secasvar *sav,
129 const struct esp_algorithm *algo, int ivlen)
130 {
131 struct mbuf *s;
132 struct mbuf *d, *d0 = NULL, *dp;
133 int soff, doff; /* offset from the head of chain, to head of this mbuf */
134 int sn, dn; /* offset from the head of the mbuf, to meat */
135 size_t ivoff, bodyoff;
136 union cblock cblock;
137 u_int8_t keystream[AES_BLOCKSIZE], *nonce;
138 u_int32_t ctr;
139 u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
140 struct mbuf *scut;
141 int scutoff;
142 int i;
143 int blocklen;
144 aesctr_ctx *ctx;
145
146 if (ivlen != sav->ivlen) {
147 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
148 "unsupported ivlen %d\n", algo->name, ivlen));
149 goto fail;
150 }
151
152 /* assumes blocklen == padbound */
153 blocklen = algo->padbound;
154
155 ivoff = off + sizeof(struct newesp);
156 bodyoff = off + sizeof(struct newesp) + ivlen;
157
158 /* setup counter block */
159 nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
160 bcopy(nonce, cblock.v.nonce, NONCESIZE);
161 m_copydata(m, ivoff, ivlen, cblock.v.iv);
162 ctr = 1;
163
164 if (m->m_pkthdr.len < bodyoff) {
165 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
166 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
167 goto fail;
168 }
169 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
170 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
171 "payload length must be multiple of %d\n",
172 algo->name, blocklen));
173 goto fail;
174 }
175
176 s = m;
177 d = d0 = dp = NULL;
178 soff = doff = sn = dn = 0;
179 sp = NULL;
180
181 /* skip bodyoff */
182 while (soff < bodyoff) {
183 if (soff + s->m_len > bodyoff) {
184 sn = bodyoff - soff;
185 break;
186 }
187
188 soff += s->m_len;
189 s = s->m_next;
190 }
191 scut = s;
192 scutoff = sn;
193
194 /* skip over empty mbuf */
195 while (s && s->m_len == 0)
196 s = s->m_next;
197
198 while (soff < m->m_pkthdr.len) {
199 /* source */
200 if (sn + blocklen <= s->m_len) {
201 /* body is continuous */
202 sp = mtod(s, u_int8_t *) + sn;
203 } else {
204 /* body is non-continuous */
205 m_copydata(s, sn, blocklen, (caddr_t)sbuf);
206 sp = sbuf;
207 }
208
209 /* destination */
210 if (!d || dn + blocklen > d->m_len) {
211 if (d)
212 dp = d;
213 MGET(d, M_NOWAIT, MT_DATA);
214 i = m->m_pkthdr.len - (soff + sn);
215 if (d && i > MLEN) {
216 MCLGET(d, M_NOWAIT);
217 if ((d->m_flags & M_EXT) == 0) {
218 m_free(d);
219 d = NULL;
220 }
221 }
222 if (!d) {
223 goto nomem;
224 }
225 if (!d0)
226 d0 = d;
227 if (dp)
228 dp->m_next = d;
229 d->m_len = 0;
230 d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
231 if (d->m_len > i)
232 d->m_len = i;
233 dn = 0;
234 }
235
236 /* put counter into counter block */
237 cblock.v.ctr = htonl(ctr);
238
239 /* setup keystream */
240 ctx = (aesctr_ctx *)sav->sched;
241 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
242
243 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
244 dst = mtod(d, u_int8_t *) + dn;
245 for (i = 0; i < blocklen; i++)
246 dst[i] ^= keystream[i];
247
248 ctr++;
249
250 sn += blocklen;
251 dn += blocklen;
252
253 /* find the next source block */
254 while (s && sn >= s->m_len) {
255 sn -= s->m_len;
256 soff += s->m_len;
257 s = s->m_next;
258 }
259
260 /* skip over empty mbuf */
261 while (s && s->m_len == 0)
262 s = s->m_next;
263 }
264
265 m_freem(scut->m_next);
266 scut->m_len = scutoff;
267 scut->m_next = d0;
268
269 /* just in case */
270 bzero(&cblock, sizeof(cblock));
271 bzero(keystream, sizeof(keystream));
272
273 return 0;
274
275 fail:
276 m_freem(m);
277 if (d0)
278 m_freem(d0);
279 return EINVAL;
280
281 nomem:
282 m_freem(m);
283 if (d0)
284 m_freem(d0);
285 return ENOBUFS;
286 }
287
288 int
289 esp_aesctr_encrypt(struct mbuf *m, size_t off, size_t plen, struct secasvar *sav,
290 const struct esp_algorithm *algo, int ivlen)
291 {
292 struct mbuf *s;
293 struct mbuf *d, *d0, *dp;
294 int soff, doff; /* offset from the head of chain, to head of this mbuf */
295 int sn, dn; /* offset from the head of the mbuf, to meat */
296 size_t ivoff, bodyoff;
297 union cblock cblock;
298 u_int8_t keystream[AES_BLOCKSIZE], *nonce;
299 u_int32_t ctr;
300 u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
301 struct mbuf *scut;
302 int scutoff;
303 int i;
304 int blocklen;
305 aesctr_ctx *ctx;
306
307 if (ivlen != sav->ivlen) {
308 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
309 "unsupported ivlen %d\n", algo->name, ivlen));
310 m_freem(m);
311 return EINVAL;
312 }
313
314 /* assumes blocklen == padbound */
315 blocklen = algo->padbound;
316
317 ivoff = off + sizeof(struct newesp);
318 bodyoff = off + sizeof(struct newesp) + ivlen;
319
320 /* put iv into the packet. */
321 /* maybe it is better to overwrite dest, not source */
322 m_copyback(m, ivoff, ivlen, sav->iv);
323
324 /* setup counter block */
325 nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
326 bcopy(nonce, cblock.v.nonce, NONCESIZE);
327 m_copydata(m, ivoff, ivlen, cblock.v.iv);
328 ctr = 1;
329
330 if (m->m_pkthdr.len < bodyoff) {
331 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
332 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
333 m_freem(m);
334 return EINVAL;
335 }
336 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
337 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
338 "payload length must be multiple of %lu\n",
339 algo->name, (unsigned long)algo->padbound));
340 m_freem(m);
341 return EINVAL;
342 }
343
344 s = m;
345 d = d0 = dp = NULL;
346 soff = doff = sn = dn = 0;
347 sp = NULL;
348
349 /* skip bodyoff */
350 while (soff < bodyoff) {
351 if (soff + s->m_len > bodyoff) {
352 sn = bodyoff - soff;
353 break;
354 }
355
356 soff += s->m_len;
357 s = s->m_next;
358 }
359 scut = s;
360 scutoff = sn;
361
362 /* skip over empty mbuf */
363 while (s && s->m_len == 0)
364 s = s->m_next;
365
366 while (soff < m->m_pkthdr.len) {
367 /* source */
368 if (sn + blocklen <= s->m_len) {
369 /* body is continuous */
370 sp = mtod(s, u_int8_t *) + sn;
371 } else {
372 /* body is non-continuous */
373 m_copydata(s, sn, blocklen, (caddr_t)sbuf);
374 sp = sbuf;
375 }
376
377 /* destination */
378 if (!d || dn + blocklen > d->m_len) {
379 if (d)
380 dp = d;
381 MGET(d, M_NOWAIT, MT_DATA);
382 i = m->m_pkthdr.len - (soff + sn);
383 if (d && i > MLEN) {
384 MCLGET(d, M_NOWAIT);
385 if ((d->m_flags & M_EXT) == 0) {
386 m_free(d);
387 d = NULL;
388 }
389 }
390 if (!d) {
391 m_freem(m);
392 if (d0)
393 m_freem(d0);
394 return ENOBUFS;
395 }
396 if (!d0)
397 d0 = d;
398 if (dp)
399 dp->m_next = d;
400 d->m_len = 0;
401 d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
402 if (d->m_len > i)
403 d->m_len = i;
404 dn = 0;
405 }
406
407 /* put counter into counter block */
408 cblock.v.ctr = htonl(ctr);
409
410 /* setup keystream */
411 ctx = (aesctr_ctx *)sav->sched;
412 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
413
414 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
415 dst = mtod(d, u_int8_t *) + dn;
416 for (i = 0; i < blocklen; i++)
417 dst[i] ^= keystream[i];
418
419 ctr++;
420
421 sn += blocklen;
422 dn += blocklen;
423
424 /* find the next source block */
425 while (s && sn >= s->m_len) {
426 sn -= s->m_len;
427 soff += s->m_len;
428 s = s->m_next;
429 }
430
431 /* skip over empty mbuf */
432 while (s && s->m_len == 0)
433 s = s->m_next;
434 }
435
436 m_freem(scut->m_next);
437 scut->m_len = scutoff;
438 scut->m_next = d0;
439
440 /* just in case */
441 bzero(&cblock, sizeof(cblock));
442 bzero(keystream, sizeof(keystream));
443
444 key_sa_stir_iv(sav);
445
446 return 0;
447 }
Cache object: b23d7c152857b9d2e96db77d741689b3
|