mirror of https://github.com/proski/madwifi
359 lines
11 KiB
C
359 lines
11 KiB
C
/*-
|
|
* Copyright (c) 2004 Sam Leffler, Errno Consulting
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of the
|
|
* GNU General Public License ("GPL") version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* WEP test module.
|
|
*
|
|
* Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
|
|
*
|
|
* To use this tester load the net80211 layer (either as a module or
|
|
* by statically configuring it into your kernel), then insmod this
|
|
* module. It should automatically run all test cases and print
|
|
* information for each. To run one or more tests you can specify a
|
|
* tests parameter to the module that is a bit mask of the set of tests
|
|
* you want; e.g. insmod wep_test tests=7 will run only test MPDUs
|
|
* 1, 2, and 3.
|
|
*/
|
|
#if !defined(AUTOCONF_INCLUDED) && !defined(CONFIG_LOCALVERSION)
|
|
#include <linux/config.h>
|
|
#endif
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
#include "if_media.h"
|
|
#include <net80211/ieee80211_var.h>
|
|
|
|
/*
|
|
MPDU data
|
|
aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
|
|
0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
|
|
20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
|
|
41 43 41 43 41 43 41 41 41 00 00 20 00 01
|
|
|
|
RC4 encryption is performed as follows:
|
|
17
|
|
18 Key fb 02 9e 30 31 32 33 34
|
|
Plaintext
|
|
aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
|
|
22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
|
|
00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
|
|
43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
|
|
Ciphertext
|
|
f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
|
|
5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
|
|
1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
|
|
40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
|
|
The plaintext consists of the MPDU data, followed by a 4-octet CRC-32
|
|
calculated over the MPDU data.
|
|
19 The expanded MPDU, after WEP encapsulation, is as follows:
|
|
20
|
|
21 IV fb 02 9e 80
|
|
MPDU data
|
|
f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d 5f 58 a5
|
|
03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14 1d 48 5f 8a a8 36
|
|
de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10 40 b2 4b 7d 1a 69 38 56 ed
|
|
0d 43 98 e7 ae e3 bf 0e
|
|
ICV 2a 2c a8 f7
|
|
*/
|
|
static const u_int8_t test1_key[] = { /* TK (w/o IV) */
|
|
0x30, 0x31, 0x32, 0x33, 0x34,
|
|
};
|
|
static const u_int8_t test1_plaintext[] = { /* Plaintext MPDU */
|
|
0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28, /* 802.11 Header */
|
|
0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
|
|
0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
|
|
0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, /* Plaintext data */
|
|
0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
|
|
0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
|
|
0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
|
|
0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
|
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
|
|
0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
|
|
0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
|
|
0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
|
|
0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
|
|
};
|
|
static const u_int8_t test1_encrypted[] = { /* Encrypted MPDU */
|
|
0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
|
|
0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
|
|
0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
|
|
0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
|
|
0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
|
|
0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
|
|
0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
|
|
0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
|
|
0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
|
|
0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
|
|
0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
|
|
0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
|
|
0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
|
|
0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
|
|
0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
|
|
};
|
|
|
|
/* XXX fix byte order of iv */
|
|
#define TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
|
|
name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
|
|
test##n##_key, sizeof(test##n##_key), \
|
|
test##n##_plaintext, sizeof(test##n##_plaintext), \
|
|
test##n##_encrypted, sizeof(test##n##_encrypted) \
|
|
}
|
|
|
|
static struct ciphertest {
|
|
const char *name;
|
|
int cipher;
|
|
int keyix;
|
|
u_int8_t iv[4];
|
|
const u_int8_t *key;
|
|
size_t key_len;
|
|
const u_int8_t *plaintext;
|
|
size_t plaintext_len;
|
|
const u_int8_t *encrypted;
|
|
size_t encrypted_len;
|
|
} weptests[] = {
|
|
TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
|
|
};
|
|
|
|
static void
|
|
dumpdata(const char *tag, const void *p, size_t len)
|
|
{
|
|
int i;
|
|
|
|
printk("%s: 0x%p len %zu", tag, p, len);
|
|
for (i = 0; i < len; i++) {
|
|
if ((i % 16) == 0)
|
|
printk("\n%03d:", i);
|
|
printk(" %02x", ((u_int8_t *)p)[i]);
|
|
}
|
|
printk("\n");
|
|
}
|
|
|
|
static void
|
|
cmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < genlen; i++)
|
|
if (((u_int8_t *)gen)[i] != ((u_int8_t *)ref)[i]) {
|
|
printk("first difference at byte %u\n", i);
|
|
break;
|
|
}
|
|
dumpdata("Generated", gen, genlen);
|
|
dumpdata("Reference", ref, reflen);
|
|
}
|
|
|
|
struct wep_ctx_hw { /* for use with h/w support */
|
|
struct ieee80211vap *wc_vap; /* for diagnostics + statistics */
|
|
struct ieee80211com *wc_ic; /* for diagnostics */
|
|
u_int32_t wc_iv; /* initial vector for crypto */
|
|
};
|
|
|
|
static int
|
|
runtest(struct ieee80211vap *vap, struct ciphertest *t)
|
|
{
|
|
struct ieee80211_key *key;
|
|
struct sk_buff *skb = NULL;
|
|
const struct ieee80211_cipher *cip;
|
|
u_int8_t mac[IEEE80211_ADDR_LEN];
|
|
struct wep_ctx_hw *ctx;
|
|
int hdrlen;
|
|
|
|
printk("%s: ", t->name);
|
|
|
|
if (!ieee80211_crypto_available(vap, t->cipher)) {
|
|
printk("FAIL: ieee80211_crypto_available failed\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Setup key.
|
|
*/
|
|
key = &vap->iv_nw_keys[t->keyix];
|
|
key->wk_keyix = t->keyix;
|
|
if (!ieee80211_crypto_newkey(vap, t->cipher,
|
|
IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV,
|
|
key)) {
|
|
printk("FAIL: ieee80211_crypto_newkey failed\n");
|
|
goto bad;
|
|
}
|
|
|
|
memcpy(key->wk_key, t->key, t->key_len);
|
|
key->wk_keylen = t->key_len;
|
|
if (!ieee80211_crypto_setkey(vap, key, mac, NULL)) {
|
|
printk("FAIL: ieee80211_crypto_setkey failed\n");
|
|
goto bad;
|
|
}
|
|
cip = key->wk_cipher;
|
|
|
|
/*
|
|
* Craft encrypted frame from known data.
|
|
*/
|
|
skb = ieee80211_dev_alloc_skb(t->encrypted_len);
|
|
if (skb == NULL) {
|
|
printk("FAIL: unable to allocate skbuff\n");
|
|
goto bad;
|
|
}
|
|
memcpy(skb_put(skb, t->encrypted_len), t->encrypted, t->encrypted_len);
|
|
|
|
/*
|
|
* Decrypt frame.
|
|
*/
|
|
hdrlen = ieee80211_hdrspace(vap->iv_ic, skb->data);
|
|
if (!(*cip->ic_decap)(key, skb, hdrlen)) {
|
|
printk("FAIL: wep decap failed\n");
|
|
cmpfail(skb->data, skb->len,
|
|
t->plaintext, t->plaintext_len);
|
|
goto bad;
|
|
}
|
|
/*
|
|
* Verify: frame length, frame contents.
|
|
*/
|
|
if (skb->len != t->plaintext_len) {
|
|
printk("FAIL: decap botch; length mismatch\n");
|
|
cmpfail(skb->data, skb->len,
|
|
t->plaintext, t->plaintext_len);
|
|
goto bad;
|
|
} else if (memcmp(skb->data, t->plaintext, t->plaintext_len)) {
|
|
printk("FAIL: decap botch; data does not compare\n");
|
|
cmpfail(skb->data, skb->len,
|
|
t->plaintext, sizeof(t->plaintext));
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* Encrypt frame.
|
|
*/
|
|
ctx = (struct wep_ctx_hw *)key->wk_private;
|
|
memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv)); /* for encap/encrypt */
|
|
if (!(*cip->ic_encap)(key, skb, t->keyix << 6)) {
|
|
printk("FAIL: wep encap failed\n");
|
|
goto bad;
|
|
}
|
|
/*
|
|
* Verify: frame length, frame contents.
|
|
*/
|
|
if (skb->len != t->encrypted_len) {
|
|
printk("FAIL: encap data length mismatch\n");
|
|
cmpfail(skb->data, skb->len,
|
|
t->encrypted, t->encrypted_len);
|
|
goto bad;
|
|
} else if (memcmp(skb->data, t->encrypted, skb->len)) {
|
|
printk("FAIL: encrypt data does not compare\n");
|
|
cmpfail(skb->data, skb->len,
|
|
t->encrypted, t->encrypted_len);
|
|
dumpdata("Plaintext", t->plaintext, t->plaintext_len);
|
|
goto bad;
|
|
}
|
|
if (skb != NULL)
|
|
ieee80211_dev_kfree_skb(&skb);
|
|
ieee80211_crypto_delkey(vap, key, NULL);
|
|
printk("PASS\n");
|
|
return 1;
|
|
bad:
|
|
if (skb != NULL)
|
|
ieee80211_dev_kfree_skb(&skb);
|
|
ieee80211_crypto_delkey(vap, key, NULL);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Module glue.
|
|
*/
|
|
MODULE_AUTHOR("Errno Consulting, Sam Leffler");
|
|
MODULE_DESCRIPTION("802.11 wireless support: WEP cipher tester");
|
|
#ifdef MODULE_LICENSE
|
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
#endif
|
|
|
|
static int tests = -1;
|
|
static int debug = 0;
|
|
|
|
#include <linux/moduleparam.h>
|
|
module_param(tests, int, 0600);
|
|
module_param(debug, int, 0600);
|
|
|
|
MODULE_PARM_DESC(tests, "Specify which tests to run");
|
|
MODULE_PARM_DESC(debug, "Enable IEEE80211_MSG_CRYPTO");
|
|
|
|
static int __init
|
|
init_crypto_wep_test(void)
|
|
{
|
|
struct {
|
|
struct ieee80211vap vap;
|
|
struct ieee80211com ic;
|
|
struct net_device netdev;
|
|
} *buf;
|
|
struct ieee80211vap *vap;
|
|
int i, pass, total;
|
|
|
|
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
vap = &buf->vap;
|
|
vap->iv_ic = &buf->ic;
|
|
vap->iv_dev = &buf->netdev;
|
|
vap->iv_ic->ic_dev = vap->iv_dev;
|
|
strncpy(vap->iv_dev->name, "WEP test", sizeof(vap->iv_dev->name) - 1);
|
|
|
|
if (debug)
|
|
vap->iv_debug = IEEE80211_MSG_CRYPTO;
|
|
|
|
ieee80211_crypto_attach(vap->iv_ic);
|
|
ieee80211_crypto_vattach(vap);
|
|
|
|
pass = 0;
|
|
total = 0;
|
|
for (i = 0; i < ARRAY_SIZE(weptests); i++)
|
|
if (tests & (1 << i)) {
|
|
total++;
|
|
pass += runtest(vap, &weptests[i]);
|
|
}
|
|
printk("%u of %u 802.11i WEP test vectors passed\n", pass, total);
|
|
ieee80211_crypto_vdetach(vap);
|
|
ieee80211_crypto_detach(vap->iv_ic);
|
|
kfree(buf);
|
|
return (pass == total ? 0 : -ENXIO);
|
|
}
|
|
module_init(init_crypto_wep_test);
|
|
|
|
static void __exit
|
|
exit_crypto_wep_test(void)
|
|
{
|
|
}
|
|
module_exit(exit_crypto_wep_test);
|