]>
Commit | Line | Data |
---|---|---|
2e479416 JM |
1 | /* |
2 | * Wired Equivalent Privacy (WEP) | |
3 | * Copyright (c) 2010, Jouni Malinen <j@w1.fi> | |
4 | * | |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
2e479416 JM |
7 | */ |
8 | ||
9 | #include "utils/includes.h" | |
10 | ||
11 | #include "utils/common.h" | |
12 | #include "common/ieee802_11_defs.h" | |
13 | #include "wlantest.h" | |
14 | ||
15 | ||
16 | void wep_crypt(u8 *key, u8 *buf, size_t plen) | |
17 | { | |
18 | u32 i, j, k; | |
19 | u8 S[256]; | |
20 | #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) | |
21 | u8 *pos; | |
22 | ||
23 | /* Setup RC4 state */ | |
24 | for (i = 0; i < 256; i++) | |
25 | S[i] = i; | |
26 | j = 0; | |
27 | for (i = 0; i < 256; i++) { | |
28 | j = (j + S[i] + key[i & 0x0f]) & 0xff; | |
29 | S_SWAP(i, j); | |
30 | } | |
31 | ||
32 | /* Apply RC4 to data */ | |
33 | pos = buf; | |
34 | i = j = 0; | |
35 | for (k = 0; k < plen; k++) { | |
36 | i = (i + 1) & 0xff; | |
37 | j = (j + S[i]) & 0xff; | |
38 | S_SWAP(i, j); | |
39 | *pos ^= S[(S[i] + S[j]) & 0xff]; | |
40 | pos++; | |
41 | } | |
42 | } | |
43 | ||
44 | ||
45 | static int try_wep(const u8 *key, size_t key_len, const u8 *data, | |
46 | size_t data_len, u8 *plain) | |
47 | { | |
48 | u32 icv, rx_icv; | |
49 | u8 k[16]; | |
50 | int i, j; | |
51 | ||
52 | for (i = 0, j = 0; i < sizeof(k); i++) { | |
53 | k[i] = key[j]; | |
54 | j++; | |
55 | if (j >= key_len) | |
56 | j = 0; | |
57 | } | |
58 | ||
59 | os_memcpy(plain, data, data_len); | |
60 | wep_crypt(k, plain, data_len); | |
61 | icv = crc32(plain, data_len - 4); | |
62 | rx_icv = WPA_GET_LE32(plain + data_len - 4); | |
63 | if (icv != rx_icv) | |
64 | return -1; | |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
69 | ||
70 | u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr, | |
71 | const u8 *data, size_t data_len, size_t *decrypted_len) | |
72 | { | |
73 | u8 *plain; | |
74 | struct wlantest_wep *w; | |
75 | int found = 0; | |
76 | u8 key[16]; | |
77 | ||
78 | if (dl_list_empty(&wt->wep)) | |
79 | return NULL; | |
80 | ||
81 | if (data_len < 4 + 4) | |
82 | return NULL; | |
83 | plain = os_malloc(data_len - 4); | |
84 | if (plain == NULL) | |
85 | return NULL; | |
86 | ||
87 | dl_list_for_each(w, &wt->wep, struct wlantest_wep, list) { | |
88 | os_memcpy(key, data, 3); | |
89 | os_memcpy(key + 3, w->key, w->key_len); | |
90 | if (try_wep(key, 3 + w->key_len, data + 4, data_len - 4, plain) | |
91 | == 0) { | |
92 | found = 1; | |
93 | break; | |
94 | } | |
95 | } | |
96 | if (!found) { | |
97 | os_free(plain); | |
98 | return NULL; | |
99 | } | |
100 | ||
101 | *decrypted_len = data_len - 4 - 4; | |
102 | return plain; | |
103 | } |