xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211_crypto_wep.c (revision ff3124eff995e6cd8ebd8c6543648e0670920034)
1 /*
2  * Copyright 2008 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-2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 /*
41  * IEEE 802.11 WEP crypto support.
42  */
43 #include <sys/byteorder.h>
44 #include <sys/crypto/common.h>
45 #include <sys/crypto/api.h>
46 #include <sys/crc32.h>
47 #include <sys/random.h>
48 #include <sys/strsun.h>
49 #include "net80211_impl.h"
50 
51 static  void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
52 static  void wep_detach(struct ieee80211_key *);
53 static  int wep_setkey(struct ieee80211_key *);
54 static  int wep_encap(struct ieee80211_key *, mblk_t *, uint8_t keyid);
55 static  int wep_decap(struct ieee80211_key *, mblk_t *, int);
56 static  int wep_enmic(struct ieee80211_key *, mblk_t *, int);
57 static  int wep_demic(struct ieee80211_key *, mblk_t *, int);
58 
59 const struct ieee80211_cipher wep = {
60 	"WEP",
61 	IEEE80211_CIPHER_WEP,
62 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
63 	IEEE80211_WEP_CRCLEN,
64 	0,
65 	wep_attach,
66 	wep_detach,
67 	wep_setkey,
68 	wep_encap,
69 	wep_decap,
70 	wep_enmic,
71 	wep_demic,
72 };
73 
74 int rc4_init(crypto_context_t *, const uint8_t *, int);
75 int rc4_crypt(crypto_context_t, const uint8_t *, uint8_t *, int);
76 int rc4_final(crypto_context_t, uint8_t *, int);
77 
78 static	int wep_encrypt(struct ieee80211_key *, mblk_t *, int);
79 static	int wep_decrypt(struct ieee80211_key *, mblk_t *, int);
80 
81 struct wep_ctx {
82 	ieee80211com_t *wc_ic;		/* for diagnostics */
83 	uint32_t	wc_iv;		/* initial vector for crypto */
84 };
85 
86 /* Table of CRCs of all 8-bit messages */
87 static uint32_t crc_table[] = { CRC32_TABLE };
88 
89 /* ARGSUSED */
90 static void *
91 wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
92 {
93 	struct wep_ctx *ctx;
94 
95 	ctx = kmem_zalloc(sizeof (struct wep_ctx), KM_NOSLEEP);
96 	if (ctx == NULL)
97 		return (NULL);
98 
99 	ctx->wc_ic = ic;
100 	(void) random_get_pseudo_bytes((unsigned char *)&ctx->wc_iv,
101 	    sizeof (uint32_t));
102 	return (ctx);
103 }
104 
105 static void
106 wep_detach(struct ieee80211_key *k)
107 {
108 	struct wep_ctx *ctx = k->wk_private;
109 
110 	if (ctx != NULL)
111 		kmem_free(ctx, sizeof (struct wep_ctx));
112 }
113 
114 static int
115 wep_setkey(struct ieee80211_key *k)
116 {
117 	/*
118 	 * WEP key length is standardized to 40-bit. Many
119 	 * implementations support 104-bit WEP kwys.
120 	 */
121 	return (k->wk_keylen == 40/NBBY || k->wk_keylen == 104/NBBY);
122 }
123 
124 /*
125  * Add privacy headers appropriate for the specified key.
126  */
127 static int
128 wep_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
129 {
130 	struct wep_ctx *ctx = k->wk_private;
131 	struct ieee80211_frame *wh = (struct ieee80211_frame *)mp->b_rptr;
132 	uint32_t iv;
133 	uint8_t *ivp;
134 	int hdrlen;
135 
136 	if (mp == NULL)
137 		return (0);
138 	hdrlen = ieee80211_hdrspace(wh);
139 
140 	ivp = (uint8_t *)wh;
141 	ivp += hdrlen;
142 
143 	/*
144 	 * IV must not duplicate during the lifetime of the key.
145 	 * But no mechanism to renew keys is defined in IEEE 802.11
146 	 * WEP.  And IV may be duplicated between other stations
147 	 * because of the session key itself is shared.
148 	 * So we use pseudo random IV for now, though it is not the
149 	 * right way.
150 	 */
151 	iv = ctx->wc_iv;
152 	/*
153 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
154 	 * (B, 255, N) with 3 <= B < 8
155 	 */
156 	if ((iv & 0xff00) == 0xff00) {
157 		int B = (iv & 0xff0000) >> 16;
158 		if (3 <= B && B < 16)
159 			iv = (B+1) << 16;
160 	}
161 	ctx->wc_iv = iv + 1;
162 
163 	ivp[2] = (uint8_t)(iv >> 0);
164 	ivp[1] = (uint8_t)(iv >> 8);
165 	ivp[0] = (uint8_t)(iv >> 16);
166 
167 	/* Key ID and pad */
168 	ivp[IEEE80211_WEP_IVLEN] = keyid;
169 
170 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
171 	    (wep_encrypt(k, mp, hdrlen) == 0))
172 		return (0);
173 
174 	return (1);
175 }
176 
177 /*
178  * Validate and strip privacy headers (and trailer) for a
179  * received frame.  If necessary, decrypt the frame using
180  * the specified key.
181  */
182 static int
183 wep_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
184 {
185 	struct ieee80211_frame *wh, whbuf;
186 
187 	wh = (struct ieee80211_frame *)mp->b_rptr;
188 
189 	/*
190 	 * Check if the device handled the decrypt in hardware.
191 	 * If so we just strip the header; otherwise we need to
192 	 * handle the decrypt in software.
193 	 */
194 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
195 	    (wep_decrypt(k, mp, hdrlen) == 0)) {
196 		ieee80211_err("WEP ICV mismatch on decrypt\n");
197 		return (0);
198 	}
199 
200 	/*
201 	 * Copy up 802.11 header and strip crypto bits.
202 	 */
203 	bcopy(wh, &whbuf, sizeof (whbuf));
204 	mp->b_rptr += wep.ic_header;
205 	bcopy(&whbuf, mp->b_rptr, hdrlen);
206 	mp->b_wptr -= wep.ic_trailer;
207 
208 	return (1);
209 }
210 
211 /*
212  * Add MIC to the frame as needed.
213  */
214 /* ARGSUSED */
215 static int
216 wep_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
217 {
218 	return (1);
219 }
220 
221 /*
222  * Verify and strip MIC from the frame.
223  */
224 /* ARGSUSED */
225 static int
226 wep_demic(struct ieee80211_key *k, mblk_t *mp, int force)
227 {
228 	return (1);
229 }
230 
231 static int
232 wep_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
233 {
234 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
235 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
236 	uint8_t *icv;
237 	uint32_t crc;
238 	crypto_context_t ctx;
239 	int rv;
240 
241 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
242 
243 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
244 
245 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
246 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
247 	    key->wk_keylen);
248 
249 	ctx = NULL;
250 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
251 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
252 
253 	if (rv != CRYPTO_SUCCESS)
254 		return (0);
255 
256 	/* calculate CRC over unencrypted data */
257 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
258 	    MBLKL(mp) - (hdrlen + wep.ic_header),
259 	    -1U, crc_table);
260 
261 	/* encrypt data */
262 	(void) rc4_crypt(ctx,
263 	    mp->b_rptr + hdrlen + wep.ic_header,
264 	    mp->b_rptr + hdrlen + wep.ic_header,
265 	    MBLKL(mp) - (hdrlen + wep.ic_header));
266 
267 	/* tack on ICV */
268 	*(uint32_t *)crcbuf = LE_32(~crc);
269 	icv = mp->b_wptr;
270 	mp->b_wptr += IEEE80211_WEP_CRCLEN;
271 	(void) rc4_crypt(ctx, crcbuf, icv, IEEE80211_WEP_CRCLEN);
272 
273 	(void) rc4_final(ctx, icv, IEEE80211_WEP_CRCLEN);
274 
275 	return (1);
276 }
277 
278 static int
279 wep_decrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
280 {
281 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
282 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
283 	uint8_t *icv;
284 	uint32_t crc;
285 	crypto_context_t ctx;
286 	int rv;
287 
288 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
289 
290 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
291 
292 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
293 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
294 	    key->wk_keylen);
295 
296 	ctx = NULL;
297 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
298 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
299 
300 	if (rv != CRYPTO_SUCCESS)
301 		return (0);
302 
303 	/* decrypt data */
304 	(void) rc4_crypt(ctx,
305 	    mp->b_rptr + hdrlen + wep.ic_header,
306 	    mp->b_rptr + hdrlen + wep.ic_header,
307 	    MBLKL(mp) -
308 	    (hdrlen + wep.ic_header + wep.ic_trailer));
309 
310 	/* calculate CRC over unencrypted data */
311 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
312 	    MBLKL(mp) -
313 	    (hdrlen + wep.ic_header + wep.ic_trailer),
314 	    -1U, crc_table);
315 
316 	/* decrypt ICV and compare to CRC */
317 	icv = mp->b_wptr - IEEE80211_WEP_CRCLEN;
318 	(void) rc4_crypt(ctx, icv, crcbuf, IEEE80211_WEP_CRCLEN);
319 
320 	(void) rc4_final(ctx, crcbuf, IEEE80211_WEP_CRCLEN);
321 
322 	return (crc == ~LE_32(*(uint32_t *)crcbuf));
323 }
324 
325 /*
326  * rc_init() -  To init the key, for multiply encryption/decryption
327  * Using the Kernel encryption framework
328  */
329 int
330 rc4_init(crypto_context_t *ctx, const uint8_t *key, int keylen)
331 {
332 	crypto_mechanism_t mech;
333 	crypto_key_t crkey;
334 	int rv;
335 
336 	bzero(&crkey, sizeof (crkey));
337 
338 	crkey.ck_format = CRYPTO_KEY_RAW;
339 	crkey.ck_data   = (char *)key;
340 	/* keys are measured in bits, not bytes, so multiply by 8 */
341 	crkey.ck_length = keylen * 8;
342 
343 	mech.cm_type	  = crypto_mech2id(SUN_CKM_RC4);
344 	mech.cm_param	  = NULL;
345 	mech.cm_param_len = 0;
346 
347 	rv = crypto_encrypt_init(&mech, &crkey, NULL, ctx, NULL);
348 	if (rv != CRYPTO_SUCCESS)
349 		cmn_err(CE_WARN, "rc4_init failed (%x)", rv);
350 
351 	return (rv);
352 }
353 
354 /*
355  * rc4_crypt
356  *
357  * Use the Kernel encryption framework to provide the
358  * crypto operations for the indicated data.
359  */
360 int
361 rc4_crypt(crypto_context_t ctx, const uint8_t *inbuf,
362 	uint8_t *outbuf, int buflen)
363 {
364 	int rv = CRYPTO_FAILED;
365 
366 	crypto_data_t d1, d2;
367 
368 	ASSERT(inbuf  != NULL);
369 	ASSERT(outbuf != NULL);
370 
371 	bzero(&d1, sizeof (d1));
372 	bzero(&d2, sizeof (d2));
373 
374 	d1.cd_format = CRYPTO_DATA_RAW;
375 	d1.cd_offset = 0;
376 	d1.cd_length = buflen;
377 	d1.cd_raw.iov_base = (char *)inbuf;
378 	d1.cd_raw.iov_len  = buflen;
379 
380 	d2.cd_format = CRYPTO_DATA_RAW;
381 	d2.cd_offset = 0;
382 	d2.cd_length = buflen;
383 	d2.cd_raw.iov_base = (char *)outbuf;
384 	d2.cd_raw.iov_len  = buflen;
385 
386 	rv = crypto_encrypt_update(ctx, &d1, &d2, NULL);
387 
388 	if (rv != CRYPTO_SUCCESS)
389 		cmn_err(CE_WARN, "rc4_crypt failed (%x)", rv);
390 	return (rv);
391 }
392 
393 /*
394  * rc4_final
395  *
396  * Use the Kernel encryption framework to provide the
397  * crypto operations for the indicated data.
398  */
399 int
400 rc4_final(crypto_context_t ctx, uint8_t *outbuf, int buflen)
401 {
402 	int rv = CRYPTO_FAILED;
403 
404 	crypto_data_t d2;
405 
406 	ASSERT(outbuf != NULL);
407 
408 	bzero(&d2, sizeof (d2));
409 
410 	d2.cd_format = CRYPTO_DATA_RAW;
411 	d2.cd_offset = 0;
412 	d2.cd_length = buflen;
413 	d2.cd_raw.iov_base = (char *)outbuf;
414 	d2.cd_raw.iov_len = buflen;
415 
416 	rv = crypto_encrypt_final(ctx, &d2, NULL);
417 
418 	if (rv != CRYPTO_SUCCESS)
419 		cmn_err(CE_WARN, "rc4_final failed (%x)", rv);
420 	return (rv);
421 }
422