Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[802.11] Add support for WEP-protected networks
WEP is a highly flawed cryptosystem, barely better than no encryption at all,
but many people still use it. It does have the advantage of being very simple
and small in code size.

Signed-off-by: Marty Connor <mdc@etherboot.org>
  • Loading branch information
rwcr authored and Marty Connor committed Jan 5, 2010
1 parent 1327a78 commit 01b4f52
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/config/config_net80211.c
Expand Up @@ -31,3 +31,10 @@ REQUIRE_OBJECT ( iwmgmt_cmd );
REQUIRE_OBJECT ( wireless_errors );
#endif

/*
* Drag in 802.11 cryptosystems and handshaking protocols
*
*/
#ifdef CRYPTO_80211_WEP
REQUIRE_OBJECT ( wep );
#endif
6 changes: 6 additions & 0 deletions src/config/general.h
Expand Up @@ -64,6 +64,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
//#undef SANBOOT_PROTO_AOE /* AoE protocol */
//#undef SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */

/*
* 802.11 cryptosystems and handshaking protocols
*
*/
#define CRYPTO_80211_WEP /* WEP encryption (deprecated and insecure!) */

/*
* Name resolution modules
*
Expand Down
1 change: 1 addition & 0 deletions src/include/gpxe/errfile.h
Expand Up @@ -159,6 +159,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ib_cmrc ( ERRFILE_NET | 0x00210000 )
#define ERRFILE_ib_srp ( ERRFILE_NET | 0x00220000 )
#define ERRFILE_sec80211 ( ERRFILE_NET | 0x00230000 )
#define ERRFILE_wep ( ERRFILE_NET | 0x00240000 )

#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
Expand Down
303 changes: 303 additions & 0 deletions src/net/80211/wep.c
@@ -0,0 +1,303 @@
/*
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

FILE_LICENCE ( GPL2_OR_LATER );

#include <gpxe/net80211.h>
#include <gpxe/sec80211.h>
#include <gpxe/crypto.h>
#include <gpxe/arc4.h>
#include <gpxe/crc32.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/** @file
*
* The WEP wireless encryption method (insecure!)
*
* The data field in a WEP-encrypted packet contains a 3-byte
* initialisation vector, one-byte Key ID field (only the bottom two
* bits are ever used), encrypted data, and a 4-byte encrypted CRC of
* the plaintext data, called the ICV. To decrypt it, the IV is
* prepended to the shared key and the data stream (including ICV) is
* run through the ARC4 stream cipher; if the ICV matches a CRC32
* calculated on the plaintext, the packet is valid.
*
* For efficiency and code-size reasons, this file assumes it is
* running on a little-endian machine.
*/

/** Length of WEP initialisation vector */
#define WEP_IV_LEN 3

/** Length of WEP key ID byte */
#define WEP_KID_LEN 1

/** Length of WEP ICV checksum */
#define WEP_ICV_LEN 4

/** Maximum length of WEP key */
#define WEP_MAX_KEY 16

/** Amount of data placed before the encrypted bytes */
#define WEP_HEADER_LEN 4

/** Amount of data placed after the encrypted bytes */
#define WEP_TRAILER_LEN 4

/** Total WEP overhead bytes */
#define WEP_OVERHEAD 8

/** Context for WEP encryption and decryption */
struct wep_ctx
{
/** Encoded WEP key
*
* The actual key bytes are stored beginning at offset 3, to
* leave room for easily inserting the IV before a particular
* operation.
*/
u8 key[WEP_IV_LEN + WEP_MAX_KEY];

/** Length of WEP key (not including IV bytes) */
int keylen;

/** ARC4 context */
struct arc4_ctx arc4;
};

/**
* Initialize WEP algorithm
*
* @v crypto 802.11 cryptographic algorithm
* @v key WEP key to use
* @v keylen Length of WEP key
* @v rsc Initial receive sequence counter (unused)
* @ret rc Return status code
*
* Standard key lengths are 5 and 13 bytes; 16-byte keys are
* occasionally supported as an extension to the standard.
*/
static int wep_init ( struct net80211_crypto *crypto, const void *key,
int keylen, const void *rsc __unused )
{
struct wep_ctx *ctx = crypto->priv;

ctx->keylen = ( keylen > WEP_MAX_KEY ? WEP_MAX_KEY : keylen );
memcpy ( ctx->key + WEP_IV_LEN, key, ctx->keylen );

return 0;
}

/**
* Encrypt packet using WEP
*
* @v crypto 802.11 cryptographic algorithm
* @v iob I/O buffer of plaintext packet
* @ret eiob Newly allocated I/O buffer for encrypted packet, or NULL
*
* If memory allocation fails, @c NULL is returned.
*/
static struct io_buffer * wep_encrypt ( struct net80211_crypto *crypto,
struct io_buffer *iob )
{
struct wep_ctx *ctx = crypto->priv;
struct io_buffer *eiob;
struct ieee80211_frame *hdr;
const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
int datalen = iob_len ( iob ) - hdrlen;
int newlen = hdrlen + datalen + WEP_OVERHEAD;
u32 iv, icv;

eiob = alloc_iob ( newlen );
if ( ! eiob )
return NULL;

memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
hdr = eiob->data;
hdr->fc |= IEEE80211_FC_PROTECTED;

/* Calculate IV, put it in the header (with key ID byte = 0), and
set it up at the start of the encryption key. */
iv = random() & 0xffffff; /* IV in bottom 3 bytes, top byte = KID = 0 */
memcpy ( iob_put ( eiob, WEP_HEADER_LEN ), &iv, WEP_HEADER_LEN );
memcpy ( ctx->key, &iv, WEP_IV_LEN );

/* Encrypt the data using RC4 */
cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
ctx->keylen + WEP_IV_LEN );
cipher_encrypt ( &arc4_algorithm, &ctx->arc4, iob->data + hdrlen,
iob_put ( eiob, datalen ), datalen );

/* Add ICV */
icv = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
cipher_encrypt ( &arc4_algorithm, &ctx->arc4, &icv,
iob_put ( eiob, WEP_ICV_LEN ), WEP_ICV_LEN );

return eiob;
}

/**
* Decrypt packet using WEP
*
* @v crypto 802.11 cryptographic algorithm
* @v eiob I/O buffer of encrypted packet
* @ret iob Newly allocated I/O buffer for plaintext packet, or NULL
*
* If a consistency check for the decryption fails (usually indicating
* an invalid key), @c NULL is returned.
*/
static struct io_buffer * wep_decrypt ( struct net80211_crypto *crypto,
struct io_buffer *eiob )
{
struct wep_ctx *ctx = crypto->priv;
struct io_buffer *iob;
struct ieee80211_frame *hdr;
const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
int datalen = iob_len ( eiob ) - hdrlen - WEP_OVERHEAD;
int newlen = hdrlen + datalen;
u32 iv, icv, crc;

iob = alloc_iob ( newlen );
if ( ! iob )
return NULL;

memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
hdr = iob->data;
hdr->fc &= ~IEEE80211_FC_PROTECTED;

/* Strip off IV and use it to initialize cryptosystem */
memcpy ( &iv, eiob->data + hdrlen, 4 );
iv &= 0xffffff; /* ignore key ID byte */
memcpy ( ctx->key, &iv, WEP_IV_LEN );

/* Decrypt the data using RC4 */
cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
ctx->keylen + WEP_IV_LEN );
cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
WEP_HEADER_LEN, iob_put ( iob, datalen ), datalen );

/* Strip off ICV and verify it */
cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
WEP_HEADER_LEN + datalen, &icv, WEP_ICV_LEN );
crc = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
if ( crc != icv ) {
DBGC ( crypto, "WEP %p CRC mismatch: expect %08x, get %08x\n",
crypto, icv, crc );
free_iob ( iob );
return NULL;
}
return iob;
}

/** WEP cryptosystem for 802.11 */
struct net80211_crypto wep_crypto __net80211_crypto = {
.algorithm = NET80211_CRYPT_WEP,
.init = wep_init,
.encrypt = wep_encrypt,
.decrypt = wep_decrypt,
.priv_len = sizeof ( struct wep_ctx ),
};

/**
* Initialize trivial 802.11 security handshaker
*
* @v dev 802.11 device
* @v ctx Security handshaker
*
* This simply fetches a WEP key from netX/key, and if it exists,
* installs WEP cryptography on the 802.11 device. No real handshaking
* is performed.
*/
static int trivial_init ( struct net80211_device *dev )
{
u8 key[WEP_MAX_KEY]; /* support up to 128-bit keys */
int len;
int rc;

if ( dev->associating &&
dev->associating->crypto == NET80211_CRYPT_NONE )
return 0; /* no crypto? OK. */

len = fetch_setting ( netdev_settings ( dev->netdev ),
&net80211_key_setting, key, WEP_MAX_KEY );

if ( len <= 0 ) {
DBGC ( dev, "802.11 %p cannot do WEP without a key\n", dev );
return -EACCES;
}

/* Full 128-bit keys are a nonstandard extension, but they're
utterly trivial to support, so we do. */
if ( len != 5 && len != 13 && len != 16 ) {
DBGC ( dev, "802.11 %p invalid WEP key length %d\n",
dev, len );
return -EINVAL;
}

DBGC ( dev, "802.11 %p installing %d-bit WEP\n", dev, len * 8 );

rc = sec80211_install ( &dev->crypto, NET80211_CRYPT_WEP, key, len,
NULL );
if ( rc < 0 )
return rc;

return 0;
}

/**
* Check for key change on trivial 802.11 security handshaker
*
* @v dev 802.11 device
* @v ctx Security handshaker
*/
static int trivial_change_key ( struct net80211_device *dev )
{
u8 key[WEP_MAX_KEY];
int len;
int change = 0;

/* If going from WEP to clear, or something else to WEP, reassociate. */
if ( ! dev->crypto || ( dev->crypto->init != wep_init ) )
change ^= 1;

len = fetch_setting ( netdev_settings ( dev->netdev ),
&net80211_key_setting, key, WEP_MAX_KEY );
if ( len <= 0 )
change ^= 1;

/* Changing crypto type => return nonzero to reassociate. */
if ( change )
return -EINVAL;

/* Going from no crypto to still no crypto => nothing to do. */
if ( len <= 0 )
return 0;

/* Otherwise, reinitialise WEP with new key. */
return wep_init ( dev->crypto, key, len, NULL );
}

/** Trivial 802.11 security handshaker */
struct net80211_handshaker trivial_handshaker __net80211_handshaker = {
.protocol = NET80211_SECPROT_NONE,
.init = trivial_init,
.change_key = trivial_change_key,
.priv_len = 0,
};

0 comments on commit 01b4f52

Please sign in to comment.