Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / staging / rtl8187se / ieee80211 / ieee80211_crypt_wep.c
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/module.h>
14 #include <linux/init.h>
15 #include <linux/slab.h>
16 #include <linux/random.h>
17 #include <linux/skbuff.h>
18 #include <asm/string.h>
19
20 #include "ieee80211.h"
21
22 #include <linux/crypto.h>
23 #include <linux/scatterlist.h>
24 #include <linux/crc32.h>
25
26 MODULE_AUTHOR("Jouni Malinen");
27 MODULE_DESCRIPTION("Host AP crypt: WEP");
28 MODULE_LICENSE("GPL");
29
30
31
32 struct prism2_wep_data {
33         u32 iv;
34 #define WEP_KEY_LEN 13
35         u8 key[WEP_KEY_LEN + 1];
36         u8 key_len;
37         u8 key_idx;
38         struct crypto_blkcipher *tx_tfm;
39         struct crypto_blkcipher *rx_tfm;
40 };
41
42
43 static void * prism2_wep_init(int keyidx)
44 {
45         struct prism2_wep_data *priv;
46
47         priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
48         if (priv == NULL)
49                 goto fail;
50         priv->key_idx = keyidx;
51         priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
52         if (IS_ERR(priv->tx_tfm)) {
53                 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
54                        "crypto API arc4\n");
55                 priv->tx_tfm = NULL;
56                 goto fail;
57         }
58         priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
59         if (IS_ERR(priv->rx_tfm)) {
60                 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
61                        "crypto API arc4\n");
62                 priv->rx_tfm = NULL;
63                 goto fail;
64         }
65
66         /* start WEP IV from a random value */
67         get_random_bytes(&priv->iv, 4);
68
69         return priv;
70
71 fail:
72         if (priv) {
73                 if (priv->tx_tfm)
74                         crypto_free_blkcipher(priv->tx_tfm);
75                 if (priv->rx_tfm)
76                         crypto_free_blkcipher(priv->rx_tfm);
77                 kfree(priv);
78         }
79
80         return NULL;
81 }
82
83
84 static void prism2_wep_deinit(void *priv)
85 {
86         struct prism2_wep_data *_priv = priv;
87
88         if (_priv) {
89                 if (_priv->tx_tfm)
90                         crypto_free_blkcipher(_priv->tx_tfm);
91                 if (_priv->rx_tfm)
92                         crypto_free_blkcipher(_priv->rx_tfm);
93         }
94
95         kfree(priv);
96 }
97
98
99 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
100  * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
101  * so the payload length increases with 8 bytes.
102  *
103  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
104  */
105 static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
106 {
107         struct prism2_wep_data *wep = priv;
108         struct blkcipher_desc desc = { .tfm = wep->tx_tfm };
109         u32 klen, len;
110         u8 key[WEP_KEY_LEN + 3];
111         u8 *pos;
112         u32 crc;
113         u8 *icv;
114         struct scatterlist sg;
115
116         if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
117             skb->len < hdr_len)
118                 return -1;
119
120         len = skb->len - hdr_len;
121         pos = skb_push(skb, 4);
122         memmove(pos, pos + 4, hdr_len);
123         pos += hdr_len;
124
125         klen = 3 + wep->key_len;
126
127         wep->iv++;
128
129         /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
130          * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
131          * can be used to speedup attacks, so avoid using them. */
132         if ((wep->iv & 0xff00) == 0xff00) {
133                 u8 B = (wep->iv >> 16) & 0xff;
134                 if (B >= 3 && B < klen)
135                         wep->iv += 0x0100;
136         }
137
138         /* Prepend 24-bit IV to RC4 key and TX frame */
139         *pos++ = key[0] = (wep->iv >> 16) & 0xff;
140         *pos++ = key[1] = (wep->iv >> 8) & 0xff;
141         *pos++ = key[2] = wep->iv & 0xff;
142         *pos++ = wep->key_idx << 6;
143
144         /* Copy rest of the WEP key (the secret part) */
145         memcpy(key + 3, wep->key, wep->key_len);
146
147         /* Append little-endian CRC32 and encrypt it to produce ICV */
148         crc = ~crc32_le(~0, pos, len);
149         icv = skb_put(skb, 4);
150         icv[0] = crc;
151         icv[1] = crc >> 8;
152         icv[2] = crc >> 16;
153         icv[3] = crc >> 24;
154
155         crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
156         sg_init_one(&sg, pos, len + 4);
157
158         return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
159 }
160
161
162 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
163  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
164  * ICV (4 bytes). len includes both IV and ICV.
165  *
166  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
167  * failure. If frame is OK, IV and ICV will be removed.
168  */
169 static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
170 {
171         struct prism2_wep_data *wep = priv;
172         struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
173         u32 klen, plen;
174         u8 key[WEP_KEY_LEN + 3];
175         u8 keyidx, *pos;
176         u32 crc;
177         u8 icv[4];
178         struct scatterlist sg;
179
180         if (skb->len < hdr_len + 8)
181                 return -1;
182
183         pos = skb->data + hdr_len;
184         key[0] = *pos++;
185         key[1] = *pos++;
186         key[2] = *pos++;
187         keyidx = *pos++ >> 6;
188         if (keyidx != wep->key_idx)
189                 return -1;
190
191         klen = 3 + wep->key_len;
192
193         /* Copy rest of the WEP key (the secret part) */
194         memcpy(key + 3, wep->key, wep->key_len);
195
196         /* Apply RC4 to data and compute CRC32 over decrypted data */
197         plen = skb->len - hdr_len - 8;
198
199         crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
200         sg_init_one(&sg, pos, plen + 4);
201
202         if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
203                 return -7;
204
205         crc = ~crc32_le(~0, pos, plen);
206         icv[0] = crc;
207         icv[1] = crc >> 8;
208         icv[2] = crc >> 16;
209         icv[3] = crc >> 24;
210
211         if (memcmp(icv, pos + plen, 4) != 0) {
212                 /* ICV mismatch - drop frame */
213                 return -2;
214         }
215
216         /* Remove IV and ICV */
217         memmove(skb->data + 4, skb->data, hdr_len);
218         skb_pull(skb, 4);
219         skb_trim(skb, skb->len - 4);
220         return 0;
221 }
222
223
224 static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
225 {
226         struct prism2_wep_data *wep = priv;
227
228         if (len < 0 || len > WEP_KEY_LEN)
229                 return -1;
230
231         memcpy(wep->key, key, len);
232         wep->key_len = len;
233
234         return 0;
235 }
236
237
238 static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
239 {
240         struct prism2_wep_data *wep = priv;
241
242         if (len < wep->key_len)
243                 return -1;
244
245         memcpy(key, wep->key, wep->key_len);
246
247         return wep->key_len;
248 }
249
250
251 static char * prism2_wep_print_stats(char *p, void *priv)
252 {
253         struct prism2_wep_data *wep = priv;
254         p += sprintf(p, "key[%d] alg=WEP len=%d\n",
255                      wep->key_idx, wep->key_len);
256         return p;
257 }
258
259
260 static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
261         .name                   = "WEP",
262         .init                   = prism2_wep_init,
263         .deinit                 = prism2_wep_deinit,
264         .encrypt_mpdu           = prism2_wep_encrypt,
265         .decrypt_mpdu           = prism2_wep_decrypt,
266         .encrypt_msdu           = NULL,
267         .decrypt_msdu           = NULL,
268         .set_key                = prism2_wep_set_key,
269         .get_key                = prism2_wep_get_key,
270         .print_stats            = prism2_wep_print_stats,
271         .extra_prefix_len       = 4, /* IV */
272         .extra_postfix_len      = 4, /* ICV */
273         .owner                  = THIS_MODULE,
274 };
275
276
277 int ieee80211_crypto_wep_init(void)
278 {
279         return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
280 }
281
282
283 void ieee80211_crypto_wep_exit(void)
284 {
285         ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
286 }
287
288
289 void ieee80211_wep_null(void)
290 {
291 //      printk("============>%s()\n", __func__);
292         return;
293 }