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