1 /* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */
4 * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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>
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
67 u_int32_t r_ek
[(RIJNDAEL_MAXNR
+1)*4];
68 int r_nr
; /* key-length-dependent number of rounds */
72 esp_aesctr_mature(struct secasvar
*sav
)
75 const struct esp_algorithm
*algo
;
77 algo
= esp_algorithm_lookup(sav
->alg_enc
);
80 "esp_aeesctr_mature %s: unsupported algorithm.\n",
85 keylen
= sav
->key_enc
->sadb_key_bits
;
86 if (keylen
< algo
->keymin
|| algo
->keymax
< keylen
) {
88 "esp_aesctr_mature %s: invalid key length %d.\n",
89 algo
->name
, sav
->key_enc
->sadb_key_bits
));
93 /* rijndael key + nonce */
94 if (!(keylen
== 128 + 32 || keylen
== 192 + 32 || keylen
== 256 + 32)) {
96 "esp_aesctr_mature %s: invalid key length %d.\n",
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
)
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)
128 esp_aesctr_decrypt(struct mbuf
*m
, size_t off
, struct secasvar
*sav
,
129 const struct esp_algorithm
*algo
, int ivlen
)
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
;
137 u_int8_t keystream
[AES_BLOCKSIZE
], *nonce
;
140 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
147 if (ivlen
!= sav
->ivlen
) {
148 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: "
149 "unsupported ivlen %d\n", algo
->name
, ivlen
));
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
);
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
));
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
));
179 soff
= doff
= sn
= dn
= 0;
183 while (soff
< bodyoff
) {
184 if (soff
+ s
->m_len
> bodyoff
) {
195 /* skip over empty mbuf */
196 while (s
&& s
->m_len
== 0)
199 while (soff
< m
->m_pkthdr
.len
) {
201 if (sn
+ blocklen
<= s
->m_len
) {
202 /* body is continuous */
203 sp
= mtod(s
, u_int8_t
*) + sn
;
205 /* body is non-continuous */
206 m_copydata(s
, sn
, blocklen
, (caddr_t
)sbuf
);
211 if (!d
|| dn
+ blocklen
> d
->m_len
) {
214 MGET(d
, M_NOWAIT
, MT_DATA
);
215 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
218 if ((d
->m_flags
& M_EXT
) == 0) {
231 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
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
];
254 /* find the next source block */
255 while (s
&& sn
>= s
->m_len
) {
261 /* skip over empty mbuf */
262 while (s
&& s
->m_len
== 0)
266 m_freem(scut
->m_next
);
267 scut
->m_len
= scutoff
;
271 bzero(&cblock
, sizeof(cblock
));
272 bzero(keystream
, sizeof(keystream
));
290 esp_aesctr_encrypt(struct mbuf
*m
, size_t off
, size_t plen
, struct secasvar
*sav
,
291 const struct esp_algorithm
*algo
, int ivlen
)
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
;
299 u_int8_t keystream
[AES_BLOCKSIZE
], *nonce
;
301 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
308 if (ivlen
!= sav
->ivlen
) {
309 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: "
310 "unsupported ivlen %d\n", algo
->name
, ivlen
));
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
);
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
));
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
));
347 soff
= doff
= sn
= dn
= 0;
351 while (soff
< bodyoff
) {
352 if (soff
+ s
->m_len
> bodyoff
) {
363 /* skip over empty mbuf */
364 while (s
&& s
->m_len
== 0)
367 while (soff
< m
->m_pkthdr
.len
) {
369 if (sn
+ blocklen
<= s
->m_len
) {
370 /* body is continuous */
371 sp
= mtod(s
, u_int8_t
*) + sn
;
373 /* body is non-continuous */
374 m_copydata(s
, sn
, blocklen
, (caddr_t
)sbuf
);
379 if (!d
|| dn
+ blocklen
> d
->m_len
) {
382 MGET(d
, M_NOWAIT
, MT_DATA
);
383 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
386 if ((d
->m_flags
& M_EXT
) == 0) {
402 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
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
];
425 /* find the next source block */
426 while (s
&& sn
>= s
->m_len
) {
432 /* skip over empty mbuf */
433 while (s
&& s
->m_len
== 0)
437 m_freem(scut
->m_next
);
438 scut
->m_len
= scutoff
;
442 bzero(&cblock
, sizeof(cblock
));
443 bzero(keystream
, sizeof(keystream
));