linprocfs - Introduce /proc/mounts
[dragonfly.git] / sys / netinet6 / esp_aesctr.c
bloba4f6d8afc0e57286e789d9a5eae94617a70f2ba1
1 /* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */
3 /*-
4 * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project.
5 * All rights reserved.
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.
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.
31 * $FreeBSD$
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>
41 #include <net/if.h>
42 #include <net/route.h>
44 #include <netinet/in.h>
46 #include <netinet6/ipsec.h>
47 #include <netinet6/esp.h>
48 #include <netinet6/esp_aesctr.h>
50 #include <netproto/key/key.h>
52 #include <crypto/rijndael/rijndael.h>
54 #define AES_BLOCKSIZE 16
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];
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;
71 int
72 esp_aesctr_mature(struct secasvar *sav)
74 int keylen;
75 const struct esp_algorithm *algo;
77 algo = esp_algorithm_lookup(sav->alg_enc);
78 if (!algo) {
79 ipseclog((LOG_ERR,
80 "esp_aeesctr_mature %s: unsupported algorithm.\n",
81 algo->name));
82 return 1;
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;
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;
101 return 0;
104 size_t
105 esp_aesctr_schedlen(const struct esp_algorithm *algo)
108 return sizeof(aesctr_ctx);
112 esp_aesctr_schedule(const struct esp_algorithm *algo, struct secasvar *sav)
114 aesctr_ctx *ctx;
115 int keylen;
117 /* SA key = AES key + nonce */
118 keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8;
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;
128 esp_aesctr_decrypt(struct mbuf *m, size_t off, struct secasvar *sav,
129 const struct esp_algorithm *algo, int ivlen)
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 *ivp;
140 u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
141 struct mbuf *scut;
142 int scutoff;
143 int i;
144 int blocklen;
145 aesctr_ctx *ctx;
147 if (ivlen != sav->ivlen) {
148 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
149 "unsupported ivlen %d\n", algo->name, ivlen));
150 goto fail;
153 /* assumes blocklen == padbound */
154 blocklen = algo->padbound;
156 ivoff = off + sizeof(struct newesp);
157 bodyoff = off + sizeof(struct newesp) + ivlen;
159 /* setup counter block */
160 nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
161 bcopy(nonce, cblock.v.nonce, NONCESIZE);
162 m_copydata(m, ivoff, ivlen, cblock.v.iv);
163 ctr = 1;
165 if (m->m_pkthdr.len < bodyoff) {
166 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
167 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
168 goto fail;
170 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
171 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
172 "payload length must be multiple of %d\n",
173 algo->name, blocklen));
174 goto fail;
177 s = m;
178 d = d0 = dp = NULL;
179 soff = doff = sn = dn = 0;
180 ivp = sp = NULL;
182 /* skip bodyoff */
183 while (soff < bodyoff) {
184 if (soff + s->m_len > bodyoff) {
185 sn = bodyoff - soff;
186 break;
189 soff += s->m_len;
190 s = s->m_next;
192 scut = s;
193 scutoff = sn;
195 /* skip over empty mbuf */
196 while (s && s->m_len == 0)
197 s = s->m_next;
199 while (soff < m->m_pkthdr.len) {
200 /* source */
201 if (sn + blocklen <= s->m_len) {
202 /* body is continuous */
203 sp = mtod(s, u_int8_t *) + sn;
204 } else {
205 /* body is non-continuous */
206 m_copydata(s, sn, blocklen, (caddr_t)sbuf);
207 sp = sbuf;
210 /* destination */
211 if (!d || dn + blocklen > d->m_len) {
212 if (d)
213 dp = d;
214 MGET(d, M_NOWAIT, MT_DATA);
215 i = m->m_pkthdr.len - (soff + sn);
216 if (d && i > MLEN) {
217 MCLGET(d, M_NOWAIT);
218 if ((d->m_flags & M_EXT) == 0) {
219 m_free(d);
220 d = NULL;
223 if (!d) {
224 goto nomem;
226 if (!d0)
227 d0 = d;
228 if (dp)
229 dp->m_next = d;
230 d->m_len = 0;
231 d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
232 if (d->m_len > i)
233 d->m_len = i;
234 dn = 0;
237 /* put counter into counter block */
238 cblock.v.ctr = htonl(ctr);
240 /* setup keystream */
241 ctx = (aesctr_ctx *)sav->sched;
242 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
244 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
245 dst = mtod(d, u_int8_t *) + dn;
246 for (i = 0; i < blocklen; i++)
247 dst[i] ^= keystream[i];
249 ctr++;
251 sn += blocklen;
252 dn += blocklen;
254 /* find the next source block */
255 while (s && sn >= s->m_len) {
256 sn -= s->m_len;
257 soff += s->m_len;
258 s = s->m_next;
261 /* skip over empty mbuf */
262 while (s && s->m_len == 0)
263 s = s->m_next;
266 m_freem(scut->m_next);
267 scut->m_len = scutoff;
268 scut->m_next = d0;
270 /* just in case */
271 bzero(&cblock, sizeof(cblock));
272 bzero(keystream, sizeof(keystream));
274 return 0;
276 fail:
277 m_freem(m);
278 if (d0)
279 m_freem(d0);
280 return EINVAL;
282 nomem:
283 m_freem(m);
284 if (d0)
285 m_freem(d0);
286 return ENOBUFS;
290 esp_aesctr_encrypt(struct mbuf *m, size_t off, size_t plen, struct secasvar *sav,
291 const struct esp_algorithm *algo, int ivlen)
293 struct mbuf *s;
294 struct mbuf *d, *d0, *dp;
295 int soff, doff; /* offset from the head of chain, to head of this mbuf */
296 int sn, dn; /* offset from the head of the mbuf, to meat */
297 size_t ivoff, bodyoff;
298 union cblock cblock;
299 u_int8_t keystream[AES_BLOCKSIZE], *nonce;
300 u_int32_t ctr;
301 u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
302 struct mbuf *scut;
303 int scutoff;
304 int i;
305 int blocklen;
306 aesctr_ctx *ctx;
308 if (ivlen != sav->ivlen) {
309 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
310 "unsupported ivlen %d\n", algo->name, ivlen));
311 m_freem(m);
312 return EINVAL;
315 /* assumes blocklen == padbound */
316 blocklen = algo->padbound;
318 ivoff = off + sizeof(struct newesp);
319 bodyoff = off + sizeof(struct newesp) + ivlen;
321 /* put iv into the packet. */
322 /* maybe it is better to overwrite dest, not source */
323 m_copyback(m, ivoff, ivlen, sav->iv);
325 /* setup counter block */
326 nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
327 bcopy(nonce, cblock.v.nonce, NONCESIZE);
328 m_copydata(m, ivoff, ivlen, cblock.v.iv);
329 ctr = 1;
331 if (m->m_pkthdr.len < bodyoff) {
332 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
333 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
334 m_freem(m);
335 return EINVAL;
337 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
338 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
339 "payload length must be multiple of %lu\n",
340 algo->name, (unsigned long)algo->padbound));
341 m_freem(m);
342 return EINVAL;
345 s = m;
346 d = d0 = dp = NULL;
347 soff = doff = sn = dn = 0;
348 sp = NULL;
350 /* skip bodyoff */
351 while (soff < bodyoff) {
352 if (soff + s->m_len > bodyoff) {
353 sn = bodyoff - soff;
354 break;
357 soff += s->m_len;
358 s = s->m_next;
360 scut = s;
361 scutoff = sn;
363 /* skip over empty mbuf */
364 while (s && s->m_len == 0)
365 s = s->m_next;
367 while (soff < m->m_pkthdr.len) {
368 /* source */
369 if (sn + blocklen <= s->m_len) {
370 /* body is continuous */
371 sp = mtod(s, u_int8_t *) + sn;
372 } else {
373 /* body is non-continuous */
374 m_copydata(s, sn, blocklen, (caddr_t)sbuf);
375 sp = sbuf;
378 /* destination */
379 if (!d || dn + blocklen > d->m_len) {
380 if (d)
381 dp = d;
382 MGET(d, M_NOWAIT, MT_DATA);
383 i = m->m_pkthdr.len - (soff + sn);
384 if (d && i > MLEN) {
385 MCLGET(d, M_NOWAIT);
386 if ((d->m_flags & M_EXT) == 0) {
387 m_free(d);
388 d = NULL;
391 if (!d) {
392 m_freem(m);
393 if (d0)
394 m_freem(d0);
395 return ENOBUFS;
397 if (!d0)
398 d0 = d;
399 if (dp)
400 dp->m_next = d;
401 d->m_len = 0;
402 d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
403 if (d->m_len > i)
404 d->m_len = i;
405 dn = 0;
408 /* put counter into counter block */
409 cblock.v.ctr = htonl(ctr);
411 /* setup keystream */
412 ctx = (aesctr_ctx *)sav->sched;
413 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
415 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
416 dst = mtod(d, u_int8_t *) + dn;
417 for (i = 0; i < blocklen; i++)
418 dst[i] ^= keystream[i];
420 ctr++;
422 sn += blocklen;
423 dn += blocklen;
425 /* find the next source block */
426 while (s && sn >= s->m_len) {
427 sn -= s->m_len;
428 soff += s->m_len;
429 s = s->m_next;
432 /* skip over empty mbuf */
433 while (s && s->m_len == 0)
434 s = s->m_next;
437 m_freem(scut->m_next);
438 scut->m_len = scutoff;
439 scut->m_next = d0;
441 /* just in case */
442 bzero(&cblock, sizeof(cblock));
443 bzero(keystream, sizeof(keystream));
445 key_sa_stir_iv(sav);
447 return 0;