2 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") version 2 as published by the Free
18 * Software Foundation.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_wep.c,v 1.7 2005/06/10 16:11:24 sam Exp $");
37 __KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_wep.c,v 1.7 2006/11/16 01:33:40 christos Exp $");
41 * IEEE 802.11 WEP crypto support.
43 #include <sys/param.h>
44 #include <sys/systm.h>
46 #include <sys/malloc.h>
47 #include <sys/kernel.h>
48 #include <sys/endian.h>
50 #include <sys/socket.h>
53 #include <net/if_ether.h>
54 #include <net/if_media.h>
56 #include <net80211/ieee80211_var.h>
58 static void *wep_attach(struct ieee80211com
*, struct ieee80211_key
*);
59 static void wep_detach(struct ieee80211_key
*);
60 static int wep_setkey(struct ieee80211_key
*);
61 static int wep_encap(struct ieee80211_key
*, struct mbuf
*, u_int8_t keyid
);
62 static int wep_decap(struct ieee80211_key
*, struct mbuf
*, int hdrlen
);
63 static int wep_enmic(struct ieee80211_key
*, struct mbuf
*, int);
64 static int wep_demic(struct ieee80211_key
*, struct mbuf
*, int);
66 const struct ieee80211_cipher ieee80211_cipher_wep
= {
68 .ic_cipher
= IEEE80211_CIPHER_WEP
,
69 .ic_header
= IEEE80211_WEP_IVLEN
+ IEEE80211_WEP_KIDLEN
,
70 .ic_trailer
= IEEE80211_WEP_CRCLEN
,
72 .ic_attach
= wep_attach
,
73 .ic_detach
= wep_detach
,
74 .ic_setkey
= wep_setkey
,
75 .ic_encap
= wep_encap
,
76 .ic_decap
= wep_decap
,
77 .ic_enmic
= wep_enmic
,
78 .ic_demic
= wep_demic
,
81 #define wep ieee80211_cipher_wep
83 static int wep_encrypt(struct ieee80211_key
*, struct mbuf
*, int hdrlen
);
84 static int wep_decrypt(struct ieee80211_key
*, struct mbuf
*, int hdrlen
);
87 struct ieee80211com
*wc_ic
; /* for diagnostics */
88 u_int32_t wc_iv
; /* initial vector for crypto */
92 wep_attach(struct ieee80211com
*ic
, struct ieee80211_key
*k
)
96 ctx
= malloc(sizeof(struct wep_ctx
),
97 M_DEVBUF
, M_NOWAIT
| M_ZERO
);
99 ic
->ic_stats
.is_crypto_nomem
++;
104 get_random_bytes(&ctx
->wc_iv
, sizeof(ctx
->wc_iv
));
109 wep_detach(struct ieee80211_key
*k
)
111 struct wep_ctx
*ctx
= k
->wk_private
;
117 wep_setkey(struct ieee80211_key
*k
)
119 return k
->wk_keylen
>= 40/NBBY
;
123 * Add privacy headers appropriate for the specified key.
126 wep_encap(struct ieee80211_key
*k
, struct mbuf
*m
, u_int8_t keyid
)
128 struct wep_ctx
*ctx
= k
->wk_private
;
129 struct ieee80211com
*ic
= ctx
->wc_ic
;
134 hdrlen
= ieee80211_hdrspace(ic
, mtod(m
, void *));
137 * Copy down 802.11 header and add the IV + KeyID.
139 M_PREPEND(m
, wep
.ic_header
, M_NOWAIT
);
142 ivp
= mtod(m
, u_int8_t
*);
143 ovbcopy(ivp
+ wep
.ic_header
, ivp
, hdrlen
);
148 * IV must not duplicate during the lifetime of the key.
149 * But no mechanism to renew keys is defined in IEEE 802.11
150 * for WEP. And the IV may be duplicated at other stations
151 * because the session key itself is shared. So we use a
152 * pseudo random IV for now, though it is not the right way.
154 * NB: Rather than use a strictly random IV we select a
155 * random one to start and then increment the value for
156 * each frame. This is an explicit tradeoff between
157 * overhead and security. Given the basic insecurity of
158 * WEP this seems worthwhile.
162 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
163 * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
166 if ((iv
& 0xff00) == 0xff00) {
167 int B
= (iv
& 0xff0000) >> 16;
168 if (3 <= B
&& B
< 16)
174 * NB: Preserve byte order of IV for packet
175 * sniffers; it doesn't matter otherwise.
177 #if _BYTE_ORDER == _BIG_ENDIAN
189 * Finally, do software encrypt if neeed.
191 if ((k
->wk_flags
& IEEE80211_KEY_SWCRYPT
) &&
192 !wep_encrypt(k
, m
, hdrlen
))
199 * Add MIC to the frame as needed.
202 wep_enmic(struct ieee80211_key
*k
, struct mbuf
*m
,
210 * Validate and strip privacy headers (and trailer) for a
211 * received frame. If necessary, decrypt the frame using
215 wep_decap(struct ieee80211_key
*k
, struct mbuf
*m
, int hdrlen
)
217 struct wep_ctx
*ctx
= k
->wk_private
;
218 struct ieee80211_frame
*wh
;
220 wh
= mtod(m
, struct ieee80211_frame
*);
223 * Check if the device handled the decrypt in hardware.
224 * If so we just strip the header; otherwise we need to
225 * handle the decrypt in software.
227 if ((k
->wk_flags
& IEEE80211_KEY_SWCRYPT
) &&
228 !wep_decrypt(k
, m
, hdrlen
)) {
229 IEEE80211_DPRINTF(ctx
->wc_ic
, IEEE80211_MSG_CRYPTO
,
230 "[%s] WEP ICV mismatch on decrypt\n",
231 ether_sprintf(wh
->i_addr2
));
232 ctx
->wc_ic
->ic_stats
.is_rx_wepfail
++;
237 * Copy up 802.11 header and strip crypto bits.
239 ovbcopy(mtod(m
, void *), mtod(m
, u_int8_t
*) + wep
.ic_header
, hdrlen
);
240 m_adj(m
, wep
.ic_header
);
241 m_adj(m
, -wep
.ic_trailer
);
247 * Verify and strip MIC from the frame.
250 wep_demic(struct ieee80211_key
*k
, struct mbuf
*skb
,
256 static const uint32_t crc32_table
[256] = {
257 0x00000000L
, 0x77073096L
, 0xee0e612cL
, 0x990951baL
, 0x076dc419L
,
258 0x706af48fL
, 0xe963a535L
, 0x9e6495a3L
, 0x0edb8832L
, 0x79dcb8a4L
,
259 0xe0d5e91eL
, 0x97d2d988L
, 0x09b64c2bL
, 0x7eb17cbdL
, 0xe7b82d07L
,
260 0x90bf1d91L
, 0x1db71064L
, 0x6ab020f2L
, 0xf3b97148L
, 0x84be41deL
,
261 0x1adad47dL
, 0x6ddde4ebL
, 0xf4d4b551L
, 0x83d385c7L
, 0x136c9856L
,
262 0x646ba8c0L
, 0xfd62f97aL
, 0x8a65c9ecL
, 0x14015c4fL
, 0x63066cd9L
,
263 0xfa0f3d63L
, 0x8d080df5L
, 0x3b6e20c8L
, 0x4c69105eL
, 0xd56041e4L
,
264 0xa2677172L
, 0x3c03e4d1L
, 0x4b04d447L
, 0xd20d85fdL
, 0xa50ab56bL
,
265 0x35b5a8faL
, 0x42b2986cL
, 0xdbbbc9d6L
, 0xacbcf940L
, 0x32d86ce3L
,
266 0x45df5c75L
, 0xdcd60dcfL
, 0xabd13d59L
, 0x26d930acL
, 0x51de003aL
,
267 0xc8d75180L
, 0xbfd06116L
, 0x21b4f4b5L
, 0x56b3c423L
, 0xcfba9599L
,
268 0xb8bda50fL
, 0x2802b89eL
, 0x5f058808L
, 0xc60cd9b2L
, 0xb10be924L
,
269 0x2f6f7c87L
, 0x58684c11L
, 0xc1611dabL
, 0xb6662d3dL
, 0x76dc4190L
,
270 0x01db7106L
, 0x98d220bcL
, 0xefd5102aL
, 0x71b18589L
, 0x06b6b51fL
,
271 0x9fbfe4a5L
, 0xe8b8d433L
, 0x7807c9a2L
, 0x0f00f934L
, 0x9609a88eL
,
272 0xe10e9818L
, 0x7f6a0dbbL
, 0x086d3d2dL
, 0x91646c97L
, 0xe6635c01L
,
273 0x6b6b51f4L
, 0x1c6c6162L
, 0x856530d8L
, 0xf262004eL
, 0x6c0695edL
,
274 0x1b01a57bL
, 0x8208f4c1L
, 0xf50fc457L
, 0x65b0d9c6L
, 0x12b7e950L
,
275 0x8bbeb8eaL
, 0xfcb9887cL
, 0x62dd1ddfL
, 0x15da2d49L
, 0x8cd37cf3L
,
276 0xfbd44c65L
, 0x4db26158L
, 0x3ab551ceL
, 0xa3bc0074L
, 0xd4bb30e2L
,
277 0x4adfa541L
, 0x3dd895d7L
, 0xa4d1c46dL
, 0xd3d6f4fbL
, 0x4369e96aL
,
278 0x346ed9fcL
, 0xad678846L
, 0xda60b8d0L
, 0x44042d73L
, 0x33031de5L
,
279 0xaa0a4c5fL
, 0xdd0d7cc9L
, 0x5005713cL
, 0x270241aaL
, 0xbe0b1010L
,
280 0xc90c2086L
, 0x5768b525L
, 0x206f85b3L
, 0xb966d409L
, 0xce61e49fL
,
281 0x5edef90eL
, 0x29d9c998L
, 0xb0d09822L
, 0xc7d7a8b4L
, 0x59b33d17L
,
282 0x2eb40d81L
, 0xb7bd5c3bL
, 0xc0ba6cadL
, 0xedb88320L
, 0x9abfb3b6L
,
283 0x03b6e20cL
, 0x74b1d29aL
, 0xead54739L
, 0x9dd277afL
, 0x04db2615L
,
284 0x73dc1683L
, 0xe3630b12L
, 0x94643b84L
, 0x0d6d6a3eL
, 0x7a6a5aa8L
,
285 0xe40ecf0bL
, 0x9309ff9dL
, 0x0a00ae27L
, 0x7d079eb1L
, 0xf00f9344L
,
286 0x8708a3d2L
, 0x1e01f268L
, 0x6906c2feL
, 0xf762575dL
, 0x806567cbL
,
287 0x196c3671L
, 0x6e6b06e7L
, 0xfed41b76L
, 0x89d32be0L
, 0x10da7a5aL
,
288 0x67dd4accL
, 0xf9b9df6fL
, 0x8ebeeff9L
, 0x17b7be43L
, 0x60b08ed5L
,
289 0xd6d6a3e8L
, 0xa1d1937eL
, 0x38d8c2c4L
, 0x4fdff252L
, 0xd1bb67f1L
,
290 0xa6bc5767L
, 0x3fb506ddL
, 0x48b2364bL
, 0xd80d2bdaL
, 0xaf0a1b4cL
,
291 0x36034af6L
, 0x41047a60L
, 0xdf60efc3L
, 0xa867df55L
, 0x316e8eefL
,
292 0x4669be79L
, 0xcb61b38cL
, 0xbc66831aL
, 0x256fd2a0L
, 0x5268e236L
,
293 0xcc0c7795L
, 0xbb0b4703L
, 0x220216b9L
, 0x5505262fL
, 0xc5ba3bbeL
,
294 0xb2bd0b28L
, 0x2bb45a92L
, 0x5cb36a04L
, 0xc2d7ffa7L
, 0xb5d0cf31L
,
295 0x2cd99e8bL
, 0x5bdeae1dL
, 0x9b64c2b0L
, 0xec63f226L
, 0x756aa39cL
,
296 0x026d930aL
, 0x9c0906a9L
, 0xeb0e363fL
, 0x72076785L
, 0x05005713L
,
297 0x95bf4a82L
, 0xe2b87a14L
, 0x7bb12baeL
, 0x0cb61b38L
, 0x92d28e9bL
,
298 0xe5d5be0dL
, 0x7cdcefb7L
, 0x0bdbdf21L
, 0x86d3d2d4L
, 0xf1d4e242L
,
299 0x68ddb3f8L
, 0x1fda836eL
, 0x81be16cdL
, 0xf6b9265bL
, 0x6fb077e1L
,
300 0x18b74777L
, 0x88085ae6L
, 0xff0f6a70L
, 0x66063bcaL
, 0x11010b5cL
,
301 0x8f659effL
, 0xf862ae69L
, 0x616bffd3L
, 0x166ccf45L
, 0xa00ae278L
,
302 0xd70dd2eeL
, 0x4e048354L
, 0x3903b3c2L
, 0xa7672661L
, 0xd06016f7L
,
303 0x4969474dL
, 0x3e6e77dbL
, 0xaed16a4aL
, 0xd9d65adcL
, 0x40df0b66L
,
304 0x37d83bf0L
, 0xa9bcae53L
, 0xdebb9ec5L
, 0x47b2cf7fL
, 0x30b5ffe9L
,
305 0xbdbdf21cL
, 0xcabac28aL
, 0x53b39330L
, 0x24b4a3a6L
, 0xbad03605L
,
306 0xcdd70693L
, 0x54de5729L
, 0x23d967bfL
, 0xb3667a2eL
, 0xc4614ab8L
,
307 0x5d681b02L
, 0x2a6f2b94L
, 0xb40bbe37L
, 0xc30c8ea1L
, 0x5a05df1bL
,
312 wep_encrypt(struct ieee80211_key
*key
, struct mbuf
*m0
, int hdrlen
)
314 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
315 struct wep_ctx
*ctx
= key
->wk_private
;
317 u_int8_t rc4key
[IEEE80211_WEP_IVLEN
+ IEEE80211_KEYBUF_SIZE
];
318 uint8_t icv
[IEEE80211_WEP_CRCLEN
];
319 uint32_t i
, j
, k
, crc
;
320 size_t buflen
, data_len
;
325 ctx
->wc_ic
->ic_stats
.is_crypto_wep
++;
327 /* NB: this assumes the header was pulled up */
328 memcpy(rc4key
, mtod(m
, u_int8_t
*) + hdrlen
, IEEE80211_WEP_IVLEN
);
329 memcpy(rc4key
+ IEEE80211_WEP_IVLEN
, key
->wk_key
, key
->wk_keylen
);
331 /* Setup RC4 state */
332 for (i
= 0; i
< 256; i
++)
335 keylen
= key
->wk_keylen
+ IEEE80211_WEP_IVLEN
;
336 for (i
= 0; i
< 256; i
++) {
337 j
= (j
+ S
[i
] + rc4key
[i
% keylen
]) & 0xff;
341 off
= hdrlen
+ wep
.ic_header
;
342 data_len
= m
->m_pkthdr
.len
- off
;
344 /* Compute CRC32 over unencrypted data and apply RC4 to data */
347 pos
= mtod(m
, uint8_t *) + off
;
348 buflen
= m
->m_len
- off
;
350 if (buflen
> data_len
)
353 for (k
= 0; k
< buflen
; k
++) {
354 crc
= crc32_table
[(crc
^ *pos
) & 0xff] ^ (crc
>> 8);
356 j
= (j
+ S
[i
]) & 0xff;
358 *pos
++ ^= S
[(S
[i
] + S
[j
]) & 0xff];
360 if (m
->m_next
== NULL
) {
361 if (data_len
!= 0) { /* out of data */
362 IEEE80211_DPRINTF(ctx
->wc_ic
,
363 IEEE80211_MSG_CRYPTO
,
364 "[%s] out of data for WEP (data_len %zu)\n",
365 ether_sprintf(mtod(m0
,
366 struct ieee80211_frame
*)->i_addr2
),
373 pos
= mtod(m
, uint8_t *);
378 /* Append little-endian CRC32 and encrypt it to produce ICV */
383 for (k
= 0; k
< IEEE80211_WEP_CRCLEN
; k
++) {
385 j
= (j
+ S
[i
]) & 0xff;
387 icv
[k
] ^= S
[(S
[i
] + S
[j
]) & 0xff];
389 return m_append(m0
, IEEE80211_WEP_CRCLEN
, icv
);
394 wep_decrypt(struct ieee80211_key
*key
, struct mbuf
*m0
, int hdrlen
)
396 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
397 struct wep_ctx
*ctx
= key
->wk_private
;
399 u_int8_t rc4key
[IEEE80211_WEP_IVLEN
+ IEEE80211_KEYBUF_SIZE
];
400 uint8_t icv
[IEEE80211_WEP_CRCLEN
];
401 uint32_t i
, j
, k
, crc
;
402 size_t buflen
, data_len
;
407 ctx
->wc_ic
->ic_stats
.is_crypto_wep
++;
409 /* NB: this assumes the header was pulled up */
410 memcpy(rc4key
, mtod(m
, u_int8_t
*) + hdrlen
, IEEE80211_WEP_IVLEN
);
411 memcpy(rc4key
+ IEEE80211_WEP_IVLEN
, key
->wk_key
, key
->wk_keylen
);
413 /* Setup RC4 state */
414 for (i
= 0; i
< 256; i
++)
417 keylen
= key
->wk_keylen
+ IEEE80211_WEP_IVLEN
;
418 for (i
= 0; i
< 256; i
++) {
419 j
= (j
+ S
[i
] + rc4key
[i
% keylen
]) & 0xff;
423 off
= hdrlen
+ wep
.ic_header
;
424 data_len
= m
->m_pkthdr
.len
- (off
+ wep
.ic_trailer
),
426 /* Compute CRC32 over unencrypted data and apply RC4 to data */
429 pos
= mtod(m
, uint8_t *) + off
;
430 buflen
= m
->m_len
- off
;
432 if (buflen
> data_len
)
435 for (k
= 0; k
< buflen
; k
++) {
437 j
= (j
+ S
[i
]) & 0xff;
439 *pos
^= S
[(S
[i
] + S
[j
]) & 0xff];
440 crc
= crc32_table
[(crc
^ *pos
) & 0xff] ^ (crc
>> 8);
445 if (data_len
!= 0) { /* out of data */
446 IEEE80211_DPRINTF(ctx
->wc_ic
,
447 IEEE80211_MSG_CRYPTO
,
448 "[%s] out of data for WEP (data_len %zu)\n",
449 ether_sprintf(mtod(m0
,
450 struct ieee80211_frame
*)->i_addr2
),
456 pos
= mtod(m
, uint8_t *);
461 /* Encrypt little-endian CRC32 and verify that it matches with
467 for (k
= 0; k
< IEEE80211_WEP_CRCLEN
; k
++) {
469 j
= (j
+ S
[i
]) & 0xff;
471 /* XXX assumes ICV is contiguous in mbuf */
472 if ((icv
[k
] ^ S
[(S
[i
] + S
[j
]) & 0xff]) != *pos
++) {
473 /* ICV mismatch - drop frame */
481 IEEE80211_CRYPTO_SETUP(wep_register
)
483 ieee80211_crypto_register(&wep
);