1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/version.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/random.h>
18#include <linux/skbuff.h>
19#include <asm/string.h>
20
21#include "ieee80211.h"
22
23#include <linux/crypto.h>
24#include <linux/scatterlist.h>
25#include <linux/crc32.h>
26
27MODULE_AUTHOR("Jouni Malinen");
28MODULE_DESCRIPTION("Host AP crypt: WEP");
29MODULE_LICENSE("GPL");
30
31
32
33struct prism2_wep_data {
34 u32 iv;
35#define WEP_KEY_LEN 13
36 u8 key[WEP_KEY_LEN + 1];
37 u8 key_len;
38 u8 key_idx;
39 struct crypto_blkcipher *tx_tfm;
40 struct crypto_blkcipher *rx_tfm;
41};
42
43
44static void * prism2_wep_init(int keyidx)
45{
46 struct prism2_wep_data *priv;
47
48 priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
49 if (priv == NULL)
50 goto fail;
51 memset(priv, 0, sizeof(*priv));
52 priv->key_idx = keyidx;
53 priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
54 if (IS_ERR(priv->tx_tfm)) {
55 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
56 "crypto API arc4\n");
57 priv->tx_tfm = NULL;
58 goto fail;
59 }
60 priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
61 if (IS_ERR(priv->rx_tfm)) {
62 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
63 "crypto API arc4\n");
64 priv->rx_tfm = NULL;
65 goto fail;
66 }
67
68
69 get_random_bytes(&priv->iv, 4);
70
71 return priv;
72
73fail:
74 if (priv) {
75 if (priv->tx_tfm)
76 crypto_free_blkcipher(priv->tx_tfm);
77 if (priv->rx_tfm)
78 crypto_free_blkcipher(priv->rx_tfm);
79 kfree(priv);
80 }
81
82 return NULL;
83}
84
85
86static void prism2_wep_deinit(void *priv)
87{
88 struct prism2_wep_data *_priv = priv;
89
90 if (_priv) {
91 if (_priv->tx_tfm)
92 crypto_free_blkcipher(_priv->tx_tfm);
93 if (_priv->rx_tfm)
94 crypto_free_blkcipher(_priv->rx_tfm);
95 }
96
97 kfree(priv);
98}
99
100
101
102
103
104
105
106
107static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
108{
109 struct prism2_wep_data *wep = priv;
110 struct blkcipher_desc desc = { .tfm = wep->tx_tfm };
111 u32 klen, len;
112 u8 key[WEP_KEY_LEN + 3];
113 u8 *pos;
114 u32 crc;
115 u8 *icv;
116 struct scatterlist sg;
117
118 if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
119 skb->len < hdr_len)
120 return -1;
121
122 len = skb->len - hdr_len;
123 pos = skb_push(skb, 4);
124 memmove(pos, pos + 4, hdr_len);
125 pos += hdr_len;
126
127 klen = 3 + wep->key_len;
128
129 wep->iv++;
130
131
132
133
134 if ((wep->iv & 0xff00) == 0xff00) {
135 u8 B = (wep->iv >> 16) & 0xff;
136 if (B >= 3 && B < klen)
137 wep->iv += 0x0100;
138 }
139
140
141 *pos++ = key[0] = (wep->iv >> 16) & 0xff;
142 *pos++ = key[1] = (wep->iv >> 8) & 0xff;
143 *pos++ = key[2] = wep->iv & 0xff;
144 *pos++ = wep->key_idx << 6;
145
146
147 memcpy(key + 3, wep->key, wep->key_len);
148
149
150 crc = ~crc32_le(~0, pos, len);
151 icv = skb_put(skb, 4);
152 icv[0] = crc;
153 icv[1] = crc >> 8;
154 icv[2] = crc >> 16;
155 icv[3] = crc >> 24;
156
157 crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
158 sg_init_one(&sg, pos, len + 4);
159
160 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
161}
162
163
164
165
166
167
168
169
170
171static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
172{
173 struct prism2_wep_data *wep = priv;
174 struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
175 u32 klen, plen;
176 u8 key[WEP_KEY_LEN + 3];
177 u8 keyidx, *pos;
178 u32 crc;
179 u8 icv[4];
180 struct scatterlist sg;
181
182 if (skb->len < hdr_len + 8)
183 return -1;
184
185 pos = skb->data + hdr_len;
186 key[0] = *pos++;
187 key[1] = *pos++;
188 key[2] = *pos++;
189 keyidx = *pos++ >> 6;
190 if (keyidx != wep->key_idx)
191 return -1;
192
193 klen = 3 + wep->key_len;
194
195
196 memcpy(key + 3, wep->key, wep->key_len);
197
198
199 plen = skb->len - hdr_len - 8;
200
201 crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
202 sg_init_one(&sg, pos, plen + 4);
203
204 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
205 return -7;
206
207 crc = ~crc32_le(~0, pos, plen);
208 icv[0] = crc;
209 icv[1] = crc >> 8;
210 icv[2] = crc >> 16;
211 icv[3] = crc >> 24;
212
213 if (memcmp(icv, pos + plen, 4) != 0) {
214
215 return -2;
216 }
217
218
219 memmove(skb->data + 4, skb->data, hdr_len);
220 skb_pull(skb, 4);
221 skb_trim(skb, skb->len - 4);
222 return 0;
223}
224
225
226static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
227{
228 struct prism2_wep_data *wep = priv;
229
230 if (len < 0 || len > WEP_KEY_LEN)
231 return -1;
232
233 memcpy(wep->key, key, len);
234 wep->key_len = len;
235
236 return 0;
237}
238
239
240static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
241{
242 struct prism2_wep_data *wep = priv;
243
244 if (len < wep->key_len)
245 return -1;
246
247 memcpy(key, wep->key, wep->key_len);
248
249 return wep->key_len;
250}
251
252
253static char * prism2_wep_print_stats(char *p, void *priv)
254{
255 struct prism2_wep_data *wep = priv;
256 p += sprintf(p, "key[%d] alg=WEP len=%d\n",
257 wep->key_idx, wep->key_len);
258 return p;
259}
260
261
262static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
263 .name = "WEP",
264 .init = prism2_wep_init,
265 .deinit = prism2_wep_deinit,
266 .encrypt_mpdu = prism2_wep_encrypt,
267 .decrypt_mpdu = prism2_wep_decrypt,
268 .encrypt_msdu = NULL,
269 .decrypt_msdu = NULL,
270 .set_key = prism2_wep_set_key,
271 .get_key = prism2_wep_get_key,
272 .print_stats = prism2_wep_print_stats,
273 .extra_prefix_len = 4,
274 .extra_postfix_len = 4,
275 .owner = THIS_MODULE,
276};
277
278
279int ieee80211_crypto_wep_init(void)
280{
281 return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
282}
283
284
285void ieee80211_crypto_wep_exit(void)
286{
287 ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
288}
289
290
291void ieee80211_wep_null(void)
292{
293
294 return;
295}
296