18a1b9b6aSSam Leffler /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4b032f27cSSam Leffler * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
58a1b9b6aSSam Leffler * All rights reserved.
68a1b9b6aSSam Leffler *
78a1b9b6aSSam Leffler * Redistribution and use in source and binary forms, with or without
88a1b9b6aSSam Leffler * modification, are permitted provided that the following conditions
98a1b9b6aSSam Leffler * are met:
108a1b9b6aSSam Leffler * 1. Redistributions of source code must retain the above copyright
118a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer.
128a1b9b6aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright
138a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer in the
148a1b9b6aSSam Leffler * documentation and/or other materials provided with the distribution.
158a1b9b6aSSam Leffler *
168a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
178a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
188a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
198a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
208a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
218a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
228a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
238a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
248a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
258a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268a1b9b6aSSam Leffler */
278a1b9b6aSSam Leffler
288a1b9b6aSSam Leffler #include <sys/cdefs.h>
298a1b9b6aSSam Leffler /*
308a1b9b6aSSam Leffler * IEEE 802.11 WEP crypto support.
318a1b9b6aSSam Leffler */
32b032f27cSSam Leffler #include "opt_wlan.h"
33b032f27cSSam Leffler
348a1b9b6aSSam Leffler #include <sys/param.h>
358a1b9b6aSSam Leffler #include <sys/systm.h>
368a1b9b6aSSam Leffler #include <sys/mbuf.h>
378a1b9b6aSSam Leffler #include <sys/malloc.h>
388a1b9b6aSSam Leffler #include <sys/kernel.h>
398a1b9b6aSSam Leffler #include <sys/module.h>
408a1b9b6aSSam Leffler #include <sys/endian.h>
418a1b9b6aSSam Leffler
428a1b9b6aSSam Leffler #include <sys/socket.h>
438a1b9b6aSSam Leffler
448a1b9b6aSSam Leffler #include <net/if.h>
458a1b9b6aSSam Leffler #include <net/if_media.h>
468a1b9b6aSSam Leffler #include <net/ethernet.h>
478a1b9b6aSSam Leffler
488a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
498a1b9b6aSSam Leffler
50b032f27cSSam Leffler static void *wep_attach(struct ieee80211vap *, struct ieee80211_key *);
518a1b9b6aSSam Leffler static void wep_detach(struct ieee80211_key *);
528a1b9b6aSSam Leffler static int wep_setkey(struct ieee80211_key *);
53c0cb9349SAdrian Chadd static void wep_setiv(struct ieee80211_key *, uint8_t *);
54ef0d8f63SAdrian Chadd static int wep_encap(struct ieee80211_key *, struct mbuf *);
55c0cb9349SAdrian Chadd static int wep_decap(struct ieee80211_key *, struct mbuf *, int);
5696d88463SSam Leffler static int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
5796d88463SSam Leffler static int wep_demic(struct ieee80211_key *, struct mbuf *, int);
588a1b9b6aSSam Leffler
598a1b9b6aSSam Leffler static const struct ieee80211_cipher wep = {
608a1b9b6aSSam Leffler .ic_name = "WEP",
618a1b9b6aSSam Leffler .ic_cipher = IEEE80211_CIPHER_WEP,
628a1b9b6aSSam Leffler .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
638a1b9b6aSSam Leffler .ic_trailer = IEEE80211_WEP_CRCLEN,
648a1b9b6aSSam Leffler .ic_miclen = 0,
658a1b9b6aSSam Leffler .ic_attach = wep_attach,
668a1b9b6aSSam Leffler .ic_detach = wep_detach,
678a1b9b6aSSam Leffler .ic_setkey = wep_setkey,
68c0cb9349SAdrian Chadd .ic_setiv = wep_setiv,
698a1b9b6aSSam Leffler .ic_encap = wep_encap,
708a1b9b6aSSam Leffler .ic_decap = wep_decap,
718a1b9b6aSSam Leffler .ic_enmic = wep_enmic,
728a1b9b6aSSam Leffler .ic_demic = wep_demic,
738a1b9b6aSSam Leffler };
748a1b9b6aSSam Leffler
758a1b9b6aSSam Leffler static int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
768a1b9b6aSSam Leffler static int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
778a1b9b6aSSam Leffler
788a1b9b6aSSam Leffler struct wep_ctx {
79b032f27cSSam Leffler struct ieee80211vap *wc_vap; /* for diagnostics+statistics */
80b032f27cSSam Leffler struct ieee80211com *wc_ic;
8168e8e04eSSam Leffler uint32_t wc_iv; /* initial vector for crypto */
828a1b9b6aSSam Leffler };
838a1b9b6aSSam Leffler
84d16441fdSSam Leffler /* number of references from net80211 layer */
85d16441fdSSam Leffler static int nrefs = 0;
86d16441fdSSam Leffler
878a1b9b6aSSam Leffler static void *
wep_attach(struct ieee80211vap * vap,struct ieee80211_key * k)88b032f27cSSam Leffler wep_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
898a1b9b6aSSam Leffler {
908a1b9b6aSSam Leffler struct wep_ctx *ctx;
918a1b9b6aSSam Leffler
92b9b53389SAdrian Chadd ctx = (struct wep_ctx *) IEEE80211_MALLOC(sizeof(struct wep_ctx),
93b9b53389SAdrian Chadd M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
948a1b9b6aSSam Leffler if (ctx == NULL) {
95b032f27cSSam Leffler vap->iv_stats.is_crypto_nomem++;
968a1b9b6aSSam Leffler return NULL;
978a1b9b6aSSam Leffler }
988a1b9b6aSSam Leffler
99b032f27cSSam Leffler ctx->wc_vap = vap;
100b032f27cSSam Leffler ctx->wc_ic = vap->iv_ic;
101af7d9f8eSBjoern A. Zeeb net80211_get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv));
102d16441fdSSam Leffler nrefs++; /* NB: we assume caller locking */
1038a1b9b6aSSam Leffler return ctx;
1048a1b9b6aSSam Leffler }
1058a1b9b6aSSam Leffler
1068a1b9b6aSSam Leffler static void
wep_detach(struct ieee80211_key * k)1078a1b9b6aSSam Leffler wep_detach(struct ieee80211_key *k)
1088a1b9b6aSSam Leffler {
1098a1b9b6aSSam Leffler struct wep_ctx *ctx = k->wk_private;
1108a1b9b6aSSam Leffler
111b9b53389SAdrian Chadd IEEE80211_FREE(ctx, M_80211_CRYPTO);
112d16441fdSSam Leffler KASSERT(nrefs > 0, ("imbalanced attach/detach"));
113d16441fdSSam Leffler nrefs--; /* NB: we assume caller locking */
1148a1b9b6aSSam Leffler }
1158a1b9b6aSSam Leffler
1168a1b9b6aSSam Leffler static int
wep_setkey(struct ieee80211_key * k)1178a1b9b6aSSam Leffler wep_setkey(struct ieee80211_key *k)
1188a1b9b6aSSam Leffler {
1198a1b9b6aSSam Leffler return k->wk_keylen >= 40/NBBY;
1208a1b9b6aSSam Leffler }
1218a1b9b6aSSam Leffler
122c0cb9349SAdrian Chadd static void
wep_setiv(struct ieee80211_key * k,uint8_t * ivp)123c0cb9349SAdrian Chadd wep_setiv(struct ieee80211_key *k, uint8_t *ivp)
1248a1b9b6aSSam Leffler {
1258a1b9b6aSSam Leffler struct wep_ctx *ctx = k->wk_private;
126ef0d8f63SAdrian Chadd struct ieee80211vap *vap = ctx->wc_vap;
12768e8e04eSSam Leffler uint32_t iv;
128ef0d8f63SAdrian Chadd uint8_t keyid;
1298a1b9b6aSSam Leffler
130ef0d8f63SAdrian Chadd keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
131ef0d8f63SAdrian Chadd
1328a1b9b6aSSam Leffler /*
1338a1b9b6aSSam Leffler * XXX
1348a1b9b6aSSam Leffler * IV must not duplicate during the lifetime of the key.
1358a1b9b6aSSam Leffler * But no mechanism to renew keys is defined in IEEE 802.11
1368a1b9b6aSSam Leffler * for WEP. And the IV may be duplicated at other stations
1378a1b9b6aSSam Leffler * because the session key itself is shared. So we use a
1388a1b9b6aSSam Leffler * pseudo random IV for now, though it is not the right way.
1398a1b9b6aSSam Leffler *
1408a1b9b6aSSam Leffler * NB: Rather than use a strictly random IV we select a
1418a1b9b6aSSam Leffler * random one to start and then increment the value for
1428a1b9b6aSSam Leffler * each frame. This is an explicit tradeoff between
1438a1b9b6aSSam Leffler * overhead and security. Given the basic insecurity of
1448a1b9b6aSSam Leffler * WEP this seems worthwhile.
1458a1b9b6aSSam Leffler */
1468a1b9b6aSSam Leffler
1478a1b9b6aSSam Leffler /*
1488a1b9b6aSSam Leffler * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
1498a1b9b6aSSam Leffler * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
1508a1b9b6aSSam Leffler */
1518a1b9b6aSSam Leffler iv = ctx->wc_iv;
1528a1b9b6aSSam Leffler if ((iv & 0xff00) == 0xff00) {
1538a1b9b6aSSam Leffler int B = (iv & 0xff0000) >> 16;
1548a1b9b6aSSam Leffler if (3 <= B && B < 16)
1558a1b9b6aSSam Leffler iv += 0x0100;
1568a1b9b6aSSam Leffler }
1578a1b9b6aSSam Leffler ctx->wc_iv = iv + 1;
1588a1b9b6aSSam Leffler
1598a1b9b6aSSam Leffler /*
1608a1b9b6aSSam Leffler * NB: Preserve byte order of IV for packet
1618a1b9b6aSSam Leffler * sniffers; it doesn't matter otherwise.
1628a1b9b6aSSam Leffler */
1638a1b9b6aSSam Leffler #if _BYTE_ORDER == _BIG_ENDIAN
1648a1b9b6aSSam Leffler ivp[0] = iv >> 0;
1658a1b9b6aSSam Leffler ivp[1] = iv >> 8;
1668a1b9b6aSSam Leffler ivp[2] = iv >> 16;
1678a1b9b6aSSam Leffler #else
1688a1b9b6aSSam Leffler ivp[2] = iv >> 0;
1698a1b9b6aSSam Leffler ivp[1] = iv >> 8;
1708a1b9b6aSSam Leffler ivp[0] = iv >> 16;
1718a1b9b6aSSam Leffler #endif
1728a1b9b6aSSam Leffler ivp[3] = keyid;
173c0cb9349SAdrian Chadd }
174c0cb9349SAdrian Chadd
175c0cb9349SAdrian Chadd /*
176c0cb9349SAdrian Chadd * Add privacy headers appropriate for the specified key.
177c0cb9349SAdrian Chadd */
178c0cb9349SAdrian Chadd static int
wep_encap(struct ieee80211_key * k,struct mbuf * m)179c0cb9349SAdrian Chadd wep_encap(struct ieee80211_key *k, struct mbuf *m)
180c0cb9349SAdrian Chadd {
181c0cb9349SAdrian Chadd struct wep_ctx *ctx = k->wk_private;
182c0cb9349SAdrian Chadd struct ieee80211com *ic = ctx->wc_ic;
183f29b9193SAdrian Chadd struct ieee80211_frame *wh;
184c0cb9349SAdrian Chadd uint8_t *ivp;
185c0cb9349SAdrian Chadd int hdrlen;
186f29b9193SAdrian Chadd int is_mgmt;
187c0cb9349SAdrian Chadd
188c0cb9349SAdrian Chadd hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
189f29b9193SAdrian Chadd wh = mtod(m, struct ieee80211_frame *);
190f29b9193SAdrian Chadd is_mgmt = IEEE80211_IS_MGMT(wh);
191f29b9193SAdrian Chadd
192f29b9193SAdrian Chadd /*
193f29b9193SAdrian Chadd * Check to see if IV is required.
194f29b9193SAdrian Chadd */
195f29b9193SAdrian Chadd if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
196f29b9193SAdrian Chadd return 1;
197f29b9193SAdrian Chadd if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV))
198f29b9193SAdrian Chadd return 1;
199c0cb9349SAdrian Chadd
200c0cb9349SAdrian Chadd /*
201c0cb9349SAdrian Chadd * Copy down 802.11 header and add the IV + KeyID.
202c0cb9349SAdrian Chadd */
203bd29f817SBjoern A. Zeeb M_PREPEND(m, wep.ic_header, IEEE80211_M_NOWAIT);
204c0cb9349SAdrian Chadd if (m == NULL)
205c0cb9349SAdrian Chadd return 0;
206c0cb9349SAdrian Chadd ivp = mtod(m, uint8_t *);
207c0cb9349SAdrian Chadd ovbcopy(ivp + wep.ic_header, ivp, hdrlen);
208c0cb9349SAdrian Chadd ivp += hdrlen;
209c0cb9349SAdrian Chadd
210c0cb9349SAdrian Chadd wep_setiv(k, ivp);
2118a1b9b6aSSam Leffler
2128a1b9b6aSSam Leffler /*
213bf0b7b45SAdrian Chadd * Finally, do software encrypt if needed.
2148a1b9b6aSSam Leffler */
2155c1f7f19SSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
2168a1b9b6aSSam Leffler !wep_encrypt(k, m, hdrlen))
2178a1b9b6aSSam Leffler return 0;
2188a1b9b6aSSam Leffler
2198a1b9b6aSSam Leffler return 1;
2208a1b9b6aSSam Leffler }
2218a1b9b6aSSam Leffler
2228a1b9b6aSSam Leffler /*
2238a1b9b6aSSam Leffler * Add MIC to the frame as needed.
2248a1b9b6aSSam Leffler */
2258a1b9b6aSSam Leffler static int
wep_enmic(struct ieee80211_key * k,struct mbuf * m,int force)22696d88463SSam Leffler wep_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
2278a1b9b6aSSam Leffler {
2288a1b9b6aSSam Leffler
2298a1b9b6aSSam Leffler return 1;
2308a1b9b6aSSam Leffler }
2318a1b9b6aSSam Leffler
2328a1b9b6aSSam Leffler /*
2338a1b9b6aSSam Leffler * Validate and strip privacy headers (and trailer) for a
2348a1b9b6aSSam Leffler * received frame. If necessary, decrypt the frame using
2358a1b9b6aSSam Leffler * the specified key.
2368a1b9b6aSSam Leffler */
2378a1b9b6aSSam Leffler static int
wep_decap(struct ieee80211_key * k,struct mbuf * m,int hdrlen)2382cc12adeSSam Leffler wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
2398a1b9b6aSSam Leffler {
2408a1b9b6aSSam Leffler struct wep_ctx *ctx = k->wk_private;
241b032f27cSSam Leffler struct ieee80211vap *vap = ctx->wc_vap;
242f29b9193SAdrian Chadd const struct ieee80211_rx_stats *rxs;
2438a1b9b6aSSam Leffler
244f29b9193SAdrian Chadd rxs = ieee80211_get_rx_params_ptr(m);
245f29b9193SAdrian Chadd
246f29b9193SAdrian Chadd if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))
247f29b9193SAdrian Chadd goto finish;
248f29b9193SAdrian Chadd
2498a1b9b6aSSam Leffler /*
2508a1b9b6aSSam Leffler * Check if the device handled the decrypt in hardware.
2518a1b9b6aSSam Leffler * If so we just strip the header; otherwise we need to
2528a1b9b6aSSam Leffler * handle the decrypt in software.
2538a1b9b6aSSam Leffler */
2545c1f7f19SSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
2558a1b9b6aSSam Leffler !wep_decrypt(k, m, hdrlen)) {
25605ea7a3eSBjoern A. Zeeb #ifdef IEEE80211_DEBUG
25705ea7a3eSBjoern A. Zeeb struct ieee80211_frame *wh;
25805ea7a3eSBjoern A. Zeeb
25905ea7a3eSBjoern A. Zeeb wh = mtod(m, struct ieee80211_frame *);
26005ea7a3eSBjoern A. Zeeb #endif
261b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
262b032f27cSSam Leffler "%s", "WEP ICV mismatch on decrypt");
263b032f27cSSam Leffler vap->iv_stats.is_rx_wepfail++;
2648a1b9b6aSSam Leffler return 0;
2658a1b9b6aSSam Leffler }
2668a1b9b6aSSam Leffler
2678a1b9b6aSSam Leffler /*
2688a1b9b6aSSam Leffler * Copy up 802.11 header and strip crypto bits.
2698a1b9b6aSSam Leffler */
27068e8e04eSSam Leffler ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + wep.ic_header, hdrlen);
2718a1b9b6aSSam Leffler m_adj(m, wep.ic_header);
272f29b9193SAdrian Chadd
273f29b9193SAdrian Chadd finish:
274f29b9193SAdrian Chadd /* XXX TODO: do we have to strip this for offload devices? */
2758a1b9b6aSSam Leffler m_adj(m, -wep.ic_trailer);
2768a1b9b6aSSam Leffler
2778a1b9b6aSSam Leffler return 1;
2788a1b9b6aSSam Leffler }
2798a1b9b6aSSam Leffler
2808a1b9b6aSSam Leffler /*
2818a1b9b6aSSam Leffler * Verify and strip MIC from the frame.
2828a1b9b6aSSam Leffler */
2838a1b9b6aSSam Leffler static int
wep_demic(struct ieee80211_key * k,struct mbuf * skb,int force)28496d88463SSam Leffler wep_demic(struct ieee80211_key *k, struct mbuf *skb, int force)
2858a1b9b6aSSam Leffler {
2868a1b9b6aSSam Leffler return 1;
2878a1b9b6aSSam Leffler }
2888a1b9b6aSSam Leffler
2898a1b9b6aSSam Leffler static const uint32_t crc32_table[256] = {
2908a1b9b6aSSam Leffler 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2918a1b9b6aSSam Leffler 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2928a1b9b6aSSam Leffler 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2938a1b9b6aSSam Leffler 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2948a1b9b6aSSam Leffler 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2958a1b9b6aSSam Leffler 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2968a1b9b6aSSam Leffler 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2978a1b9b6aSSam Leffler 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2988a1b9b6aSSam Leffler 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2998a1b9b6aSSam Leffler 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
3008a1b9b6aSSam Leffler 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
3018a1b9b6aSSam Leffler 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
3028a1b9b6aSSam Leffler 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
3038a1b9b6aSSam Leffler 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
3048a1b9b6aSSam Leffler 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
3058a1b9b6aSSam Leffler 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
3068a1b9b6aSSam Leffler 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
3078a1b9b6aSSam Leffler 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
3088a1b9b6aSSam Leffler 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
3098a1b9b6aSSam Leffler 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
3108a1b9b6aSSam Leffler 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
3118a1b9b6aSSam Leffler 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
3128a1b9b6aSSam Leffler 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
3138a1b9b6aSSam Leffler 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
3148a1b9b6aSSam Leffler 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
3158a1b9b6aSSam Leffler 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
3168a1b9b6aSSam Leffler 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
3178a1b9b6aSSam Leffler 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
3188a1b9b6aSSam Leffler 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
3198a1b9b6aSSam Leffler 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
3208a1b9b6aSSam Leffler 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
3218a1b9b6aSSam Leffler 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
3228a1b9b6aSSam Leffler 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
3238a1b9b6aSSam Leffler 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
3248a1b9b6aSSam Leffler 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
3258a1b9b6aSSam Leffler 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
3268a1b9b6aSSam Leffler 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
3278a1b9b6aSSam Leffler 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
3288a1b9b6aSSam Leffler 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
3298a1b9b6aSSam Leffler 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
3308a1b9b6aSSam Leffler 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
3318a1b9b6aSSam Leffler 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
3328a1b9b6aSSam Leffler 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
3338a1b9b6aSSam Leffler 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
3348a1b9b6aSSam Leffler 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
3358a1b9b6aSSam Leffler 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
3368a1b9b6aSSam Leffler 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
3378a1b9b6aSSam Leffler 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
3388a1b9b6aSSam Leffler 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
3398a1b9b6aSSam Leffler 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
3408a1b9b6aSSam Leffler 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
3418a1b9b6aSSam Leffler 0x2d02ef8dL
3428a1b9b6aSSam Leffler };
3438a1b9b6aSSam Leffler
3448a1b9b6aSSam Leffler static int
wep_encrypt(struct ieee80211_key * key,struct mbuf * m0,int hdrlen)3458a1b9b6aSSam Leffler wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
3468a1b9b6aSSam Leffler {
3478a1b9b6aSSam Leffler #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
3488a1b9b6aSSam Leffler struct wep_ctx *ctx = key->wk_private;
349b032f27cSSam Leffler struct ieee80211vap *vap = ctx->wc_vap;
3508a1b9b6aSSam Leffler struct mbuf *m = m0;
35168e8e04eSSam Leffler uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
3528a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN];
3538a1b9b6aSSam Leffler uint32_t i, j, k, crc;
3548a1b9b6aSSam Leffler size_t buflen, data_len;
3558a1b9b6aSSam Leffler uint8_t S[256];
3568a1b9b6aSSam Leffler uint8_t *pos;
3578a1b9b6aSSam Leffler u_int off, keylen;
3588a1b9b6aSSam Leffler
359b032f27cSSam Leffler vap->iv_stats.is_crypto_wep++;
3608a1b9b6aSSam Leffler
3618a1b9b6aSSam Leffler /* NB: this assumes the header was pulled up */
36268e8e04eSSam Leffler memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
3638a1b9b6aSSam Leffler memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
3648a1b9b6aSSam Leffler
3658a1b9b6aSSam Leffler /* Setup RC4 state */
3668a1b9b6aSSam Leffler for (i = 0; i < 256; i++)
3678a1b9b6aSSam Leffler S[i] = i;
3688a1b9b6aSSam Leffler j = 0;
3698a1b9b6aSSam Leffler keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
3708a1b9b6aSSam Leffler for (i = 0; i < 256; i++) {
3718a1b9b6aSSam Leffler j = (j + S[i] + rc4key[i % keylen]) & 0xff;
3728a1b9b6aSSam Leffler S_SWAP(i, j);
3738a1b9b6aSSam Leffler }
3748a1b9b6aSSam Leffler
3758a1b9b6aSSam Leffler off = hdrlen + wep.ic_header;
3768a1b9b6aSSam Leffler data_len = m->m_pkthdr.len - off;
3778a1b9b6aSSam Leffler
3788a1b9b6aSSam Leffler /* Compute CRC32 over unencrypted data and apply RC4 to data */
3798a1b9b6aSSam Leffler crc = ~0;
3808a1b9b6aSSam Leffler i = j = 0;
3818a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off;
3828a1b9b6aSSam Leffler buflen = m->m_len - off;
3838a1b9b6aSSam Leffler for (;;) {
3848a1b9b6aSSam Leffler if (buflen > data_len)
3858a1b9b6aSSam Leffler buflen = data_len;
3868a1b9b6aSSam Leffler data_len -= buflen;
3878a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) {
3888a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
3898a1b9b6aSSam Leffler i = (i + 1) & 0xff;
3908a1b9b6aSSam Leffler j = (j + S[i]) & 0xff;
3918a1b9b6aSSam Leffler S_SWAP(i, j);
3928a1b9b6aSSam Leffler *pos++ ^= S[(S[i] + S[j]) & 0xff];
3938a1b9b6aSSam Leffler }
3948a1b9b6aSSam Leffler if (m->m_next == NULL) {
3958a1b9b6aSSam Leffler if (data_len != 0) { /* out of data */
396b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
3978a1b9b6aSSam Leffler ether_sprintf(mtod(m0,
3988a1b9b6aSSam Leffler struct ieee80211_frame *)->i_addr2),
399b032f27cSSam Leffler "out of data for WEP (data_len %zu)",
4008a1b9b6aSSam Leffler data_len);
401b032f27cSSam Leffler /* XXX stat */
4028a1b9b6aSSam Leffler return 0;
4038a1b9b6aSSam Leffler }
4048a1b9b6aSSam Leffler break;
4058a1b9b6aSSam Leffler }
4068a1b9b6aSSam Leffler m = m->m_next;
4078a1b9b6aSSam Leffler pos = mtod(m, uint8_t *);
4088a1b9b6aSSam Leffler buflen = m->m_len;
4098a1b9b6aSSam Leffler }
4108a1b9b6aSSam Leffler crc = ~crc;
4118a1b9b6aSSam Leffler
4128a1b9b6aSSam Leffler /* Append little-endian CRC32 and encrypt it to produce ICV */
4138a1b9b6aSSam Leffler icv[0] = crc;
4148a1b9b6aSSam Leffler icv[1] = crc >> 8;
4158a1b9b6aSSam Leffler icv[2] = crc >> 16;
4168a1b9b6aSSam Leffler icv[3] = crc >> 24;
4178a1b9b6aSSam Leffler for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
4188a1b9b6aSSam Leffler i = (i + 1) & 0xff;
4198a1b9b6aSSam Leffler j = (j + S[i]) & 0xff;
4208a1b9b6aSSam Leffler S_SWAP(i, j);
4218a1b9b6aSSam Leffler icv[k] ^= S[(S[i] + S[j]) & 0xff];
4228a1b9b6aSSam Leffler }
4238a1b9b6aSSam Leffler return m_append(m0, IEEE80211_WEP_CRCLEN, icv);
4248a1b9b6aSSam Leffler #undef S_SWAP
4258a1b9b6aSSam Leffler }
4268a1b9b6aSSam Leffler
4278a1b9b6aSSam Leffler static int
wep_decrypt(struct ieee80211_key * key,struct mbuf * m0,int hdrlen)4288a1b9b6aSSam Leffler wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
4298a1b9b6aSSam Leffler {
4308a1b9b6aSSam Leffler #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
4318a1b9b6aSSam Leffler struct wep_ctx *ctx = key->wk_private;
432b032f27cSSam Leffler struct ieee80211vap *vap = ctx->wc_vap;
4338a1b9b6aSSam Leffler struct mbuf *m = m0;
43468e8e04eSSam Leffler uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
4358a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN];
4368a1b9b6aSSam Leffler uint32_t i, j, k, crc;
4378a1b9b6aSSam Leffler size_t buflen, data_len;
4388a1b9b6aSSam Leffler uint8_t S[256];
4398a1b9b6aSSam Leffler uint8_t *pos;
4408a1b9b6aSSam Leffler u_int off, keylen;
4418a1b9b6aSSam Leffler
442b032f27cSSam Leffler vap->iv_stats.is_crypto_wep++;
4438a1b9b6aSSam Leffler
4448a1b9b6aSSam Leffler /* NB: this assumes the header was pulled up */
44568e8e04eSSam Leffler memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
4468a1b9b6aSSam Leffler memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
4478a1b9b6aSSam Leffler
4488a1b9b6aSSam Leffler /* Setup RC4 state */
4498a1b9b6aSSam Leffler for (i = 0; i < 256; i++)
4508a1b9b6aSSam Leffler S[i] = i;
4518a1b9b6aSSam Leffler j = 0;
4528a1b9b6aSSam Leffler keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
4538a1b9b6aSSam Leffler for (i = 0; i < 256; i++) {
4548a1b9b6aSSam Leffler j = (j + S[i] + rc4key[i % keylen]) & 0xff;
4558a1b9b6aSSam Leffler S_SWAP(i, j);
4568a1b9b6aSSam Leffler }
4578a1b9b6aSSam Leffler
4588a1b9b6aSSam Leffler off = hdrlen + wep.ic_header;
459a061aa46SPedro F. Giffuni data_len = m->m_pkthdr.len - (off + wep.ic_trailer);
4608a1b9b6aSSam Leffler
4618a1b9b6aSSam Leffler /* Compute CRC32 over unencrypted data and apply RC4 to data */
4628a1b9b6aSSam Leffler crc = ~0;
4638a1b9b6aSSam Leffler i = j = 0;
4648a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off;
4658a1b9b6aSSam Leffler buflen = m->m_len - off;
4668a1b9b6aSSam Leffler for (;;) {
4678a1b9b6aSSam Leffler if (buflen > data_len)
4688a1b9b6aSSam Leffler buflen = data_len;
4698a1b9b6aSSam Leffler data_len -= buflen;
4708a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) {
4718a1b9b6aSSam Leffler i = (i + 1) & 0xff;
4728a1b9b6aSSam Leffler j = (j + S[i]) & 0xff;
4738a1b9b6aSSam Leffler S_SWAP(i, j);
4748a1b9b6aSSam Leffler *pos ^= S[(S[i] + S[j]) & 0xff];
4758a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
4768a1b9b6aSSam Leffler pos++;
4778a1b9b6aSSam Leffler }
4788a1b9b6aSSam Leffler m = m->m_next;
4798a1b9b6aSSam Leffler if (m == NULL) {
4808a1b9b6aSSam Leffler if (data_len != 0) { /* out of data */
481b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
482b032f27cSSam Leffler mtod(m0, struct ieee80211_frame *)->i_addr2,
483b032f27cSSam Leffler "out of data for WEP (data_len %zu)",
4848a1b9b6aSSam Leffler data_len);
4858a1b9b6aSSam Leffler return 0;
4868a1b9b6aSSam Leffler }
4878a1b9b6aSSam Leffler break;
4888a1b9b6aSSam Leffler }
4898a1b9b6aSSam Leffler pos = mtod(m, uint8_t *);
4908a1b9b6aSSam Leffler buflen = m->m_len;
4918a1b9b6aSSam Leffler }
4928a1b9b6aSSam Leffler crc = ~crc;
4938a1b9b6aSSam Leffler
4948a1b9b6aSSam Leffler /* Encrypt little-endian CRC32 and verify that it matches with
4958a1b9b6aSSam Leffler * received ICV */
4968a1b9b6aSSam Leffler icv[0] = crc;
4978a1b9b6aSSam Leffler icv[1] = crc >> 8;
4988a1b9b6aSSam Leffler icv[2] = crc >> 16;
4998a1b9b6aSSam Leffler icv[3] = crc >> 24;
5008a1b9b6aSSam Leffler for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
5018a1b9b6aSSam Leffler i = (i + 1) & 0xff;
5028a1b9b6aSSam Leffler j = (j + S[i]) & 0xff;
5038a1b9b6aSSam Leffler S_SWAP(i, j);
5048a1b9b6aSSam Leffler /* XXX assumes ICV is contiguous in mbuf */
5058a1b9b6aSSam Leffler if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
5068a1b9b6aSSam Leffler /* ICV mismatch - drop frame */
5078a1b9b6aSSam Leffler return 0;
5088a1b9b6aSSam Leffler }
5098a1b9b6aSSam Leffler }
5108a1b9b6aSSam Leffler return 1;
5118a1b9b6aSSam Leffler #undef S_SWAP
5128a1b9b6aSSam Leffler }
5138a1b9b6aSSam Leffler
5148a1b9b6aSSam Leffler /*
5158a1b9b6aSSam Leffler * Module glue.
5168a1b9b6aSSam Leffler */
51768e8e04eSSam Leffler IEEE80211_CRYPTO_MODULE(wep, 1);
518