1 /*
2 * Host AP crypt: host-based WEP encryption implementation for Host AP driver
3 *
4 * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. See README and COPYING for
9 * more details.
10 */
11
12 //#include <linux/config.h>
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 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
24 //#include "crypto_compat.h"
25 #endif
26
27
28 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
29 #include "rtl_crypto.h"
30 #else
31 #include <linux/crypto.h>
32 #endif
33
34 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
35 #include <asm/scatterlist.h>
36 #else
37 #include <linux/scatterlist.h>
38 #endif
39 //#include <asm/scatterlist.h>
40 #include <linux/crc32.h>
41 //
42 /*
43 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
44 #include "rtl_crypto.h"
45 #else
46 #include <linux/crypto.h>
47 #endif
48
49 #include <asm/scatterlist.h>
50 #include <linux/crc32.h>
51 */
52 MODULE_AUTHOR("Jouni Malinen");
53 MODULE_DESCRIPTION("Host AP crypt: WEP");
54 MODULE_LICENSE("GPL");
55 #ifndef OPENSUSE_SLED
56 #define OPENSUSE_SLED 0
57 #endif
58
59 struct prism2_wep_data {
60 u32 iv;
61 #define WEP_KEY_LEN 13
62 u8 key[WEP_KEY_LEN + 1];
63 u8 key_len;
64 u8 key_idx;
65 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
66 struct crypto_tfm *tfm;
67 #else
68 struct crypto_blkcipher *tx_tfm;
69 struct crypto_blkcipher *rx_tfm;
70 #endif
71 };
72
73
74 static void * prism2_wep_init(int keyidx)
75 {
76 struct prism2_wep_data *priv;
77
78 priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
79 if (priv == NULL)
80 goto fail;
81 memset(priv, 0, sizeof(*priv));
82 priv->key_idx = keyidx;
83
84 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
85 priv->tfm = crypto_alloc_tfm("arc4", 0);
86 if (priv->tfm == NULL) {
87 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
88 "crypto API arc4\n");
89 goto fail;
90 }
91 #else
92 priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
93 if (IS_ERR(priv->tx_tfm)) {
94 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
95 "crypto API arc4\n");
96 priv->tx_tfm = NULL;
97 goto fail;
98 }
99 priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
100 if (IS_ERR(priv->rx_tfm)) {
101 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
102 "crypto API arc4\n");
103 priv->rx_tfm = NULL;
104 goto fail;
105 }
106 #endif
107
108 /* start WEP IV from a random value */
109 get_random_bytes(&priv->iv, 4);
110
111 return priv;
112
113 fail:
114 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
115 if (priv) {
116 if (priv->tfm)
117 crypto_free_tfm(priv->tfm);
118 kfree(priv);
119 }
120 #else
121 if (priv) {
122 if (priv->tx_tfm)
123 crypto_free_blkcipher(priv->tx_tfm);
124 if (priv->rx_tfm)
125 crypto_free_blkcipher(priv->rx_tfm);
126 kfree(priv);
127 }
128 #endif
129 return NULL;
130 }
131
132
133 static void prism2_wep_deinit(void *priv)
134 {
135 struct prism2_wep_data *_priv = priv;
136 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
137 if (_priv && _priv->tfm)
138 crypto_free_tfm(_priv->tfm);
139 #else
140 if (_priv) {
141 if (_priv->tx_tfm)
142 crypto_free_blkcipher(_priv->tx_tfm);
143 if (_priv->rx_tfm)
144 crypto_free_blkcipher(_priv->rx_tfm);
145 }
146 #endif
147 kfree(priv);
148 }
149
150 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
151 * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
152 * so the payload length increases with 8 bytes.
153 *
154 * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
155 */
156 static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
157 {
158 struct prism2_wep_data *wep = priv;
159 u32 klen, len;
160 u8 key[WEP_KEY_LEN + 3];
161 u8 *pos;
162 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
163 #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
164 struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
165 #endif
166 u32 crc;
167 u8 *icv;
168 struct scatterlist sg;
169 if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
170 skb->len < hdr_len)
171 return -1;
172
173 len = skb->len - hdr_len;
174 pos = skb_push(skb, 4);
175 memmove(pos, pos + 4, hdr_len);
176 pos += hdr_len;
177
178 klen = 3 + wep->key_len;
179
180 wep->iv++;
181
182 /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
183 * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
184 * can be used to speedup attacks, so avoid using them. */
185 if ((wep->iv & 0xff00) == 0xff00) {
186 u8 B = (wep->iv >> 16) & 0xff;
187 if (B >= 3 && B < klen)
188 wep->iv += 0x0100;
189 }
190
191 /* Prepend 24-bit IV to RC4 key and TX frame */
192 *pos++ = key[0] = (wep->iv >> 16) & 0xff;
193 *pos++ = key[1] = (wep->iv >> 8) & 0xff;
194 *pos++ = key[2] = wep->iv & 0xff;
195 *pos++ = wep->key_idx << 6;
196
197 /* Copy rest of the WEP key (the secret part) */
198 memcpy(key + 3, wep->key, wep->key_len);
199
200 if (!tcb_desc->bHwSec)
201 {
202
203 /* Append little-endian CRC32 and encrypt it to produce ICV */
204 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
205 crc = ~crc32_le(~0, pos, len);
206 #else
207 crc = ~ether_crc_le(len, pos);
208 #endif
209 icv = skb_put(skb, 4);
210 icv[0] = crc;
211 icv[1] = crc >> 8;
212 icv[2] = crc >> 16;
213 icv[3] = crc >> 24;
214
215 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
216 crypto_cipher_setkey(wep->tfm, key, klen);
217 sg.page = virt_to_page(pos);
218 sg.offset = offset_in_page(pos);
219 sg.length = len + 4;
220 crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
221 return 0;
222 #else
223 crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
224 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
225 sg.page = virt_to_page(pos);
226 sg.offset = offset_in_page(pos);
227 sg.length = len + 4;
228 #else
229 sg_init_one(&sg, pos, len+4);
230 #endif
231 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
232 #endif
233 }
234
235 return 0;
236 }
237
238
239 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
240 * the frame: IV (4 bytes), encrypted payload (including SNAP header),
241 * ICV (4 bytes). len includes both IV and ICV.
242 *
243 * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
244 * failure. If frame is OK, IV and ICV will be removed.
245 */
246 static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
247 {
248 struct prism2_wep_data *wep = priv;
249 u32 klen, plen;
250 u8 key[WEP_KEY_LEN + 3];
251 u8 keyidx, *pos;
252 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
253 #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
254 struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
255 #endif
256 u32 crc;
257 u8 icv[4];
258 struct scatterlist sg;
259 if (skb->len < hdr_len + 8)
260 return -1;
261
262 pos = skb->data + hdr_len;
263 key[0] = *pos++;
264 key[1] = *pos++;
265 key[2] = *pos++;
266 keyidx = *pos++ >> 6;
267 if (keyidx != wep->key_idx)
268 return -1;
269
270 klen = 3 + wep->key_len;
271
272 /* Copy rest of the WEP key (the secret part) */
273 memcpy(key + 3, wep->key, wep->key_len);
274
275 /* Apply RC4 to data and compute CRC32 over decrypted data */
276 plen = skb->len - hdr_len - 8;
277
278 if (!tcb_desc->bHwSec)
279 {
280 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
281 crypto_cipher_setkey(wep->tfm, key, klen);
282 sg.page = virt_to_page(pos);
283 sg.offset = offset_in_page(pos);
284 sg.length = plen + 4;
285 crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
286 #else
287 crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
288 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
289 sg.page = virt_to_page(pos);
290 sg.offset = offset_in_page(pos);
291 sg.length = plen + 4;
292 #else
293 sg_init_one(&sg, pos, plen+4);
294 #endif
295 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
296 return -7;
297 #endif
298 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
299 crc = ~crc32_le(~0, pos, plen);
300 #else
301 crc = ~ether_crc_le(plen, pos);
302 #endif
303 icv[0] = crc;
304 icv[1] = crc >> 8;
305 icv[2] = crc >> 16;
306 icv[3] = crc >> 24;
307 if (memcmp(icv, pos + plen, 4) != 0) {
308 /* ICV mismatch - drop frame */
309 return -2;
310 }
311 }
312 /* Remove IV and ICV */
313 memmove(skb->data + 4, skb->data, hdr_len);
314 skb_pull(skb, 4);
315 skb_trim(skb, skb->len - 4);
316
317 return 0;
318 }
319
320
321 static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
322 {
323 struct prism2_wep_data *wep = priv;
324
325 if (len < 0 || len > WEP_KEY_LEN)
326 return -1;
327
328 memcpy(wep->key, key, len);
329 wep->key_len = len;
330
331 return 0;
332 }
333
334
335 static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
336 {
337 struct prism2_wep_data *wep = priv;
338
339 if (len < wep->key_len)
340 return -1;
341
342 memcpy(key, wep->key, wep->key_len);
343
344 return wep->key_len;
345 }
346
347
348 static char * prism2_wep_print_stats(char *p, void *priv)
349 {
350 struct prism2_wep_data *wep = priv;
351 p += sprintf(p, "key[%d] alg=WEP len=%d\n",
352 wep->key_idx, wep->key_len);
353 return p;
354 }
355
356
357 static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
358 .name = "WEP",
359 .init = prism2_wep_init,
360 .deinit = prism2_wep_deinit,
361 .encrypt_mpdu = prism2_wep_encrypt,
362 .decrypt_mpdu = prism2_wep_decrypt,
363 .encrypt_msdu = NULL,
364 .decrypt_msdu = NULL,
365 .set_key = prism2_wep_set_key,
366 .get_key = prism2_wep_get_key,
367 .print_stats = prism2_wep_print_stats,
368 .extra_prefix_len = 4, /* IV */
369 .extra_postfix_len = 4, /* ICV */
370 .owner = THIS_MODULE,
371 };
372
373
374 static int __init ieee80211_crypto_wep_init(void)
375 {
376 return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
377 }
378
379
380 static void __exit ieee80211_crypto_wep_exit(void)
381 {
382 ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
383 }
384
385 void ieee80211_wep_null(void)
386 {
387 // printk("============>%s()\n", __FUNCTION__);
388 return;
389 }
390 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
391 EXPORT_SYMBOL(ieee80211_wep_null);
392 #else
393 EXPORT_SYMBOL_NOVERS(ieee80211_wep_null);
394 #endif
395
396 module_init(ieee80211_crypto_wep_init);
397 module_exit(ieee80211_crypto_wep_exit);
398
|
This page was automatically generated by the
LXR engine.
|