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