1*906Sgm89044 2*906Sgm89044 /* 3*906Sgm89044 * CDDL HEADER START 4*906Sgm89044 * 5*906Sgm89044 * The contents of this file are subject to the terms of the 6*906Sgm89044 * Common Development and Distribution License (the "License"). 7*906Sgm89044 * You may not use this file except in compliance with the License. 8*906Sgm89044 * 9*906Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*906Sgm89044 * or http://www.opensolaris.org/os/licensing. 11*906Sgm89044 * See the License for the specific language governing permissions 12*906Sgm89044 * and limitations under the License. 13*906Sgm89044 * 14*906Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each 15*906Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*906Sgm89044 * If applicable, add the following below this CDDL HEADER, with the 17*906Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying 18*906Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner] 19*906Sgm89044 * 20*906Sgm89044 * CDDL HEADER END 21*906Sgm89044 */ 22*906Sgm89044 23*906Sgm89044 /* 24*906Sgm89044 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*906Sgm89044 * Use is subject to license terms. 26*906Sgm89044 */ 27*906Sgm89044 28*906Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI" 29*906Sgm89044 30*906Sgm89044 /* 31*906Sgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x. 32*906Sgm89044 */ 33*906Sgm89044 34*906Sgm89044 #include <sys/types.h> 35*906Sgm89044 #include <sys/ddi.h> 36*906Sgm89044 #include <sys/sunddi.h> 37*906Sgm89044 #include <sys/kmem.h> 38*906Sgm89044 #include <sys/note.h> 39*906Sgm89044 #include <sys/crypto/common.h> 40*906Sgm89044 #include <sys/crypto/spi.h> 41*906Sgm89044 #include <sys/crypto/dca.h> 42*906Sgm89044 43*906Sgm89044 /* 44*906Sgm89044 * 3DES implementation. 45*906Sgm89044 */ 46*906Sgm89044 47*906Sgm89044 static int dca_3desstart(dca_t *, uint32_t, dca_request_t *); 48*906Sgm89044 static void dca_3desdone(dca_request_t *, int); 49*906Sgm89044 50*906Sgm89044 51*906Sgm89044 int 52*906Sgm89044 dca_3des(crypto_ctx_t *ctx, crypto_data_t *in, 53*906Sgm89044 crypto_data_t *out, crypto_req_handle_t req, int flags) 54*906Sgm89044 { 55*906Sgm89044 int len; 56*906Sgm89044 int rv; 57*906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 58*906Sgm89044 dca_request_t *des_ctx = ctx->cc_provider_private; 59*906Sgm89044 dca_t *dca = ctx->cc_provider; 60*906Sgm89044 crypto_data_t *nin = &reqp->dr_ctx.in_dup; 61*906Sgm89044 62*906Sgm89044 len = dca_length(in); 63*906Sgm89044 if (len % DESBLOCK) { 64*906Sgm89044 DBG(dca, DWARN, "input not an integral number of DES blocks"); 65*906Sgm89044 (void) dca_free_context(ctx); 66*906Sgm89044 if (flags & DR_DECRYPT) { 67*906Sgm89044 return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 68*906Sgm89044 } else { 69*906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 70*906Sgm89044 } 71*906Sgm89044 } 72*906Sgm89044 73*906Sgm89044 /* 74*906Sgm89044 * If cd_miscdata non-null then this contains the IV. 75*906Sgm89044 */ 76*906Sgm89044 if (in->cd_miscdata != NULL) { 77*906Sgm89044 uchar_t *p = (uchar_t *)in->cd_miscdata; 78*906Sgm89044 des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3]; 79*906Sgm89044 des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7]; 80*906Sgm89044 } 81*906Sgm89044 82*906Sgm89044 /* 83*906Sgm89044 * In-place operations (input == out) are indicated by having a 84*906Sgm89044 * NULL output. In this case set the output to point to the input. 85*906Sgm89044 */ 86*906Sgm89044 if (out == NULL) { 87*906Sgm89044 out = in; 88*906Sgm89044 } 89*906Sgm89044 if (len > dca_length(out)) { 90*906Sgm89044 DBG(dca, DWARN, "inadequate output space (need %d, got %d)", 91*906Sgm89044 len, dca_length(out)); 92*906Sgm89044 out->cd_length = len; 93*906Sgm89044 /* Do not free the context since the app will call again */ 94*906Sgm89044 return (CRYPTO_BUFFER_TOO_SMALL); 95*906Sgm89044 } 96*906Sgm89044 97*906Sgm89044 if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) { 98*906Sgm89044 (void) dca_free_context(ctx); 99*906Sgm89044 return (rv); 100*906Sgm89044 } 101*906Sgm89044 102*906Sgm89044 /* special handling for null-sized input buffers */ 103*906Sgm89044 if (len == 0) { 104*906Sgm89044 out->cd_length = 0; 105*906Sgm89044 (void) dca_free_context(ctx); 106*906Sgm89044 return (CRYPTO_SUCCESS); 107*906Sgm89044 } 108*906Sgm89044 109*906Sgm89044 /* 110*906Sgm89044 * Make a local copy of the input crypto_data_t structure. This 111*906Sgm89044 * allows it to be manipulated locally and for dealing with in-place 112*906Sgm89044 * data (ie in == out). Note that "nin" has been pre-allocated, 113*906Sgm89044 * and only fields are copied, not actual data. 114*906Sgm89044 */ 115*906Sgm89044 if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) { 116*906Sgm89044 (void) dca_free_context(ctx); 117*906Sgm89044 return (rv); 118*906Sgm89044 } 119*906Sgm89044 120*906Sgm89044 /* Set output to zero ready to take the processed data */ 121*906Sgm89044 out->cd_length = 0; 122*906Sgm89044 123*906Sgm89044 reqp->dr_kcf_req = req; 124*906Sgm89044 reqp->dr_in = nin; 125*906Sgm89044 reqp->dr_out = out; 126*906Sgm89044 reqp->dr_job_stat = DS_3DESJOBS; 127*906Sgm89044 reqp->dr_byte_stat = DS_3DESBYTES; 128*906Sgm89044 129*906Sgm89044 rv = dca_3desstart(dca, flags, reqp); 130*906Sgm89044 131*906Sgm89044 /* Context will be freed in the kCF callback function otherwise */ 132*906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 133*906Sgm89044 (void) dca_free_context(ctx); 134*906Sgm89044 } 135*906Sgm89044 return (rv); 136*906Sgm89044 } 137*906Sgm89044 138*906Sgm89044 139*906Sgm89044 void 140*906Sgm89044 dca_3desctxfree(void *arg) 141*906Sgm89044 { 142*906Sgm89044 crypto_ctx_t *ctx = (crypto_ctx_t *)arg; 143*906Sgm89044 dca_request_t *des_ctx = ctx->cc_provider_private; 144*906Sgm89044 145*906Sgm89044 if (des_ctx == NULL) 146*906Sgm89044 return; 147*906Sgm89044 148*906Sgm89044 des_ctx->dr_ctx.atomic = 0; 149*906Sgm89044 des_ctx->dr_ctx.ctx_cm_type = 0; 150*906Sgm89044 ctx->cc_provider_private = NULL; 151*906Sgm89044 152*906Sgm89044 if (des_ctx->destroy) 153*906Sgm89044 dca_destroyreq(des_ctx); 154*906Sgm89044 else 155*906Sgm89044 /* Return it to the pool */ 156*906Sgm89044 dca_freereq(des_ctx); 157*906Sgm89044 } 158*906Sgm89044 159*906Sgm89044 int 160*906Sgm89044 dca_3desupdate(crypto_ctx_t *ctx, crypto_data_t *in, 161*906Sgm89044 crypto_data_t *out, crypto_req_handle_t req, int flags) 162*906Sgm89044 { 163*906Sgm89044 int len; 164*906Sgm89044 int rawlen; 165*906Sgm89044 int rv; 166*906Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 167*906Sgm89044 dca_request_t *des_ctx = ctx->cc_provider_private; 168*906Sgm89044 dca_t *dca = ctx->cc_provider; 169*906Sgm89044 crypto_data_t *nin = &reqp->dr_ctx.in_dup; 170*906Sgm89044 171*906Sgm89044 rawlen = dca_length(in) + des_ctx->dr_ctx.residlen; 172*906Sgm89044 173*906Sgm89044 len = ROUNDDOWN(rawlen, DESBLOCK); 174*906Sgm89044 /* 175*906Sgm89044 * If cd_miscdata non-null then this contains the IV. 176*906Sgm89044 */ 177*906Sgm89044 if (in->cd_miscdata != NULL) { 178*906Sgm89044 uchar_t *p = (uchar_t *)in->cd_miscdata; 179*906Sgm89044 des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3]; 180*906Sgm89044 des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7]; 181*906Sgm89044 } 182*906Sgm89044 183*906Sgm89044 /* 184*906Sgm89044 * In-place operations (in == out) are indicated by having a 185*906Sgm89044 * NULL output. In this case set the output to point to the input. 186*906Sgm89044 */ 187*906Sgm89044 if (out == NULL) { 188*906Sgm89044 out = in; 189*906Sgm89044 } 190*906Sgm89044 if (len > dca_length(out)) { 191*906Sgm89044 DBG(dca, DWARN, "not enough output space (need %d, got %d)", 192*906Sgm89044 len, dca_length(out)); 193*906Sgm89044 out->cd_length = len; 194*906Sgm89044 /* Do not free the context since the app will call again */ 195*906Sgm89044 return (CRYPTO_BUFFER_TOO_SMALL); 196*906Sgm89044 } 197*906Sgm89044 198*906Sgm89044 if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) { 199*906Sgm89044 (void) dca_free_context(ctx); 200*906Sgm89044 return (rv); 201*906Sgm89044 } 202*906Sgm89044 203*906Sgm89044 reqp->dr_kcf_req = req; 204*906Sgm89044 205*906Sgm89044 /* 206*906Sgm89044 * From here on out, we are committed. 207*906Sgm89044 */ 208*906Sgm89044 209*906Sgm89044 if (len == 0) { 210*906Sgm89044 /* 211*906Sgm89044 * No blocks being encrypted, so we just accumulate the 212*906Sgm89044 * input for the next pass and return. 213*906Sgm89044 */ 214*906Sgm89044 if ((rv = dca_getbufbytes(in, 0, 215*906Sgm89044 (rawlen % DESBLOCK) - des_ctx->dr_ctx.residlen, 216*906Sgm89044 des_ctx->dr_ctx.resid + des_ctx->dr_ctx.residlen)) != 217*906Sgm89044 CRYPTO_SUCCESS) { 218*906Sgm89044 DBG(dca, DWARN, 219*906Sgm89044 "dca_3desupdate: dca_getbufbytes() failed for residual only pass"); 220*906Sgm89044 dca_freereq(reqp); 221*906Sgm89044 return (rv); 222*906Sgm89044 } 223*906Sgm89044 des_ctx->dr_ctx.residlen = rawlen % DESBLOCK; 224*906Sgm89044 225*906Sgm89044 out->cd_length = 0; 226*906Sgm89044 /* 227*906Sgm89044 * Do not free the context here since it will be done 228*906Sgm89044 * in the final function 229*906Sgm89044 */ 230*906Sgm89044 return (CRYPTO_SUCCESS); 231*906Sgm89044 } 232*906Sgm89044 233*906Sgm89044 /* 234*906Sgm89044 * Set up rbuf for previous residual data. 235*906Sgm89044 */ 236*906Sgm89044 if (des_ctx->dr_ctx.residlen) { 237*906Sgm89044 bcopy(des_ctx->dr_ctx.resid, des_ctx->dr_ctx.activeresid, 238*906Sgm89044 des_ctx->dr_ctx.residlen); 239*906Sgm89044 des_ctx->dr_ctx.activeresidlen = des_ctx->dr_ctx.residlen; 240*906Sgm89044 } 241*906Sgm89044 242*906Sgm89044 /* 243*906Sgm89044 * Locate and save residual data for next encrypt_update. 244*906Sgm89044 */ 245*906Sgm89044 if ((rv = dca_getbufbytes(in, len - des_ctx->dr_ctx.residlen, 246*906Sgm89044 rawlen % DESBLOCK, des_ctx->dr_ctx.resid)) != CRYPTO_SUCCESS) { 247*906Sgm89044 DBG(dca, DWARN, "dca_3desupdate: dca_getbufbytes() failed"); 248*906Sgm89044 (void) dca_free_context(ctx); 249*906Sgm89044 return (rv); 250*906Sgm89044 } 251*906Sgm89044 252*906Sgm89044 /* Calculate new residual length. */ 253*906Sgm89044 des_ctx->dr_ctx.residlen = rawlen % DESBLOCK; 254*906Sgm89044 255*906Sgm89044 /* 256*906Sgm89044 * Make a local copy of the input crypto_data_t structure. This 257*906Sgm89044 * allows it to be manipulated locally and for dealing with in-place 258*906Sgm89044 * data (ie in == out). 259*906Sgm89044 */ 260*906Sgm89044 if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) { 261*906Sgm89044 (void) dca_free_context(ctx); 262*906Sgm89044 return (rv); 263*906Sgm89044 } 264*906Sgm89044 265*906Sgm89044 /* Set output to zero ready to take the processed data */ 266*906Sgm89044 out->cd_length = 0; 267*906Sgm89044 268*906Sgm89044 reqp->dr_in = nin; 269*906Sgm89044 reqp->dr_out = out; 270*906Sgm89044 reqp->dr_job_stat = DS_3DESJOBS; 271*906Sgm89044 reqp->dr_byte_stat = DS_3DESBYTES; 272*906Sgm89044 273*906Sgm89044 rv = dca_3desstart(dca, flags, reqp); 274*906Sgm89044 275*906Sgm89044 /* 276*906Sgm89044 * As this is multi-part the context is cleared on success 277*906Sgm89044 * (CRYPTO_QUEUED) in dca_3desfinal(). 278*906Sgm89044 */ 279*906Sgm89044 280*906Sgm89044 if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) { 281*906Sgm89044 (void) dca_free_context(ctx); 282*906Sgm89044 } 283*906Sgm89044 return (rv); 284*906Sgm89044 } 285*906Sgm89044 286*906Sgm89044 int 287*906Sgm89044 dca_3desfinal(crypto_ctx_t *ctx, crypto_data_t *out, int mode) 288*906Sgm89044 { 289*906Sgm89044 dca_request_t *des_ctx = ctx->cc_provider_private; 290*906Sgm89044 dca_t *dca = ctx->cc_provider; 291*906Sgm89044 int rv = CRYPTO_SUCCESS; 292*906Sgm89044 293*906Sgm89044 ASSERT(ctx->cc_provider_private != NULL); 294*906Sgm89044 /* 295*906Sgm89044 * There must be no unprocessed ciphertext/plaintext. 296*906Sgm89044 * This happens if the length of the last data is 297*906Sgm89044 * not a multiple of the DES block length. 298*906Sgm89044 */ 299*906Sgm89044 if (des_ctx->dr_ctx.residlen != 0) { 300*906Sgm89044 DBG(dca, DWARN, "dca_3desfinal: invalid nonzero residual"); 301*906Sgm89044 if (mode & DR_DECRYPT) { 302*906Sgm89044 rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; 303*906Sgm89044 } else { 304*906Sgm89044 rv = CRYPTO_DATA_LEN_RANGE; 305*906Sgm89044 } 306*906Sgm89044 } 307*906Sgm89044 (void) dca_free_context(ctx); 308*906Sgm89044 out->cd_length = 0; 309*906Sgm89044 return (rv); 310*906Sgm89044 } 311*906Sgm89044 312*906Sgm89044 int 313*906Sgm89044 dca_3desatomic(crypto_provider_handle_t provider, 314*906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 315*906Sgm89044 crypto_key_t *key, crypto_data_t *input, crypto_data_t *output, 316*906Sgm89044 int kmflag, crypto_req_handle_t req, int mode) 317*906Sgm89044 { 318*906Sgm89044 crypto_ctx_t ctx; /* on the stack */ 319*906Sgm89044 int rv; 320*906Sgm89044 321*906Sgm89044 ctx.cc_provider = provider; 322*906Sgm89044 ctx.cc_session = session_id; 323*906Sgm89044 324*906Sgm89044 /* 325*906Sgm89044 * Input must be a multiple of the block size. This test only 326*906Sgm89044 * works for non-padded mechanisms when the blocksize is 2^N. 327*906Sgm89044 */ 328*906Sgm89044 if ((dca_length(input) & (DESBLOCK - 1)) != 0) { 329*906Sgm89044 DBG(NULL, DWARN, "dca_3desatomic: input not multiple of BS"); 330*906Sgm89044 if (mode & DR_DECRYPT) { 331*906Sgm89044 return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 332*906Sgm89044 } else { 333*906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 334*906Sgm89044 } 335*906Sgm89044 } 336*906Sgm89044 337*906Sgm89044 rv = dca_3desctxinit(&ctx, mechanism, key, kmflag, mode); 338*906Sgm89044 if (rv != CRYPTO_SUCCESS) { 339*906Sgm89044 DBG(NULL, DWARN, "dca_3desatomic: dca_3desctxinit() failed"); 340*906Sgm89044 return (rv); 341*906Sgm89044 } 342*906Sgm89044 343*906Sgm89044 /* 344*906Sgm89044 * Set the atomic flag so that the hardware callback function 345*906Sgm89044 * will free the context. 346*906Sgm89044 */ 347*906Sgm89044 ((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1; 348*906Sgm89044 349*906Sgm89044 rv = dca_3des(&ctx, input, output, req, mode); 350*906Sgm89044 if ((rv != CRYPTO_QUEUED) && (rv != CRYPTO_SUCCESS)) { 351*906Sgm89044 DBG(NULL, DWARN, "dca_3desatomic: dca_3des() failed"); 352*906Sgm89044 output->cd_length = 0; 353*906Sgm89044 } 354*906Sgm89044 355*906Sgm89044 /* 356*906Sgm89044 * The features of dca_3desfinal() are implemented within 357*906Sgm89044 * dca_3desdone() due to the asynchronous nature of dca_3des(). 358*906Sgm89044 */ 359*906Sgm89044 360*906Sgm89044 /* 361*906Sgm89044 * The context will be freed in the hardware callback function if it 362*906Sgm89044 * is queued 363*906Sgm89044 */ 364*906Sgm89044 if (rv != CRYPTO_QUEUED) 365*906Sgm89044 dca_3desctxfree(&ctx); 366*906Sgm89044 367*906Sgm89044 return (rv); 368*906Sgm89044 } 369*906Sgm89044 370*906Sgm89044 int 371*906Sgm89044 dca_3desstart(dca_t *dca, uint32_t flags, dca_request_t *reqp) 372*906Sgm89044 { 373*906Sgm89044 size_t len; 374*906Sgm89044 crypto_data_t *in = reqp->dr_in; 375*906Sgm89044 int rv; 376*906Sgm89044 dca_request_t *ctx = reqp; 377*906Sgm89044 uint32_t iv[2]; 378*906Sgm89044 379*906Sgm89044 /* 380*906Sgm89044 * Preconditions: 381*906Sgm89044 * 1) in and out point to the "right" buffers. 382*906Sgm89044 * 2) in->b_bcount - in->b_resid == initial offset 383*906Sgm89044 * 3) likewise for out 384*906Sgm89044 * 4) there is enough space in the output 385*906Sgm89044 * 5) we perform a block for block encrypt 386*906Sgm89044 */ 387*906Sgm89044 len = ctx->dr_ctx.activeresidlen + dca_length(in); 388*906Sgm89044 len = ROUNDDOWN(min(len, MAXPACKET), DESBLOCK); 389*906Sgm89044 reqp->dr_pkt_length = (uint16_t)len; 390*906Sgm89044 391*906Sgm89044 /* collect IVs for this pass */ 392*906Sgm89044 iv[0] = ctx->dr_ctx.iv[0]; 393*906Sgm89044 iv[1] = ctx->dr_ctx.iv[1]; 394*906Sgm89044 395*906Sgm89044 /* 396*906Sgm89044 * And also, for decrypt, collect the IV for the next pass. For 397*906Sgm89044 * decrypt, the IV must be collected BEFORE decryption, or else 398*906Sgm89044 * we will lose it. (For encrypt, we grab the IV AFTER encryption, 399*906Sgm89044 * in dca_3desdone. 400*906Sgm89044 */ 401*906Sgm89044 if (flags & DR_DECRYPT) { 402*906Sgm89044 uchar_t ivstore[DESBLOCK]; 403*906Sgm89044 uchar_t *ivp = ivstore; 404*906Sgm89044 405*906Sgm89044 /* get last 8 bytes of ciphertext for IV of next op */ 406*906Sgm89044 /* 407*906Sgm89044 * If we're processing only a DESBLOCKS worth of data 408*906Sgm89044 * and there is active residual present then it will be 409*906Sgm89044 * needed for the IV also. 410*906Sgm89044 */ 411*906Sgm89044 if ((len == DESBLOCK) && ctx->dr_ctx.activeresidlen) { 412*906Sgm89044 /* Bring the active residual into play */ 413*906Sgm89044 bcopy(ctx->dr_ctx.activeresid, ivstore, 414*906Sgm89044 ctx->dr_ctx.activeresidlen); 415*906Sgm89044 rv = dca_getbufbytes(in, 0, 416*906Sgm89044 DESBLOCK - ctx->dr_ctx.activeresidlen, 417*906Sgm89044 ivstore + ctx->dr_ctx.activeresidlen); 418*906Sgm89044 } else { 419*906Sgm89044 rv = dca_getbufbytes(in, 420*906Sgm89044 len - DESBLOCK - ctx->dr_ctx.activeresidlen, 421*906Sgm89044 DESBLOCK, ivstore); 422*906Sgm89044 } 423*906Sgm89044 424*906Sgm89044 if (rv != CRYPTO_SUCCESS) { 425*906Sgm89044 DBG(dca, DWARN, 426*906Sgm89044 "dca_3desstart: dca_getbufbytes() failed"); 427*906Sgm89044 return (rv); 428*906Sgm89044 } 429*906Sgm89044 430*906Sgm89044 /* store as a pair of native 32-bit values */ 431*906Sgm89044 ctx->dr_ctx.iv[0] = 432*906Sgm89044 ivp[0]<<24 | ivp[1]<<16 | ivp[2]<<8 | ivp[3]; 433*906Sgm89044 ctx->dr_ctx.iv[1] = 434*906Sgm89044 ivp[4]<<24 | ivp[5]<<16 | ivp[6]<<8 | ivp[7]; 435*906Sgm89044 } 436*906Sgm89044 437*906Sgm89044 /* For now we force a pullup. Add direct DMA later. */ 438*906Sgm89044 reqp->dr_flags &= ~(DR_SCATTER | DR_GATHER); 439*906Sgm89044 if ((len < dca_mindma) || (ctx->dr_ctx.activeresidlen > 0) || 440*906Sgm89044 dca_sgcheck(dca, reqp->dr_in, DCA_SG_CONTIG) || 441*906Sgm89044 dca_sgcheck(dca, reqp->dr_out, DCA_SG_WALIGN)) { 442*906Sgm89044 reqp->dr_flags |= DR_SCATTER | DR_GATHER; 443*906Sgm89044 } 444*906Sgm89044 445*906Sgm89044 /* Try to do direct DMA. */ 446*906Sgm89044 if (!(reqp->dr_flags & (DR_SCATTER | DR_GATHER))) { 447*906Sgm89044 if (dca_bindchains(reqp, len, len) == DDI_SUCCESS) { 448*906Sgm89044 reqp->dr_in->cd_offset += len; 449*906Sgm89044 reqp->dr_in->cd_length -= len; 450*906Sgm89044 } else { 451*906Sgm89044 DBG(dca, DWARN, 452*906Sgm89044 "dca_3desstart: dca_bindchains() failed"); 453*906Sgm89044 return (CRYPTO_DEVICE_ERROR); 454*906Sgm89044 } 455*906Sgm89044 } 456*906Sgm89044 457*906Sgm89044 /* gather the data into the device */ 458*906Sgm89044 if (reqp->dr_flags & DR_GATHER) { 459*906Sgm89044 rv = dca_resid_gather(in, (char *)ctx->dr_ctx.activeresid, 460*906Sgm89044 &ctx->dr_ctx.activeresidlen, reqp->dr_ibuf_kaddr, len); 461*906Sgm89044 if (rv != CRYPTO_SUCCESS) { 462*906Sgm89044 DBG(dca, DWARN, 463*906Sgm89044 "dca_3desstart: dca_resid_gather() failed"); 464*906Sgm89044 return (rv); 465*906Sgm89044 } 466*906Sgm89044 /* 467*906Sgm89044 * Setup for scattering the result back out 468*906Sgm89044 * The output buffer is a multi-entry chain for x86 and 469*906Sgm89044 * a single entry chain for Sparc. 470*906Sgm89044 * Use the actual length if the first entry is sufficient. 471*906Sgm89044 */ 472*906Sgm89044 (void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, len, 473*906Sgm89044 DDI_DMA_SYNC_FORDEV); 474*906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah, 475*906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 476*906Sgm89044 reqp->destroy = TRUE; 477*906Sgm89044 return (CRYPTO_DEVICE_ERROR); 478*906Sgm89044 } 479*906Sgm89044 480*906Sgm89044 reqp->dr_in_paddr = reqp->dr_ibuf_head.dc_buffer_paddr; 481*906Sgm89044 reqp->dr_in_next = reqp->dr_ibuf_head.dc_next_paddr; 482*906Sgm89044 if (len > reqp->dr_ibuf_head.dc_buffer_length) 483*906Sgm89044 reqp->dr_in_len = reqp->dr_ibuf_head.dc_buffer_length; 484*906Sgm89044 else 485*906Sgm89044 reqp->dr_in_len = len; 486*906Sgm89044 } 487*906Sgm89044 /* 488*906Sgm89044 * Setup for scattering the result back out 489*906Sgm89044 * The output buffer is a multi-entry chain for x86 and 490*906Sgm89044 * a single entry chain for Sparc. 491*906Sgm89044 * Use the actual length if the first entry is sufficient. 492*906Sgm89044 */ 493*906Sgm89044 if (reqp->dr_flags & DR_SCATTER) { 494*906Sgm89044 reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr; 495*906Sgm89044 reqp->dr_out_next = reqp->dr_obuf_head.dc_next_paddr; 496*906Sgm89044 if (len > reqp->dr_obuf_head.dc_buffer_length) 497*906Sgm89044 reqp->dr_out_len = reqp->dr_obuf_head.dc_buffer_length; 498*906Sgm89044 else 499*906Sgm89044 reqp->dr_out_len = len; 500*906Sgm89044 } 501*906Sgm89044 502*906Sgm89044 reqp->dr_flags |= flags; 503*906Sgm89044 reqp->dr_callback = dca_3desdone; 504*906Sgm89044 505*906Sgm89044 /* write out the context structure */ 506*906Sgm89044 PUTCTX32(reqp, CTX_3DESIVHI, iv[0]); 507*906Sgm89044 PUTCTX32(reqp, CTX_3DESIVLO, iv[1]); 508*906Sgm89044 509*906Sgm89044 /* schedule the work by doing a submit */ 510*906Sgm89044 return (dca_start(dca, reqp, MCR1, 1)); 511*906Sgm89044 } 512*906Sgm89044 513*906Sgm89044 void 514*906Sgm89044 dca_3desdone(dca_request_t *reqp, int errno) 515*906Sgm89044 { 516*906Sgm89044 crypto_data_t *out = reqp->dr_out; 517*906Sgm89044 dca_request_t *ctx = reqp; 518*906Sgm89044 ASSERT(ctx != NULL); 519*906Sgm89044 520*906Sgm89044 if (errno == CRYPTO_SUCCESS) { 521*906Sgm89044 size_t off; 522*906Sgm89044 /* 523*906Sgm89044 * Save the offset: this has to be done *before* dca_scatter 524*906Sgm89044 * modifies the buffer. We take the initial offset into the 525*906Sgm89044 * first buf, and add that to the total packet size to find 526*906Sgm89044 * the end of the packet. 527*906Sgm89044 */ 528*906Sgm89044 off = dca_length(out) + reqp->dr_pkt_length - DESBLOCK; 529*906Sgm89044 530*906Sgm89044 if (reqp->dr_flags & DR_SCATTER) { 531*906Sgm89044 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0, 532*906Sgm89044 reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL); 533*906Sgm89044 if (dca_check_dma_handle(reqp->dr_dca, 534*906Sgm89044 reqp->dr_obuf_dmah, DCA_FM_ECLASS_NONE) != 535*906Sgm89044 DDI_SUCCESS) { 536*906Sgm89044 reqp->destroy = TRUE; 537*906Sgm89044 errno = CRYPTO_DEVICE_ERROR; 538*906Sgm89044 goto errout; 539*906Sgm89044 } 540*906Sgm89044 541*906Sgm89044 errno = dca_scatter(reqp->dr_obuf_kaddr, 542*906Sgm89044 reqp->dr_out, reqp->dr_out_len, 0); 543*906Sgm89044 if (errno != CRYPTO_SUCCESS) { 544*906Sgm89044 DBG(NULL, DWARN, 545*906Sgm89044 "dca_3desdone: dca_scatter() failed"); 546*906Sgm89044 goto errout; 547*906Sgm89044 } 548*906Sgm89044 549*906Sgm89044 } else { 550*906Sgm89044 /* we've processed some more data */ 551*906Sgm89044 out->cd_length += reqp->dr_pkt_length; 552*906Sgm89044 } 553*906Sgm89044 554*906Sgm89044 555*906Sgm89044 /* 556*906Sgm89044 * For encryption only, we have to grab the IV for the 557*906Sgm89044 * next pass AFTER encryption. 558*906Sgm89044 */ 559*906Sgm89044 if (reqp->dr_flags & DR_ENCRYPT) { 560*906Sgm89044 uchar_t ivstore[DESBLOCK]; 561*906Sgm89044 uchar_t *iv = ivstore; 562*906Sgm89044 563*906Sgm89044 /* get last 8 bytes for IV of next op */ 564*906Sgm89044 errno = dca_getbufbytes(out, off, DESBLOCK, iv); 565*906Sgm89044 if (errno != CRYPTO_SUCCESS) { 566*906Sgm89044 DBG(NULL, DWARN, 567*906Sgm89044 "dca_3desdone: dca_getbufbytes() failed"); 568*906Sgm89044 goto errout; 569*906Sgm89044 } 570*906Sgm89044 /* store as a pair of native 32-bit values */ 571*906Sgm89044 ctx->dr_ctx.iv[0] = 572*906Sgm89044 iv[0]<<24 | iv[1]<<16 | iv[2]<<8 | iv[3]; 573*906Sgm89044 ctx->dr_ctx.iv[1] = 574*906Sgm89044 iv[4]<<24 | iv[5]<<16 | iv[6]<<8 | iv[7]; 575*906Sgm89044 } 576*906Sgm89044 577*906Sgm89044 /* 578*906Sgm89044 * If there is more to do, then reschedule another 579*906Sgm89044 * pass. 580*906Sgm89044 */ 581*906Sgm89044 if (dca_length(reqp->dr_in) >= 8) { 582*906Sgm89044 errno = dca_3desstart(reqp->dr_dca, reqp->dr_flags, 583*906Sgm89044 reqp); 584*906Sgm89044 if (errno == CRYPTO_QUEUED) { 585*906Sgm89044 return; 586*906Sgm89044 } 587*906Sgm89044 } 588*906Sgm89044 } 589*906Sgm89044 590*906Sgm89044 errout: 591*906Sgm89044 592*906Sgm89044 /* 593*906Sgm89044 * If this is an atomic operation perform the final function 594*906Sgm89044 * tasks (equivalent to to dca_3desfinal()). 595*906Sgm89044 */ 596*906Sgm89044 if (reqp->dr_ctx.atomic) { 597*906Sgm89044 if ((errno == CRYPTO_SUCCESS) && (ctx->dr_ctx.residlen != 0)) { 598*906Sgm89044 DBG(NULL, DWARN, 599*906Sgm89044 "dca_3desdone: invalid nonzero residual"); 600*906Sgm89044 if (reqp->dr_flags & DR_DECRYPT) { 601*906Sgm89044 errno = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; 602*906Sgm89044 } else { 603*906Sgm89044 errno = CRYPTO_DATA_LEN_RANGE; 604*906Sgm89044 } 605*906Sgm89044 } 606*906Sgm89044 } 607*906Sgm89044 608*906Sgm89044 ASSERT(reqp->dr_kcf_req != NULL); 609*906Sgm89044 /* notify framework that request is completed */ 610*906Sgm89044 crypto_op_notification(reqp->dr_kcf_req, errno); 611*906Sgm89044 DBG(NULL, DINTR, 612*906Sgm89044 "dca_3desdone: returning %d to the kef via crypto_op_notification", 613*906Sgm89044 errno); 614*906Sgm89044 615*906Sgm89044 /* This has to be done after notifing the framework */ 616*906Sgm89044 if (reqp->dr_ctx.atomic) { 617*906Sgm89044 reqp->dr_context = NULL; 618*906Sgm89044 reqp->dr_ctx.atomic = 0; 619*906Sgm89044 reqp->dr_ctx.ctx_cm_type = 0; 620*906Sgm89044 if (reqp->destroy) 621*906Sgm89044 dca_destroyreq(reqp); 622*906Sgm89044 else 623*906Sgm89044 dca_freereq(reqp); 624*906Sgm89044 } 625*906Sgm89044 } 626*906Sgm89044 627*906Sgm89044 /* ARGSUSED */ 628*906Sgm89044 int 629*906Sgm89044 dca_3desctxinit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 630*906Sgm89044 crypto_key_t *key, int kmflag, int flags) 631*906Sgm89044 { 632*906Sgm89044 dca_request_t *des_ctx; 633*906Sgm89044 dca_t *dca = ctx->cc_provider; 634*906Sgm89044 uchar_t *param; 635*906Sgm89044 uchar_t *value; 636*906Sgm89044 size_t paramsz; 637*906Sgm89044 unsigned len; 638*906Sgm89044 int i, j; 639*906Sgm89044 640*906Sgm89044 paramsz = mechanism->cm_param_len; 641*906Sgm89044 param = (uchar_t *)mechanism->cm_param; 642*906Sgm89044 if ((paramsz != 0) && (paramsz != DES_IV_LEN)) { 643*906Sgm89044 DBG(NULL, DWARN, 644*906Sgm89044 "dca_3desctxinit: parameter(IV) length not %d (%d)", 645*906Sgm89044 DES_IV_LEN, paramsz); 646*906Sgm89044 return (CRYPTO_MECHANISM_PARAM_INVALID); 647*906Sgm89044 } 648*906Sgm89044 649*906Sgm89044 if ((des_ctx = dca_getreq(dca, MCR1, 1)) == NULL) { 650*906Sgm89044 dca_error(dca, "unable to allocate request for 3DES"); 651*906Sgm89044 return (CRYPTO_HOST_MEMORY); 652*906Sgm89044 } 653*906Sgm89044 /* 654*906Sgm89044 * Identify and store the IV as a pair of native 32-bit words. 655*906Sgm89044 * 656*906Sgm89044 * If cm_param == NULL then the IV comes from the cd_miscdata field 657*906Sgm89044 * in the crypto_data structure. 658*906Sgm89044 */ 659*906Sgm89044 if (param != NULL) { 660*906Sgm89044 ASSERT(paramsz == DES_IV_LEN); 661*906Sgm89044 des_ctx->dr_ctx.iv[0] = param[0]<<24 | param[1]<<16 | 662*906Sgm89044 param[2]<<8 | param[3]; 663*906Sgm89044 des_ctx->dr_ctx.iv[1] = param[4]<<24 | param[5]<<16 | 664*906Sgm89044 param[6]<<8 | param[7]; 665*906Sgm89044 } 666*906Sgm89044 des_ctx->dr_ctx.residlen = 0; 667*906Sgm89044 des_ctx->dr_ctx.activeresidlen = 0; 668*906Sgm89044 des_ctx->dr_ctx.ctx_cm_type = mechanism->cm_type; 669*906Sgm89044 ctx->cc_provider_private = des_ctx; 670*906Sgm89044 671*906Sgm89044 if (key->ck_format != CRYPTO_KEY_RAW) { 672*906Sgm89044 DBG(NULL, DWARN, 673*906Sgm89044 "dca_3desctxinit: only raw crypto key type support with DES/3DES"); 674*906Sgm89044 dca_3desctxfree(ctx); 675*906Sgm89044 return (CRYPTO_KEY_TYPE_INCONSISTENT); 676*906Sgm89044 } 677*906Sgm89044 678*906Sgm89044 len = key->ck_length; 679*906Sgm89044 value = (uchar_t *)key->ck_data; 680*906Sgm89044 681*906Sgm89044 if (flags & DR_TRIPLE) { 682*906Sgm89044 /* 3DES */ 683*906Sgm89044 switch (len) { 684*906Sgm89044 case 192: 685*906Sgm89044 for (i = 0; i < 6; i++) { 686*906Sgm89044 des_ctx->dr_ctx.key[i] = 0; 687*906Sgm89044 for (j = 0; j < 4; j++) { 688*906Sgm89044 des_ctx->dr_ctx.key[i] <<= 8; 689*906Sgm89044 des_ctx->dr_ctx.key[i] |= *value; 690*906Sgm89044 value++; 691*906Sgm89044 } 692*906Sgm89044 } 693*906Sgm89044 break; 694*906Sgm89044 695*906Sgm89044 case 128: 696*906Sgm89044 for (i = 0; i < 4; i++) { 697*906Sgm89044 des_ctx->dr_ctx.key[i] = 0; 698*906Sgm89044 for (j = 0; j < 4; j++) { 699*906Sgm89044 des_ctx->dr_ctx.key[i] <<= 8; 700*906Sgm89044 des_ctx->dr_ctx.key[i] |= *value; 701*906Sgm89044 value++; 702*906Sgm89044 } 703*906Sgm89044 } 704*906Sgm89044 des_ctx->dr_ctx.key[4] = des_ctx->dr_ctx.key[0]; 705*906Sgm89044 des_ctx->dr_ctx.key[5] = des_ctx->dr_ctx.key[1]; 706*906Sgm89044 break; 707*906Sgm89044 708*906Sgm89044 default: 709*906Sgm89044 DBG(NULL, DWARN, "Incorrect 3DES keysize (%d)", len); 710*906Sgm89044 dca_3desctxfree(ctx); 711*906Sgm89044 return (CRYPTO_KEY_SIZE_RANGE); 712*906Sgm89044 } 713*906Sgm89044 } else { 714*906Sgm89044 /* single DES */ 715*906Sgm89044 if (len != 64) { 716*906Sgm89044 DBG(NULL, DWARN, "Incorrect DES keysize (%d)", len); 717*906Sgm89044 dca_3desctxfree(ctx); 718*906Sgm89044 return (CRYPTO_KEY_SIZE_RANGE); 719*906Sgm89044 } 720*906Sgm89044 des_ctx->dr_ctx.key[0] = 721*906Sgm89044 value[0]<<24 | value[1]<<16 | value[2]<<8 | value[3]; 722*906Sgm89044 des_ctx->dr_ctx.key[1] = 723*906Sgm89044 value[4]<<24 | value[5]<<16 | value[6]<<8 | value[7]; 724*906Sgm89044 /* for single des just repeat des key */ 725*906Sgm89044 des_ctx->dr_ctx.key[4] = 726*906Sgm89044 des_ctx->dr_ctx.key[2] = des_ctx->dr_ctx.key[0]; 727*906Sgm89044 des_ctx->dr_ctx.key[5] = 728*906Sgm89044 des_ctx->dr_ctx.key[3] = des_ctx->dr_ctx.key[1]; 729*906Sgm89044 } 730*906Sgm89044 731*906Sgm89044 /* 732*906Sgm89044 * Setup the context here so that we do not need to setup it up 733*906Sgm89044 * for every update 734*906Sgm89044 */ 735*906Sgm89044 PUTCTX16(des_ctx, CTX_LENGTH, CTX_3DES_LENGTH); 736*906Sgm89044 PUTCTX16(des_ctx, CTX_CMD, CMD_3DES); 737*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESDIRECTION, 738*906Sgm89044 flags & DR_ENCRYPT ? CTX_3DES_ENCRYPT : CTX_3DES_DECRYPT); 739*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY1HI, des_ctx->dr_ctx.key[0]); 740*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY1LO, des_ctx->dr_ctx.key[1]); 741*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY2HI, des_ctx->dr_ctx.key[2]); 742*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY2LO, des_ctx->dr_ctx.key[3]); 743*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY3HI, des_ctx->dr_ctx.key[4]); 744*906Sgm89044 PUTCTX32(des_ctx, CTX_3DESKEY3LO, des_ctx->dr_ctx.key[5]); 745*906Sgm89044 746*906Sgm89044 return (CRYPTO_SUCCESS); 747*906Sgm89044 } 748