diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2011-01-14 17:43:17 +0200 |
---|---|---|
committer | Jouni Malinen <j@w1.fi> | 2011-01-14 17:43:17 +0200 |
commit | 2e479416d1bfa584eddf7d335cf969ea6fe1f89c (patch) | |
tree | 0ef076cbd4031ef46afe8e0eeff30062aaa19be7 | |
parent | 3558c41ee71ff0e34aca47412b33019630c8e922 (diff) | |
download | external_wpa_supplicant_8_ti-2e479416d1bfa584eddf7d335cf969ea6fe1f89c.zip external_wpa_supplicant_8_ti-2e479416d1bfa584eddf7d335cf969ea6fe1f89c.tar.gz external_wpa_supplicant_8_ti-2e479416d1bfa584eddf7d335cf969ea6fe1f89c.tar.bz2 |
wlantest: Add support for decrypting WEP frames
-rw-r--r-- | wlantest/Makefile | 1 | ||||
-rw-r--r-- | wlantest/bss.c | 9 | ||||
-rw-r--r-- | wlantest/rx_data.c | 17 | ||||
-rw-r--r-- | wlantest/sta.c | 12 | ||||
-rw-r--r-- | wlantest/tkip.c | 32 | ||||
-rw-r--r-- | wlantest/wep.c | 109 | ||||
-rw-r--r-- | wlantest/wlantest.c | 31 | ||||
-rw-r--r-- | wlantest/wlantest.h | 11 |
8 files changed, 189 insertions, 33 deletions
diff --git a/wlantest/Makefile b/wlantest/Makefile index 378efab..c165ed4 100644 --- a/wlantest/Makefile +++ b/wlantest/Makefile @@ -66,6 +66,7 @@ OBJS += ccmp.o OBJS += tkip.o OBJS += ctrl.o OBJS += inject.o +OBJS += wep.o LIBS += -lpcap diff --git a/wlantest/bss.c b/wlantest/bss.c index e7942af..a4a3155 100644 --- a/wlantest/bss.c +++ b/wlantest/bss.c @@ -16,6 +16,7 @@ #include "utils/common.h" #include "common/defs.h" +#include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "crypto/sha1.h" #include "wlantest.h" @@ -132,6 +133,9 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss, struct wpa_ie_data data; int update = 0; + if (bss->capab_info != bss->prev_capab_info) + update = 1; + if (elems->ssid == NULL || elems->ssid_len > 32) { wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon " "frame for " MACSTR, MAC2STR(bss->bssid)); @@ -195,6 +199,7 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss, if (!update) return; + bss->prev_capab_info = bss->capab_info; bss->proto = 0; bss->pairwise_cipher = 0; bss->group_cipher = 0; @@ -236,6 +241,10 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss, !(bss->rsn_capab & WPA_CAPABILITY_MFPC)) bss->mgmt_group_cipher = 0; + if (!bss->wpaie[0] && !bss->rsnie[0] && + (bss->capab_info & WLAN_CAPABILITY_PRIVACY)) + bss->group_cipher = WPA_CIPHER_WEP40; + wpa_printf(MSG_INFO, "BSS " MACSTR " proto=%s%s%s" "pairwise=%s%s%s%s" diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index a8312b6..95daaf2 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -144,7 +144,8 @@ static void rx_data_bss_prot_group(struct wlantest *wt, } keyid = data[3] >> 6; - if (bss->gtk_len[keyid] == 0) { + if (bss->gtk_len[keyid] == 0 && bss->group_cipher != WPA_CIPHER_WEP40) + { wpa_printf(MSG_MSGDUMP, "No GTK known to decrypt the frame " "(A2=" MACSTR " KeyID=%d)", MAC2STR(hdr->addr2), keyid); @@ -153,6 +154,8 @@ static void rx_data_bss_prot_group(struct wlantest *wt, if (bss->group_cipher == WPA_CIPHER_TKIP) tkip_get_pn(pn, data); + else if (bss->group_cipher == WPA_CIPHER_WEP40) + goto skip_replay_det; else ccmp_get_pn(pn, data); if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) { @@ -167,9 +170,12 @@ static void rx_data_bss_prot_group(struct wlantest *wt, wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6); } +skip_replay_det: if (bss->group_cipher == WPA_CIPHER_TKIP) decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len, &dlen); + else if (bss->group_cipher == WPA_CIPHER_WEP40) + decrypted = wep_decrypt(wt, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len, &dlen); @@ -237,7 +243,9 @@ static void rx_data_bss_prot(struct wlantest *wt, } } } - if ((sta == NULL || !sta->ptk_set) && tk == NULL) { + if ((sta == NULL || + (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) && + tk == NULL) { wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame"); return; } @@ -300,6 +308,8 @@ static void rx_data_bss_prot(struct wlantest *wt, if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) tkip_get_pn(pn, data); + else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) + goto skip_replay_det; else ccmp_get_pn(pn, data); if (os_memcmp(pn, rsc, 6) <= 0) { @@ -314,10 +324,13 @@ static void rx_data_bss_prot(struct wlantest *wt, wpa_hexdump(MSG_INFO, "RSC", rsc, 6); } +skip_replay_det: if (tk) decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen); else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen); + else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) + decrypted = wep_decrypt(wt, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen); if (decrypted) { diff --git a/wlantest/sta.c b/wlantest/sta.c index bfa6ee0..6e012b8 100644 --- a/wlantest/sta.c +++ b/wlantest/sta.c @@ -16,6 +16,7 @@ #include "utils/common.h" #include "common/defs.h" +#include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "wlantest.h" @@ -97,8 +98,16 @@ void sta_update_assoc(struct wlantest_sta *sta, struct ieee802_11_elems *elems) wpa_printf(MSG_INFO, "Failed to parse WPA IE from " MACSTR, MAC2STR(sta->addr)); } - } else + } else { sta->rsnie[0] = 0; + sta->proto = 0; + sta->pairwise_cipher = 0; + sta->key_mgmt = 0; + sta->rsn_capab = 0; + if (sta->assocreq_capab_info & WLAN_CAPABILITY_PRIVACY) + sta->pairwise_cipher = WPA_CIPHER_WEP40; + goto skip_rsn_wpa; + } sta->proto = data.proto; sta->pairwise_cipher = data.pairwise_cipher; @@ -130,6 +139,7 @@ void sta_update_assoc(struct wlantest_sta *sta, struct ieee802_11_elems *elems) "MFPR", MAC2STR(sta->addr), MAC2STR(bss->bssid)); } +skip_rsn_wpa: wpa_printf(MSG_INFO, "STA " MACSTR " proto=%s%s%s" "pairwise=%s%s%s%s" diff --git a/wlantest/tkip.c b/wlantest/tkip.c index 3da64c5..3533914 100644 --- a/wlantest/tkip.c +++ b/wlantest/tkip.c @@ -19,6 +19,9 @@ #include "wlantest.h" +void wep_crypt(u8 *key, u8 *buf, size_t plen); + + static inline u16 RotR1(u16 val) { return (val >> 1) | (val << 15); @@ -172,35 +175,6 @@ static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, } -static void wep_crypt(u8 *key, u8 *buf, size_t plen) -{ - u32 i, j, k; - u8 S[256]; -#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) - u8 *pos; - - /* Setup RC4 state */ - for (i = 0; i < 256; i++) - S[i] = i; - j = 0; - for (i = 0; i < 256; i++) { - j = (j + S[i] + key[i & 0x0f]) & 0xff; - S_SWAP(i, j); - } - - /* Apply RC4 to data */ - pos = buf; - i = j = 0; - for (k = 0; k < plen; k++) { - i = (i + 1) & 0xff; - j = (j + S[i]) & 0xff; - S_SWAP(i, j); - *pos ^= S[(S[i] + S[j]) & 0xff]; - pos++; - } -} - - static inline u32 rotl(u32 val, int bits) { return (val << bits) | (val >> (32 - bits)); diff --git a/wlantest/wep.c b/wlantest/wep.c new file mode 100644 index 0000000..13ff218 --- /dev/null +++ b/wlantest/wep.c @@ -0,0 +1,109 @@ +/* + * Wired Equivalent Privacy (WEP) + * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "wlantest.h" + + +void wep_crypt(u8 *key, u8 *buf, size_t plen) +{ + u32 i, j, k; + u8 S[256]; +#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) + u8 *pos; + + /* Setup RC4 state */ + for (i = 0; i < 256; i++) + S[i] = i; + j = 0; + for (i = 0; i < 256; i++) { + j = (j + S[i] + key[i & 0x0f]) & 0xff; + S_SWAP(i, j); + } + + /* Apply RC4 to data */ + pos = buf; + i = j = 0; + for (k = 0; k < plen; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos ^= S[(S[i] + S[j]) & 0xff]; + pos++; + } +} + + +static int try_wep(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *plain) +{ + u32 icv, rx_icv; + u8 k[16]; + int i, j; + + for (i = 0, j = 0; i < sizeof(k); i++) { + k[i] = key[j]; + j++; + if (j >= key_len) + j = 0; + } + + os_memcpy(plain, data, data_len); + wep_crypt(k, plain, data_len); + icv = crc32(plain, data_len - 4); + rx_icv = WPA_GET_LE32(plain + data_len - 4); + if (icv != rx_icv) + return -1; + + return 0; +} + + +u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, size_t *decrypted_len) +{ + u8 *plain; + struct wlantest_wep *w; + int found = 0; + u8 key[16]; + + if (dl_list_empty(&wt->wep)) + return NULL; + + if (data_len < 4 + 4) + return NULL; + plain = os_malloc(data_len - 4); + if (plain == NULL) + return NULL; + + dl_list_for_each(w, &wt->wep, struct wlantest_wep, list) { + os_memcpy(key, data, 3); + os_memcpy(key + 3, w->key, w->key_len); + if (try_wep(key, 3 + w->key_len, data + 4, data_len - 4, plain) + == 0) { + found = 1; + break; + } + } + if (!found) { + os_free(plain); + return NULL; + } + + *decrypted_len = data_len - 4 - 4; + return plain; +} diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c index a98513a..17b3dd3 100644 --- a/wlantest/wlantest.c +++ b/wlantest/wlantest.c @@ -66,6 +66,7 @@ static void wlantest_init(struct wlantest *wt) dl_list_init(&wt->secret); dl_list_init(&wt->radius); dl_list_init(&wt->pmk); + dl_list_init(&wt->wep); } @@ -82,6 +83,7 @@ static void wlantest_deinit(struct wlantest *wt) struct wlantest_radius_secret *s, *sn; struct wlantest_radius *r, *rn; struct wlantest_pmk *pmk, *np; + struct wlantest_wep *wep, *nw; if (wt->ctrl_sock >= 0) ctrl_deinit(wt); @@ -98,6 +100,8 @@ static void wlantest_deinit(struct wlantest *wt) radius_deinit(r); dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list) pmk_deinit(pmk); + dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list) + os_free(wep); write_pcap_deinit(wt); } @@ -132,6 +136,28 @@ static void add_secret(struct wlantest *wt, const char *secret) } +static void add_wep(struct wlantest *wt, const char *key) +{ + struct wlantest_wep *w; + size_t len = os_strlen(key); + + if (len != 2 * 5 && len != 2 * 13) { + wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key); + return; + } + w = os_zalloc(sizeof(*w)); + if (w == NULL) + return; + if (hexstr2bin(key, w->key, len / 2) < 0) { + os_free(w); + wpa_printf(MSG_INFO, "Invalid WEP key '%s'", key); + return; + } + w->key_len = len / 2; + dl_list_add(&wt->wep, &w->list); +} + + int main(int argc, char *argv[]) { int c; @@ -152,7 +178,7 @@ int main(int argc, char *argv[]) wlantest_init(&wt); for (;;) { - c = getopt(argc, argv, "cdhi:I:p:P:qr:R:w:"); + c = getopt(argc, argv, "cdhi:I:p:P:qr:R:w:W:"); if (c < 0) break; switch (c) { @@ -190,6 +216,9 @@ int main(int argc, char *argv[]) case 'w': write_file = optarg; break; + case 'W': + add_wep(&wt, optarg); + break; default: usage(); return -1; diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index d938346..4301504 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -44,6 +44,12 @@ struct wlantest_pmk { u8 pmk[32]; }; +struct wlantest_wep { + struct dl_list list; + size_t key_len; + u8 key[13]; +}; + struct wlantest_sta { struct dl_list list; struct wlantest_bss *bss; @@ -106,6 +112,7 @@ struct wlantest_bss { struct dl_list list; u8 bssid[ETH_ALEN]; u16 capab_info; + u16 prev_capab_info; u8 ssid[32]; size_t ssid_len; int proberesp_seen; @@ -154,6 +161,7 @@ struct wlantest { struct dl_list secret; /* struct wlantest_radius_secret */ struct dl_list radius; /* struct wlantest_radius */ struct dl_list pmk; /* struct wlantest_pmk */ + struct dl_list wep; /* struct wlantest_wep */ unsigned int rx_mgmt; unsigned int rx_ctrl; @@ -223,6 +231,9 @@ u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos, u8 *pn, int keyid, size_t *encrypted_len); void tkip_get_pn(u8 *pn, const u8 *data); +u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, size_t *decrypted_len); + int ctrl_init(struct wlantest *wt); void ctrl_deinit(struct wlantest *wt); |