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 } 306