]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_rijndael.c
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 $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/socket.h>
36 #include <sys/queue.h>
37 #include <sys/syslog.h>
40 #include <kern/locks.h>
43 #include <net/route.h>
45 #include <netinet6/ipsec.h>
46 #include <netinet6/esp.h>
47 #include <netinet6/esp_rijndael.h>
49 #include <crypto/aes/aes.h>
51 #include <netkey/key.h>
53 #include <net/net_osdep.h>
55 #define AES_BLOCKLEN 16
57 extern lck_mtx_t
*sadb_mutex
;
61 __unused
const struct esp_algorithm
*algo
)
64 return sizeof(aes_ctx
);
69 __unused
const struct esp_algorithm
*algo
,
73 lck_mtx_assert(sadb_mutex
, LCK_MTX_ASSERT_OWNED
);
74 aes_ctx
*ctx
= (aes_ctx
*)sav
->sched
;
76 aes_decrypt_key(_KEYBUF(sav
->key_enc
), _KEYLEN(sav
->key_enc
), &ctx
->decrypt
);
77 aes_encrypt_key(_KEYBUF(sav
->key_enc
), _KEYLEN(sav
->key_enc
), &ctx
->encrypt
);
83 /* The following 2 functions decrypt or encrypt the contents of
84 * the mbuf chain passed in keeping the IP and ESP header's in place,
86 * The code attempts to call the crypto code with the largest chunk
87 * of data it can based on the amount of source data in
88 * the current source mbuf and the space remaining in the current
89 * destination mbuf. The crypto code requires data to be a multiples
90 * of 16 bytes. A separate buffer is used when a 16 byte block spans
94 * off = offset to ESP header
96 * local vars for source:
97 * soff = offset from beginning of the chain to the head of the
99 * scut = last mbuf that contains headers to be retained
100 * scutoff = offset to end of the headers in scut
101 * s = the current mbuf
102 * sn = current offset to data in s (next source data to process)
104 * local vars for dest:
107 * dn = current offset in d (next location to store result)
112 esp_cbc_decrypt_aes(m
, off
, sav
, algo
, ivlen
)
115 struct secasvar
*sav
;
116 const struct esp_algorithm
*algo
;
120 struct mbuf
*d
, *d0
, *dp
;
121 int soff
; /* offset from the head of chain, to head of this mbuf */
122 int sn
, dn
; /* offset from the head of the mbuf, to meat */
123 size_t ivoff
, bodyoff
;
124 u_int8_t iv
[AES_BLOCKLEN
], *dptr
;
125 u_int8_t sbuf
[AES_BLOCKLEN
], *sp
;
131 if (ivlen
!= AES_BLOCKLEN
) {
132 ipseclog((LOG_ERR
, "esp_cbc_decrypt %s: "
133 "unsupported ivlen %d\n", algo
->name
, ivlen
));
138 if (sav
->flags
& SADB_X_EXT_OLD
) {
140 ivoff
= off
+ sizeof(struct esp
);
141 bodyoff
= off
+ sizeof(struct esp
) + ivlen
;
143 ivoff
= off
+ sizeof(struct newesp
);
144 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
147 if (m
->m_pkthdr
.len
< bodyoff
) {
148 ipseclog((LOG_ERR
, "esp_cbc_decrypt %s: bad len %d/%lu\n",
149 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
153 if ((m
->m_pkthdr
.len
- bodyoff
) % AES_BLOCKLEN
) {
154 ipseclog((LOG_ERR
, "esp_cbc_decrypt %s: "
155 "payload length must be multiple of %d\n",
156 algo
->name
, AES_BLOCKLEN
));
162 m_copydata(m
, ivoff
, ivlen
, iv
);
169 /* skip header/IV offset */
170 while (soff
< bodyoff
) {
171 if (soff
+ s
->m_len
> bodyoff
) {
182 /* skip over empty mbuf */
183 while (s
&& s
->m_len
== 0)
186 while (soff
< m
->m_pkthdr
.len
) {
188 if (sn
+ AES_BLOCKLEN
<= s
->m_len
) {
189 /* body is continuous */
190 sp
= mtod(s
, u_int8_t
*) + sn
;
192 len
-= len
% AES_BLOCKLEN
; // full blocks only
194 /* body is non-continuous */
195 m_copydata(s
, sn
, AES_BLOCKLEN
, sbuf
);
197 len
= AES_BLOCKLEN
; // 1 block only in sbuf
201 if (!d
|| dn
+ AES_BLOCKLEN
> d
->m_len
) {
204 MGET(d
, M_DONTWAIT
, MT_DATA
);
205 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
207 MCLGET(d
, M_DONTWAIT
);
208 if ((d
->m_flags
& M_EXT
) == 0) {
209 d
= m_mbigget(d
, M_DONTWAIT
);
210 if ((d
->m_flags
& M_EXT
) == 0) {
226 d
->m_len
= M_TRAILINGSPACE(d
);
227 d
->m_len
-= d
->m_len
% AES_BLOCKLEN
;
230 dptr
= mtod(d
, u_int8_t
*);
234 /* adjust len if greater than space available in dest */
235 if (len
> d
->m_len
- dn
)
239 aes_decrypt_cbc(sp
, iv
, len
>> 4, dptr
+ dn
,
240 (aes_decrypt_ctx
*)(&(((aes_ctx
*)sav
->sched
)->decrypt
)));
247 bcopy(sp
+ len
- AES_BLOCKLEN
, iv
, AES_BLOCKLEN
);
249 /* find the next source block */
250 while (s
&& sn
>= s
->m_len
) {
258 /* free un-needed source mbufs and add dest mbufs to chain */
259 m_freem(scut
->m_next
);
260 scut
->m_len
= scutoff
;
264 bzero(iv
, sizeof(iv
));
265 bzero(sbuf
, sizeof(sbuf
));
274 __unused
size_t plen
,
275 struct secasvar
*sav
,
276 const struct esp_algorithm
*algo
,
280 struct mbuf
*d
, *d0
, *dp
;
281 int soff
; /* offset from the head of chain, to head of this mbuf */
282 int sn
, dn
; /* offset from the head of the mbuf, to meat */
283 size_t ivoff
, bodyoff
;
284 u_int8_t
*ivp
, *dptr
;
285 u_int8_t sbuf
[AES_BLOCKLEN
], *sp
;
290 if (ivlen
!= AES_BLOCKLEN
) {
291 ipseclog((LOG_ERR
, "esp_cbc_encrypt %s: "
292 "unsupported ivlen %d\n", algo
->name
, ivlen
));
297 if (sav
->flags
& SADB_X_EXT_OLD
) {
299 ivoff
= off
+ sizeof(struct esp
);
300 bodyoff
= off
+ sizeof(struct esp
) + ivlen
;
302 ivoff
= off
+ sizeof(struct newesp
);
303 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
306 /* put iv into the packet */
307 m_copyback(m
, ivoff
, ivlen
, sav
->iv
);
310 if (m
->m_pkthdr
.len
< bodyoff
) {
311 ipseclog((LOG_ERR
, "esp_cbc_encrypt %s: bad len %d/%lu\n",
312 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
316 if ((m
->m_pkthdr
.len
- bodyoff
) % AES_BLOCKLEN
) {
317 ipseclog((LOG_ERR
, "esp_cbc_encrypt %s: "
318 "payload length must be multiple of %lu\n",
319 algo
->name
, AES_BLOCKLEN
));
329 /* skip headers/IV */
330 while (soff
< bodyoff
) {
331 if (soff
+ s
->m_len
> bodyoff
) {
342 /* skip over empty mbuf */
343 while (s
&& s
->m_len
== 0)
346 while (soff
< m
->m_pkthdr
.len
) {
348 if (sn
+ AES_BLOCKLEN
<= s
->m_len
) {
349 /* body is continuous */
350 sp
= mtod(s
, u_int8_t
*) + sn
;
352 len
-= len
% AES_BLOCKLEN
; // full blocks only
354 /* body is non-continuous */
355 m_copydata(s
, sn
, AES_BLOCKLEN
, sbuf
);
357 len
= AES_BLOCKLEN
; // 1 block only in sbuf
361 if (!d
|| dn
+ AES_BLOCKLEN
> d
->m_len
) {
364 MGET(d
, M_DONTWAIT
, MT_DATA
);
365 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
367 MCLGET(d
, M_DONTWAIT
);
368 if ((d
->m_flags
& M_EXT
) == 0) {
369 d
= m_mbigget(d
, M_DONTWAIT
);
370 if ((d
->m_flags
& M_EXT
) == 0) {
387 d
->m_len
= M_TRAILINGSPACE(d
);
388 d
->m_len
-= d
->m_len
% AES_BLOCKLEN
;
391 dptr
= mtod(d
, u_int8_t
*);
395 /* adjust len if greater than space available */
396 if (len
> d
->m_len
- dn
)
400 aes_encrypt_cbc(sp
, ivp
, len
>> 4, dptr
+ dn
,
401 (aes_encrypt_ctx
*)(&(((aes_ctx
*)sav
->sched
)->encrypt
)));
408 ivp
= dptr
+ dn
- AES_BLOCKLEN
; // last block encrypted
410 /* find the next source block and skip empty mbufs */
411 while (s
&& sn
>= s
->m_len
) {
419 /* free un-needed source mbufs and add dest mbufs to chain */
420 m_freem(scut
->m_next
);
421 scut
->m_len
= scutoff
;
425 bzero(sbuf
, sizeof(sbuf
));