Blame view

net/wireless/lib80211_crypt_wep.c 7.08 KB
b453872c3   Jeff Garzik   [NET] ieee80211 s...
1
  /*
274bfb8dc   John W. Linville   lib80211: absorb ...
2
   * lib80211 crypt: host-based WEP encryption implementation for lib80211
b453872c3   Jeff Garzik   [NET] ieee80211 s...
3
   *
85d32e7b0   Jouni Malinen   [PATCH] Update my...
4
   * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
274bfb8dc   John W. Linville   lib80211: absorb ...
5
   * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
6
7
8
9
10
11
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation. See README and COPYING for
   * more details.
   */
f12cc2090   Herbert Xu   [CRYPTO] users: U...
12
  #include <linux/err.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
13
14
15
16
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/random.h>
117636092   Ralf Baechle   [PATCH] Fix break...
17
  #include <linux/scatterlist.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
18
  #include <linux/skbuff.h>
d7fe0f241   Al Viro   [PATCH] severing ...
19
  #include <linux/mm.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
20
  #include <asm/string.h>
274bfb8dc   John W. Linville   lib80211: absorb ...
21
  #include <net/lib80211.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
22

b453872c3   Jeff Garzik   [NET] ieee80211 s...
23
  #include <linux/crypto.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
24
25
26
  #include <linux/crc32.h>
  
  MODULE_AUTHOR("Jouni Malinen");
274bfb8dc   John W. Linville   lib80211: absorb ...
27
  MODULE_DESCRIPTION("lib80211 crypt: WEP");
b453872c3   Jeff Garzik   [NET] ieee80211 s...
28
  MODULE_LICENSE("GPL");
274bfb8dc   John W. Linville   lib80211: absorb ...
29
  struct lib80211_wep_data {
b453872c3   Jeff Garzik   [NET] ieee80211 s...
30
31
32
33
34
  	u32 iv;
  #define WEP_KEY_LEN 13
  	u8 key[WEP_KEY_LEN + 1];
  	u8 key_len;
  	u8 key_idx;
28eb177df   Jeff Garzik   Merge branch 'mas...
35
36
  	struct crypto_blkcipher *tx_tfm;
  	struct crypto_blkcipher *rx_tfm;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
37
  };
274bfb8dc   John W. Linville   lib80211: absorb ...
38
  static void *lib80211_wep_init(int keyidx)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
39
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
40
  	struct lib80211_wep_data *priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
41

0da974f4f   Panagiotis Issaris   [NET]: Conversion...
42
  	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
43
44
  	if (priv == NULL)
  		goto fail;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
45
  	priv->key_idx = keyidx;
28eb177df   Jeff Garzik   Merge branch 'mas...
46
47
  	priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
  	if (IS_ERR(priv->tx_tfm)) {
183798799   Jeff Garzik   net/ieee80211: fi...
48
  		priv->tx_tfm = NULL;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
49
50
  		goto fail;
  	}
28eb177df   Jeff Garzik   Merge branch 'mas...
51
52
  	priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
  	if (IS_ERR(priv->rx_tfm)) {
183798799   Jeff Garzik   net/ieee80211: fi...
53
  		priv->rx_tfm = NULL;
5a6569497   Zhu Yi   [PATCH] ieee80211...
54
55
  		goto fail;
  	}
b453872c3   Jeff Garzik   [NET] ieee80211 s...
56
57
58
59
  	/* start WEP IV from a random value */
  	get_random_bytes(&priv->iv, 4);
  
  	return priv;
0edd5b449   Jeff Garzik   [wireless ieee802...
60
        fail:
b453872c3   Jeff Garzik   [NET] ieee80211 s...
61
  	if (priv) {
5a6569497   Zhu Yi   [PATCH] ieee80211...
62
  		if (priv->tx_tfm)
28eb177df   Jeff Garzik   Merge branch 'mas...
63
  			crypto_free_blkcipher(priv->tx_tfm);
5a6569497   Zhu Yi   [PATCH] ieee80211...
64
  		if (priv->rx_tfm)
28eb177df   Jeff Garzik   Merge branch 'mas...
65
  			crypto_free_blkcipher(priv->rx_tfm);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
66
67
68
69
  		kfree(priv);
  	}
  	return NULL;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
70
  static void lib80211_wep_deinit(void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
71
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
72
  	struct lib80211_wep_data *_priv = priv;
5a6569497   Zhu Yi   [PATCH] ieee80211...
73
74
  	if (_priv) {
  		if (_priv->tx_tfm)
28eb177df   Jeff Garzik   Merge branch 'mas...
75
  			crypto_free_blkcipher(_priv->tx_tfm);
5a6569497   Zhu Yi   [PATCH] ieee80211...
76
  		if (_priv->rx_tfm)
28eb177df   Jeff Garzik   Merge branch 'mas...
77
  			crypto_free_blkcipher(_priv->rx_tfm);
5a6569497   Zhu Yi   [PATCH] ieee80211...
78
  	}
b453872c3   Jeff Garzik   [NET] ieee80211 s...
79
80
  	kfree(priv);
  }
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
81
  /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
274bfb8dc   John W. Linville   lib80211: absorb ...
82
  static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
9184d9348   Zhu Yi   [PATCH] ieee80211...
83
  			       u8 *key, int keylen, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
84
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
85
  	struct lib80211_wep_data *wep = priv;
6572e91d5   Rajkumar Manoharan   wireless: Fix war...
86
  	u32 klen;
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
87
  	u8 *pos;
642656518   YOSHIFUJI Hideaki   [NET] IEEE80211: ...
88

a4bf26f30   Johannes Berg   [PATCH] ieee80211...
89
  	if (skb_headroom(skb) < 4 || skb->len < hdr_len)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
90
  		return -1;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  	pos = skb_push(skb, 4);
  	memmove(pos, pos + 4, hdr_len);
  	pos += hdr_len;
  
  	klen = 3 + wep->key_len;
  
  	wep->iv++;
  
  	/* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
  	 * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
  	 * can be used to speedup attacks, so avoid using them. */
  	if ((wep->iv & 0xff00) == 0xff00) {
  		u8 B = (wep->iv >> 16) & 0xff;
  		if (B >= 3 && B < klen)
  			wep->iv += 0x0100;
  	}
  
  	/* Prepend 24-bit IV to RC4 key and TX frame */
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
109
110
111
  	*pos++ = (wep->iv >> 16) & 0xff;
  	*pos++ = (wep->iv >> 8) & 0xff;
  	*pos++ = wep->iv & 0xff;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
112
  	*pos++ = wep->key_idx << 6;
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
113
114
115
116
117
118
119
120
121
  	return 0;
  }
  
  /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
   * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
   * so the payload length increases with 8 bytes.
   *
   * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
   */
274bfb8dc   John W. Linville   lib80211: absorb ...
122
  static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
123
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
124
  	struct lib80211_wep_data *wep = priv;
28eb177df   Jeff Garzik   Merge branch 'mas...
125
  	struct blkcipher_desc desc = { .tfm = wep->tx_tfm };
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
126
127
128
129
  	u32 crc, klen, len;
  	u8 *pos, *icv;
  	struct scatterlist sg;
  	u8 key[WEP_KEY_LEN + 3];
274bfb8dc   John W. Linville   lib80211: absorb ...
130
  	/* other checks are in lib80211_wep_build_iv */
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
131
132
  	if (skb_tailroom(skb) < 4)
  		return -1;
642656518   YOSHIFUJI Hideaki   [NET] IEEE80211: ...
133

a4bf26f30   Johannes Berg   [PATCH] ieee80211...
134
  	/* add the IV to the frame */
274bfb8dc   John W. Linville   lib80211: absorb ...
135
  	if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv))
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
136
  		return -1;
642656518   YOSHIFUJI Hideaki   [NET] IEEE80211: ...
137

a4bf26f30   Johannes Berg   [PATCH] ieee80211...
138
  	/* Copy the IV into the first 3 bytes of the key */
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
139
  	skb_copy_from_linear_data_offset(skb, hdr_len, key, 3);
a4bf26f30   Johannes Berg   [PATCH] ieee80211...
140

b453872c3   Jeff Garzik   [NET] ieee80211 s...
141
142
  	/* Copy rest of the WEP key (the secret part) */
  	memcpy(key + 3, wep->key, wep->key_len);
642656518   YOSHIFUJI Hideaki   [NET] IEEE80211: ...
143

a4bf26f30   Johannes Berg   [PATCH] ieee80211...
144
145
146
  	len = skb->len - hdr_len - 4;
  	pos = skb->data + hdr_len + 4;
  	klen = 3 + wep->key_len;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
147

a4bf26f30   Johannes Berg   [PATCH] ieee80211...
148
  	/* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
149
150
151
152
153
154
  	crc = ~crc32_le(~0, pos, len);
  	icv = skb_put(skb, 4);
  	icv[0] = crc;
  	icv[1] = crc >> 8;
  	icv[2] = crc >> 16;
  	icv[3] = crc >> 24;
28eb177df   Jeff Garzik   Merge branch 'mas...
155
  	crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
fa05f1286   Jens Axboe   Update net/ to us...
156
  	sg_init_one(&sg, pos, len + 4);
f12cc2090   Herbert Xu   [CRYPTO] users: U...
157
  	return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
158
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
159
160
161
162
163
164
165
  /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
   * the frame: IV (4 bytes), encrypted payload (including SNAP header),
   * ICV (4 bytes). len includes both IV and ICV.
   *
   * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
   * failure. If frame is OK, IV and ICV will be removed.
   */
274bfb8dc   John W. Linville   lib80211: absorb ...
166
  static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
167
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
168
  	struct lib80211_wep_data *wep = priv;
28eb177df   Jeff Garzik   Merge branch 'mas...
169
  	struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
b453872c3   Jeff Garzik   [NET] ieee80211 s...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  	u32 crc, klen, plen;
  	u8 key[WEP_KEY_LEN + 3];
  	u8 keyidx, *pos, icv[4];
  	struct scatterlist sg;
  
  	if (skb->len < hdr_len + 8)
  		return -1;
  
  	pos = skb->data + hdr_len;
  	key[0] = *pos++;
  	key[1] = *pos++;
  	key[2] = *pos++;
  	keyidx = *pos++ >> 6;
  	if (keyidx != wep->key_idx)
  		return -1;
  
  	klen = 3 + wep->key_len;
  
  	/* Copy rest of the WEP key (the secret part) */
  	memcpy(key + 3, wep->key, wep->key_len);
  
  	/* Apply RC4 to data and compute CRC32 over decrypted data */
  	plen = skb->len - hdr_len - 8;
28eb177df   Jeff Garzik   Merge branch 'mas...
193
  	crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
fa05f1286   Jens Axboe   Update net/ to us...
194
  	sg_init_one(&sg, pos, plen + 4);
f12cc2090   Herbert Xu   [CRYPTO] users: U...
195
196
  	if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
  		return -7;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  
  	crc = ~crc32_le(~0, pos, plen);
  	icv[0] = crc;
  	icv[1] = crc >> 8;
  	icv[2] = crc >> 16;
  	icv[3] = crc >> 24;
  	if (memcmp(icv, pos + plen, 4) != 0) {
  		/* ICV mismatch - drop frame */
  		return -2;
  	}
  
  	/* Remove IV and ICV */
  	memmove(skb->data + 4, skb->data, hdr_len);
  	skb_pull(skb, 4);
  	skb_trim(skb, skb->len - 4);
  
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
215
  static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
216
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
217
  	struct lib80211_wep_data *wep = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
218
219
220
221
222
223
224
225
226
  
  	if (len < 0 || len > WEP_KEY_LEN)
  		return -1;
  
  	memcpy(wep->key, key, len);
  	wep->key_len = len;
  
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
227
  static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
228
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
229
  	struct lib80211_wep_data *wep = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
230
231
232
233
234
235
236
237
  
  	if (len < wep->key_len)
  		return -1;
  
  	memcpy(key, wep->key, wep->key_len);
  
  	return wep->key_len;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
238
  static char *lib80211_wep_print_stats(char *p, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
239
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
240
  	struct lib80211_wep_data *wep = priv;
0edd5b449   Jeff Garzik   [wireless ieee802...
241
242
  	p += sprintf(p, "key[%d] alg=WEP len=%d
  ", wep->key_idx, wep->key_len);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
243
244
  	return p;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
245
  static struct lib80211_crypto_ops lib80211_crypt_wep = {
74079fdce   James Ketrenos   [PATCH] ieee80211...
246
  	.name = "WEP",
274bfb8dc   John W. Linville   lib80211: absorb ...
247
248
  	.init = lib80211_wep_init,
  	.deinit = lib80211_wep_deinit,
274bfb8dc   John W. Linville   lib80211: absorb ...
249
250
  	.encrypt_mpdu = lib80211_wep_encrypt,
  	.decrypt_mpdu = lib80211_wep_decrypt,
74079fdce   James Ketrenos   [PATCH] ieee80211...
251
252
  	.encrypt_msdu = NULL,
  	.decrypt_msdu = NULL,
274bfb8dc   John W. Linville   lib80211: absorb ...
253
254
255
  	.set_key = lib80211_wep_set_key,
  	.get_key = lib80211_wep_get_key,
  	.print_stats = lib80211_wep_print_stats,
1264fc049   James Ketrenos   [PATCH] ieee80211...
256
257
  	.extra_mpdu_prefix_len = 4,	/* IV */
  	.extra_mpdu_postfix_len = 4,	/* ICV */
74079fdce   James Ketrenos   [PATCH] ieee80211...
258
  	.owner = THIS_MODULE,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
259
  };
274bfb8dc   John W. Linville   lib80211: absorb ...
260
  static int __init lib80211_crypto_wep_init(void)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
261
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
262
  	return lib80211_register_crypto_ops(&lib80211_crypt_wep);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
263
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
264
  static void __exit lib80211_crypto_wep_exit(void)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
265
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
266
  	lib80211_unregister_crypto_ops(&lib80211_crypt_wep);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
267
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
268
269
  module_init(lib80211_crypto_wep_init);
  module_exit(lib80211_crypto_wep_exit);