1 /* $NetBSD: esp_aesctr.c,v 1.11 2009/03/19 08:22:29 he Exp $ */
2 /* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */
5 * Copyright (C) 1995, 1996, 1997, 1998 and 2003 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/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: esp_aesctr.c,v 1.11 2009/03/19 08:22:29 he Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
40 #include <sys/syslog.h>
44 #include <net/route.h>
46 #include <netinet/in.h>
48 #include <netinet6/ipsec.h>
49 #include <netinet6/esp.h>
50 #include <netinet6/esp_aesctr.h>
52 #include <netkey/key.h>
54 #include <crypto/rijndael/rijndael.h>
56 #include <net/net_osdep.h>
58 #define AES_BLOCKSIZE 16
71 u_int32_t r_ek
[(RIJNDAEL_MAXNR
+1)*4];
72 int r_nr
; /* key-length-dependent number of rounds */
76 esp_aesctr_mature(struct secasvar
*sav
)
79 const struct esp_algorithm
*algo
;
81 algo
= esp_algorithm_lookup(sav
->alg_enc
);
84 "esp_aeesctr_mature %s: unsupported algorithm.\n",
89 keylen
= sav
->key_enc
->sadb_key_bits
;
90 if (keylen
< algo
->keymin
|| algo
->keymax
< keylen
) {
92 "esp_aesctr_mature %s: invalid key length %d.\n",
93 algo
->name
, sav
->key_enc
->sadb_key_bits
));
97 /* rijndael key + nonce */
98 if (!(keylen
== 128 + 32 || keylen
== 192 + 32 || keylen
== 256 + 32)) {
100 "esp_aesctr_mature %s: invalid key length %d.\n",
101 algo
->name
, keylen
));
109 esp_aesctr_schedlen(const struct esp_algorithm
*algo
)
112 return sizeof(aesctr_ctx
);
116 esp_aesctr_schedule(const struct esp_algorithm
*algo
,
117 struct secasvar
*sav
)
122 /* SA key = AES key + nonce */
123 keylen
= _KEYLEN(sav
->key_enc
) * 8 - NONCESIZE
* 8;
125 ctx
= (aesctr_ctx
*)sav
->sched
;
126 if ((ctx
->r_nr
= rijndaelKeySetupEnc(ctx
->r_ek
,
127 (char *)_KEYBUF(sav
->key_enc
), keylen
)) == 0)
133 esp_aesctr_decrypt(struct mbuf
*m
, size_t off
, struct secasvar
*sav
,
134 const struct esp_algorithm
*algo
, int ivlen
)
137 struct mbuf
*d
, *d0
= NULL
, *dp
;
138 int soff
, doff
; /* offset from the head of chain, to head of this mbuf */
139 int sn
, dn
; /* offset from the head of the mbuf, to meat */
140 size_t ivoff
, bodyoff
;
142 u_int8_t keystream
[AES_BLOCKSIZE
], *nonce
;
145 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
152 if (ivlen
!= sav
->ivlen
) {
153 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: "
154 "unsupported ivlen %d\n", algo
->name
, ivlen
));
158 /* assumes blocklen == padbound */
159 blocklen
= algo
->padbound
;
161 ivoff
= off
+ sizeof(struct newesp
);
162 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
164 /* setup counter block */
165 nonce
= _KEYBUF(sav
->key_enc
) + _KEYLEN(sav
->key_enc
) - NONCESIZE
;
166 memcpy(cblock
.v
.nonce
, nonce
, NONCESIZE
);
167 m_copydata(m
, ivoff
, ivlen
, cblock
.v
.iv
);
170 if (m
->m_pkthdr
.len
< bodyoff
) {
171 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
172 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
175 if ((m
->m_pkthdr
.len
- bodyoff
) % blocklen
) {
176 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: "
177 "payload length must be multiple of %d\n",
178 algo
->name
, blocklen
));
184 soff
= doff
= sn
= dn
= 0;
188 while (soff
< bodyoff
) {
189 if (soff
+ s
->m_len
> bodyoff
) {
200 /* skip over empty mbuf */
201 while (s
&& s
->m_len
== 0)
204 while (soff
< m
->m_pkthdr
.len
) {
206 if (sn
+ blocklen
<= s
->m_len
) {
207 /* body is continuous */
208 sp
= mtod(s
, u_int8_t
*) + sn
;
210 /* body is non-continuous */
211 m_copydata(s
, sn
, blocklen
, (void *)sbuf
);
216 if (!d
|| dn
+ blocklen
> d
->m_len
) {
219 MGET(d
, M_DONTWAIT
, MT_DATA
);
220 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
222 MCLGET(d
, M_DONTWAIT
);
223 if ((d
->m_flags
& M_EXT
) == 0) {
236 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
242 /* put counter into counter block */
243 cblock
.v
.ctr
= htonl(ctr
);
245 /* setup keystream */
246 ctx
= (aesctr_ctx
*)sav
->sched
;
247 rijndaelEncrypt(ctx
->r_ek
, ctx
->r_nr
, cblock
.cblock
, keystream
);
249 memcpy(mtod(d
, u_int8_t
*) + dn
, sp
, blocklen
);
250 dst
= mtod(d
, u_int8_t
*) + dn
;
251 for (i
= 0; i
< blocklen
; i
++)
252 dst
[i
] ^= keystream
[i
];
259 /* find the next source block */
260 while (s
&& sn
>= s
->m_len
) {
266 /* skip over empty mbuf */
267 while (s
&& s
->m_len
== 0)
271 m_freem(scut
->m_next
);
272 scut
->m_len
= scutoff
;
276 memset(&cblock
, 0, sizeof(cblock
));
277 memset(keystream
, 0, sizeof(keystream
));
299 struct secasvar
*sav
,
300 const struct esp_algorithm
*algo
,
305 struct mbuf
*d
, *d0
, *dp
;
306 int soff
, doff
; /* offset from the head of chain, to head of this mbuf */
307 int sn
, dn
; /* offset from the head of the mbuf, to meat */
308 size_t ivoff
, bodyoff
;
310 u_int8_t keystream
[AES_BLOCKSIZE
], *nonce
;
312 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
319 if (ivlen
!= sav
->ivlen
) {
320 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: "
321 "unsupported ivlen %d\n", algo
->name
, ivlen
));
326 /* assumes blocklen == padbound */
327 blocklen
= algo
->padbound
;
329 ivoff
= off
+ sizeof(struct newesp
);
330 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
332 /* put iv into the packet. */
333 /* maybe it is better to overwrite dest, not source */
334 m_copyback(m
, ivoff
, ivlen
, sav
->iv
);
336 /* setup counter block */
337 nonce
= _KEYBUF(sav
->key_enc
) + _KEYLEN(sav
->key_enc
) - NONCESIZE
;
338 memcpy(cblock
.v
.nonce
, nonce
, NONCESIZE
);
339 m_copydata(m
, ivoff
, ivlen
, cblock
.v
.iv
);
342 if (m
->m_pkthdr
.len
< bodyoff
) {
343 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
344 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
348 if ((m
->m_pkthdr
.len
- bodyoff
) % blocklen
) {
349 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: "
350 "payload length must be multiple of %lu\n",
351 algo
->name
, (unsigned long)algo
->padbound
));
358 soff
= doff
= sn
= dn
= 0;
362 while (soff
< bodyoff
) {
363 if (soff
+ s
->m_len
> bodyoff
) {
374 /* skip over empty mbuf */
375 while (s
&& s
->m_len
== 0)
378 while (soff
< m
->m_pkthdr
.len
) {
380 if (sn
+ blocklen
<= s
->m_len
) {
381 /* body is continuous */
382 sp
= mtod(s
, u_int8_t
*) + sn
;
384 /* body is non-continuous */
385 m_copydata(s
, sn
, blocklen
, (void *)sbuf
);
390 if (!d
|| dn
+ blocklen
> d
->m_len
) {
393 MGET(d
, M_DONTWAIT
, MT_DATA
);
394 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
396 MCLGET(d
, M_DONTWAIT
);
397 if ((d
->m_flags
& M_EXT
) == 0) {
413 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
419 /* put counter into counter block */
420 cblock
.v
.ctr
= htonl(ctr
);
422 /* setup keystream */
423 ctx
= (aesctr_ctx
*)sav
->sched
;
424 rijndaelEncrypt(ctx
->r_ek
, ctx
->r_nr
, cblock
.cblock
, keystream
);
426 memcpy(mtod(d
, u_int8_t
*) + dn
, sp
, blocklen
);
427 dst
= mtod(d
, u_int8_t
*) + dn
;
428 for (i
= 0; i
< blocklen
; i
++)
429 dst
[i
] ^= keystream
[i
];
436 /* find the next source block */
437 while (s
&& sn
>= s
->m_len
) {
443 /* skip over empty mbuf */
444 while (s
&& s
->m_len
== 0)
448 m_freem(scut
->m_next
);
449 scut
->m_len
= scutoff
;
453 memset(&cblock
, 0, sizeof(cblock
));
454 memset(keystream
, 0, sizeof(keystream
));