1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * RC4 provider for the Kernel Cryptographic Framework (KCF) 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/systm.h> 35*0Sstevel@tonic-gate #include <sys/modctl.h> 36*0Sstevel@tonic-gate #include <sys/cmn_err.h> 37*0Sstevel@tonic-gate #include <sys/ddi.h> 38*0Sstevel@tonic-gate #include <sys/crypto/common.h> 39*0Sstevel@tonic-gate #include <sys/crypto/spi.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/strsun.h> 42*0Sstevel@tonic-gate #include <arcfour.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate extern struct mod_ops mod_cryptoops; 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * Module linkage information for the kernel. 48*0Sstevel@tonic-gate */ 49*0Sstevel@tonic-gate static struct modlcrypto modlcrypto = { 50*0Sstevel@tonic-gate &mod_cryptoops, 51*0Sstevel@tonic-gate "RC4 Kernel SW Provider %I%" 52*0Sstevel@tonic-gate }; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 55*0Sstevel@tonic-gate MODREV_1, 56*0Sstevel@tonic-gate (void *)&modlcrypto, 57*0Sstevel@tonic-gate NULL 58*0Sstevel@tonic-gate }; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* 61*0Sstevel@tonic-gate * CSPI information (entry points, provider info, etc.) 62*0Sstevel@tonic-gate */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate #define RC4_MECH_INFO_TYPE 0 65*0Sstevel@tonic-gate /* 66*0Sstevel@tonic-gate * Mechanism info structure passed to KCF during registration. 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate static crypto_mech_info_t rc4_mech_info_tab[] = { 69*0Sstevel@tonic-gate {SUN_CKM_RC4, RC4_MECH_INFO_TYPE, 70*0Sstevel@tonic-gate CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | 71*0Sstevel@tonic-gate CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC, 72*0Sstevel@tonic-gate ARCFOUR_MIN_KEY_BITS, ARCFOUR_MAX_KEY_BITS, 73*0Sstevel@tonic-gate CRYPTO_KEYSIZE_UNIT_IN_BITS} 74*0Sstevel@tonic-gate }; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate static void rc4_provider_status(crypto_provider_handle_t, uint_t *); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate static crypto_control_ops_t rc4_control_ops = { 79*0Sstevel@tonic-gate rc4_provider_status 80*0Sstevel@tonic-gate }; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate static int rc4_common_init(crypto_ctx_t *, crypto_mechanism_t *, 83*0Sstevel@tonic-gate crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate static int rc4_crypt_update(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 86*0Sstevel@tonic-gate crypto_req_handle_t); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate static int rc4_crypt_final(crypto_ctx_t *, crypto_data_t *, 89*0Sstevel@tonic-gate crypto_req_handle_t); 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate static int rc4_crypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 92*0Sstevel@tonic-gate crypto_req_handle_t); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate static int rc4_crypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 95*0Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 96*0Sstevel@tonic-gate crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate static crypto_cipher_ops_t rc4_cipher_ops = { 100*0Sstevel@tonic-gate rc4_common_init, 101*0Sstevel@tonic-gate rc4_crypt, 102*0Sstevel@tonic-gate rc4_crypt_update, 103*0Sstevel@tonic-gate rc4_crypt_final, 104*0Sstevel@tonic-gate rc4_crypt_atomic, 105*0Sstevel@tonic-gate rc4_common_init, 106*0Sstevel@tonic-gate rc4_crypt, 107*0Sstevel@tonic-gate rc4_crypt_update, 108*0Sstevel@tonic-gate rc4_crypt_final, 109*0Sstevel@tonic-gate rc4_crypt_atomic 110*0Sstevel@tonic-gate }; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate static int rc4_free_context(crypto_ctx_t *); 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate static crypto_ctx_ops_t rc4_ctx_ops = { 115*0Sstevel@tonic-gate NULL, 116*0Sstevel@tonic-gate rc4_free_context 117*0Sstevel@tonic-gate }; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate static crypto_ops_t rc4_crypto_ops = { 120*0Sstevel@tonic-gate &rc4_control_ops, 121*0Sstevel@tonic-gate NULL, 122*0Sstevel@tonic-gate &rc4_cipher_ops, 123*0Sstevel@tonic-gate NULL, 124*0Sstevel@tonic-gate NULL, 125*0Sstevel@tonic-gate NULL, 126*0Sstevel@tonic-gate NULL, 127*0Sstevel@tonic-gate NULL, 128*0Sstevel@tonic-gate NULL, 129*0Sstevel@tonic-gate NULL, 130*0Sstevel@tonic-gate NULL, 131*0Sstevel@tonic-gate NULL, 132*0Sstevel@tonic-gate NULL, 133*0Sstevel@tonic-gate &rc4_ctx_ops 134*0Sstevel@tonic-gate }; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static crypto_provider_info_t rc4_prov_info = { 137*0Sstevel@tonic-gate CRYPTO_SPI_VERSION_1, 138*0Sstevel@tonic-gate "RC4 Software Provider", 139*0Sstevel@tonic-gate CRYPTO_SW_PROVIDER, 140*0Sstevel@tonic-gate {&modlinkage}, 141*0Sstevel@tonic-gate NULL, 142*0Sstevel@tonic-gate &rc4_crypto_ops, 143*0Sstevel@tonic-gate sizeof (rc4_mech_info_tab)/sizeof (crypto_mech_info_t), 144*0Sstevel@tonic-gate rc4_mech_info_tab 145*0Sstevel@tonic-gate }; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate static crypto_kcf_provider_handle_t rc4_prov_handle = NULL; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate static mblk_t *advance_position(mblk_t *, off_t, uchar_t **); 150*0Sstevel@tonic-gate static int crypto_arcfour_crypt(ARCFour_key *, uchar_t *, crypto_data_t *, 151*0Sstevel@tonic-gate int); 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate int 154*0Sstevel@tonic-gate _init(void) 155*0Sstevel@tonic-gate { 156*0Sstevel@tonic-gate int ret; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * Register with KCF. If the registration fails, log an error 160*0Sstevel@tonic-gate * and uninstall the module. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if ((ret = crypto_register_provider(&rc4_prov_info, 163*0Sstevel@tonic-gate &rc4_prov_handle)) != CRYPTO_SUCCESS) { 164*0Sstevel@tonic-gate cmn_err(CE_WARN, "_init: crypto_register_provider(%s)" 165*0Sstevel@tonic-gate "failed (0x%x)", "arcfour", ret); 166*0Sstevel@tonic-gate return (EACCES); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) { 170*0Sstevel@tonic-gate int rv; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate ASSERT(rc4_prov_handle != NULL); 173*0Sstevel@tonic-gate /* We should not return if the unregister returns busy. */ 174*0Sstevel@tonic-gate while ((rv = crypto_unregister_provider(rc4_prov_handle)) 175*0Sstevel@tonic-gate == CRYPTO_BUSY) { 176*0Sstevel@tonic-gate cmn_err(CE_WARN, "_init: crypto_unregister_provider(%s)" 177*0Sstevel@tonic-gate " failed (0x%x). Retrying.", "arcfour", rv); 178*0Sstevel@tonic-gate /* wait 10 seconds and try again. */ 179*0Sstevel@tonic-gate delay(10 * drv_usectohz(1000000)); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate return (0); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate int 187*0Sstevel@tonic-gate _fini(void) 188*0Sstevel@tonic-gate { 189*0Sstevel@tonic-gate int ret; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * Unregister from KCF if previous registration succeeded. 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate if (rc4_prov_handle != NULL) { 195*0Sstevel@tonic-gate if ((ret = crypto_unregister_provider(rc4_prov_handle)) != 196*0Sstevel@tonic-gate CRYPTO_SUCCESS) { 197*0Sstevel@tonic-gate cmn_err(CE_WARN, "_fini: crypto_unregister_provider(%s)" 198*0Sstevel@tonic-gate " failed (0x%x)", "arcfour", ret); 199*0Sstevel@tonic-gate return (EBUSY); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate rc4_prov_handle = NULL; 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate int 208*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * KCF software provider control entry points. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate /* ARGSUSED */ 218*0Sstevel@tonic-gate static void 219*0Sstevel@tonic-gate rc4_provider_status(crypto_provider_handle_t provider, uint_t *status) 220*0Sstevel@tonic-gate { 221*0Sstevel@tonic-gate *status = CRYPTO_PROVIDER_READY; 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* ARGSUSED */ 225*0Sstevel@tonic-gate static int 226*0Sstevel@tonic-gate rc4_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 227*0Sstevel@tonic-gate crypto_key_t *key, crypto_spi_ctx_template_t template, 228*0Sstevel@tonic-gate crypto_req_handle_t req) 229*0Sstevel@tonic-gate { 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* EXPORT DELETE START */ 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate ARCFour_key *keystream; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate if ((mechanism)->cm_type != RC4_MECH_INFO_TYPE) 236*0Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) 239*0Sstevel@tonic-gate return (CRYPTO_KEY_TYPE_INCONSISTENT); 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate if (key->ck_length < ARCFOUR_MIN_KEY_BITS || 242*0Sstevel@tonic-gate key->ck_length > ARCFOUR_MAX_KEY_BITS) { 243*0Sstevel@tonic-gate return (CRYPTO_KEY_SIZE_RANGE); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * Allocate an RC4 key stream. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate if ((keystream = kmem_alloc(sizeof (ARCFour_key), 250*0Sstevel@tonic-gate crypto_kmflag(req))) == NULL) 251*0Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate arcfour_key_init(keystream, key->ck_data, key->ck_length >> 3); 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate ctx->cc_provider_private = keystream; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* EXPORT DELETE END */ 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate static int 263*0Sstevel@tonic-gate rc4_crypt(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 264*0Sstevel@tonic-gate crypto_req_handle_t req) 265*0Sstevel@tonic-gate { 266*0Sstevel@tonic-gate int ret; 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate ret = rc4_crypt_update(ctx, input, output, req); 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate if (ret != CRYPTO_BUFFER_TOO_SMALL) 271*0Sstevel@tonic-gate (void) rc4_free_context(ctx); 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate return (ret); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* ARGSUSED */ 277*0Sstevel@tonic-gate static int 278*0Sstevel@tonic-gate rc4_crypt_update(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output, 279*0Sstevel@tonic-gate crypto_req_handle_t req) 280*0Sstevel@tonic-gate { 281*0Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* EXPORT DELETE START */ 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate ARCFour_key *key; 286*0Sstevel@tonic-gate off_t saveoffset; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate key = ctx->cc_provider_private; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* Simple case: in-line encipherment */ 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate if (output == NULL) { 295*0Sstevel@tonic-gate switch (input->cd_format) { 296*0Sstevel@tonic-gate case CRYPTO_DATA_RAW: { 297*0Sstevel@tonic-gate char *start, *end; 298*0Sstevel@tonic-gate start = input->cd_raw.iov_base + input->cd_offset; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate end = input->cd_raw.iov_base + input->cd_raw.iov_len; 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (start + input->cd_length > end) 303*0Sstevel@tonic-gate return (CRYPTO_DATA_INVALID); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate arcfour_crypt(key, (uchar_t *)start, (uchar_t *)start, 306*0Sstevel@tonic-gate input->cd_length); 307*0Sstevel@tonic-gate break; 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate case CRYPTO_DATA_MBLK: { 310*0Sstevel@tonic-gate uchar_t *start, *end; 311*0Sstevel@tonic-gate size_t len, left; 312*0Sstevel@tonic-gate mblk_t *mp = input->cd_mp, *mp1, *mp2; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate ASSERT(mp != NULL); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate mp1 = advance_position(mp, input->cd_offset, &start); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (mp1 == NULL) 319*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate mp2 = advance_position(mp, input->cd_offset + 322*0Sstevel@tonic-gate input->cd_length, &end); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (mp2 == NULL) 325*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate left = input->cd_length; 328*0Sstevel@tonic-gate while (mp1 != NULL) { 329*0Sstevel@tonic-gate if (mp1->b_wptr - start > left) { 330*0Sstevel@tonic-gate len = left; 331*0Sstevel@tonic-gate arcfour_crypt(key, start, start, len); 332*0Sstevel@tonic-gate mp1 = NULL; 333*0Sstevel@tonic-gate } else { 334*0Sstevel@tonic-gate len = mp1->b_wptr - start; 335*0Sstevel@tonic-gate arcfour_crypt(key, start, start, len); 336*0Sstevel@tonic-gate mp1 = mp1->b_cont; 337*0Sstevel@tonic-gate start = mp1->b_rptr; 338*0Sstevel@tonic-gate left -= len; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate break; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate case CRYPTO_DATA_UIO: { 344*0Sstevel@tonic-gate uio_t *uiop = input->cd_uio; 345*0Sstevel@tonic-gate off_t offset = input->cd_offset; 346*0Sstevel@tonic-gate size_t length = input->cd_length; 347*0Sstevel@tonic-gate uint_t vec_idx; 348*0Sstevel@tonic-gate size_t cur_len; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * Jump to the first iovec containing data to be 352*0Sstevel@tonic-gate * processed. 353*0Sstevel@tonic-gate */ 354*0Sstevel@tonic-gate for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 355*0Sstevel@tonic-gate offset >= uiop->uio_iov[vec_idx].iov_len; 356*0Sstevel@tonic-gate offset -= uiop->uio_iov[vec_idx++].iov_len); 357*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt) { 358*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * Now process the iovecs. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate while (vec_idx < uiop->uio_iovcnt && length > 0) { 365*0Sstevel@tonic-gate uchar_t *start; 366*0Sstevel@tonic-gate iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate cur_len = MIN(iovp->iov_len - offset, length); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate start = (uchar_t *)(iovp->iov_base + offset); 371*0Sstevel@tonic-gate arcfour_crypt(key, start + offset, 372*0Sstevel@tonic-gate start + offset, cur_len); 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate length -= cur_len; 375*0Sstevel@tonic-gate vec_idx++; 376*0Sstevel@tonic-gate offset = 0; 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt && length > 0) { 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate break; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * We need to just return the length needed to store the output. 391*0Sstevel@tonic-gate * We should not destroy the context for the following case. 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate if (input->cd_length > output->cd_length) { 395*0Sstevel@tonic-gate output->cd_length = input->cd_length; 396*0Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate saveoffset = output->cd_offset; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate switch (input->cd_format) { 402*0Sstevel@tonic-gate case CRYPTO_DATA_RAW: { 403*0Sstevel@tonic-gate char *start, *end; 404*0Sstevel@tonic-gate start = input->cd_raw.iov_base + input->cd_offset; 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate end = input->cd_raw.iov_base + input->cd_raw.iov_len; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (start + input->cd_length > end) 409*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate ret = crypto_arcfour_crypt(key, (uchar_t *)start, output, 412*0Sstevel@tonic-gate input->cd_length); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 415*0Sstevel@tonic-gate return (ret); 416*0Sstevel@tonic-gate break; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate case CRYPTO_DATA_MBLK: { 419*0Sstevel@tonic-gate uchar_t *start, *end; 420*0Sstevel@tonic-gate size_t len, left; 421*0Sstevel@tonic-gate mblk_t *mp = input->cd_mp, *mp1, *mp2; 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate ASSERT(mp != NULL); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate mp1 = advance_position(mp, input->cd_offset, &start); 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate if (mp1 == NULL) 428*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate mp2 = advance_position(mp, input->cd_offset + input->cd_length, 431*0Sstevel@tonic-gate &end); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if (mp2 == NULL) 434*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate left = input->cd_length; 437*0Sstevel@tonic-gate while (mp1 != NULL) { 438*0Sstevel@tonic-gate if (mp1->b_wptr - start > left) { 439*0Sstevel@tonic-gate len = left; 440*0Sstevel@tonic-gate ret = crypto_arcfour_crypt(key, start, output, 441*0Sstevel@tonic-gate len); 442*0Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 443*0Sstevel@tonic-gate return (ret); 444*0Sstevel@tonic-gate mp1 = NULL; 445*0Sstevel@tonic-gate } else { 446*0Sstevel@tonic-gate len = mp1->b_wptr - start; 447*0Sstevel@tonic-gate ret = crypto_arcfour_crypt(key, start, output, 448*0Sstevel@tonic-gate len); 449*0Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 450*0Sstevel@tonic-gate return (ret); 451*0Sstevel@tonic-gate mp1 = mp1->b_cont; 452*0Sstevel@tonic-gate start = mp1->b_rptr; 453*0Sstevel@tonic-gate left -= len; 454*0Sstevel@tonic-gate output->cd_offset += len; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate break; 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate case CRYPTO_DATA_UIO: { 460*0Sstevel@tonic-gate uio_t *uiop = input->cd_uio; 461*0Sstevel@tonic-gate off_t offset = input->cd_offset; 462*0Sstevel@tonic-gate size_t length = input->cd_length; 463*0Sstevel@tonic-gate uint_t vec_idx; 464*0Sstevel@tonic-gate size_t cur_len; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* 467*0Sstevel@tonic-gate * Jump to the first iovec containing data to be 468*0Sstevel@tonic-gate * processed. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 471*0Sstevel@tonic-gate offset >= uiop->uio_iov[vec_idx].iov_len; 472*0Sstevel@tonic-gate offset -= uiop->uio_iov[vec_idx++].iov_len); 473*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt) { 474*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* 478*0Sstevel@tonic-gate * Now process the iovecs. 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate while (vec_idx < uiop->uio_iovcnt && length > 0) { 481*0Sstevel@tonic-gate uchar_t *start; 482*0Sstevel@tonic-gate iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 483*0Sstevel@tonic-gate cur_len = MIN(iovp->iov_len - offset, length); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate start = (uchar_t *)(iovp->iov_base + offset); 486*0Sstevel@tonic-gate ret = crypto_arcfour_crypt(key, start + offset, 487*0Sstevel@tonic-gate output, cur_len); 488*0Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 489*0Sstevel@tonic-gate return (ret); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate length -= cur_len; 492*0Sstevel@tonic-gate vec_idx++; 493*0Sstevel@tonic-gate offset = 0; 494*0Sstevel@tonic-gate output->cd_offset += cur_len; 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt && length > 0) { 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate output->cd_offset = saveoffset; 505*0Sstevel@tonic-gate output->cd_length = input->cd_length; 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate /* EXPORT DELETE END */ 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate return (ret); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /* ARGSUSED */ 513*0Sstevel@tonic-gate static int rc4_crypt_final(crypto_ctx_t *ctx, crypto_data_t *data, 514*0Sstevel@tonic-gate crypto_req_handle_t req) 515*0Sstevel@tonic-gate { 516*0Sstevel@tonic-gate /* No final part for streams ciphers. Just free the context */ 517*0Sstevel@tonic-gate if (data != NULL) 518*0Sstevel@tonic-gate data->cd_length = 0; 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate return (rc4_free_context(ctx)); 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* ARGSUSED */ 524*0Sstevel@tonic-gate static int 525*0Sstevel@tonic-gate rc4_crypt_atomic(crypto_provider_handle_t handle, crypto_session_id_t session, 526*0Sstevel@tonic-gate crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *input, 527*0Sstevel@tonic-gate crypto_data_t *output, crypto_spi_ctx_template_t template, 528*0Sstevel@tonic-gate crypto_req_handle_t req) 529*0Sstevel@tonic-gate { 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate crypto_ctx_t ctx; 532*0Sstevel@tonic-gate int ret; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate ret = rc4_common_init(&ctx, mechanism, key, template, req); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 537*0Sstevel@tonic-gate return (ret); 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate ret = rc4_crypt_update(&ctx, input, output, req); 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate (void) rc4_free_context(&ctx); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate return (ret); 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate /* ARGSUSED */ 547*0Sstevel@tonic-gate static int 548*0Sstevel@tonic-gate rc4_free_context(crypto_ctx_t *ctx) 549*0Sstevel@tonic-gate { 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate /* EXPORT DELETE START */ 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate ARCFour_key *keystream = ctx->cc_provider_private; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (keystream != NULL) { 556*0Sstevel@tonic-gate bzero(keystream, sizeof (ARCFour_key)); 557*0Sstevel@tonic-gate kmem_free(keystream, sizeof (ARCFour_key)); 558*0Sstevel@tonic-gate ctx->cc_provider_private = NULL; 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate /* EXPORT DELETE END */ 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate /* Encrypts a contiguous input 'in' into the 'out' crypto_data_t */ 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate static int 569*0Sstevel@tonic-gate crypto_arcfour_crypt(ARCFour_key *key, uchar_t *in, crypto_data_t *out, 570*0Sstevel@tonic-gate int length) 571*0Sstevel@tonic-gate { 572*0Sstevel@tonic-gate switch (out->cd_format) { 573*0Sstevel@tonic-gate case CRYPTO_DATA_RAW: { 574*0Sstevel@tonic-gate uchar_t *start, *end; 575*0Sstevel@tonic-gate start = (uchar_t *)(out->cd_raw.iov_base + 576*0Sstevel@tonic-gate out->cd_offset); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate end = (uchar_t *)(out->cd_raw.iov_base + 579*0Sstevel@tonic-gate out->cd_raw.iov_len); 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (start + out->cd_length > end) 582*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate arcfour_crypt(key, in, start, length); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate case CRYPTO_DATA_MBLK: { 589*0Sstevel@tonic-gate uchar_t *start, *end; 590*0Sstevel@tonic-gate size_t len, left; 591*0Sstevel@tonic-gate mblk_t *mp = out->cd_mp, *mp1, *mp2; 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate ASSERT(mp != NULL); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate mp1 = advance_position(mp, out->cd_offset, &start); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate if (mp1 == NULL) 598*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate mp2 = advance_position(mp, out->cd_offset + 601*0Sstevel@tonic-gate out->cd_length, &end); 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate if (mp2 == NULL) 604*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate left = length; 607*0Sstevel@tonic-gate while (mp1 != NULL) { 608*0Sstevel@tonic-gate if (mp1->b_wptr - start > left) { 609*0Sstevel@tonic-gate len = left; 610*0Sstevel@tonic-gate arcfour_crypt(key, in, start, len); 611*0Sstevel@tonic-gate mp1 = NULL; 612*0Sstevel@tonic-gate } else { 613*0Sstevel@tonic-gate len = mp1->b_wptr - start; 614*0Sstevel@tonic-gate arcfour_crypt(key, in, start, len); 615*0Sstevel@tonic-gate mp1 = mp1->b_cont; 616*0Sstevel@tonic-gate start = mp1->b_rptr; 617*0Sstevel@tonic-gate left -= len; 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate break; 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate case CRYPTO_DATA_UIO: { 623*0Sstevel@tonic-gate uio_t *uiop = out->cd_uio; 624*0Sstevel@tonic-gate off_t offset = out->cd_offset; 625*0Sstevel@tonic-gate size_t len = length; 626*0Sstevel@tonic-gate uint_t vec_idx; 627*0Sstevel@tonic-gate size_t cur_len; 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate /* 630*0Sstevel@tonic-gate * Jump to the first iovec containing data to be 631*0Sstevel@tonic-gate * processed. 632*0Sstevel@tonic-gate */ 633*0Sstevel@tonic-gate for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 634*0Sstevel@tonic-gate offset >= uiop->uio_iov[vec_idx].iov_len; 635*0Sstevel@tonic-gate offset -= uiop->uio_iov[vec_idx++].iov_len); 636*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt) { 637*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate /* 641*0Sstevel@tonic-gate * Now process the iovecs. 642*0Sstevel@tonic-gate */ 643*0Sstevel@tonic-gate while (vec_idx < uiop->uio_iovcnt && len > 0) { 644*0Sstevel@tonic-gate uchar_t *start; 645*0Sstevel@tonic-gate iovec_t *iovp = &(uiop->uio_iov[vec_idx]); 646*0Sstevel@tonic-gate cur_len = MIN(iovp->iov_len - offset, len); 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate start = (uchar_t *)(iovp->iov_base + offset); 649*0Sstevel@tonic-gate arcfour_crypt(key, start + offset, 650*0Sstevel@tonic-gate start + offset, cur_len); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate len -= cur_len; 653*0Sstevel@tonic-gate vec_idx++; 654*0Sstevel@tonic-gate offset = 0; 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate if (vec_idx == uiop->uio_iovcnt && len > 0) { 658*0Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate break; 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate default: 663*0Sstevel@tonic-gate return (CRYPTO_DATA_INVALID); 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate /* 669*0Sstevel@tonic-gate * Advances 'offset' bytes from the beginning of the first block in 'mp', 670*0Sstevel@tonic-gate * possibly jumping across b_cont boundary 671*0Sstevel@tonic-gate * '*cpp' is set to the position of the byte we want, and the block where 672*0Sstevel@tonic-gate * 'cpp' is returned. 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate static mblk_t * 675*0Sstevel@tonic-gate advance_position(mblk_t *mp, off_t offset, uchar_t **cpp) 676*0Sstevel@tonic-gate { 677*0Sstevel@tonic-gate mblk_t *mp1 = mp; 678*0Sstevel@tonic-gate size_t l; 679*0Sstevel@tonic-gate off_t o = offset; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate while (mp1 != NULL) { 682*0Sstevel@tonic-gate l = MBLKL(mp1); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate if (l <= o) { 685*0Sstevel@tonic-gate o -= l; 686*0Sstevel@tonic-gate mp1 = mp1->b_cont; 687*0Sstevel@tonic-gate } else { 688*0Sstevel@tonic-gate *cpp = (uchar_t *)(mp1->b_rptr + o); 689*0Sstevel@tonic-gate break; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate return (mp1); 693*0Sstevel@tonic-gate } 694