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: unsupported algorithm %d\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
;
139 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
146 if (ivlen
!= sav
->ivlen
) {
147 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: "
148 "unsupported ivlen %d\n", algo
->name
, ivlen
));
152 /* assumes blocklen == padbound */
153 blocklen
= algo
->padbound
;
155 ivoff
= off
+ sizeof(struct newesp
);
156 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
158 /* setup counter block */
159 nonce
= _KEYBUF(sav
->key_enc
) + _KEYLEN(sav
->key_enc
) - NONCESIZE
;
160 bcopy(nonce
, cblock
.v
.nonce
, NONCESIZE
);
161 m_copydata(m
, ivoff
, ivlen
, cblock
.v
.iv
);
164 if (m
->m_pkthdr
.len
< bodyoff
) {
165 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
166 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
169 if ((m
->m_pkthdr
.len
- bodyoff
) % blocklen
) {
170 ipseclog((LOG_ERR
, "esp_aesctr_decrypt %s: "
171 "payload length must be multiple of %d\n",
172 algo
->name
, blocklen
));
178 soff
= doff
= sn
= dn
= 0;
182 while (soff
< bodyoff
) {
183 if (soff
+ s
->m_len
> bodyoff
) {
194 /* skip over empty mbuf */
195 while (s
&& s
->m_len
== 0)
198 while (soff
< m
->m_pkthdr
.len
) {
200 if (sn
+ blocklen
<= s
->m_len
) {
201 /* body is continuous */
202 sp
= mtod(s
, u_int8_t
*) + sn
;
204 /* body is non-continuous */
205 m_copydata(s
, sn
, blocklen
, (caddr_t
)sbuf
);
210 if (!d
|| dn
+ blocklen
> d
->m_len
) {
213 MGET(d
, M_NOWAIT
, MT_DATA
);
214 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
217 if ((d
->m_flags
& M_EXT
) == 0) {
230 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
236 /* put counter into counter block */
237 cblock
.v
.ctr
= htonl(ctr
);
239 /* setup keystream */
240 ctx
= (aesctr_ctx
*)sav
->sched
;
241 rijndaelEncrypt(ctx
->r_ek
, ctx
->r_nr
, cblock
.cblock
, keystream
);
243 bcopy(sp
, mtod(d
, u_int8_t
*) + dn
, blocklen
);
244 dst
= mtod(d
, u_int8_t
*) + dn
;
245 for (i
= 0; i
< blocklen
; i
++)
246 dst
[i
] ^= keystream
[i
];
253 /* find the next source block */
254 while (s
&& sn
>= s
->m_len
) {
260 /* skip over empty mbuf */
261 while (s
&& s
->m_len
== 0)
265 m_freem(scut
->m_next
);
266 scut
->m_len
= scutoff
;
270 bzero(&cblock
, sizeof(cblock
));
271 bzero(keystream
, sizeof(keystream
));
289 esp_aesctr_encrypt(struct mbuf
*m
, size_t off
, size_t plen
, struct secasvar
*sav
,
290 const struct esp_algorithm
*algo
, int ivlen
)
293 struct mbuf
*d
, *d0
, *dp
;
294 int soff
, doff
; /* offset from the head of chain, to head of this mbuf */
295 int sn
, dn
; /* offset from the head of the mbuf, to meat */
296 size_t ivoff
, bodyoff
;
298 u_int8_t keystream
[AES_BLOCKSIZE
], *nonce
;
300 u_int8_t sbuf
[AES_BLOCKSIZE
], *sp
, *dst
;
307 if (ivlen
!= sav
->ivlen
) {
308 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: "
309 "unsupported ivlen %d\n", algo
->name
, ivlen
));
314 /* assumes blocklen == padbound */
315 blocklen
= algo
->padbound
;
317 ivoff
= off
+ sizeof(struct newesp
);
318 bodyoff
= off
+ sizeof(struct newesp
) + ivlen
;
320 /* put iv into the packet. */
321 /* maybe it is better to overwrite dest, not source */
322 m_copyback(m
, ivoff
, ivlen
, sav
->iv
);
324 /* setup counter block */
325 nonce
= _KEYBUF(sav
->key_enc
) + _KEYLEN(sav
->key_enc
) - NONCESIZE
;
326 bcopy(nonce
, cblock
.v
.nonce
, NONCESIZE
);
327 m_copydata(m
, ivoff
, ivlen
, cblock
.v
.iv
);
330 if (m
->m_pkthdr
.len
< bodyoff
) {
331 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
332 algo
->name
, m
->m_pkthdr
.len
, (unsigned long)bodyoff
));
336 if ((m
->m_pkthdr
.len
- bodyoff
) % blocklen
) {
337 ipseclog((LOG_ERR
, "esp_aesctr_encrypt %s: "
338 "payload length must be multiple of %lu\n",
339 algo
->name
, (unsigned long)algo
->padbound
));
346 soff
= doff
= sn
= dn
= 0;
350 while (soff
< bodyoff
) {
351 if (soff
+ s
->m_len
> bodyoff
) {
362 /* skip over empty mbuf */
363 while (s
&& s
->m_len
== 0)
366 while (soff
< m
->m_pkthdr
.len
) {
368 if (sn
+ blocklen
<= s
->m_len
) {
369 /* body is continuous */
370 sp
= mtod(s
, u_int8_t
*) + sn
;
372 /* body is non-continuous */
373 m_copydata(s
, sn
, blocklen
, (caddr_t
)sbuf
);
378 if (!d
|| dn
+ blocklen
> d
->m_len
) {
381 MGET(d
, M_NOWAIT
, MT_DATA
);
382 i
= m
->m_pkthdr
.len
- (soff
+ sn
);
385 if ((d
->m_flags
& M_EXT
) == 0) {
401 d
->m_len
= (M_TRAILINGSPACE(d
) / blocklen
) * blocklen
;
407 /* put counter into counter block */
408 cblock
.v
.ctr
= htonl(ctr
);
410 /* setup keystream */
411 ctx
= (aesctr_ctx
*)sav
->sched
;
412 rijndaelEncrypt(ctx
->r_ek
, ctx
->r_nr
, cblock
.cblock
, keystream
);
414 bcopy(sp
, mtod(d
, u_int8_t
*) + dn
, blocklen
);
415 dst
= mtod(d
, u_int8_t
*) + dn
;
416 for (i
= 0; i
< blocklen
; i
++)
417 dst
[i
] ^= keystream
[i
];
424 /* find the next source block */
425 while (s
&& sn
>= s
->m_len
) {
431 /* skip over empty mbuf */
432 while (s
&& s
->m_len
== 0)
436 m_freem(scut
->m_next
);
437 scut
->m_len
= scutoff
;
441 bzero(&cblock
, sizeof(cblock
));
442 bzero(keystream
, sizeof(keystream
));