Merge commit '80d5689f5d4588adc071138e25e9d0d5252d9b55'
[unleashed.git] / kernel / net / net80211 / net80211_crypto_wep.c
blobd8d3f0a65dcaf68a2d523d43f14f80878077ec3b
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
9 * All rights reserved.
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.
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.
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.
39 * IEEE 802.11 WEP crypto support.
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"
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);
57 const struct ieee80211_cipher wep = {
58 "WEP",
59 IEEE80211_CIPHER_WEP,
60 IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
61 IEEE80211_WEP_CRCLEN,
63 wep_attach,
64 wep_detach,
65 wep_setkey,
66 wep_encap,
67 wep_decap,
68 wep_enmic,
69 wep_demic,
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);
76 static int wep_encrypt(struct ieee80211_key *, mblk_t *, int);
77 static int wep_decrypt(struct ieee80211_key *, mblk_t *, int);
79 struct wep_ctx {
80 ieee80211com_t *wc_ic; /* for diagnostics */
81 uint32_t wc_iv; /* initial vector for crypto */
84 /* Table of CRCs of all 8-bit messages */
85 static uint32_t crc_table[] = { CRC32_TABLE };
87 /* ARGSUSED */
88 static void *
89 wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
91 struct wep_ctx *ctx;
93 ctx = kmem_zalloc(sizeof (struct wep_ctx), KM_NOSLEEP);
94 if (ctx == NULL)
95 return (NULL);
97 ctx->wc_ic = ic;
98 (void) random_get_pseudo_bytes((unsigned char *)&ctx->wc_iv,
99 sizeof (uint32_t));
100 return (ctx);
103 static void
104 wep_detach(struct ieee80211_key *k)
106 struct wep_ctx *ctx = k->wk_private;
108 if (ctx != NULL)
109 kmem_free(ctx, sizeof (struct wep_ctx));
112 static int
113 wep_setkey(struct ieee80211_key *k)
116 * WEP key length is standardized to 40-bit. Many
117 * implementations support 104-bit WEP kwys.
119 return (k->wk_keylen == 40/NBBY || k->wk_keylen == 104/NBBY);
123 * Add privacy headers appropriate for the specified key.
125 static int
126 wep_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
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;
134 if (mp == NULL)
135 return (0);
136 hdrlen = ieee80211_hdrspace(ctx->wc_ic, wh);
138 ivp = (uint8_t *)wh;
139 ivp += hdrlen;
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.
149 iv = ctx->wc_iv;
151 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
152 * (B, 255, N) with 3 <= B < 8
154 if ((iv & 0xff00) == 0xff00) {
155 int B = (iv & 0xff0000) >> 16;
156 if (3 <= B && B < 16)
157 iv = (B+1) << 16;
159 ctx->wc_iv = iv + 1;
161 ivp[2] = (uint8_t)(iv >> 0);
162 ivp[1] = (uint8_t)(iv >> 8);
163 ivp[0] = (uint8_t)(iv >> 16);
165 /* Key ID and pad */
166 ivp[IEEE80211_WEP_IVLEN] = keyid;
168 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
169 (wep_encrypt(k, mp, hdrlen) == 0))
170 return (0);
172 return (1);
176 * Validate and strip privacy headers (and trailer) for a
177 * received frame. If necessary, decrypt the frame using
178 * the specified key.
180 static int
181 wep_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
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.
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);
195 * Copy up 802.11 header and strip crypto bits.
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;
201 return (1);
205 * Add MIC to the frame as needed.
207 /* ARGSUSED */
208 static int
209 wep_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
211 return (1);
215 * Verify and strip MIC from the frame.
217 /* ARGSUSED */
218 static int
219 wep_demic(struct ieee80211_key *k, mblk_t *mp, int force)
221 return (1);
224 static int
225 wep_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
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;
234 ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
236 /* ctx->wc_ic->isc_stats.is_crypto_wep++; */
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);
242 ctx = NULL;
243 rv = rc4_init(&ctx, (const uint8_t *)rc4key,
244 IEEE80211_WEP_IVLEN + key->wk_keylen);
246 if (rv != CRYPTO_SUCCESS)
247 return (0);
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);
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));
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);
266 (void) rc4_final(ctx, icv, IEEE80211_WEP_CRCLEN);
268 return (1);
271 static int
272 wep_decrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
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;
281 ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
283 /* ctx->wc_ic->isc_stats.is_crypto_wep++; */
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);
289 ctx = NULL;
290 rv = rc4_init(&ctx, (const uint8_t *)rc4key,
291 IEEE80211_WEP_IVLEN + key->wk_keylen);
293 if (rv != CRYPTO_SUCCESS)
294 return (0);
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));
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);
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);
313 (void) rc4_final(ctx, crcbuf, IEEE80211_WEP_CRCLEN);
315 return (crc == ~LE_32(*(uint32_t *)crcbuf));
319 * rc_init() - To init the key, for multiply encryption/decryption
320 * Using the Kernel encryption framework
323 rc4_init(crypto_context_t *ctx, const uint8_t *key, int keylen)
325 crypto_mechanism_t mech;
326 crypto_key_t crkey;
327 int rv;
329 bzero(&crkey, sizeof (crkey));
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;
336 mech.cm_type = crypto_mech2id(SUN_CKM_RC4);
337 mech.cm_param = NULL;
338 mech.cm_param_len = 0;
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);
344 return (rv);
348 * rc4_crypt
350 * Use the Kernel encryption framework to provide the
351 * crypto operations for the indicated data.
354 rc4_crypt(crypto_context_t ctx, const uint8_t *inbuf,
355 uint8_t *outbuf, int buflen)
357 int rv = CRYPTO_FAILED;
359 crypto_data_t d1, d2;
361 ASSERT(inbuf != NULL);
362 ASSERT(outbuf != NULL);
364 bzero(&d1, sizeof (d1));
365 bzero(&d2, sizeof (d2));
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;
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;
379 rv = crypto_encrypt_update(ctx, &d1, &d2, NULL);
381 if (rv != CRYPTO_SUCCESS)
382 cmn_err(CE_WARN, "rc4_crypt failed (%x)", rv);
383 return (rv);
387 * rc4_final
389 * Use the Kernel encryption framework to provide the
390 * crypto operations for the indicated data.
393 rc4_final(crypto_context_t ctx, uint8_t *outbuf, int buflen)
395 int rv = CRYPTO_FAILED;
397 crypto_data_t d2;
399 ASSERT(outbuf != NULL);
401 bzero(&d2, sizeof (d2));
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;
409 rv = crypto_encrypt_final(ctx, &d2, NULL);
411 if (rv != CRYPTO_SUCCESS)
412 cmn_err(CE_WARN, "rc4_final failed (%x)", rv);
413 return (rv);