1 /* $NetBSD: ieee80211_crypto_wep.c,v 1.13 2020/11/03 15:06:50 mlelstv Exp $ */
2
3 /*
4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifdef __FreeBSD__
36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_wep.c,v 1.7 2005/06/10 16:11:24 sam Exp $");
37 #endif
38 #ifdef __NetBSD__
39 __KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_wep.c,v 1.13 2020/11/03 15:06:50 mlelstv Exp $");
40 #endif
41
42 /*
43 * IEEE 802.11 WEP crypto support.
44 */
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/mbuf.h>
48 #include <sys/kmem.h>
49 #include <sys/kernel.h>
50 #include <sys/endian.h>
51
52 #include <sys/socket.h>
53
54 #include <net/if.h>
55 #include <net/if_ether.h>
56 #include <net/if_media.h>
57
58 #include <net80211/ieee80211_var.h>
59
60 static void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
61 static void wep_detach(struct ieee80211_key *);
62 static int wep_setkey(struct ieee80211_key *);
63 static int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid);
64 static int wep_decap(struct ieee80211_key *, struct mbuf *, int hdrlen);
65 static int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
66 static int wep_demic(struct ieee80211_key *, struct mbuf *, int);
67
68 const struct ieee80211_cipher ieee80211_cipher_wep = {
69 .ic_name = "WEP",
70 .ic_cipher = IEEE80211_CIPHER_WEP,
71 .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
72 .ic_trailer = IEEE80211_WEP_CRCLEN,
73 .ic_miclen = 0,
74 .ic_attach = wep_attach,
75 .ic_detach = wep_detach,
76 .ic_setkey = wep_setkey,
77 .ic_encap = wep_encap,
78 .ic_decap = wep_decap,
79 .ic_enmic = wep_enmic,
80 .ic_demic = wep_demic,
81 };
82
83 #define wep ieee80211_cipher_wep
84
85 static int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
86 static int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
87
88 struct wep_ctx {
89 struct ieee80211com *wc_ic; /* for diagnostics */
90 u_int32_t wc_iv; /* initial vector for crypto */
91 };
92
93 static void *
94 wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
95 {
96 struct wep_ctx *ctx;
97
98 ctx = kmem_intr_zalloc(sizeof(struct wep_ctx), KM_NOSLEEP);
99 if (ctx == NULL) {
100 ic->ic_stats.is_crypto_nomem++;
101 return NULL;
102 }
103
104 ctx->wc_ic = ic;
105 get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv));
106 return ctx;
107 }
108
109 static void
110 wep_detach(struct ieee80211_key *k)
111 {
112 struct wep_ctx *ctx = k->wk_private;
113
114 kmem_intr_free(ctx, sizeof(struct wep_ctx));
115 }
116
117 static int
118 wep_setkey(struct ieee80211_key *k)
119 {
120 return k->wk_keylen >= 40/NBBY;
121 }
122
123 /*
124 * Add privacy headers appropriate for the specified key.
125 */
126 static int
127 wep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
128 {
129 struct wep_ctx *ctx = k->wk_private;
130 struct ieee80211com *ic = ctx->wc_ic;
131 u_int32_t iv;
132 u_int8_t *ivp;
133 int hdrlen;
134
135 hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
136 ivp = mtod(m, u_int8_t *) + hdrlen;
137
138 /*
139 * XXX
140 * IV must not duplicate during the lifetime of the key.
141 * But no mechanism to renew keys is defined in IEEE 802.11
142 * for WEP. And the IV may be duplicated at other stations
143 * because the session key itself is shared. So we use a
144 * pseudo random IV for now, though it is not the right way.
145 *
146 * NB: Rather than use a strictly random IV we select a
147 * random one to start and then increment the value for
148 * each frame. This is an explicit tradeoff between
149 * overhead and security. Given the basic insecurity of
150 * WEP this seems worthwhile.
151 */
152
153 /*
154 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
155 * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
156 */
157 iv = ctx->wc_iv;
158 if ((iv & 0xff00) == 0xff00) {
159 int B = (iv & 0xff0000) >> 16;
160 if (3 <= B && B < 16)
161 iv += 0x0100;
162 }
163 ctx->wc_iv = iv + 1;
164
165 /*
166 * NB: Preserve byte order of IV for packet
167 * sniffers; it doesn't matter otherwise.
168 */
169 #if _BYTE_ORDER == _BIG_ENDIAN
170 ivp[0] = iv >> 0;
171 ivp[1] = iv >> 8;
172 ivp[2] = iv >> 16;
173 #else
174 ivp[2] = iv >> 0;
175 ivp[1] = iv >> 8;
176 ivp[0] = iv >> 16;
177 #endif
178 ivp[3] = keyid;
179
180 /*
181 * Finally, do software encrypt if neeed.
182 */
183 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
184 !wep_encrypt(k, m, hdrlen))
185 return 0;
186
187 return 1;
188 }
189
190 /*
191 * Add MIC to the frame as needed.
192 */
193 static int
194 wep_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
195 {
196
197 return 1;
198 }
199
200 /*
201 * Validate and strip privacy headers (and trailer) for a
202 * received frame. If necessary, decrypt the frame using
203 * the specified key.
204 */
205 static int
206 wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
207 {
208 struct wep_ctx *ctx = k->wk_private;
209 struct ieee80211_frame *wh;
210
211 wh = mtod(m, struct ieee80211_frame *);
212
213 /*
214 * Check if the device handled the decrypt in hardware.
215 * If so we just strip the header; otherwise we need to
216 * handle the decrypt in software.
217 */
218 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
219 !wep_decrypt(k, m, hdrlen)) {
220 IEEE80211_DPRINTF(ctx->wc_ic, IEEE80211_MSG_CRYPTO,
221 "[%s] WEP ICV mismatch on decrypt\n",
222 ether_sprintf(wh->i_addr2));
223 ctx->wc_ic->ic_stats.is_rx_wepfail++;
224 return 0;
225 }
226
227 /*
228 * Copy up 802.11 header and strip crypto bits.
229 */
230 memmove(mtod(m, u_int8_t *) + wep.ic_header, mtod(m, void *), hdrlen);
231 m_adj(m, wep.ic_header);
232 m_adj(m, -wep.ic_trailer);
233
234 return 1;
235 }
236
237 /*
238 * Verify and strip MIC from the frame.
239 */
240 static int
241 wep_demic(struct ieee80211_key *k, struct mbuf *skb,
242 int force)
243 {
244 return 1;
245 }
246
247 static const uint32_t crc32_table[256] = {
248 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
249 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
250 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
251 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
252 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
253 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
254 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
255 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
256 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
257 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
258 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
259 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
260 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
261 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
262 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
263 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
264 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
265 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
266 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
267 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
268 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
269 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
270 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
271 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
272 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
273 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
274 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
275 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
276 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
277 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
278 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
279 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
280 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
281 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
282 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
283 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
284 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
285 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
286 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
287 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
288 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
289 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
290 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
291 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
292 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
293 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
294 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
295 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
296 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
297 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
298 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
299 0x2d02ef8dL
300 };
301
302 static int
303 wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
304 {
305 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
306 struct wep_ctx *ctx = key->wk_private;
307 struct mbuf *m = m0;
308 u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
309 uint8_t icv[IEEE80211_WEP_CRCLEN];
310 uint32_t i, j, k, crc;
311 size_t buflen, data_len;
312 uint8_t S[256];
313 uint8_t *pos;
314 u_int off, keylen;
315
316 ctx->wc_ic->ic_stats.is_crypto_wep++;
317
318 /*
319 * NB: this assumes the header was pulled up; it was done in
320 * ieee80211_crypto_encap().
321 */
322 memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
323 memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
324
325 /* Setup RC4 state */
326 for (i = 0; i < 256; i++)
327 S[i] = i;
328 j = 0;
329 keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
330 for (i = 0; i < 256; i++) {
331 j = (j + S[i] + rc4key[i % keylen]) & 0xff;
332 S_SWAP(i, j);
333 }
334
335 off = hdrlen + wep.ic_header;
336 data_len = m->m_pkthdr.len - off;
337
338 /* Compute CRC32 over unencrypted data and apply RC4 to data */
339 crc = ~0;
340 i = j = 0;
341 pos = mtod(m, uint8_t *) + off;
342 buflen = m->m_len - off;
343 for (;;) {
344 if (buflen > data_len)
345 buflen = data_len;
346 data_len -= buflen;
347 for (k = 0; k < buflen; k++) {
348 crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
349 i = (i + 1) & 0xff;
350 j = (j + S[i]) & 0xff;
351 S_SWAP(i, j);
352 *pos++ ^= S[(S[i] + S[j]) & 0xff];
353 }
354 if (m->m_next == NULL) {
355 if (data_len != 0) { /* out of data */
356 IEEE80211_DPRINTF(ctx->wc_ic,
357 IEEE80211_MSG_CRYPTO,
358 "[%s] out of data for WEP (data_len %zu)\n",
359 ether_sprintf(mtod(m0,
360 struct ieee80211_frame *)->i_addr2),
361 data_len);
362 return 0;
363 }
364 break;
365 }
366 m = m->m_next;
367 pos = mtod(m, uint8_t *);
368 buflen = m->m_len;
369 }
370 crc = ~crc;
371
372 /* Append little-endian CRC32 and encrypt it to produce ICV */
373 icv[0] = crc;
374 icv[1] = crc >> 8;
375 icv[2] = crc >> 16;
376 icv[3] = crc >> 24;
377 for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
378 i = (i + 1) & 0xff;
379 j = (j + S[i]) & 0xff;
380 S_SWAP(i, j);
381 icv[k] ^= S[(S[i] + S[j]) & 0xff];
382 }
383 return m_append(m0, IEEE80211_WEP_CRCLEN, icv);
384 #undef S_SWAP
385 }
386
387 static int
388 wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
389 {
390 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
391 struct wep_ctx *ctx = key->wk_private;
392 struct mbuf *m = m0;
393 u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
394 uint8_t icv[IEEE80211_WEP_CRCLEN];
395 uint32_t i, j, k, crc;
396 size_t buflen, data_len;
397 uint8_t S[256];
398 uint8_t *pos;
399 u_int off, keylen;
400
401 ctx->wc_ic->ic_stats.is_crypto_wep++;
402
403 /* NB: this assumes the header was pulled up */
404 memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
405 memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
406
407 /* Setup RC4 state */
408 for (i = 0; i < 256; i++)
409 S[i] = i;
410 j = 0;
411 keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
412 for (i = 0; i < 256; i++) {
413 j = (j + S[i] + rc4key[i % keylen]) & 0xff;
414 S_SWAP(i, j);
415 }
416
417 off = hdrlen + wep.ic_header;
418 data_len = m->m_pkthdr.len - (off + wep.ic_trailer);
419
420 /* Compute CRC32 over unencrypted data and apply RC4 to data */
421 crc = ~0;
422 i = j = 0;
423 pos = mtod(m, uint8_t *) + off;
424 buflen = m->m_len - off;
425 for (;;) {
426 if (buflen > data_len)
427 buflen = data_len;
428 data_len -= buflen;
429 for (k = 0; k < buflen; k++) {
430 i = (i + 1) & 0xff;
431 j = (j + S[i]) & 0xff;
432 S_SWAP(i, j);
433 *pos ^= S[(S[i] + S[j]) & 0xff];
434 crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
435 pos++;
436 }
437 m = m->m_next;
438 if (m == NULL) {
439 if (data_len != 0) { /* out of data */
440 IEEE80211_DPRINTF(ctx->wc_ic,
441 IEEE80211_MSG_CRYPTO,
442 "[%s] out of data for WEP (data_len %zu)\n",
443 ether_sprintf(mtod(m0,
444 struct ieee80211_frame *)->i_addr2),
445 data_len);
446 return 0;
447 }
448 break;
449 }
450 pos = mtod(m, uint8_t *);
451 buflen = m->m_len;
452 }
453 crc = ~crc;
454
455 /*
456 * Encrypt little-endian CRC32 and verify that it matches with
457 * received ICV
458 */
459 icv[0] = crc;
460 icv[1] = crc >> 8;
461 icv[2] = crc >> 16;
462 icv[3] = crc >> 24;
463 for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
464 i = (i + 1) & 0xff;
465 j = (j + S[i]) & 0xff;
466 S_SWAP(i, j);
467 /* XXX assumes ICV is contiguous in mbuf */
468 if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
469 /* ICV mismatch - drop frame */
470 return 0;
471 }
472 }
473 return 1;
474 #undef S_SWAP
475 }
476
477 IEEE80211_CRYPTO_SETUP(wep_register)
478 {
479 ieee80211_crypto_register(&wep);
480 }
Cache object: 310fa3bfb1ed41aa9490f218ef0b128e
|