ieee80211_crypto.c revision 116742
1/*- 2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 3. Neither the names of the above-listed copyright holders nor the names 16 * of any contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * Alternatively, this software may be distributed under the terms of the 20 * GNU General Public License ("GPL") version 2 as published by the Free 21 * Software Foundation. 22 * 23 * NO WARRANTY 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34 * THE POSSIBILITY OF SUCH DAMAGES. 35 * 36 * $Id: ieee80211_crypto.c,v 1.2 2003/06/22 06:16:32 sam Exp $ 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto.c 116742 2003-06-23 16:55:01Z sam $"); 41 42#include "opt_inet.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/mbuf.h> 47#include <sys/malloc.h> 48#include <sys/kernel.h> 49#include <sys/socket.h> 50#include <sys/sockio.h> 51#include <sys/endian.h> 52#include <sys/errno.h> 53#include <sys/bus.h> 54#include <sys/proc.h> 55#include <sys/sysctl.h> 56 57#include <machine/atomic.h> 58 59#include <net/if.h> 60#include <net/if_dl.h> 61#include <net/if_media.h> 62#include <net/if_arp.h> 63#include <net/ethernet.h> 64#include <net/if_llc.h> 65 66#include <net80211/ieee80211_var.h> 67 68#include <net/bpf.h> 69 70#ifdef INET 71#include <netinet/in.h> 72#include <netinet/if_ether.h> 73#endif 74 75#include <crypto/rc4/rc4.h> 76#define arc4_ctxlen() sizeof (struct rc4_state) 77#define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l) 78#define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) 79 80static void ieee80211_crc_init(void); 81static u_int32_t ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len); 82 83void 84ieee80211_crypto_attach(struct ifnet *ifp) 85{ 86 struct ieee80211com *ic = (void *)ifp; 87 88 /* 89 * Setup crypto support. 90 */ 91 ieee80211_crc_init(); 92 ic->ic_iv = arc4random(); 93} 94 95void 96ieee80211_crypto_detach(struct ifnet *ifp) 97{ 98 struct ieee80211com *ic = (void *)ifp; 99 100 if (ic->ic_wep_ctx != NULL) { 101 free(ic->ic_wep_ctx, M_DEVBUF); 102 ic->ic_wep_ctx = NULL; 103 } 104} 105 106struct mbuf * 107ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) 108{ 109 struct ieee80211com *ic = (void *)ifp; 110 struct mbuf *m, *n, *n0; 111 struct ieee80211_frame *wh; 112 int i, left, len, moff, noff, kid; 113 u_int32_t iv, crc; 114 u_int8_t *ivp; 115 void *ctx; 116 u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 117 u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; 118 119 n0 = NULL; 120 if ((ctx = ic->ic_wep_ctx) == NULL) { 121 ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); 122 if (ctx == NULL) 123 goto fail; 124 ic->ic_wep_ctx = ctx; 125 } 126 m = m0; 127 left = m->m_pkthdr.len; 128 MGET(n, M_DONTWAIT, m->m_type); 129 n0 = n; 130 if (n == NULL) 131 goto fail; 132 M_MOVE_PKTHDR(n, m); 133 len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; 134 if (txflag) { 135 n->m_pkthdr.len += len; 136 } else { 137 n->m_pkthdr.len -= len; 138 left -= len; 139 } 140 n->m_len = MHLEN; 141 if (n->m_pkthdr.len >= MINCLSIZE) { 142 MCLGET(n, M_DONTWAIT); 143 if (n->m_flags & M_EXT) 144 n->m_len = n->m_ext.ext_size; 145 } 146 len = sizeof(struct ieee80211_frame); 147 memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); 148 wh = mtod(n, struct ieee80211_frame *); 149 left -= len; 150 moff = len; 151 noff = len; 152 if (txflag) { 153 kid = ic->ic_wep_txkey; 154 wh->i_fc[1] |= IEEE80211_FC1_WEP; 155 iv = ic->ic_iv; 156 /* 157 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 158 * (B, 255, N) with 3 <= B < 8 159 */ 160 if (iv >= 0x03ff00 && 161 (iv & 0xf8ff00) == 0x00ff00) 162 iv += 0x000100; 163 ic->ic_iv = iv + 1; 164 /* put iv in little endian to prepare 802.11i */ 165 ivp = mtod(n, u_int8_t *) + noff; 166 for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { 167 ivp[i] = iv & 0xff; 168 iv >>= 8; 169 } 170 ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ 171 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 172 } else { 173 wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 174 ivp = mtod(m, u_int8_t *) + moff; 175 kid = ivp[IEEE80211_WEP_IVLEN] >> 6; 176 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; 177 } 178 memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); 179 memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, 180 ic->ic_nw_keys[kid].wk_len); 181 arc4_setkey(ctx, keybuf, 182 IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); 183 184 /* encrypt with calculating CRC */ 185 crc = ~0; 186 while (left > 0) { 187 len = m->m_len - moff; 188 if (len == 0) { 189 m = m->m_next; 190 moff = 0; 191 continue; 192 } 193 if (len > n->m_len - noff) { 194 len = n->m_len - noff; 195 if (len == 0) { 196 MGET(n->m_next, M_DONTWAIT, n->m_type); 197 if (n->m_next == NULL) 198 goto fail; 199 n = n->m_next; 200 n->m_len = MLEN; 201 if (left >= MINCLSIZE) { 202 MCLGET(n, M_DONTWAIT); 203 if (n->m_flags & M_EXT) 204 n->m_len = n->m_ext.ext_size; 205 } 206 noff = 0; 207 continue; 208 } 209 } 210 if (len > left) 211 len = left; 212 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, 213 mtod(m, caddr_t) + moff, len); 214 if (txflag) 215 crc = ieee80211_crc_update(crc, 216 mtod(m, u_int8_t *) + moff, len); 217 else 218 crc = ieee80211_crc_update(crc, 219 mtod(n, u_int8_t *) + noff, len); 220 left -= len; 221 moff += len; 222 noff += len; 223 } 224 crc = ~crc; 225 if (txflag) { 226 *(u_int32_t *)crcbuf = htole32(crc); 227 if (n->m_len >= noff + sizeof(crcbuf)) 228 n->m_len = noff + sizeof(crcbuf); 229 else { 230 n->m_len = noff; 231 MGET(n->m_next, M_DONTWAIT, n->m_type); 232 if (n->m_next == NULL) 233 goto fail; 234 n = n->m_next; 235 n->m_len = sizeof(crcbuf); 236 noff = 0; 237 } 238 arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, 239 sizeof(crcbuf)); 240 } else { 241 n->m_len = noff; 242 for (noff = 0; noff < sizeof(crcbuf); noff += len) { 243 len = sizeof(crcbuf) - noff; 244 if (len > m->m_len - moff) 245 len = m->m_len - moff; 246 if (len > 0) 247 arc4_encrypt(ctx, crcbuf + noff, 248 mtod(m, caddr_t) + moff, len); 249 m = m->m_next; 250 moff = 0; 251 } 252 if (crc != le32toh(*(u_int32_t *)crcbuf)) { 253#ifdef IEEE80211_DEBUG 254 if (ieee80211_debug) { 255 if_printf(ifp, "decrypt CRC error\n"); 256 if (ieee80211_debug > 1) 257 ieee80211_dump_pkt(n0->m_data, 258 n0->m_len, -1, -1); 259 } 260#endif 261 goto fail; 262 } 263 } 264 m_freem(m0); 265 return n0; 266 267 fail: 268 m_freem(m0); 269 m_freem(n0); 270 return NULL; 271} 272 273/* 274 * CRC 32 -- routine from RFC 2083 275 */ 276 277/* Table of CRCs of all 8-bit messages */ 278static u_int32_t ieee80211_crc_table[256]; 279 280/* Make the table for a fast CRC. */ 281static void 282ieee80211_crc_init(void) 283{ 284 u_int32_t c; 285 int n, k; 286 287 for (n = 0; n < 256; n++) { 288 c = (u_int32_t)n; 289 for (k = 0; k < 8; k++) { 290 if (c & 1) 291 c = 0xedb88320UL ^ (c >> 1); 292 else 293 c = c >> 1; 294 } 295 ieee80211_crc_table[n] = c; 296 } 297} 298 299/* 300 * Update a running CRC with the bytes buf[0..len-1]--the CRC 301 * should be initialized to all 1's, and the transmitted value 302 * is the 1's complement of the final running CRC 303 */ 304 305static u_int32_t 306ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) 307{ 308 u_int8_t *endbuf; 309 310 for (endbuf = buf + len; buf < endbuf; buf++) 311 crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); 312 return crc; 313} 314