]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/esp_rijndael.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_rijndael.c
CommitLineData
9bccf70c
A
1/* $FreeBSD: src/sys/netinet6/esp_rijndael.c,v 1.1.2.1 2001/07/03 11:01:50 ume Exp $ */
2/* $KAME: esp_rijndael.c,v 1.4 2001/03/02 05:53:05 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/socket.h>
36#include <sys/queue.h>
91447636
A
37#include <sys/syslog.h>
38#include <sys/mbuf.h>
39
40#include <kern/locks.h>
9bccf70c
A
41
42#include <net/if.h>
43#include <net/route.h>
44
45#include <netinet6/ipsec.h>
46#include <netinet6/esp.h>
47#include <netinet6/esp_rijndael.h>
48
91447636 49#include <crypto/aes/aes.h>
9bccf70c
A
50
51#include <net/net_osdep.h>
52
91447636
A
53#define AES_BLOCKLEN 16
54
55extern lck_mtx_t *sadb_mutex;
56
9bccf70c 57int
91447636 58esp_aes_schedlen(algo)
9bccf70c
A
59 const struct esp_algorithm *algo;
60{
61
91447636 62 return sizeof(aes_ctx);
9bccf70c
A
63}
64
65int
91447636 66esp_aes_schedule(algo, sav)
9bccf70c
A
67 const struct esp_algorithm *algo;
68 struct secasvar *sav;
69{
91447636
A
70 aes_ctx *ctx = (aes_ctx*)sav->sched;
71
72 gen_tabs();
73 aes_decrypt_key(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc), &ctx->decrypt);
74 aes_encrypt_key(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc), &ctx->encrypt);
75
9bccf70c
A
76 return 0;
77}
78
91447636
A
79
80/* The following 2 functions decrypt or encrypt the contents of
81 * the mbuf chain passed in keeping the IP and ESP header's in place,
82 * along with the IV.
83 * The code attempts to call the crypto code with the largest chunk
84 * of data it can based on the amount of source data in
85 * the current source mbuf and the space remaining in the current
86 * destination mbuf. The crypto code requires data to be a multiples
87 * of 16 bytes. A separate buffer is used when a 16 byte block spans
88 * mbufs.
89 *
90 * m = mbuf chain
91 * off = offset to ESP header
92 *
93 * local vars for source:
94 * soff = offset from beginning of the chain to the head of the
95 * current mbuf.
96 * scut = last mbuf that contains headers to be retained
97 * scutoff = offset to end of the headers in scut
98 * s = the current mbuf
99 * sn = current offset to data in s (next source data to process)
100 *
101 * local vars for dest:
102 * d0 = head of chain
103 * d = current mbuf
104 * dn = current offset in d (next location to store result)
105 */
106
107
9bccf70c 108int
91447636
A
109esp_cbc_decrypt_aes(m, off, sav, algo, ivlen)
110 struct mbuf *m;
111 size_t off;
9bccf70c 112 struct secasvar *sav;
91447636
A
113 const struct esp_algorithm *algo;
114 int ivlen;
9bccf70c 115{
91447636
A
116 struct mbuf *s;
117 struct mbuf *d, *d0, *dp;
118 int soff; /* offset from the head of chain, to head of this mbuf */
119 int sn, dn; /* offset from the head of the mbuf, to meat */
120 size_t ivoff, bodyoff;
121 u_int8_t iv[AES_BLOCKLEN], *dptr;
122 u_int8_t sbuf[AES_BLOCKLEN], *sp;
123 struct mbuf *scut;
124 int scutoff;
125 int i, len;
126
127
128 if (ivlen != AES_BLOCKLEN) {
129 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
130 "unsupported ivlen %d\n", algo->name, ivlen));
131 m_freem(m);
132 return EINVAL;
133 }
134
135 if (sav->flags & SADB_X_EXT_OLD) {
136 /* RFC 1827 */
137 ivoff = off + sizeof(struct esp);
138 bodyoff = off + sizeof(struct esp) + ivlen;
139 } else {
140 ivoff = off + sizeof(struct newesp);
141 bodyoff = off + sizeof(struct newesp) + ivlen;
142 }
143
144 if (m->m_pkthdr.len < bodyoff) {
145 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",
146 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
147 m_freem(m);
148 return EINVAL;
149 }
150 if ((m->m_pkthdr.len - bodyoff) % AES_BLOCKLEN) {
151 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
152 "payload length must be multiple of %d\n",
153 algo->name, AES_BLOCKLEN));
154 m_freem(m);
155 return EINVAL;
156 }
157
158 /* grab iv */
159 m_copydata(m, ivoff, ivlen, iv);
160
161 lck_mtx_unlock(sadb_mutex);
162 s = m;
163 soff = sn = dn = 0;
164 d = d0 = dp = NULL;
165 sp = dptr = NULL;
166
167 /* skip header/IV offset */
168 while (soff < bodyoff) {
169 if (soff + s->m_len > bodyoff) {
170 sn = bodyoff - soff;
171 break;
172 }
173
174 soff += s->m_len;
175 s = s->m_next;
176 }
177 scut = s;
178 scutoff = sn;
179
180 /* skip over empty mbuf */
181 while (s && s->m_len == 0)
182 s = s->m_next;
183
184 while (soff < m->m_pkthdr.len) {
185 /* source */
186 if (sn + AES_BLOCKLEN <= s->m_len) {
187 /* body is continuous */
188 sp = mtod(s, u_int8_t *) + sn;
189 len = s->m_len - sn;
190 len -= len % AES_BLOCKLEN; // full blocks only
191 } else {
192 /* body is non-continuous */
193 m_copydata(s, sn, AES_BLOCKLEN, sbuf);
194 sp = sbuf;
195 len = AES_BLOCKLEN; // 1 block only in sbuf
196 }
197
198 /* destination */
199 if (!d || dn + AES_BLOCKLEN > d->m_len) {
200 if (d)
201 dp = d;
202 MGET(d, M_DONTWAIT, MT_DATA);
203 i = m->m_pkthdr.len - (soff + sn);
204 if (d && i > MLEN) {
205 MCLGET(d, M_DONTWAIT);
206 if ((d->m_flags & M_EXT) == 0) {
207 m_free(d);
208 d = NULL;
209 }
210 }
211 if (!d) {
212 m_freem(m);
213 if (d0)
214 m_freem(d0);
215 lck_mtx_lock(sadb_mutex);
216 return ENOBUFS;
217 }
218 if (!d0)
219 d0 = d;
220 if (dp)
221 dp->m_next = d;
222 d->m_len = M_TRAILINGSPACE(d);
223 d->m_len -= d->m_len % AES_BLOCKLEN;
224 if (d->m_len > i)
225 d->m_len = i;
226 dptr = mtod(d, u_int8_t *);
227 dn = 0;
228 }
229
230 /* adjust len if greater than space available in dest */
231 if (len > d->m_len - dn)
232 len = d->m_len - dn;
233
234 /* decrypt */
235 aes_decrypt_cbc(sp, iv, len >> 4, dptr + dn,
236 (aes_decrypt_ctx*)(&(((aes_ctx*)sav->sched)->decrypt)));
237
238 /* udpate offsets */
239 sn += len;
240 dn += len;
241
242 // next iv
243 bcopy(sp + len - AES_BLOCKLEN, iv, AES_BLOCKLEN);
244
245 /* find the next source block */
246 while (s && sn >= s->m_len) {
247 sn -= s->m_len;
248 soff += s->m_len;
249 s = s->m_next;
250 }
251
252 }
253
254 /* free un-needed source mbufs and add dest mbufs to chain */
255 m_freem(scut->m_next);
256 scut->m_len = scutoff;
257 scut->m_next = d0;
258
259 /* just in case */
260 bzero(iv, sizeof(iv));
261 bzero(sbuf, sizeof(sbuf));
262 lck_mtx_lock(sadb_mutex);
263
9bccf70c
A
264 return 0;
265}
266
267int
91447636
A
268esp_cbc_encrypt_aes(m, off, plen, sav, algo, ivlen)
269 struct mbuf *m;
270 size_t off;
271 size_t plen;
9bccf70c 272 struct secasvar *sav;
91447636
A
273 const struct esp_algorithm *algo;
274 int ivlen;
9bccf70c 275{
91447636
A
276 struct mbuf *s;
277 struct mbuf *d, *d0, *dp;
278 int soff, doff; /* offset from the head of chain, to head of this mbuf */
279 int sn, dn; /* offset from the head of the mbuf, to meat */
280 size_t ivoff, bodyoff;
281 u_int8_t *ivp, *dptr;
282 u_int8_t sbuf[AES_BLOCKLEN], *sp;
283 struct mbuf *scut;
284 int scutoff;
285 int i, len;
286
287 if (ivlen != AES_BLOCKLEN) {
288 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
289 "unsupported ivlen %d\n", algo->name, ivlen));
290 m_freem(m);
291 return EINVAL;
292 }
293
294 if (sav->flags & SADB_X_EXT_OLD) {
295 /* RFC 1827 */
296 ivoff = off + sizeof(struct esp);
297 bodyoff = off + sizeof(struct esp) + ivlen;
298 } else {
299 ivoff = off + sizeof(struct newesp);
300 bodyoff = off + sizeof(struct newesp) + ivlen;
301 }
302
303 /* put iv into the packet */
304 m_copyback(m, ivoff, ivlen, sav->iv);
305 ivp = sav->iv;
306
307 if (m->m_pkthdr.len < bodyoff) {
308 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",
309 algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
310 m_freem(m);
311 return EINVAL;
312 }
313 if ((m->m_pkthdr.len - bodyoff) % AES_BLOCKLEN) {
314 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
315 "payload length must be multiple of %lu\n",
316 algo->name, AES_BLOCKLEN));
317 m_freem(m);
318 return EINVAL;
319 }
320 lck_mtx_unlock(sadb_mutex);
321
322 s = m;
323 soff = sn = dn = 0;
324 d = d0 = dp = NULL;
325 sp = dptr = NULL;
326
327 /* skip headers/IV */
328 while (soff < bodyoff) {
329 if (soff + s->m_len > bodyoff) {
330 sn = bodyoff - soff;
331 break;
332 }
333
334 soff += s->m_len;
335 s = s->m_next;
336 }
337 scut = s;
338 scutoff = sn;
339
340 /* skip over empty mbuf */
341 while (s && s->m_len == 0)
342 s = s->m_next;
343
344 while (soff < m->m_pkthdr.len) {
345 /* source */
346 if (sn + AES_BLOCKLEN <= s->m_len) {
347 /* body is continuous */
348 sp = mtod(s, u_int8_t *) + sn;
349 len = s->m_len - sn;
350 len -= len % AES_BLOCKLEN; // full blocks only
351 } else {
352 /* body is non-continuous */
353 m_copydata(s, sn, AES_BLOCKLEN, sbuf);
354 sp = sbuf;
355 len = AES_BLOCKLEN; // 1 block only in sbuf
356 }
357
358 /* destination */
359 if (!d || dn + AES_BLOCKLEN > d->m_len) {
360 if (d)
361 dp = d;
362 MGET(d, M_DONTWAIT, MT_DATA);
363 i = m->m_pkthdr.len - (soff + sn);
364 if (d && i > MLEN) {
365 MCLGET(d, M_DONTWAIT);
366 if ((d->m_flags & M_EXT) == 0) {
367 m_free(d);
368 d = NULL;
369 }
370 }
371 if (!d) {
372 m_freem(m);
373 if (d0)
374 m_freem(d0);
375 lck_mtx_lock(sadb_mutex);
376 return ENOBUFS;
377 }
378 if (!d0)
379 d0 = d;
380 if (dp)
381 dp->m_next = d;
382
383 d->m_len = M_TRAILINGSPACE(d);
384 d->m_len -= d->m_len % AES_BLOCKLEN;
385 if (d->m_len > i)
386 d->m_len = i;
387 dptr = mtod(d, u_int8_t *);
388 dn = 0;
389 }
390
391 /* adjust len if greater than space available */
392 if (len > d->m_len - dn)
393 len = d->m_len - dn;
394
395 /* encrypt */
396 aes_encrypt_cbc(sp, ivp, len >> 4, dptr + dn,
397 (aes_encrypt_ctx*)(&(((aes_ctx*)sav->sched)->encrypt)));
398
399 /* update offsets */
400 sn += len;
401 dn += len;
402
403 /* next iv */
404 ivp = dptr + dn - AES_BLOCKLEN; // last block encrypted
405
406 /* find the next source block and skip empty mbufs */
407 while (s && sn >= s->m_len) {
408 sn -= s->m_len;
409 soff += s->m_len;
410 s = s->m_next;
411 }
412
413 }
414
415 /* free un-needed source mbufs and add dest mbufs to chain */
416 m_freem(scut->m_next);
417 scut->m_len = scutoff;
418 scut->m_next = d0;
419
420 /* just in case */
421 bzero(sbuf, sizeof(sbuf));
422 lck_mtx_lock(sadb_mutex);
423 key_sa_stir_iv(sav);
424
9bccf70c
A
425 return 0;
426}