1 /* $OpenBSD: ieee80211_crypto_wep.c,v 1.17 2018/11/09 14:14:31 claudio Exp $ */
2
3 /*-
4 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * This code implements Wired Equivalent Privacy (WEP) defined in
21 * IEEE Std 802.11-2007 section 8.2.1.
22 */
23
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/mbuf.h>
27 #include <sys/malloc.h>
28 #include <sys/kernel.h>
29 #include <sys/socket.h>
30 #include <sys/endian.h>
31
32 #include <net/if.h>
33 #include <net/if_dl.h>
34 #include <net/if_media.h>
35
36 #include <netinet/in.h>
37 #include <netinet/if_ether.h>
38
39 #include <net80211/ieee80211_var.h>
40 #include <net80211/ieee80211_crypto.h>
41
42 #include <crypto/arc4.h>
43
44 /* WEP software crypto context */
45 struct ieee80211_wep_ctx {
46 struct rc4_ctx rc4;
47 u_int32_t iv;
48 };
49
50 /*
51 * Initialize software crypto context. This function can be overridden
52 * by drivers doing hardware crypto.
53 */
54 int
55 ieee80211_wep_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
56 {
57 struct ieee80211_wep_ctx *ctx;
58
59 ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
60 if (ctx == NULL)
61 return ENOMEM;
62 k->k_priv = ctx;
63 return 0;
64 }
65
66 void
67 ieee80211_wep_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
68 {
69 if (k->k_priv != NULL) {
70 explicit_bzero(k->k_priv, sizeof(struct ieee80211_wep_ctx));
71 free(k->k_priv, M_DEVBUF, sizeof(struct ieee80211_wep_ctx));
72 }
73 k->k_priv = NULL;
74 }
75
76 /* shortcut */
77 #define IEEE80211_WEP_HDRLEN \
78 (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
79
80 struct mbuf *
81 ieee80211_wep_encrypt(struct ieee80211com *ic, struct mbuf *m0,
82 struct ieee80211_key *k)
83 {
84 struct ieee80211_wep_ctx *ctx = k->k_priv;
85 u_int8_t wepseed[16];
86 const struct ieee80211_frame *wh;
87 struct mbuf *n0, *m, *n;
88 u_int8_t *ivp, *icvp;
89 u_int32_t iv, crc;
90 int left, moff, noff, len, hdrlen;
91
92 MGET(n0, M_DONTWAIT, m0->m_type);
93 if (n0 == NULL)
94 goto nospace;
95 if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
96 goto nospace;
97 n0->m_pkthdr.len += IEEE80211_WEP_HDRLEN;
98 n0->m_len = MHLEN;
99 if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
100 MCLGET(n0, M_DONTWAIT);
101 if (n0->m_flags & M_EXT)
102 n0->m_len = n0->m_ext.ext_size;
103 }
104 if (n0->m_len > n0->m_pkthdr.len)
105 n0->m_len = n0->m_pkthdr.len;
106
107 /* copy 802.11 header */
108 wh = mtod(m0, struct ieee80211_frame *);
109 hdrlen = ieee80211_get_hdrlen(wh);
110 memcpy(mtod(n0, caddr_t), wh, hdrlen);
111
112 /* select a new IV for every MPDU */
113 iv = (ctx->iv != 0) ? ctx->iv : arc4random();
114 /* skip weak IVs from Fluhrer/Mantin/Shamir */
115 if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00)
116 iv += 0x000100;
117 ctx->iv = iv + 1;
118 ivp = mtod(n0, u_int8_t *) + hdrlen;
119 ivp[0] = iv;
120 ivp[1] = iv >> 8;
121 ivp[2] = iv >> 16;
122 ivp[3] = k->k_id << 6;
123
124 /* compute WEP seed: concatenate IV and WEP Key */
125 memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
126 memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
127 rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
128 explicit_bzero(wepseed, sizeof(wepseed));
129
130 /* encrypt frame body and compute WEP ICV */
131 m = m0;
132 n = n0;
133 moff = hdrlen;
134 noff = hdrlen + IEEE80211_WEP_HDRLEN;
135 left = m0->m_pkthdr.len - moff;
136 crc = ~0;
137 while (left > 0) {
138 if (moff == m->m_len) {
139 /* nothing left to copy from m */
140 m = m->m_next;
141 moff = 0;
142 }
143 if (noff == n->m_len) {
144 /* n is full and there's more data to copy */
145 MGET(n->m_next, M_DONTWAIT, n->m_type);
146 if (n->m_next == NULL)
147 goto nospace;
148 n = n->m_next;
149 n->m_len = MLEN;
150 if (left >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
151 MCLGET(n, M_DONTWAIT);
152 if (n->m_flags & M_EXT)
153 n->m_len = n->m_ext.ext_size;
154 }
155 if (n->m_len > left)
156 n->m_len = left;
157 noff = 0;
158 }
159 len = min(m->m_len - moff, n->m_len - noff);
160
161 crc = ether_crc32_le_update(crc, mtod(m, caddr_t) + moff, len);
162 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
163 mtod(n, caddr_t) + noff, len);
164
165 moff += len;
166 noff += len;
167 left -= len;
168 }
169
170 /* reserve trailing space for WEP ICV */
171 if (m_trailingspace(n) < IEEE80211_WEP_CRCLEN) {
172 MGET(n->m_next, M_DONTWAIT, n->m_type);
173 if (n->m_next == NULL)
174 goto nospace;
175 n = n->m_next;
176 n->m_len = 0;
177 }
178
179 /* finalize WEP ICV */
180 icvp = mtod(n, caddr_t) + n->m_len;
181 crc = ~crc;
182 icvp[0] = crc;
183 icvp[1] = crc >> 8;
184 icvp[2] = crc >> 16;
185 icvp[3] = crc >> 24;
186 rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
187 n->m_len += IEEE80211_WEP_CRCLEN;
188 n0->m_pkthdr.len += IEEE80211_WEP_CRCLEN;
189
190 m_freem(m0);
191 return n0;
192 nospace:
193 ic->ic_stats.is_tx_nombuf++;
194 m_freem(m0);
195 m_freem(n0);
196 return NULL;
197 }
198
199 struct mbuf *
200 ieee80211_wep_decrypt(struct ieee80211com *ic, struct mbuf *m0,
201 struct ieee80211_key *k)
202 {
203 struct ieee80211_wep_ctx *ctx = k->k_priv;
204 struct ieee80211_frame *wh;
205 u_int8_t wepseed[16];
206 u_int32_t crc, crc0;
207 u_int8_t *ivp;
208 struct mbuf *n0, *m, *n;
209 int hdrlen, left, moff, noff, len;
210
211 wh = mtod(m0, struct ieee80211_frame *);
212 hdrlen = ieee80211_get_hdrlen(wh);
213
214 if (m0->m_pkthdr.len < hdrlen + IEEE80211_WEP_TOTLEN) {
215 m_freem(m0);
216 return NULL;
217 }
218
219 /* concatenate IV and WEP Key */
220 ivp = (u_int8_t *)wh + hdrlen;
221 memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
222 memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
223 rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
224 explicit_bzero(wepseed, sizeof(wepseed));
225
226 MGET(n0, M_DONTWAIT, m0->m_type);
227 if (n0 == NULL)
228 goto nospace;
229 if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
230 goto nospace;
231 n0->m_pkthdr.len -= IEEE80211_WEP_TOTLEN;
232 n0->m_len = MHLEN;
233 if (n0->m_pkthdr.len >= MINCLSIZE) {
234 MCLGET(n0, M_DONTWAIT);
235 if (n0->m_flags & M_EXT)
236 n0->m_len = n0->m_ext.ext_size;
237 }
238 if (n0->m_len > n0->m_pkthdr.len)
239 n0->m_len = n0->m_pkthdr.len;
240
241 /* copy 802.11 header and clear protected bit */
242 memcpy(mtod(n0, caddr_t), wh, hdrlen);
243 wh = mtod(n0, struct ieee80211_frame *);
244 wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
245
246 /* decrypt frame body and compute WEP ICV */
247 m = m0;
248 n = n0;
249 moff = hdrlen + IEEE80211_WEP_HDRLEN;
250 noff = hdrlen;
251 left = n0->m_pkthdr.len - noff;
252 crc = ~0;
253 while (left > 0) {
254 if (moff == m->m_len) {
255 /* nothing left to copy from m */
256 m = m->m_next;
257 moff = 0;
258 }
259 if (noff == n->m_len) {
260 /* n is full and there's more data to copy */
261 MGET(n->m_next, M_DONTWAIT, n->m_type);
262 if (n->m_next == NULL)
263 goto nospace;
264 n = n->m_next;
265 n->m_len = MLEN;
266 if (left >= MINCLSIZE) {
267 MCLGET(n, M_DONTWAIT);
268 if (n->m_flags & M_EXT)
269 n->m_len = n->m_ext.ext_size;
270 }
271 if (n->m_len > left)
272 n->m_len = left;
273 noff = 0;
274 }
275 len = min(m->m_len - moff, n->m_len - noff);
276
277 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
278 mtod(n, caddr_t) + noff, len);
279 crc = ether_crc32_le_update(crc, mtod(n, caddr_t) + noff, len);
280
281 moff += len;
282 noff += len;
283 left -= len;
284 }
285
286 /* decrypt ICV and compare it with calculated ICV */
287 m_copydata(m, moff, IEEE80211_WEP_CRCLEN, (caddr_t)&crc0);
288 rc4_crypt(&ctx->rc4, (caddr_t)&crc0, (caddr_t)&crc0,
289 IEEE80211_WEP_CRCLEN);
290 crc = ~crc;
291 if (crc != letoh32(crc0)) {
292 ic->ic_stats.is_rx_decryptcrc++;
293 m_freem(m0);
294 m_freem(n0);
295 return NULL;
296 }
297
298 m_freem(m0);
299 return n0;
300 nospace:
301 ic->ic_stats.is_rx_nombuf++;
302 m_freem(m0);
303 m_freem(n0);
304 return NULL;
305 }
Cache object: d25fd319878bf24d9382797d1fab3963
|