xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211_crypto_wep.c (revision e8d80663e4f91871f843bb8ad9108dc0b76dfcf3)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2001 Atsushi Onoe
8  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * Alternatively, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2 as published by the Free
24  * Software Foundation.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * IEEE 802.11 WEP crypto support.
40  */
41 #include <sys/byteorder.h>
42 #include <sys/crypto/common.h>
43 #include <sys/crypto/api.h>
44 #include <sys/crc32.h>
45 #include <sys/random.h>
46 #include <sys/strsun.h>
47 #include "net80211_impl.h"
48 
49 static  void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
50 static  void wep_detach(struct ieee80211_key *);
51 static  int wep_setkey(struct ieee80211_key *);
52 static  int wep_encap(struct ieee80211_key *, mblk_t *, uint8_t keyid);
53 static  int wep_decap(struct ieee80211_key *, mblk_t *, int);
54 static  int wep_enmic(struct ieee80211_key *, mblk_t *, int);
55 static  int wep_demic(struct ieee80211_key *, mblk_t *, int);
56 
57 const struct ieee80211_cipher wep = {
58 	"WEP",
59 	IEEE80211_CIPHER_WEP,
60 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
61 	IEEE80211_WEP_CRCLEN,
62 	0,
63 	wep_attach,
64 	wep_detach,
65 	wep_setkey,
66 	wep_encap,
67 	wep_decap,
68 	wep_enmic,
69 	wep_demic,
70 };
71 
72 int rc4_init(crypto_context_t *, const uint8_t *, int);
73 int rc4_crypt(crypto_context_t, const uint8_t *, uint8_t *, int);
74 int rc4_final(crypto_context_t, uint8_t *, int);
75 
76 static	int wep_encrypt(struct ieee80211_key *, mblk_t *, int);
77 static	int wep_decrypt(struct ieee80211_key *, mblk_t *, int);
78 
79 struct wep_ctx {
80 	ieee80211com_t *wc_ic;		/* for diagnostics */
81 	uint32_t	wc_iv;		/* initial vector for crypto */
82 };
83 
84 /* Table of CRCs of all 8-bit messages */
85 static uint32_t crc_table[] = { CRC32_TABLE };
86 
87 /* ARGSUSED */
88 static void *
89 wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
90 {
91 	struct wep_ctx *ctx;
92 
93 	ctx = kmem_zalloc(sizeof (struct wep_ctx), KM_NOSLEEP);
94 	if (ctx == NULL)
95 		return (NULL);
96 
97 	ctx->wc_ic = ic;
98 	(void) random_get_pseudo_bytes((unsigned char *)&ctx->wc_iv,
99 	    sizeof (uint32_t));
100 	return (ctx);
101 }
102 
103 static void
104 wep_detach(struct ieee80211_key *k)
105 {
106 	struct wep_ctx *ctx = k->wk_private;
107 
108 	if (ctx != NULL)
109 		kmem_free(ctx, sizeof (struct wep_ctx));
110 }
111 
112 static int
113 wep_setkey(struct ieee80211_key *k)
114 {
115 	/*
116 	 * WEP key length is standardized to 40-bit. Many
117 	 * implementations support 104-bit WEP kwys.
118 	 */
119 	return (k->wk_keylen == 40/NBBY || k->wk_keylen == 104/NBBY);
120 }
121 
122 /*
123  * Add privacy headers appropriate for the specified key.
124  */
125 static int
126 wep_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
127 {
128 	struct wep_ctx *ctx = k->wk_private;
129 	struct ieee80211_frame *wh = (struct ieee80211_frame *)mp->b_rptr;
130 	uint32_t iv;
131 	uint8_t *ivp;
132 	int hdrlen;
133 
134 	if (mp == NULL)
135 		return (0);
136 	hdrlen = ieee80211_hdrspace(ctx->wc_ic, wh);
137 
138 	ivp = (uint8_t *)wh;
139 	ivp += hdrlen;
140 
141 	/*
142 	 * IV must not duplicate during the lifetime of the key.
143 	 * But no mechanism to renew keys is defined in IEEE 802.11
144 	 * WEP.  And IV may be duplicated between other stations
145 	 * because of the session key itself is shared.
146 	 * So we use pseudo random IV for now, though it is not the
147 	 * right way.
148 	 */
149 	iv = ctx->wc_iv;
150 	/*
151 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
152 	 * (B, 255, N) with 3 <= B < 8
153 	 */
154 	if ((iv & 0xff00) == 0xff00) {
155 		int B = (iv & 0xff0000) >> 16;
156 		if (3 <= B && B < 16)
157 			iv = (B+1) << 16;
158 	}
159 	ctx->wc_iv = iv + 1;
160 
161 	ivp[2] = (uint8_t)(iv >> 0);
162 	ivp[1] = (uint8_t)(iv >> 8);
163 	ivp[0] = (uint8_t)(iv >> 16);
164 
165 	/* Key ID and pad */
166 	ivp[IEEE80211_WEP_IVLEN] = keyid;
167 
168 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
169 	    (wep_encrypt(k, mp, hdrlen) == 0))
170 		return (0);
171 
172 	return (1);
173 }
174 
175 /*
176  * Validate and strip privacy headers (and trailer) for a
177  * received frame.  If necessary, decrypt the frame using
178  * the specified key.
179  */
180 static int
181 wep_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
182 {
183 	/*
184 	 * Check if the device handled the decrypt in hardware.
185 	 * If so we just strip the header; otherwise we need to
186 	 * handle the decrypt in software.
187 	 */
188 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
189 	    (wep_decrypt(k, mp, hdrlen) == 0)) {
190 		ieee80211_err("WEP ICV mismatch on decrypt\n");
191 		return (0);
192 	}
193 
194 	/*
195 	 * Copy up 802.11 header and strip crypto bits.
196 	 */
197 	(void) memmove(mp->b_rptr + wep.ic_header, mp->b_rptr, hdrlen);
198 	mp->b_rptr += wep.ic_header;
199 	mp->b_wptr -= wep.ic_trailer;
200 
201 	return (1);
202 }
203 
204 /*
205  * Add MIC to the frame as needed.
206  */
207 /* ARGSUSED */
208 static int
209 wep_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
210 {
211 	return (1);
212 }
213 
214 /*
215  * Verify and strip MIC from the frame.
216  */
217 /* ARGSUSED */
218 static int
219 wep_demic(struct ieee80211_key *k, mblk_t *mp, int force)
220 {
221 	return (1);
222 }
223 
224 static int
225 wep_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
226 {
227 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
228 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
229 	uint8_t *icv;
230 	uint32_t crc;
231 	crypto_context_t ctx;
232 	int rv;
233 
234 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
235 
236 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
237 
238 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
239 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
240 	    key->wk_keylen);
241 
242 	ctx = NULL;
243 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
244 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
245 
246 	if (rv != CRYPTO_SUCCESS)
247 		return (0);
248 
249 	/* calculate CRC over unencrypted data */
250 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
251 	    MBLKL(mp) - (hdrlen + wep.ic_header),
252 	    -1U, crc_table);
253 
254 	/* encrypt data */
255 	(void) rc4_crypt(ctx,
256 	    mp->b_rptr + hdrlen + wep.ic_header,
257 	    mp->b_rptr + hdrlen + wep.ic_header,
258 	    MBLKL(mp) - (hdrlen + wep.ic_header));
259 
260 	/* tack on ICV */
261 	*(uint32_t *)crcbuf = LE_32(~crc);
262 	icv = mp->b_wptr;
263 	mp->b_wptr += IEEE80211_WEP_CRCLEN;
264 	(void) rc4_crypt(ctx, crcbuf, icv, IEEE80211_WEP_CRCLEN);
265 
266 	(void) rc4_final(ctx, icv, IEEE80211_WEP_CRCLEN);
267 
268 	return (1);
269 }
270 
271 static int
272 wep_decrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
273 {
274 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
275 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
276 	uint8_t *icv;
277 	uint32_t crc;
278 	crypto_context_t ctx;
279 	int rv;
280 
281 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
282 
283 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
284 
285 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
286 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
287 	    key->wk_keylen);
288 
289 	ctx = NULL;
290 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
291 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
292 
293 	if (rv != CRYPTO_SUCCESS)
294 		return (0);
295 
296 	/* decrypt data */
297 	(void) rc4_crypt(ctx,
298 	    mp->b_rptr + hdrlen + wep.ic_header,
299 	    mp->b_rptr + hdrlen + wep.ic_header,
300 	    MBLKL(mp) -
301 	    (hdrlen + wep.ic_header + wep.ic_trailer));
302 
303 	/* calculate CRC over unencrypted data */
304 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
305 	    MBLKL(mp) -
306 	    (hdrlen + wep.ic_header + wep.ic_trailer),
307 	    -1U, crc_table);
308 
309 	/* decrypt ICV and compare to CRC */
310 	icv = mp->b_wptr - IEEE80211_WEP_CRCLEN;
311 	(void) rc4_crypt(ctx, icv, crcbuf, IEEE80211_WEP_CRCLEN);
312 
313 	(void) rc4_final(ctx, crcbuf, IEEE80211_WEP_CRCLEN);
314 
315 	return (crc == ~LE_32(*(uint32_t *)crcbuf));
316 }
317 
318 /*
319  * rc_init() -  To init the key, for multiply encryption/decryption
320  * Using the Kernel encryption framework
321  */
322 int
323 rc4_init(crypto_context_t *ctx, const uint8_t *key, int keylen)
324 {
325 	crypto_mechanism_t mech;
326 	crypto_key_t crkey;
327 	int rv;
328 
329 	bzero(&crkey, sizeof (crkey));
330 
331 	crkey.ck_format = CRYPTO_KEY_RAW;
332 	crkey.ck_data   = (char *)key;
333 	/* keys are measured in bits, not bytes, so multiply by 8 */
334 	crkey.ck_length = keylen * 8;
335 
336 	mech.cm_type	  = crypto_mech2id(SUN_CKM_RC4);
337 	mech.cm_param	  = NULL;
338 	mech.cm_param_len = 0;
339 
340 	rv = crypto_encrypt_init(&mech, &crkey, NULL, ctx, NULL);
341 	if (rv != CRYPTO_SUCCESS)
342 		cmn_err(CE_WARN, "rc4_init failed (%x)", rv);
343 
344 	return (rv);
345 }
346 
347 /*
348  * rc4_crypt
349  *
350  * Use the Kernel encryption framework to provide the
351  * crypto operations for the indicated data.
352  */
353 int
354 rc4_crypt(crypto_context_t ctx, const uint8_t *inbuf,
355 	uint8_t *outbuf, int buflen)
356 {
357 	int rv = CRYPTO_FAILED;
358 
359 	crypto_data_t d1, d2;
360 
361 	ASSERT(inbuf  != NULL);
362 	ASSERT(outbuf != NULL);
363 
364 	bzero(&d1, sizeof (d1));
365 	bzero(&d2, sizeof (d2));
366 
367 	d1.cd_format = CRYPTO_DATA_RAW;
368 	d1.cd_offset = 0;
369 	d1.cd_length = buflen;
370 	d1.cd_raw.iov_base = (char *)inbuf;
371 	d1.cd_raw.iov_len  = buflen;
372 
373 	d2.cd_format = CRYPTO_DATA_RAW;
374 	d2.cd_offset = 0;
375 	d2.cd_length = buflen;
376 	d2.cd_raw.iov_base = (char *)outbuf;
377 	d2.cd_raw.iov_len  = buflen;
378 
379 	rv = crypto_encrypt_update(ctx, &d1, &d2, NULL);
380 
381 	if (rv != CRYPTO_SUCCESS)
382 		cmn_err(CE_WARN, "rc4_crypt failed (%x)", rv);
383 	return (rv);
384 }
385 
386 /*
387  * rc4_final
388  *
389  * Use the Kernel encryption framework to provide the
390  * crypto operations for the indicated data.
391  */
392 int
393 rc4_final(crypto_context_t ctx, uint8_t *outbuf, int buflen)
394 {
395 	int rv = CRYPTO_FAILED;
396 
397 	crypto_data_t d2;
398 
399 	ASSERT(outbuf != NULL);
400 
401 	bzero(&d2, sizeof (d2));
402 
403 	d2.cd_format = CRYPTO_DATA_RAW;
404 	d2.cd_offset = 0;
405 	d2.cd_length = buflen;
406 	d2.cd_raw.iov_base = (char *)outbuf;
407 	d2.cd_raw.iov_len = buflen;
408 
409 	rv = crypto_encrypt_final(ctx, &d2, NULL);
410 
411 	if (rv != CRYPTO_SUCCESS)
412 		cmn_err(CE_WARN, "rc4_final failed (%x)", rv);
413 	return (rv);
414 }
415