|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2009 Joshua Oreman <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <ipxe/net80211.h> ! 22: #include <ipxe/sec80211.h> ! 23: #include <ipxe/crypto.h> ! 24: #include <ipxe/arc4.h> ! 25: #include <ipxe/crc32.h> ! 26: #include <stdlib.h> ! 27: #include <string.h> ! 28: #include <errno.h> ! 29: ! 30: /** @file ! 31: * ! 32: * The WEP wireless encryption method (insecure!) ! 33: * ! 34: * The data field in a WEP-encrypted packet contains a 3-byte ! 35: * initialisation vector, one-byte Key ID field (only the bottom two ! 36: * bits are ever used), encrypted data, and a 4-byte encrypted CRC of ! 37: * the plaintext data, called the ICV. To decrypt it, the IV is ! 38: * prepended to the shared key and the data stream (including ICV) is ! 39: * run through the ARC4 stream cipher; if the ICV matches a CRC32 ! 40: * calculated on the plaintext, the packet is valid. ! 41: * ! 42: * For efficiency and code-size reasons, this file assumes it is ! 43: * running on a little-endian machine. ! 44: */ ! 45: ! 46: /** Length of WEP initialisation vector */ ! 47: #define WEP_IV_LEN 3 ! 48: ! 49: /** Length of WEP key ID byte */ ! 50: #define WEP_KID_LEN 1 ! 51: ! 52: /** Length of WEP ICV checksum */ ! 53: #define WEP_ICV_LEN 4 ! 54: ! 55: /** Maximum length of WEP key */ ! 56: #define WEP_MAX_KEY 16 ! 57: ! 58: /** Amount of data placed before the encrypted bytes */ ! 59: #define WEP_HEADER_LEN 4 ! 60: ! 61: /** Amount of data placed after the encrypted bytes */ ! 62: #define WEP_TRAILER_LEN 4 ! 63: ! 64: /** Total WEP overhead bytes */ ! 65: #define WEP_OVERHEAD 8 ! 66: ! 67: /** Context for WEP encryption and decryption */ ! 68: struct wep_ctx ! 69: { ! 70: /** Encoded WEP key ! 71: * ! 72: * The actual key bytes are stored beginning at offset 3, to ! 73: * leave room for easily inserting the IV before a particular ! 74: * operation. ! 75: */ ! 76: u8 key[WEP_IV_LEN + WEP_MAX_KEY]; ! 77: ! 78: /** Length of WEP key (not including IV bytes) */ ! 79: int keylen; ! 80: ! 81: /** ARC4 context */ ! 82: struct arc4_ctx arc4; ! 83: }; ! 84: ! 85: /** ! 86: * Initialize WEP algorithm ! 87: * ! 88: * @v crypto 802.11 cryptographic algorithm ! 89: * @v key WEP key to use ! 90: * @v keylen Length of WEP key ! 91: * @v rsc Initial receive sequence counter (unused) ! 92: * @ret rc Return status code ! 93: * ! 94: * Standard key lengths are 5 and 13 bytes; 16-byte keys are ! 95: * occasionally supported as an extension to the standard. ! 96: */ ! 97: static int wep_init ( struct net80211_crypto *crypto, const void *key, ! 98: int keylen, const void *rsc __unused ) ! 99: { ! 100: struct wep_ctx *ctx = crypto->priv; ! 101: ! 102: ctx->keylen = ( keylen > WEP_MAX_KEY ? WEP_MAX_KEY : keylen ); ! 103: memcpy ( ctx->key + WEP_IV_LEN, key, ctx->keylen ); ! 104: ! 105: return 0; ! 106: } ! 107: ! 108: /** ! 109: * Encrypt packet using WEP ! 110: * ! 111: * @v crypto 802.11 cryptographic algorithm ! 112: * @v iob I/O buffer of plaintext packet ! 113: * @ret eiob Newly allocated I/O buffer for encrypted packet, or NULL ! 114: * ! 115: * If memory allocation fails, @c NULL is returned. ! 116: */ ! 117: static struct io_buffer * wep_encrypt ( struct net80211_crypto *crypto, ! 118: struct io_buffer *iob ) ! 119: { ! 120: struct wep_ctx *ctx = crypto->priv; ! 121: struct io_buffer *eiob; ! 122: struct ieee80211_frame *hdr; ! 123: const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; ! 124: int datalen = iob_len ( iob ) - hdrlen; ! 125: int newlen = hdrlen + datalen + WEP_OVERHEAD; ! 126: u32 iv, icv; ! 127: ! 128: eiob = alloc_iob ( newlen ); ! 129: if ( ! eiob ) ! 130: return NULL; ! 131: ! 132: memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen ); ! 133: hdr = eiob->data; ! 134: hdr->fc |= IEEE80211_FC_PROTECTED; ! 135: ! 136: /* Calculate IV, put it in the header (with key ID byte = 0), and ! 137: set it up at the start of the encryption key. */ ! 138: iv = random() & 0xffffff; /* IV in bottom 3 bytes, top byte = KID = 0 */ ! 139: memcpy ( iob_put ( eiob, WEP_HEADER_LEN ), &iv, WEP_HEADER_LEN ); ! 140: memcpy ( ctx->key, &iv, WEP_IV_LEN ); ! 141: ! 142: /* Encrypt the data using RC4 */ ! 143: cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key, ! 144: ctx->keylen + WEP_IV_LEN ); ! 145: cipher_encrypt ( &arc4_algorithm, &ctx->arc4, iob->data + hdrlen, ! 146: iob_put ( eiob, datalen ), datalen ); ! 147: ! 148: /* Add ICV */ ! 149: icv = ~crc32_le ( ~0, iob->data + hdrlen, datalen ); ! 150: cipher_encrypt ( &arc4_algorithm, &ctx->arc4, &icv, ! 151: iob_put ( eiob, WEP_ICV_LEN ), WEP_ICV_LEN ); ! 152: ! 153: return eiob; ! 154: } ! 155: ! 156: /** ! 157: * Decrypt packet using WEP ! 158: * ! 159: * @v crypto 802.11 cryptographic algorithm ! 160: * @v eiob I/O buffer of encrypted packet ! 161: * @ret iob Newly allocated I/O buffer for plaintext packet, or NULL ! 162: * ! 163: * If a consistency check for the decryption fails (usually indicating ! 164: * an invalid key), @c NULL is returned. ! 165: */ ! 166: static struct io_buffer * wep_decrypt ( struct net80211_crypto *crypto, ! 167: struct io_buffer *eiob ) ! 168: { ! 169: struct wep_ctx *ctx = crypto->priv; ! 170: struct io_buffer *iob; ! 171: struct ieee80211_frame *hdr; ! 172: const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; ! 173: int datalen = iob_len ( eiob ) - hdrlen - WEP_OVERHEAD; ! 174: int newlen = hdrlen + datalen; ! 175: u32 iv, icv, crc; ! 176: ! 177: iob = alloc_iob ( newlen ); ! 178: if ( ! iob ) ! 179: return NULL; ! 180: ! 181: memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen ); ! 182: hdr = iob->data; ! 183: hdr->fc &= ~IEEE80211_FC_PROTECTED; ! 184: ! 185: /* Strip off IV and use it to initialize cryptosystem */ ! 186: memcpy ( &iv, eiob->data + hdrlen, 4 ); ! 187: iv &= 0xffffff; /* ignore key ID byte */ ! 188: memcpy ( ctx->key, &iv, WEP_IV_LEN ); ! 189: ! 190: /* Decrypt the data using RC4 */ ! 191: cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key, ! 192: ctx->keylen + WEP_IV_LEN ); ! 193: cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen + ! 194: WEP_HEADER_LEN, iob_put ( iob, datalen ), datalen ); ! 195: ! 196: /* Strip off ICV and verify it */ ! 197: cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen + ! 198: WEP_HEADER_LEN + datalen, &icv, WEP_ICV_LEN ); ! 199: crc = ~crc32_le ( ~0, iob->data + hdrlen, datalen ); ! 200: if ( crc != icv ) { ! 201: DBGC ( crypto, "WEP %p CRC mismatch: expect %08x, get %08x\n", ! 202: crypto, icv, crc ); ! 203: free_iob ( iob ); ! 204: return NULL; ! 205: } ! 206: return iob; ! 207: } ! 208: ! 209: /** WEP cryptosystem for 802.11 */ ! 210: struct net80211_crypto wep_crypto __net80211_crypto = { ! 211: .algorithm = NET80211_CRYPT_WEP, ! 212: .init = wep_init, ! 213: .encrypt = wep_encrypt, ! 214: .decrypt = wep_decrypt, ! 215: .priv_len = sizeof ( struct wep_ctx ), ! 216: }; ! 217: ! 218: /** ! 219: * Initialize trivial 802.11 security handshaker ! 220: * ! 221: * @v dev 802.11 device ! 222: * @v ctx Security handshaker ! 223: * ! 224: * This simply fetches a WEP key from netX/key, and if it exists, ! 225: * installs WEP cryptography on the 802.11 device. No real handshaking ! 226: * is performed. ! 227: */ ! 228: static int trivial_init ( struct net80211_device *dev ) ! 229: { ! 230: u8 key[WEP_MAX_KEY]; /* support up to 128-bit keys */ ! 231: int len; ! 232: int rc; ! 233: ! 234: if ( dev->associating && ! 235: dev->associating->crypto == NET80211_CRYPT_NONE ) ! 236: return 0; /* no crypto? OK. */ ! 237: ! 238: len = fetch_setting ( netdev_settings ( dev->netdev ), ! 239: &net80211_key_setting, key, WEP_MAX_KEY ); ! 240: ! 241: if ( len <= 0 ) { ! 242: DBGC ( dev, "802.11 %p cannot do WEP without a key\n", dev ); ! 243: return -EACCES; ! 244: } ! 245: ! 246: /* Full 128-bit keys are a nonstandard extension, but they're ! 247: utterly trivial to support, so we do. */ ! 248: if ( len != 5 && len != 13 && len != 16 ) { ! 249: DBGC ( dev, "802.11 %p invalid WEP key length %d\n", ! 250: dev, len ); ! 251: return -EINVAL; ! 252: } ! 253: ! 254: DBGC ( dev, "802.11 %p installing %d-bit WEP\n", dev, len * 8 ); ! 255: ! 256: rc = sec80211_install ( &dev->crypto, NET80211_CRYPT_WEP, key, len, ! 257: NULL ); ! 258: if ( rc < 0 ) ! 259: return rc; ! 260: ! 261: return 0; ! 262: } ! 263: ! 264: /** ! 265: * Check for key change on trivial 802.11 security handshaker ! 266: * ! 267: * @v dev 802.11 device ! 268: * @v ctx Security handshaker ! 269: */ ! 270: static int trivial_change_key ( struct net80211_device *dev ) ! 271: { ! 272: u8 key[WEP_MAX_KEY]; ! 273: int len; ! 274: int change = 0; ! 275: ! 276: /* If going from WEP to clear, or something else to WEP, reassociate. */ ! 277: if ( ! dev->crypto || ( dev->crypto->init != wep_init ) ) ! 278: change ^= 1; ! 279: ! 280: len = fetch_setting ( netdev_settings ( dev->netdev ), ! 281: &net80211_key_setting, key, WEP_MAX_KEY ); ! 282: if ( len <= 0 ) ! 283: change ^= 1; ! 284: ! 285: /* Changing crypto type => return nonzero to reassociate. */ ! 286: if ( change ) ! 287: return -EINVAL; ! 288: ! 289: /* Going from no crypto to still no crypto => nothing to do. */ ! 290: if ( len <= 0 ) ! 291: return 0; ! 292: ! 293: /* Otherwise, reinitialise WEP with new key. */ ! 294: return wep_init ( dev->crypto, key, len, NULL ); ! 295: } ! 296: ! 297: /** Trivial 802.11 security handshaker */ ! 298: struct net80211_handshaker trivial_handshaker __net80211_handshaker = { ! 299: .protocol = NET80211_SECPROT_NONE, ! 300: .init = trivial_init, ! 301: .change_key = trivial_change_key, ! 302: .priv_len = 0, ! 303: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.