xref: /onnv-gate/usr/src/uts/common/io/net80211/net80211_crypto_wep.c (revision 10266:bbc5945eddd7)
13147Sxc151355 /*
2*10266SQuaker.Fang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
33147Sxc151355  * Use is subject to license terms.
43147Sxc151355  */
53147Sxc151355 
63147Sxc151355 /*
73147Sxc151355  * Copyright (c) 2001 Atsushi Onoe
8*10266SQuaker.Fang@Sun.COM  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
93147Sxc151355  * All rights reserved.
103147Sxc151355  *
113147Sxc151355  * Redistribution and use in source and binary forms, with or without
123147Sxc151355  * modification, are permitted provided that the following conditions
133147Sxc151355  * are met:
143147Sxc151355  * 1. Redistributions of source code must retain the above copyright
153147Sxc151355  *    notice, this list of conditions and the following disclaimer.
163147Sxc151355  * 2. Redistributions in binary form must reproduce the above copyright
173147Sxc151355  *    notice, this list of conditions and the following disclaimer in the
183147Sxc151355  *    documentation and/or other materials provided with the distribution.
193147Sxc151355  * 3. The name of the author may not be used to endorse or promote products
203147Sxc151355  *    derived from this software without specific prior written permission.
213147Sxc151355  *
223147Sxc151355  * Alternatively, this software may be distributed under the terms of the
233147Sxc151355  * GNU General Public License ("GPL") version 2 as published by the Free
243147Sxc151355  * Software Foundation.
253147Sxc151355  *
263147Sxc151355  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
273147Sxc151355  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
283147Sxc151355  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
293147Sxc151355  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
303147Sxc151355  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
313147Sxc151355  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323147Sxc151355  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
333147Sxc151355  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
343147Sxc151355  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
353147Sxc151355  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363147Sxc151355  */
373147Sxc151355 
383147Sxc151355 /*
393147Sxc151355  * IEEE 802.11 WEP crypto support.
403147Sxc151355  */
413147Sxc151355 #include <sys/byteorder.h>
423147Sxc151355 #include <sys/crypto/common.h>
433147Sxc151355 #include <sys/crypto/api.h>
443147Sxc151355 #include <sys/crc32.h>
453147Sxc151355 #include <sys/random.h>
467249Sff224033 #include <sys/strsun.h>
473147Sxc151355 #include "net80211_impl.h"
483147Sxc151355 
493147Sxc151355 static  void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
503147Sxc151355 static  void wep_detach(struct ieee80211_key *);
513147Sxc151355 static  int wep_setkey(struct ieee80211_key *);
523147Sxc151355 static  int wep_encap(struct ieee80211_key *, mblk_t *, uint8_t keyid);
533147Sxc151355 static  int wep_decap(struct ieee80211_key *, mblk_t *, int);
543147Sxc151355 static  int wep_enmic(struct ieee80211_key *, mblk_t *, int);
553147Sxc151355 static  int wep_demic(struct ieee80211_key *, mblk_t *, int);
563147Sxc151355 
573147Sxc151355 const struct ieee80211_cipher wep = {
583147Sxc151355 	"WEP",
593147Sxc151355 	IEEE80211_CIPHER_WEP,
603147Sxc151355 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
613147Sxc151355 	IEEE80211_WEP_CRCLEN,
623147Sxc151355 	0,
633147Sxc151355 	wep_attach,
643147Sxc151355 	wep_detach,
653147Sxc151355 	wep_setkey,
663147Sxc151355 	wep_encap,
673147Sxc151355 	wep_decap,
683147Sxc151355 	wep_enmic,
693147Sxc151355 	wep_demic,
703147Sxc151355 };
713147Sxc151355 
723147Sxc151355 int rc4_init(crypto_context_t *, const uint8_t *, int);
733147Sxc151355 int rc4_crypt(crypto_context_t, const uint8_t *, uint8_t *, int);
743147Sxc151355 int rc4_final(crypto_context_t, uint8_t *, int);
753147Sxc151355 
763147Sxc151355 static	int wep_encrypt(struct ieee80211_key *, mblk_t *, int);
773147Sxc151355 static	int wep_decrypt(struct ieee80211_key *, mblk_t *, int);
783147Sxc151355 
793147Sxc151355 struct wep_ctx {
803147Sxc151355 	ieee80211com_t *wc_ic;		/* for diagnostics */
813147Sxc151355 	uint32_t	wc_iv;		/* initial vector for crypto */
823147Sxc151355 };
833147Sxc151355 
843147Sxc151355 /* Table of CRCs of all 8-bit messages */
853147Sxc151355 static uint32_t crc_table[] = { CRC32_TABLE };
863147Sxc151355 
873147Sxc151355 /* ARGSUSED */
883147Sxc151355 static void *
wep_attach(struct ieee80211com * ic,struct ieee80211_key * k)893147Sxc151355 wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
903147Sxc151355 {
913147Sxc151355 	struct wep_ctx *ctx;
923147Sxc151355 
933147Sxc151355 	ctx = kmem_zalloc(sizeof (struct wep_ctx), KM_NOSLEEP);
943147Sxc151355 	if (ctx == NULL)
953147Sxc151355 		return (NULL);
963147Sxc151355 
973147Sxc151355 	ctx->wc_ic = ic;
983147Sxc151355 	(void) random_get_pseudo_bytes((unsigned char *)&ctx->wc_iv,
993147Sxc151355 	    sizeof (uint32_t));
1003147Sxc151355 	return (ctx);
1013147Sxc151355 }
1023147Sxc151355 
1033147Sxc151355 static void
wep_detach(struct ieee80211_key * k)1043147Sxc151355 wep_detach(struct ieee80211_key *k)
1053147Sxc151355 {
1063147Sxc151355 	struct wep_ctx *ctx = k->wk_private;
1073147Sxc151355 
1083147Sxc151355 	if (ctx != NULL)
1093147Sxc151355 		kmem_free(ctx, sizeof (struct wep_ctx));
1103147Sxc151355 }
1113147Sxc151355 
1123147Sxc151355 static int
wep_setkey(struct ieee80211_key * k)1133147Sxc151355 wep_setkey(struct ieee80211_key *k)
1143147Sxc151355 {
1153147Sxc151355 	/*
1163147Sxc151355 	 * WEP key length is standardized to 40-bit. Many
1173147Sxc151355 	 * implementations support 104-bit WEP kwys.
1183147Sxc151355 	 */
1193147Sxc151355 	return (k->wk_keylen == 40/NBBY || k->wk_keylen == 104/NBBY);
1203147Sxc151355 }
1213147Sxc151355 
1223147Sxc151355 /*
1233147Sxc151355  * Add privacy headers appropriate for the specified key.
1243147Sxc151355  */
1253147Sxc151355 static int
wep_encap(struct ieee80211_key * k,mblk_t * mp,uint8_t keyid)1263147Sxc151355 wep_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
1273147Sxc151355 {
1283147Sxc151355 	struct wep_ctx *ctx = k->wk_private;
1293147Sxc151355 	struct ieee80211_frame *wh = (struct ieee80211_frame *)mp->b_rptr;
1303147Sxc151355 	uint32_t iv;
1313147Sxc151355 	uint8_t *ivp;
1323147Sxc151355 	int hdrlen;
1333147Sxc151355 
1343147Sxc151355 	if (mp == NULL)
1353147Sxc151355 		return (0);
136*10266SQuaker.Fang@Sun.COM 	hdrlen = ieee80211_hdrspace(ctx->wc_ic, wh);
1373147Sxc151355 
1383147Sxc151355 	ivp = (uint8_t *)wh;
1393147Sxc151355 	ivp += hdrlen;
1403147Sxc151355 
1413147Sxc151355 	/*
1423147Sxc151355 	 * IV must not duplicate during the lifetime of the key.
1433147Sxc151355 	 * But no mechanism to renew keys is defined in IEEE 802.11
1443147Sxc151355 	 * WEP.  And IV may be duplicated between other stations
1453147Sxc151355 	 * because of the session key itself is shared.
1463147Sxc151355 	 * So we use pseudo random IV for now, though it is not the
1473147Sxc151355 	 * right way.
1483147Sxc151355 	 */
1493147Sxc151355 	iv = ctx->wc_iv;
1503147Sxc151355 	/*
1513147Sxc151355 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
1523147Sxc151355 	 * (B, 255, N) with 3 <= B < 8
1533147Sxc151355 	 */
1543147Sxc151355 	if ((iv & 0xff00) == 0xff00) {
1553147Sxc151355 		int B = (iv & 0xff0000) >> 16;
1563147Sxc151355 		if (3 <= B && B < 16)
1573147Sxc151355 			iv = (B+1) << 16;
1583147Sxc151355 	}
1593147Sxc151355 	ctx->wc_iv = iv + 1;
1603147Sxc151355 
1613147Sxc151355 	ivp[2] = (uint8_t)(iv >> 0);
1623147Sxc151355 	ivp[1] = (uint8_t)(iv >> 8);
1633147Sxc151355 	ivp[0] = (uint8_t)(iv >> 16);
1643147Sxc151355 
1653147Sxc151355 	/* Key ID and pad */
1663147Sxc151355 	ivp[IEEE80211_WEP_IVLEN] = keyid;
1673147Sxc151355 
1683147Sxc151355 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
1693147Sxc151355 	    (wep_encrypt(k, mp, hdrlen) == 0))
1703147Sxc151355 		return (0);
1713147Sxc151355 
1723147Sxc151355 	return (1);
1733147Sxc151355 }
1743147Sxc151355 
1753147Sxc151355 /*
1763147Sxc151355  * Validate and strip privacy headers (and trailer) for a
1773147Sxc151355  * received frame.  If necessary, decrypt the frame using
1783147Sxc151355  * the specified key.
1793147Sxc151355  */
1803147Sxc151355 static int
wep_decap(struct ieee80211_key * k,mblk_t * mp,int hdrlen)1813147Sxc151355 wep_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
1823147Sxc151355 {
1833147Sxc151355 	/*
1843147Sxc151355 	 * Check if the device handled the decrypt in hardware.
1853147Sxc151355 	 * If so we just strip the header; otherwise we need to
1863147Sxc151355 	 * handle the decrypt in software.
1873147Sxc151355 	 */
1883147Sxc151355 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
1893147Sxc151355 	    (wep_decrypt(k, mp, hdrlen) == 0)) {
1903147Sxc151355 		ieee80211_err("WEP ICV mismatch on decrypt\n");
1913147Sxc151355 		return (0);
1923147Sxc151355 	}
1933147Sxc151355 
1943147Sxc151355 	/*
1953147Sxc151355 	 * Copy up 802.11 header and strip crypto bits.
1963147Sxc151355 	 */
197*10266SQuaker.Fang@Sun.COM 	(void) memmove(mp->b_rptr + wep.ic_header, mp->b_rptr, hdrlen);
1983147Sxc151355 	mp->b_rptr += wep.ic_header;
1993147Sxc151355 	mp->b_wptr -= wep.ic_trailer;
2003147Sxc151355 
2013147Sxc151355 	return (1);
2023147Sxc151355 }
2033147Sxc151355 
2043147Sxc151355 /*
2053147Sxc151355  * Add MIC to the frame as needed.
2063147Sxc151355  */
2073147Sxc151355 /* ARGSUSED */
2083147Sxc151355 static int
wep_enmic(struct ieee80211_key * k,mblk_t * mp,int force)2093147Sxc151355 wep_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
2103147Sxc151355 {
2113147Sxc151355 	return (1);
2123147Sxc151355 }
2133147Sxc151355 
2143147Sxc151355 /*
2153147Sxc151355  * Verify and strip MIC from the frame.
2163147Sxc151355  */
2173147Sxc151355 /* ARGSUSED */
2183147Sxc151355 static int
wep_demic(struct ieee80211_key * k,mblk_t * mp,int force)2193147Sxc151355 wep_demic(struct ieee80211_key *k, mblk_t *mp, int force)
2203147Sxc151355 {
2213147Sxc151355 	return (1);
2223147Sxc151355 }
2233147Sxc151355 
2243147Sxc151355 static int
wep_encrypt(struct ieee80211_key * key,mblk_t * mp,int hdrlen)2253147Sxc151355 wep_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
2263147Sxc151355 {
2273147Sxc151355 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
2283147Sxc151355 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
2293147Sxc151355 	uint8_t *icv;
2303147Sxc151355 	uint32_t crc;
2313147Sxc151355 	crypto_context_t ctx;
2323147Sxc151355 	int rv;
2333147Sxc151355 
2343147Sxc151355 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
2353147Sxc151355 
2363147Sxc151355 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
2373147Sxc151355 
2383147Sxc151355 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
2393147Sxc151355 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
2407249Sff224033 	    key->wk_keylen);
2413147Sxc151355 
2423147Sxc151355 	ctx = NULL;
2433147Sxc151355 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
2447249Sff224033 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
2453147Sxc151355 
2463147Sxc151355 	if (rv != CRYPTO_SUCCESS)
2473147Sxc151355 		return (0);
2483147Sxc151355 
2493147Sxc151355 	/* calculate CRC over unencrypted data */
2503147Sxc151355 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
2517249Sff224033 	    MBLKL(mp) - (hdrlen + wep.ic_header),
2523147Sxc151355 	    -1U, crc_table);
2533147Sxc151355 
2543147Sxc151355 	/* encrypt data */
2553147Sxc151355 	(void) rc4_crypt(ctx,
2567249Sff224033 	    mp->b_rptr + hdrlen + wep.ic_header,
2577249Sff224033 	    mp->b_rptr + hdrlen + wep.ic_header,
2587249Sff224033 	    MBLKL(mp) - (hdrlen + wep.ic_header));
2593147Sxc151355 
2603147Sxc151355 	/* tack on ICV */
2613147Sxc151355 	*(uint32_t *)crcbuf = LE_32(~crc);
2623147Sxc151355 	icv = mp->b_wptr;
2633147Sxc151355 	mp->b_wptr += IEEE80211_WEP_CRCLEN;
2643147Sxc151355 	(void) rc4_crypt(ctx, crcbuf, icv, IEEE80211_WEP_CRCLEN);
2653147Sxc151355 
2663147Sxc151355 	(void) rc4_final(ctx, icv, IEEE80211_WEP_CRCLEN);
2673147Sxc151355 
2683147Sxc151355 	return (1);
2693147Sxc151355 }
2703147Sxc151355 
2713147Sxc151355 static int
wep_decrypt(struct ieee80211_key * key,mblk_t * mp,int hdrlen)2723147Sxc151355 wep_decrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
2733147Sxc151355 {
2743147Sxc151355 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
2753147Sxc151355 	uint8_t crcbuf[IEEE80211_WEP_CRCLEN];
2763147Sxc151355 	uint8_t *icv;
2773147Sxc151355 	uint32_t crc;
2783147Sxc151355 	crypto_context_t ctx;
2793147Sxc151355 	int rv;
2803147Sxc151355 
2813147Sxc151355 	ASSERT(key->wk_flags & IEEE80211_KEY_SWCRYPT);
2823147Sxc151355 
2833147Sxc151355 	/* ctx->wc_ic->isc_stats.is_crypto_wep++; */
2843147Sxc151355 
2853147Sxc151355 	(void) memcpy(rc4key, mp->b_rptr + hdrlen, IEEE80211_WEP_IVLEN);
2863147Sxc151355 	(void) memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key,
2877249Sff224033 	    key->wk_keylen);
2883147Sxc151355 
2893147Sxc151355 	ctx = NULL;
2903147Sxc151355 	rv = rc4_init(&ctx, (const uint8_t *)rc4key,
2917249Sff224033 	    IEEE80211_WEP_IVLEN + key->wk_keylen);
2923147Sxc151355 
2933147Sxc151355 	if (rv != CRYPTO_SUCCESS)
2943147Sxc151355 		return (0);
2953147Sxc151355 
2963147Sxc151355 	/* decrypt data */
2973147Sxc151355 	(void) rc4_crypt(ctx,
2987249Sff224033 	    mp->b_rptr + hdrlen + wep.ic_header,
2997249Sff224033 	    mp->b_rptr + hdrlen + wep.ic_header,
3007249Sff224033 	    MBLKL(mp) -
3017249Sff224033 	    (hdrlen + wep.ic_header + wep.ic_trailer));
3023147Sxc151355 
3033147Sxc151355 	/* calculate CRC over unencrypted data */
3043147Sxc151355 	CRC32(crc, mp->b_rptr + hdrlen + wep.ic_header,
3057249Sff224033 	    MBLKL(mp) -
3063147Sxc151355 	    (hdrlen + wep.ic_header + wep.ic_trailer),
3073147Sxc151355 	    -1U, crc_table);
3083147Sxc151355 
3093147Sxc151355 	/* decrypt ICV and compare to CRC */
3103147Sxc151355 	icv = mp->b_wptr - IEEE80211_WEP_CRCLEN;
3113147Sxc151355 	(void) rc4_crypt(ctx, icv, crcbuf, IEEE80211_WEP_CRCLEN);
3123147Sxc151355 
3133147Sxc151355 	(void) rc4_final(ctx, crcbuf, IEEE80211_WEP_CRCLEN);
3143147Sxc151355 
3153147Sxc151355 	return (crc == ~LE_32(*(uint32_t *)crcbuf));
3163147Sxc151355 }
3173147Sxc151355 
3183147Sxc151355 /*
3193147Sxc151355  * rc_init() -  To init the key, for multiply encryption/decryption
3203147Sxc151355  * Using the Kernel encryption framework
3213147Sxc151355  */
3223147Sxc151355 int
rc4_init(crypto_context_t * ctx,const uint8_t * key,int keylen)3233147Sxc151355 rc4_init(crypto_context_t *ctx, const uint8_t *key, int keylen)
3243147Sxc151355 {
3253147Sxc151355 	crypto_mechanism_t mech;
3263147Sxc151355 	crypto_key_t crkey;
3273147Sxc151355 	int rv;
3283147Sxc151355 
3293147Sxc151355 	bzero(&crkey, sizeof (crkey));
3303147Sxc151355 
3313147Sxc151355 	crkey.ck_format = CRYPTO_KEY_RAW;
3323147Sxc151355 	crkey.ck_data   = (char *)key;
3333147Sxc151355 	/* keys are measured in bits, not bytes, so multiply by 8 */
3343147Sxc151355 	crkey.ck_length = keylen * 8;
3353147Sxc151355 
3363147Sxc151355 	mech.cm_type	  = crypto_mech2id(SUN_CKM_RC4);
3373147Sxc151355 	mech.cm_param	  = NULL;
3383147Sxc151355 	mech.cm_param_len = 0;
3393147Sxc151355 
3403147Sxc151355 	rv = crypto_encrypt_init(&mech, &crkey, NULL, ctx, NULL);
3413147Sxc151355 	if (rv != CRYPTO_SUCCESS)
3423147Sxc151355 		cmn_err(CE_WARN, "rc4_init failed (%x)", rv);
3433147Sxc151355 
3443147Sxc151355 	return (rv);
3453147Sxc151355 }
3463147Sxc151355 
3473147Sxc151355 /*
3483147Sxc151355  * rc4_crypt
3493147Sxc151355  *
3503147Sxc151355  * Use the Kernel encryption framework to provide the
3513147Sxc151355  * crypto operations for the indicated data.
3523147Sxc151355  */
3533147Sxc151355 int
rc4_crypt(crypto_context_t ctx,const uint8_t * inbuf,uint8_t * outbuf,int buflen)3543147Sxc151355 rc4_crypt(crypto_context_t ctx, const uint8_t *inbuf,
3553147Sxc151355 	uint8_t *outbuf, int buflen)
3563147Sxc151355 {
3573147Sxc151355 	int rv = CRYPTO_FAILED;
3583147Sxc151355 
3593147Sxc151355 	crypto_data_t d1, d2;
3603147Sxc151355 
3613147Sxc151355 	ASSERT(inbuf  != NULL);
3623147Sxc151355 	ASSERT(outbuf != NULL);
3633147Sxc151355 
3643147Sxc151355 	bzero(&d1, sizeof (d1));
3653147Sxc151355 	bzero(&d2, sizeof (d2));
3663147Sxc151355 
3673147Sxc151355 	d1.cd_format = CRYPTO_DATA_RAW;
3683147Sxc151355 	d1.cd_offset = 0;
3693147Sxc151355 	d1.cd_length = buflen;
3703147Sxc151355 	d1.cd_raw.iov_base = (char *)inbuf;
3713147Sxc151355 	d1.cd_raw.iov_len  = buflen;
3723147Sxc151355 
3733147Sxc151355 	d2.cd_format = CRYPTO_DATA_RAW;
3743147Sxc151355 	d2.cd_offset = 0;
3753147Sxc151355 	d2.cd_length = buflen;
3763147Sxc151355 	d2.cd_raw.iov_base = (char *)outbuf;
3773147Sxc151355 	d2.cd_raw.iov_len  = buflen;
3783147Sxc151355 
3793147Sxc151355 	rv = crypto_encrypt_update(ctx, &d1, &d2, NULL);
3803147Sxc151355 
3813147Sxc151355 	if (rv != CRYPTO_SUCCESS)
3823147Sxc151355 		cmn_err(CE_WARN, "rc4_crypt failed (%x)", rv);
3833147Sxc151355 	return (rv);
3843147Sxc151355 }
3853147Sxc151355 
3863147Sxc151355 /*
3873147Sxc151355  * rc4_final
3883147Sxc151355  *
3893147Sxc151355  * Use the Kernel encryption framework to provide the
3903147Sxc151355  * crypto operations for the indicated data.
3913147Sxc151355  */
3923147Sxc151355 int
rc4_final(crypto_context_t ctx,uint8_t * outbuf,int buflen)3933147Sxc151355 rc4_final(crypto_context_t ctx, uint8_t *outbuf, int buflen)
3943147Sxc151355 {
3953147Sxc151355 	int rv = CRYPTO_FAILED;
3963147Sxc151355 
3973147Sxc151355 	crypto_data_t d2;
3983147Sxc151355 
3993147Sxc151355 	ASSERT(outbuf != NULL);
4003147Sxc151355 
4013147Sxc151355 	bzero(&d2, sizeof (d2));
4023147Sxc151355 
4033147Sxc151355 	d2.cd_format = CRYPTO_DATA_RAW;
4043147Sxc151355 	d2.cd_offset = 0;
4053147Sxc151355 	d2.cd_length = buflen;
4063147Sxc151355 	d2.cd_raw.iov_base = (char *)outbuf;
4073147Sxc151355 	d2.cd_raw.iov_len = buflen;
4083147Sxc151355 
4093147Sxc151355 	rv = crypto_encrypt_final(ctx, &d2, NULL);
4103147Sxc151355 
4113147Sxc151355 	if (rv != CRYPTO_SUCCESS)
4123147Sxc151355 		cmn_err(CE_WARN, "rc4_final failed (%x)", rv);
4133147Sxc151355 	return (rv);
4143147Sxc151355 }
415