2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
= {
60 IEEE80211_WEP_IVLEN
+ IEEE80211_WEP_KIDLEN
,
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);
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
};
89 wep_attach(struct ieee80211com
*ic
, struct ieee80211_key
*k
)
93 ctx
= kmem_zalloc(sizeof (struct wep_ctx
), KM_NOSLEEP
);
98 (void) random_get_pseudo_bytes((unsigned char *)&ctx
->wc_iv
,
104 wep_detach(struct ieee80211_key
*k
)
106 struct wep_ctx
*ctx
= k
->wk_private
;
109 kmem_free(ctx
, sizeof (struct wep_ctx
));
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.
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
;
136 hdrlen
= ieee80211_hdrspace(ctx
->wc_ic
, wh
);
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
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)
161 ivp
[2] = (uint8_t)(iv
>> 0);
162 ivp
[1] = (uint8_t)(iv
>> 8);
163 ivp
[0] = (uint8_t)(iv
>> 16);
166 ivp
[IEEE80211_WEP_IVLEN
] = keyid
;
168 if ((k
->wk_flags
& IEEE80211_KEY_SWCRYPT
) &&
169 (wep_encrypt(k
, mp
, hdrlen
) == 0))
176 * Validate and strip privacy headers (and trailer) for a
177 * received frame. If necessary, decrypt the frame using
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");
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
;
205 * Add MIC to the frame as needed.
209 wep_enmic(struct ieee80211_key
*k
, mblk_t
*mp
, int force
)
215 * Verify and strip MIC from the frame.
219 wep_demic(struct ieee80211_key
*k
, mblk_t
*mp
, int force
)
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
];
231 crypto_context_t ctx
;
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
,
243 rv
= rc4_init(&ctx
, (const uint8_t *)rc4key
,
244 IEEE80211_WEP_IVLEN
+ key
->wk_keylen
);
246 if (rv
!= CRYPTO_SUCCESS
)
249 /* calculate CRC over unencrypted data */
250 CRC32(crc
, mp
->b_rptr
+ hdrlen
+ wep
.ic_header
,
251 MBLKL(mp
) - (hdrlen
+ wep
.ic_header
),
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
));
261 *(uint32_t *)crcbuf
= LE_32(~crc
);
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
);
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
];
278 crypto_context_t ctx
;
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
,
290 rv
= rc4_init(&ctx
, (const uint8_t *)rc4key
,
291 IEEE80211_WEP_IVLEN
+ key
->wk_keylen
);
293 if (rv
!= CRYPTO_SUCCESS
)
297 (void) rc4_crypt(ctx
,
298 mp
->b_rptr
+ hdrlen
+ wep
.ic_header
,
299 mp
->b_rptr
+ hdrlen
+ wep
.ic_header
,
301 (hdrlen
+ wep
.ic_header
+ wep
.ic_trailer
));
303 /* calculate CRC over unencrypted data */
304 CRC32(crc
, mp
->b_rptr
+ hdrlen
+ wep
.ic_header
,
306 (hdrlen
+ wep
.ic_header
+ wep
.ic_trailer
),
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
;
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
);
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
;
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
;
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
);
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
;
399 ASSERT(outbuf
!= NULL
);
401 bzero(&d2
, sizeof (d2
));
403 d2
.cd_format
= CRYPTO_DATA_RAW
;
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
);