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