xref: /illumos-gate/usr/src/uts/common/crypto/io/dca_3des.c (revision 86ef0a63e1cfa5dc98606efef379365acca98063)
188f8b78aSgm89044 
288f8b78aSgm89044 /*
388f8b78aSgm89044  * CDDL HEADER START
488f8b78aSgm89044  *
588f8b78aSgm89044  * The contents of this file are subject to the terms of the
688f8b78aSgm89044  * Common Development and Distribution License (the "License").
788f8b78aSgm89044  * You may not use this file except in compliance with the License.
888f8b78aSgm89044  *
988f8b78aSgm89044  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1088f8b78aSgm89044  * or http://www.opensolaris.org/os/licensing.
1188f8b78aSgm89044  * See the License for the specific language governing permissions
1288f8b78aSgm89044  * and limitations under the License.
1388f8b78aSgm89044  *
1488f8b78aSgm89044  * When distributing Covered Code, include this CDDL HEADER in each
1588f8b78aSgm89044  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1688f8b78aSgm89044  * If applicable, add the following below this CDDL HEADER, with the
1788f8b78aSgm89044  * fields enclosed by brackets "[]" replaced with your own identifying
1888f8b78aSgm89044  * information: Portions Copyright [yyyy] [name of copyright owner]
1988f8b78aSgm89044  *
2088f8b78aSgm89044  * CDDL HEADER END
2188f8b78aSgm89044  */
2288f8b78aSgm89044 
2388f8b78aSgm89044 /*
244b56a003SDaniel Anderson  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2588f8b78aSgm89044  * Use is subject to license terms.
2688f8b78aSgm89044  */
2788f8b78aSgm89044 
2888f8b78aSgm89044 /*
2988f8b78aSgm89044  * Deimos - cryptographic acceleration based upon Broadcom 582x.
3088f8b78aSgm89044  */
3188f8b78aSgm89044 
3288f8b78aSgm89044 #include <sys/types.h>
3388f8b78aSgm89044 #include <sys/ddi.h>
3488f8b78aSgm89044 #include <sys/sunddi.h>
3588f8b78aSgm89044 #include <sys/kmem.h>
3688f8b78aSgm89044 #include <sys/note.h>
3788f8b78aSgm89044 #include <sys/crypto/common.h>
3888f8b78aSgm89044 #include <sys/crypto/spi.h>
3988f8b78aSgm89044 #include <sys/crypto/dca.h>
4088f8b78aSgm89044 
41*86ef0a63SRichard Lowe #if defined(__x86)
424b56a003SDaniel Anderson #include <sys/byteorder.h>
434b56a003SDaniel Anderson #define	UNALIGNED_POINTERS_PERMITTED
444b56a003SDaniel Anderson #endif
454b56a003SDaniel Anderson 
4688f8b78aSgm89044 /*
4788f8b78aSgm89044  * 3DES implementation.
4888f8b78aSgm89044  */
4988f8b78aSgm89044 
5088f8b78aSgm89044 static int dca_3desstart(dca_t *, uint32_t, dca_request_t *);
5188f8b78aSgm89044 static void dca_3desdone(dca_request_t *, int);
5288f8b78aSgm89044 
5388f8b78aSgm89044 
5488f8b78aSgm89044 int
dca_3des(crypto_ctx_t * ctx,crypto_data_t * in,crypto_data_t * out,crypto_req_handle_t req,int flags)5588f8b78aSgm89044 dca_3des(crypto_ctx_t *ctx, crypto_data_t *in,
5688f8b78aSgm89044     crypto_data_t *out, crypto_req_handle_t req, int flags)
5788f8b78aSgm89044 {
5888f8b78aSgm89044 	int			len;
5988f8b78aSgm89044 	int			rv;
6088f8b78aSgm89044 	dca_request_t		*reqp = ctx->cc_provider_private;
6188f8b78aSgm89044 	dca_request_t		*des_ctx = ctx->cc_provider_private;
6288f8b78aSgm89044 	dca_t			*dca = ctx->cc_provider;
6388f8b78aSgm89044 	crypto_data_t		*nin = &reqp->dr_ctx.in_dup;
6488f8b78aSgm89044 
6588f8b78aSgm89044 	len = dca_length(in);
6688f8b78aSgm89044 	if (len % DESBLOCK) {
6788f8b78aSgm89044 		DBG(dca, DWARN, "input not an integral number of DES blocks");
6888f8b78aSgm89044 		(void) dca_free_context(ctx);
6988f8b78aSgm89044 		if (flags & DR_DECRYPT) {
7088f8b78aSgm89044 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
7188f8b78aSgm89044 		} else {
7288f8b78aSgm89044 			return (CRYPTO_DATA_LEN_RANGE);
7388f8b78aSgm89044 		}
7488f8b78aSgm89044 	}
7588f8b78aSgm89044 
7688f8b78aSgm89044 	/*
7788f8b78aSgm89044 	 * If cd_miscdata non-null then this contains the IV.
7888f8b78aSgm89044 	 */
7988f8b78aSgm89044 	if (in->cd_miscdata != NULL) {
804b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
814b56a003SDaniel Anderson 		uint32_t	*p = (uint32_t *)in->cd_miscdata;
824b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[0] = htonl(p[0]);
834b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[1] = htonl(p[1]);
844b56a003SDaniel Anderson #else
8588f8b78aSgm89044 		uchar_t	*p = (uchar_t *)in->cd_miscdata;
8688f8b78aSgm89044 		des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
8788f8b78aSgm89044 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
884b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
8988f8b78aSgm89044 	}
9088f8b78aSgm89044 
9188f8b78aSgm89044 	if (len > dca_length(out)) {
9288f8b78aSgm89044 		DBG(dca, DWARN, "inadequate output space (need %d, got %d)",
9388f8b78aSgm89044 		    len, dca_length(out));
9488f8b78aSgm89044 		out->cd_length = len;
9588f8b78aSgm89044 		/* Do not free the context since the app will call again */
9688f8b78aSgm89044 		return (CRYPTO_BUFFER_TOO_SMALL);
9788f8b78aSgm89044 	}
9888f8b78aSgm89044 
9988f8b78aSgm89044 	if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) {
10088f8b78aSgm89044 		(void) dca_free_context(ctx);
10188f8b78aSgm89044 		return (rv);
10288f8b78aSgm89044 	}
10388f8b78aSgm89044 
10488f8b78aSgm89044 	/* special handling for null-sized input buffers */
10588f8b78aSgm89044 	if (len == 0) {
10688f8b78aSgm89044 		out->cd_length = 0;
10788f8b78aSgm89044 		(void) dca_free_context(ctx);
10888f8b78aSgm89044 		return (CRYPTO_SUCCESS);
10988f8b78aSgm89044 	}
11088f8b78aSgm89044 
11188f8b78aSgm89044 	/*
11288f8b78aSgm89044 	 * Make a local copy of the input crypto_data_t structure. This
11388f8b78aSgm89044 	 * allows it to be manipulated locally and for dealing with in-place
11488f8b78aSgm89044 	 * data (ie in == out). Note that "nin" has been pre-allocated,
11588f8b78aSgm89044 	 * and only fields are copied, not actual data.
11688f8b78aSgm89044 	 */
11788f8b78aSgm89044 	if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) {
11888f8b78aSgm89044 		(void) dca_free_context(ctx);
11988f8b78aSgm89044 		return (rv);
12088f8b78aSgm89044 	}
12188f8b78aSgm89044 
12288f8b78aSgm89044 	/* Set output to zero ready to take the processed data */
12388f8b78aSgm89044 	out->cd_length = 0;
12488f8b78aSgm89044 
12588f8b78aSgm89044 	reqp->dr_kcf_req = req;
12688f8b78aSgm89044 	reqp->dr_in = nin;
12788f8b78aSgm89044 	reqp->dr_out = out;
12888f8b78aSgm89044 	reqp->dr_job_stat = DS_3DESJOBS;
12988f8b78aSgm89044 	reqp->dr_byte_stat = DS_3DESBYTES;
13088f8b78aSgm89044 
13188f8b78aSgm89044 	rv = dca_3desstart(dca, flags, reqp);
13288f8b78aSgm89044 
13388f8b78aSgm89044 	/* Context will be freed in the kCF callback function otherwise */
13488f8b78aSgm89044 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
13588f8b78aSgm89044 		(void) dca_free_context(ctx);
13688f8b78aSgm89044 	}
13788f8b78aSgm89044 	return (rv);
13888f8b78aSgm89044 }
13988f8b78aSgm89044 
14088f8b78aSgm89044 
14188f8b78aSgm89044 void
dca_3desctxfree(void * arg)14288f8b78aSgm89044 dca_3desctxfree(void *arg)
14388f8b78aSgm89044 {
14488f8b78aSgm89044 	crypto_ctx_t	*ctx = (crypto_ctx_t *)arg;
14588f8b78aSgm89044 	dca_request_t	*des_ctx = ctx->cc_provider_private;
14688f8b78aSgm89044 
14788f8b78aSgm89044 	if (des_ctx == NULL)
14888f8b78aSgm89044 		return;
14988f8b78aSgm89044 
15088f8b78aSgm89044 	des_ctx->dr_ctx.atomic = 0;
15188f8b78aSgm89044 	des_ctx->dr_ctx.ctx_cm_type = 0;
15288f8b78aSgm89044 	ctx->cc_provider_private = NULL;
15388f8b78aSgm89044 
15488f8b78aSgm89044 	if (des_ctx->destroy)
15588f8b78aSgm89044 		dca_destroyreq(des_ctx);
15688f8b78aSgm89044 	else
15788f8b78aSgm89044 		/* Return it to the pool */
15888f8b78aSgm89044 		dca_freereq(des_ctx);
15988f8b78aSgm89044 }
16088f8b78aSgm89044 
16188f8b78aSgm89044 int
dca_3desupdate(crypto_ctx_t * ctx,crypto_data_t * in,crypto_data_t * out,crypto_req_handle_t req,int flags)16288f8b78aSgm89044 dca_3desupdate(crypto_ctx_t *ctx, crypto_data_t *in,
16388f8b78aSgm89044     crypto_data_t *out, crypto_req_handle_t req, int flags)
16488f8b78aSgm89044 {
16588f8b78aSgm89044 	int			len;
16688f8b78aSgm89044 	int			rawlen;
16788f8b78aSgm89044 	int			rv;
16888f8b78aSgm89044 	dca_request_t		*reqp = ctx->cc_provider_private;
16988f8b78aSgm89044 	dca_request_t		*des_ctx = ctx->cc_provider_private;
17088f8b78aSgm89044 	dca_t			*dca = ctx->cc_provider;
17188f8b78aSgm89044 	crypto_data_t		*nin = &reqp->dr_ctx.in_dup;
17288f8b78aSgm89044 
17388f8b78aSgm89044 	rawlen = dca_length(in) + des_ctx->dr_ctx.residlen;
17488f8b78aSgm89044 
17588f8b78aSgm89044 	len = ROUNDDOWN(rawlen, DESBLOCK);
17688f8b78aSgm89044 	/*
17788f8b78aSgm89044 	 * If cd_miscdata non-null then this contains the IV.
17888f8b78aSgm89044 	 */
17988f8b78aSgm89044 	if (in->cd_miscdata != NULL) {
1804b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
1814b56a003SDaniel Anderson 		uint32_t	*p = (uint32_t *)in->cd_miscdata;
1824b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[0] = htonl(p[0]);
1834b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[1] = htonl(p[1]);
1844b56a003SDaniel Anderson #else
18588f8b78aSgm89044 		uchar_t	*p = (uchar_t *)in->cd_miscdata;
18688f8b78aSgm89044 		des_ctx->dr_ctx.iv[0] = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
18788f8b78aSgm89044 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
1884b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
18988f8b78aSgm89044 	}
19088f8b78aSgm89044 
19188f8b78aSgm89044 	if (len > dca_length(out)) {
19288f8b78aSgm89044 		DBG(dca, DWARN, "not enough output space (need %d, got %d)",
19388f8b78aSgm89044 		    len, dca_length(out));
19488f8b78aSgm89044 		out->cd_length = len;
19588f8b78aSgm89044 		/* Do not free the context since the app will call again */
19688f8b78aSgm89044 		return (CRYPTO_BUFFER_TOO_SMALL);
19788f8b78aSgm89044 	}
19888f8b78aSgm89044 
19988f8b78aSgm89044 	if ((rv = dca_verifyio(in, out)) != CRYPTO_SUCCESS) {
20088f8b78aSgm89044 		(void) dca_free_context(ctx);
20188f8b78aSgm89044 		return (rv);
20288f8b78aSgm89044 	}
20388f8b78aSgm89044 
20488f8b78aSgm89044 	reqp->dr_kcf_req = req;
20588f8b78aSgm89044 
20688f8b78aSgm89044 	/*
20788f8b78aSgm89044 	 * From here on out, we are committed.
20888f8b78aSgm89044 	 */
20988f8b78aSgm89044 
21088f8b78aSgm89044 	if (len == 0) {
21188f8b78aSgm89044 		/*
21288f8b78aSgm89044 		 * No blocks being encrypted, so we just accumulate the
21388f8b78aSgm89044 		 * input for the next pass and return.
21488f8b78aSgm89044 		 */
21588f8b78aSgm89044 		if ((rv = dca_getbufbytes(in, 0,
21688f8b78aSgm89044 		    (rawlen % DESBLOCK) - des_ctx->dr_ctx.residlen,
21788f8b78aSgm89044 		    des_ctx->dr_ctx.resid + des_ctx->dr_ctx.residlen)) !=
21888f8b78aSgm89044 		    CRYPTO_SUCCESS) {
21988f8b78aSgm89044 			DBG(dca, DWARN,
22088f8b78aSgm89044 	    "dca_3desupdate: dca_getbufbytes() failed for residual only pass");
22188f8b78aSgm89044 			dca_freereq(reqp);
22288f8b78aSgm89044 			return (rv);
22388f8b78aSgm89044 		}
22488f8b78aSgm89044 		des_ctx->dr_ctx.residlen = rawlen % DESBLOCK;
22588f8b78aSgm89044 
22688f8b78aSgm89044 		out->cd_length = 0;
22788f8b78aSgm89044 		/*
22888f8b78aSgm89044 		 * Do not free the context here since it will be done
22988f8b78aSgm89044 		 * in the final function
23088f8b78aSgm89044 		 */
23188f8b78aSgm89044 		return (CRYPTO_SUCCESS);
23288f8b78aSgm89044 	}
23388f8b78aSgm89044 
23488f8b78aSgm89044 	/*
23588f8b78aSgm89044 	 * Set up rbuf for previous residual data.
23688f8b78aSgm89044 	 */
23788f8b78aSgm89044 	if (des_ctx->dr_ctx.residlen) {
23888f8b78aSgm89044 		bcopy(des_ctx->dr_ctx.resid, des_ctx->dr_ctx.activeresid,
23988f8b78aSgm89044 		    des_ctx->dr_ctx.residlen);
24088f8b78aSgm89044 		des_ctx->dr_ctx.activeresidlen = des_ctx->dr_ctx.residlen;
24188f8b78aSgm89044 	}
24288f8b78aSgm89044 
24388f8b78aSgm89044 	/*
24488f8b78aSgm89044 	 * Locate and save residual data for next encrypt_update.
24588f8b78aSgm89044 	 */
24688f8b78aSgm89044 	if ((rv = dca_getbufbytes(in, len - des_ctx->dr_ctx.residlen,
24788f8b78aSgm89044 	    rawlen % DESBLOCK, des_ctx->dr_ctx.resid)) != CRYPTO_SUCCESS) {
24888f8b78aSgm89044 		DBG(dca, DWARN, "dca_3desupdate: dca_getbufbytes() failed");
24988f8b78aSgm89044 		(void) dca_free_context(ctx);
25088f8b78aSgm89044 		return (rv);
25188f8b78aSgm89044 	}
25288f8b78aSgm89044 
25388f8b78aSgm89044 	/* Calculate new residual length. */
25488f8b78aSgm89044 	des_ctx->dr_ctx.residlen = rawlen % DESBLOCK;
25588f8b78aSgm89044 
25688f8b78aSgm89044 	/*
25788f8b78aSgm89044 	 * Make a local copy of the input crypto_data_t structure. This
25888f8b78aSgm89044 	 * allows it to be manipulated locally and for dealing with in-place
25988f8b78aSgm89044 	 * data (ie in == out).
26088f8b78aSgm89044 	 */
26188f8b78aSgm89044 	if ((rv = dca_dupcrypto(in, nin)) != CRYPTO_SUCCESS) {
26288f8b78aSgm89044 		(void) dca_free_context(ctx);
26388f8b78aSgm89044 		return (rv);
26488f8b78aSgm89044 	}
26588f8b78aSgm89044 
26688f8b78aSgm89044 	/* Set output to zero ready to take the processed data */
26788f8b78aSgm89044 	out->cd_length = 0;
26888f8b78aSgm89044 
26988f8b78aSgm89044 	reqp->dr_in = nin;
27088f8b78aSgm89044 	reqp->dr_out = out;
27188f8b78aSgm89044 	reqp->dr_job_stat = DS_3DESJOBS;
27288f8b78aSgm89044 	reqp->dr_byte_stat = DS_3DESBYTES;
27388f8b78aSgm89044 
27488f8b78aSgm89044 	rv = dca_3desstart(dca, flags, reqp);
27588f8b78aSgm89044 
27688f8b78aSgm89044 	/*
27788f8b78aSgm89044 	 * As this is multi-part the context is cleared on success
27888f8b78aSgm89044 	 * (CRYPTO_QUEUED) in dca_3desfinal().
27988f8b78aSgm89044 	 */
28088f8b78aSgm89044 
28188f8b78aSgm89044 	if (rv != CRYPTO_QUEUED && rv != CRYPTO_BUFFER_TOO_SMALL) {
28288f8b78aSgm89044 		(void) dca_free_context(ctx);
28388f8b78aSgm89044 	}
28488f8b78aSgm89044 	return (rv);
28588f8b78aSgm89044 }
28688f8b78aSgm89044 
28788f8b78aSgm89044 int
dca_3desfinal(crypto_ctx_t * ctx,crypto_data_t * out,int mode)28888f8b78aSgm89044 dca_3desfinal(crypto_ctx_t *ctx, crypto_data_t *out, int mode)
28988f8b78aSgm89044 {
29088f8b78aSgm89044 	dca_request_t	*des_ctx = ctx->cc_provider_private;
29188f8b78aSgm89044 	dca_t		*dca = ctx->cc_provider;
29288f8b78aSgm89044 	int		rv = CRYPTO_SUCCESS;
29388f8b78aSgm89044 
29488f8b78aSgm89044 	ASSERT(ctx->cc_provider_private != NULL);
29588f8b78aSgm89044 	/*
29688f8b78aSgm89044 	 * There must be no unprocessed ciphertext/plaintext.
29788f8b78aSgm89044 	 * This happens if the length of the last data is
29888f8b78aSgm89044 	 * not a multiple of the DES block length.
29988f8b78aSgm89044 	 */
30088f8b78aSgm89044 	if (des_ctx->dr_ctx.residlen != 0) {
30188f8b78aSgm89044 		DBG(dca, DWARN, "dca_3desfinal: invalid nonzero residual");
30288f8b78aSgm89044 		if (mode & DR_DECRYPT) {
30388f8b78aSgm89044 			rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
30488f8b78aSgm89044 		} else {
30588f8b78aSgm89044 			rv = CRYPTO_DATA_LEN_RANGE;
30688f8b78aSgm89044 		}
30788f8b78aSgm89044 	}
30888f8b78aSgm89044 	(void) dca_free_context(ctx);
30988f8b78aSgm89044 	out->cd_length = 0;
31088f8b78aSgm89044 	return (rv);
31188f8b78aSgm89044 }
31288f8b78aSgm89044 
31388f8b78aSgm89044 int
dca_3desatomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * input,crypto_data_t * output,int kmflag,crypto_req_handle_t req,int mode)31488f8b78aSgm89044 dca_3desatomic(crypto_provider_handle_t provider,
31588f8b78aSgm89044     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
31688f8b78aSgm89044     crypto_key_t *key, crypto_data_t *input, crypto_data_t *output,
31788f8b78aSgm89044     int kmflag, crypto_req_handle_t req, int mode)
31888f8b78aSgm89044 {
31988f8b78aSgm89044 	crypto_ctx_t	ctx;	/* on the stack */
32088f8b78aSgm89044 	int		rv;
32188f8b78aSgm89044 
32288f8b78aSgm89044 	ctx.cc_provider = provider;
32388f8b78aSgm89044 	ctx.cc_session = session_id;
32488f8b78aSgm89044 
32588f8b78aSgm89044 	/*
32688f8b78aSgm89044 	 * Input must be a multiple of the block size. This test only
32788f8b78aSgm89044 	 * works for non-padded mechanisms when the blocksize is 2^N.
32888f8b78aSgm89044 	 */
32988f8b78aSgm89044 	if ((dca_length(input) & (DESBLOCK - 1)) != 0) {
33088f8b78aSgm89044 		DBG(NULL, DWARN, "dca_3desatomic: input not multiple of BS");
33188f8b78aSgm89044 		if (mode & DR_DECRYPT) {
33288f8b78aSgm89044 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
33388f8b78aSgm89044 		} else {
33488f8b78aSgm89044 			return (CRYPTO_DATA_LEN_RANGE);
33588f8b78aSgm89044 		}
33688f8b78aSgm89044 	}
33788f8b78aSgm89044 
33888f8b78aSgm89044 	rv = dca_3desctxinit(&ctx, mechanism, key, kmflag, mode);
33988f8b78aSgm89044 	if (rv != CRYPTO_SUCCESS) {
34088f8b78aSgm89044 		DBG(NULL, DWARN, "dca_3desatomic: dca_3desctxinit() failed");
34188f8b78aSgm89044 		return (rv);
34288f8b78aSgm89044 	}
34388f8b78aSgm89044 
34488f8b78aSgm89044 	/*
34588f8b78aSgm89044 	 * Set the atomic flag so that the hardware callback function
34688f8b78aSgm89044 	 * will free the context.
34788f8b78aSgm89044 	 */
34888f8b78aSgm89044 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
34988f8b78aSgm89044 
350d8dd9913Sgm89044 	/* check for inplace ops */
351d8dd9913Sgm89044 	if (input == output) {
352d8dd9913Sgm89044 		((dca_request_t *)ctx.cc_provider_private)->dr_flags
353d8dd9913Sgm89044 		    |= DR_INPLACE;
354d8dd9913Sgm89044 	}
355d8dd9913Sgm89044 
35688f8b78aSgm89044 	rv = dca_3des(&ctx, input, output, req, mode);
35788f8b78aSgm89044 	if ((rv != CRYPTO_QUEUED) && (rv != CRYPTO_SUCCESS)) {
35888f8b78aSgm89044 		DBG(NULL, DWARN, "dca_3desatomic: dca_3des() failed");
35988f8b78aSgm89044 		output->cd_length = 0;
36088f8b78aSgm89044 	}
36188f8b78aSgm89044 
36288f8b78aSgm89044 	/*
36388f8b78aSgm89044 	 * The features of dca_3desfinal() are implemented within
36488f8b78aSgm89044 	 * dca_3desdone() due to the asynchronous nature of dca_3des().
36588f8b78aSgm89044 	 */
36688f8b78aSgm89044 
36788f8b78aSgm89044 	/*
36888f8b78aSgm89044 	 * The context will be freed in the hardware callback function if it
36988f8b78aSgm89044 	 * is queued
37088f8b78aSgm89044 	 */
37188f8b78aSgm89044 	if (rv != CRYPTO_QUEUED)
37288f8b78aSgm89044 		dca_3desctxfree(&ctx);
37388f8b78aSgm89044 
37488f8b78aSgm89044 	return (rv);
37588f8b78aSgm89044 }
37688f8b78aSgm89044 
37788f8b78aSgm89044 int
dca_3desstart(dca_t * dca,uint32_t flags,dca_request_t * reqp)37888f8b78aSgm89044 dca_3desstart(dca_t *dca, uint32_t flags, dca_request_t *reqp)
37988f8b78aSgm89044 {
38088f8b78aSgm89044 	size_t		len;
38188f8b78aSgm89044 	crypto_data_t	*in = reqp->dr_in;
38288f8b78aSgm89044 	int		rv;
38388f8b78aSgm89044 	dca_request_t	*ctx = reqp;
38488f8b78aSgm89044 	uint32_t	iv[2];
38588f8b78aSgm89044 
38688f8b78aSgm89044 	/*
38788f8b78aSgm89044 	 * Preconditions:
38888f8b78aSgm89044 	 * 1) in and out point to the "right" buffers.
38988f8b78aSgm89044 	 * 2) in->b_bcount - in->b_resid == initial offset
39088f8b78aSgm89044 	 * 3) likewise for out
39188f8b78aSgm89044 	 * 4) there is enough space in the output
39288f8b78aSgm89044 	 * 5) we perform a block for block encrypt
39388f8b78aSgm89044 	 */
39488f8b78aSgm89044 	len = ctx->dr_ctx.activeresidlen + dca_length(in);
39588f8b78aSgm89044 	len = ROUNDDOWN(min(len, MAXPACKET), DESBLOCK);
39688f8b78aSgm89044 	reqp->dr_pkt_length = (uint16_t)len;
39788f8b78aSgm89044 
39888f8b78aSgm89044 	/* collect IVs for this pass */
39988f8b78aSgm89044 	iv[0] = ctx->dr_ctx.iv[0];
40088f8b78aSgm89044 	iv[1] = ctx->dr_ctx.iv[1];
40188f8b78aSgm89044 
40288f8b78aSgm89044 	/*
40388f8b78aSgm89044 	 * And also, for decrypt, collect the IV for the next pass.  For
40488f8b78aSgm89044 	 * decrypt, the IV must be collected BEFORE decryption, or else
40588f8b78aSgm89044 	 * we will lose it.  (For encrypt, we grab the IV AFTER encryption,
40688f8b78aSgm89044 	 * in dca_3desdone.
40788f8b78aSgm89044 	 */
40888f8b78aSgm89044 	if (flags & DR_DECRYPT) {
40988f8b78aSgm89044 		uchar_t		ivstore[DESBLOCK];
4104b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
4114b56a003SDaniel Anderson 		uint32_t	*ivp = (uint32_t *)ivstore;
4124b56a003SDaniel Anderson #else
41388f8b78aSgm89044 		uchar_t		*ivp = ivstore;
4144b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
41588f8b78aSgm89044 
41688f8b78aSgm89044 		/* get last 8 bytes of ciphertext for IV of next op */
41788f8b78aSgm89044 		/*
41888f8b78aSgm89044 		 * If we're processing only a DESBLOCKS worth of data
41988f8b78aSgm89044 		 * and there is active residual present then it will be
42088f8b78aSgm89044 		 * needed for the IV also.
42188f8b78aSgm89044 		 */
42288f8b78aSgm89044 		if ((len == DESBLOCK) && ctx->dr_ctx.activeresidlen) {
42388f8b78aSgm89044 			/* Bring the active residual into play */
42488f8b78aSgm89044 			bcopy(ctx->dr_ctx.activeresid, ivstore,
42588f8b78aSgm89044 			    ctx->dr_ctx.activeresidlen);
42688f8b78aSgm89044 			rv = dca_getbufbytes(in, 0,
42788f8b78aSgm89044 			    DESBLOCK - ctx->dr_ctx.activeresidlen,
42888f8b78aSgm89044 			    ivstore + ctx->dr_ctx.activeresidlen);
42988f8b78aSgm89044 		} else {
43088f8b78aSgm89044 			rv = dca_getbufbytes(in,
43188f8b78aSgm89044 			    len - DESBLOCK - ctx->dr_ctx.activeresidlen,
43288f8b78aSgm89044 			    DESBLOCK, ivstore);
43388f8b78aSgm89044 		}
43488f8b78aSgm89044 
43588f8b78aSgm89044 		if (rv != CRYPTO_SUCCESS) {
43688f8b78aSgm89044 			DBG(dca, DWARN,
43788f8b78aSgm89044 			    "dca_3desstart: dca_getbufbytes() failed");
43888f8b78aSgm89044 			return (rv);
43988f8b78aSgm89044 		}
44088f8b78aSgm89044 
44188f8b78aSgm89044 		/* store as a pair of native 32-bit values */
4424b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
4434b56a003SDaniel Anderson 		ctx->dr_ctx.iv[0] = htonl(ivp[0]);
4444b56a003SDaniel Anderson 		ctx->dr_ctx.iv[1] = htonl(ivp[1]);
4454b56a003SDaniel Anderson #else
44688f8b78aSgm89044 		ctx->dr_ctx.iv[0] =
44788f8b78aSgm89044 		    ivp[0]<<24 | ivp[1]<<16 | ivp[2]<<8 | ivp[3];
44888f8b78aSgm89044 		ctx->dr_ctx.iv[1] =
44988f8b78aSgm89044 		    ivp[4]<<24 | ivp[5]<<16 | ivp[6]<<8 | ivp[7];
4504b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
45188f8b78aSgm89044 	}
45288f8b78aSgm89044 
45388f8b78aSgm89044 	/* For now we force a pullup.  Add direct DMA later. */
45488f8b78aSgm89044 	reqp->dr_flags &= ~(DR_SCATTER | DR_GATHER);
45588f8b78aSgm89044 	if ((len < dca_mindma) || (ctx->dr_ctx.activeresidlen > 0) ||
45688f8b78aSgm89044 	    dca_sgcheck(dca, reqp->dr_in, DCA_SG_CONTIG) ||
45788f8b78aSgm89044 	    dca_sgcheck(dca, reqp->dr_out, DCA_SG_WALIGN)) {
45888f8b78aSgm89044 		reqp->dr_flags |= DR_SCATTER | DR_GATHER;
45988f8b78aSgm89044 	}
46088f8b78aSgm89044 
46188f8b78aSgm89044 	/* Try to do direct DMA. */
46288f8b78aSgm89044 	if (!(reqp->dr_flags & (DR_SCATTER | DR_GATHER))) {
46388f8b78aSgm89044 		if (dca_bindchains(reqp, len, len) == DDI_SUCCESS) {
46488f8b78aSgm89044 			reqp->dr_in->cd_offset += len;
46588f8b78aSgm89044 			reqp->dr_in->cd_length -= len;
46688f8b78aSgm89044 		} else {
46788f8b78aSgm89044 			DBG(dca, DWARN,
46888f8b78aSgm89044 			    "dca_3desstart: dca_bindchains() failed");
46988f8b78aSgm89044 			return (CRYPTO_DEVICE_ERROR);
47088f8b78aSgm89044 		}
47188f8b78aSgm89044 	}
47288f8b78aSgm89044 
47388f8b78aSgm89044 	/* gather the data into the device */
47488f8b78aSgm89044 	if (reqp->dr_flags & DR_GATHER) {
47588f8b78aSgm89044 		rv = dca_resid_gather(in, (char *)ctx->dr_ctx.activeresid,
47688f8b78aSgm89044 		    &ctx->dr_ctx.activeresidlen, reqp->dr_ibuf_kaddr, len);
47788f8b78aSgm89044 		if (rv != CRYPTO_SUCCESS) {
47888f8b78aSgm89044 			DBG(dca, DWARN,
47988f8b78aSgm89044 			    "dca_3desstart: dca_resid_gather() failed");
48088f8b78aSgm89044 			return (rv);
48188f8b78aSgm89044 		}
48288f8b78aSgm89044 		/*
48388f8b78aSgm89044 		 * Setup for scattering the result back out
48488f8b78aSgm89044 		 * The output buffer is a multi-entry chain for x86 and
48588f8b78aSgm89044 		 * a single entry chain for Sparc.
48688f8b78aSgm89044 		 * Use the actual length if the first entry is sufficient.
48788f8b78aSgm89044 		 */
48888f8b78aSgm89044 		(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, len,
48988f8b78aSgm89044 		    DDI_DMA_SYNC_FORDEV);
49088f8b78aSgm89044 		if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
49188f8b78aSgm89044 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
49288f8b78aSgm89044 			reqp->destroy = TRUE;
49388f8b78aSgm89044 			return (CRYPTO_DEVICE_ERROR);
49488f8b78aSgm89044 		}
49588f8b78aSgm89044 
49688f8b78aSgm89044 		reqp->dr_in_paddr = reqp->dr_ibuf_head.dc_buffer_paddr;
49788f8b78aSgm89044 		reqp->dr_in_next = reqp->dr_ibuf_head.dc_next_paddr;
49888f8b78aSgm89044 		if (len > reqp->dr_ibuf_head.dc_buffer_length)
49988f8b78aSgm89044 			reqp->dr_in_len = reqp->dr_ibuf_head.dc_buffer_length;
50088f8b78aSgm89044 		else
50188f8b78aSgm89044 			reqp->dr_in_len = len;
50288f8b78aSgm89044 	}
50388f8b78aSgm89044 	/*
50488f8b78aSgm89044 	 * Setup for scattering the result back out
50588f8b78aSgm89044 	 * The output buffer is a multi-entry chain for x86 and
50688f8b78aSgm89044 	 * a single entry chain for Sparc.
50788f8b78aSgm89044 	 * Use the actual length if the first entry is sufficient.
50888f8b78aSgm89044 	 */
50988f8b78aSgm89044 	if (reqp->dr_flags & DR_SCATTER) {
51088f8b78aSgm89044 		reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
51188f8b78aSgm89044 		reqp->dr_out_next = reqp->dr_obuf_head.dc_next_paddr;
51288f8b78aSgm89044 		if (len > reqp->dr_obuf_head.dc_buffer_length)
51388f8b78aSgm89044 			reqp->dr_out_len = reqp->dr_obuf_head.dc_buffer_length;
51488f8b78aSgm89044 		else
51588f8b78aSgm89044 			reqp->dr_out_len = len;
51688f8b78aSgm89044 	}
51788f8b78aSgm89044 
51888f8b78aSgm89044 	reqp->dr_flags |= flags;
51988f8b78aSgm89044 	reqp->dr_callback = dca_3desdone;
52088f8b78aSgm89044 
52188f8b78aSgm89044 	/* write out the context structure */
52288f8b78aSgm89044 	PUTCTX32(reqp, CTX_3DESIVHI, iv[0]);
52388f8b78aSgm89044 	PUTCTX32(reqp, CTX_3DESIVLO, iv[1]);
52488f8b78aSgm89044 
52588f8b78aSgm89044 	/* schedule the work by doing a submit */
52688f8b78aSgm89044 	return (dca_start(dca, reqp, MCR1, 1));
52788f8b78aSgm89044 }
52888f8b78aSgm89044 
52988f8b78aSgm89044 void
dca_3desdone(dca_request_t * reqp,int errno)53088f8b78aSgm89044 dca_3desdone(dca_request_t *reqp, int errno)
53188f8b78aSgm89044 {
53288f8b78aSgm89044 	crypto_data_t	*out = reqp->dr_out;
53388f8b78aSgm89044 	dca_request_t	*ctx = reqp;
53488f8b78aSgm89044 	ASSERT(ctx != NULL);
53588f8b78aSgm89044 
53688f8b78aSgm89044 	if (errno == CRYPTO_SUCCESS) {
53788f8b78aSgm89044 		size_t		off;
53888f8b78aSgm89044 		/*
53988f8b78aSgm89044 		 * Save the offset: this has to be done *before* dca_scatter
54088f8b78aSgm89044 		 * modifies the buffer.  We take the initial offset into the
54188f8b78aSgm89044 		 * first buf, and add that to the total packet size to find
54288f8b78aSgm89044 		 * the end of the packet.
54388f8b78aSgm89044 		 */
54488f8b78aSgm89044 		off = dca_length(out) + reqp->dr_pkt_length - DESBLOCK;
54588f8b78aSgm89044 
54688f8b78aSgm89044 		if (reqp->dr_flags & DR_SCATTER) {
54788f8b78aSgm89044 			(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0,
54888f8b78aSgm89044 			    reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL);
54988f8b78aSgm89044 			if (dca_check_dma_handle(reqp->dr_dca,
55088f8b78aSgm89044 			    reqp->dr_obuf_dmah, DCA_FM_ECLASS_NONE) !=
55188f8b78aSgm89044 			    DDI_SUCCESS) {
55288f8b78aSgm89044 				reqp->destroy = TRUE;
55388f8b78aSgm89044 				errno = CRYPTO_DEVICE_ERROR;
55488f8b78aSgm89044 				goto errout;
55588f8b78aSgm89044 			}
55688f8b78aSgm89044 
55788f8b78aSgm89044 			errno = dca_scatter(reqp->dr_obuf_kaddr,
55888f8b78aSgm89044 			    reqp->dr_out, reqp->dr_out_len, 0);
55988f8b78aSgm89044 			if (errno != CRYPTO_SUCCESS) {
56088f8b78aSgm89044 				DBG(NULL, DWARN,
56188f8b78aSgm89044 				    "dca_3desdone: dca_scatter() failed");
56288f8b78aSgm89044 				goto errout;
56388f8b78aSgm89044 			}
56488f8b78aSgm89044 
56588f8b78aSgm89044 		} else {
56688f8b78aSgm89044 			/* we've processed some more data */
56788f8b78aSgm89044 			out->cd_length += reqp->dr_pkt_length;
56888f8b78aSgm89044 		}
56988f8b78aSgm89044 
57088f8b78aSgm89044 
57188f8b78aSgm89044 		/*
57288f8b78aSgm89044 		 * For encryption only, we have to grab the IV for the
57388f8b78aSgm89044 		 * next pass AFTER encryption.
57488f8b78aSgm89044 		 */
57588f8b78aSgm89044 		if (reqp->dr_flags & DR_ENCRYPT) {
57688f8b78aSgm89044 			uchar_t		ivstore[DESBLOCK];
5774b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
5784b56a003SDaniel Anderson 			uint32_t	*iv = (uint32_t *)ivstore;
5794b56a003SDaniel Anderson #else
58088f8b78aSgm89044 			uchar_t		*iv = ivstore;
5814b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
58288f8b78aSgm89044 
58388f8b78aSgm89044 			/* get last 8 bytes for IV of next op */
5844b56a003SDaniel Anderson 			errno = dca_getbufbytes(out, off, DESBLOCK,
5854b56a003SDaniel Anderson 			    (uchar_t *)iv);
58688f8b78aSgm89044 			if (errno != CRYPTO_SUCCESS) {
58788f8b78aSgm89044 				DBG(NULL, DWARN,
58888f8b78aSgm89044 				    "dca_3desdone: dca_getbufbytes() failed");
58988f8b78aSgm89044 				goto errout;
59088f8b78aSgm89044 			}
5914b56a003SDaniel Anderson 
59288f8b78aSgm89044 			/* store as a pair of native 32-bit values */
5934b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
5944b56a003SDaniel Anderson 			ctx->dr_ctx.iv[0] = htonl(iv[0]);
5954b56a003SDaniel Anderson 			ctx->dr_ctx.iv[1] = htonl(iv[1]);
5964b56a003SDaniel Anderson #else
59788f8b78aSgm89044 			ctx->dr_ctx.iv[0] =
59888f8b78aSgm89044 			    iv[0]<<24 | iv[1]<<16 | iv[2]<<8 | iv[3];
59988f8b78aSgm89044 			ctx->dr_ctx.iv[1] =
60088f8b78aSgm89044 			    iv[4]<<24 | iv[5]<<16 | iv[6]<<8 | iv[7];
6014b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
60288f8b78aSgm89044 		}
60388f8b78aSgm89044 
60488f8b78aSgm89044 		/*
60588f8b78aSgm89044 		 * If there is more to do, then reschedule another
60688f8b78aSgm89044 		 * pass.
60788f8b78aSgm89044 		 */
60888f8b78aSgm89044 		if (dca_length(reqp->dr_in) >= 8) {
60988f8b78aSgm89044 			errno = dca_3desstart(reqp->dr_dca, reqp->dr_flags,
61088f8b78aSgm89044 			    reqp);
61188f8b78aSgm89044 			if (errno == CRYPTO_QUEUED) {
61288f8b78aSgm89044 				return;
61388f8b78aSgm89044 			}
61488f8b78aSgm89044 		}
61588f8b78aSgm89044 	}
61688f8b78aSgm89044 
61788f8b78aSgm89044 errout:
61888f8b78aSgm89044 
61988f8b78aSgm89044 	/*
62088f8b78aSgm89044 	 * If this is an atomic operation perform the final function
62188f8b78aSgm89044 	 * tasks (equivalent to to dca_3desfinal()).
62288f8b78aSgm89044 	 */
62388f8b78aSgm89044 	if (reqp->dr_ctx.atomic) {
62488f8b78aSgm89044 		if ((errno == CRYPTO_SUCCESS) && (ctx->dr_ctx.residlen != 0)) {
62588f8b78aSgm89044 			DBG(NULL, DWARN,
62688f8b78aSgm89044 			    "dca_3desdone: invalid nonzero residual");
62788f8b78aSgm89044 			if (reqp->dr_flags & DR_DECRYPT) {
62888f8b78aSgm89044 				errno = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
62988f8b78aSgm89044 			} else {
63088f8b78aSgm89044 				errno = CRYPTO_DATA_LEN_RANGE;
63188f8b78aSgm89044 			}
63288f8b78aSgm89044 		}
63388f8b78aSgm89044 	}
63488f8b78aSgm89044 
63588f8b78aSgm89044 	ASSERT(reqp->dr_kcf_req != NULL);
63688f8b78aSgm89044 	/* notify framework that request is completed */
63788f8b78aSgm89044 	crypto_op_notification(reqp->dr_kcf_req, errno);
63888f8b78aSgm89044 	DBG(NULL, DINTR,
63988f8b78aSgm89044 	    "dca_3desdone: returning %d to the kef via crypto_op_notification",
64088f8b78aSgm89044 	    errno);
64188f8b78aSgm89044 
64288f8b78aSgm89044 	/* This has to be done after notifing the framework */
64388f8b78aSgm89044 	if (reqp->dr_ctx.atomic) {
64488f8b78aSgm89044 		reqp->dr_context = NULL;
64588f8b78aSgm89044 		reqp->dr_ctx.atomic = 0;
64688f8b78aSgm89044 		reqp->dr_ctx.ctx_cm_type = 0;
64788f8b78aSgm89044 		if (reqp->destroy)
64888f8b78aSgm89044 			dca_destroyreq(reqp);
64988f8b78aSgm89044 		else
65088f8b78aSgm89044 			dca_freereq(reqp);
65188f8b78aSgm89044 	}
65288f8b78aSgm89044 }
65388f8b78aSgm89044 
65488f8b78aSgm89044 /* ARGSUSED */
65588f8b78aSgm89044 int
dca_3desctxinit(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag,int flags)65688f8b78aSgm89044 dca_3desctxinit(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
65788f8b78aSgm89044     crypto_key_t *key, int kmflag, int flags)
65888f8b78aSgm89044 {
65988f8b78aSgm89044 	dca_request_t	*des_ctx;
66088f8b78aSgm89044 	dca_t		*dca = ctx->cc_provider;
6614b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
6624b56a003SDaniel Anderson 	uint32_t	*param;
6634b56a003SDaniel Anderson 	uint32_t	*value32;
6644b56a003SDaniel Anderson #else
66588f8b78aSgm89044 	uchar_t		*param;
6664b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
66788f8b78aSgm89044 	uchar_t		*value;
66888f8b78aSgm89044 	size_t		paramsz;
66988f8b78aSgm89044 	unsigned	len;
67088f8b78aSgm89044 	int		i, j;
67188f8b78aSgm89044 
67288f8b78aSgm89044 	paramsz = mechanism->cm_param_len;
6734b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
6744b56a003SDaniel Anderson 	param = (uint32_t *)mechanism->cm_param;
6754b56a003SDaniel Anderson #else
67688f8b78aSgm89044 	param = (uchar_t *)mechanism->cm_param;
6774b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
6784b56a003SDaniel Anderson 
67988f8b78aSgm89044 	if ((paramsz != 0) && (paramsz != DES_IV_LEN)) {
68088f8b78aSgm89044 		DBG(NULL, DWARN,
68188f8b78aSgm89044 		    "dca_3desctxinit: parameter(IV) length not %d (%d)",
68288f8b78aSgm89044 		    DES_IV_LEN, paramsz);
68388f8b78aSgm89044 		return (CRYPTO_MECHANISM_PARAM_INVALID);
68488f8b78aSgm89044 	}
68588f8b78aSgm89044 
68688f8b78aSgm89044 	if ((des_ctx = dca_getreq(dca, MCR1, 1)) == NULL) {
68788f8b78aSgm89044 		dca_error(dca, "unable to allocate request for 3DES");
68888f8b78aSgm89044 		return (CRYPTO_HOST_MEMORY);
68988f8b78aSgm89044 	}
69088f8b78aSgm89044 	/*
69188f8b78aSgm89044 	 * Identify and store the IV as a pair of native 32-bit words.
69288f8b78aSgm89044 	 *
69388f8b78aSgm89044 	 * If cm_param == NULL then the IV comes from the cd_miscdata field
69488f8b78aSgm89044 	 * in the crypto_data structure.
69588f8b78aSgm89044 	 */
69688f8b78aSgm89044 	if (param != NULL) {
69788f8b78aSgm89044 		ASSERT(paramsz == DES_IV_LEN);
6984b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
6994b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[0] = htonl(param[0]);
7004b56a003SDaniel Anderson 		des_ctx->dr_ctx.iv[1] = htonl(param[1]);
7014b56a003SDaniel Anderson #else
70288f8b78aSgm89044 		des_ctx->dr_ctx.iv[0] = param[0]<<24 | param[1]<<16 |
70388f8b78aSgm89044 		    param[2]<<8 | param[3];
70488f8b78aSgm89044 		des_ctx->dr_ctx.iv[1] = param[4]<<24 | param[5]<<16 |
70588f8b78aSgm89044 		    param[6]<<8 | param[7];
7064b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
70788f8b78aSgm89044 	}
70888f8b78aSgm89044 	des_ctx->dr_ctx.residlen = 0;
70988f8b78aSgm89044 	des_ctx->dr_ctx.activeresidlen = 0;
71088f8b78aSgm89044 	des_ctx->dr_ctx.ctx_cm_type = mechanism->cm_type;
71188f8b78aSgm89044 	ctx->cc_provider_private = des_ctx;
71288f8b78aSgm89044 
71388f8b78aSgm89044 	if (key->ck_format != CRYPTO_KEY_RAW) {
71488f8b78aSgm89044 		DBG(NULL, DWARN,
71588f8b78aSgm89044 	"dca_3desctxinit: only raw crypto key type support with DES/3DES");
71688f8b78aSgm89044 		dca_3desctxfree(ctx);
71788f8b78aSgm89044 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
71888f8b78aSgm89044 	}
71988f8b78aSgm89044 
72088f8b78aSgm89044 	len = key->ck_length;
72188f8b78aSgm89044 	value = (uchar_t *)key->ck_data;
72288f8b78aSgm89044 
72388f8b78aSgm89044 	if (flags & DR_TRIPLE) {
72488f8b78aSgm89044 		/* 3DES */
72588f8b78aSgm89044 		switch (len) {
72688f8b78aSgm89044 		case 192:
72788f8b78aSgm89044 			for (i = 0; i < 6; i++) {
72888f8b78aSgm89044 				des_ctx->dr_ctx.key[i] = 0;
72988f8b78aSgm89044 				for (j = 0; j < 4; j++) {
73088f8b78aSgm89044 					des_ctx->dr_ctx.key[i] <<= 8;
73188f8b78aSgm89044 					des_ctx->dr_ctx.key[i] |= *value;
73288f8b78aSgm89044 					value++;
73388f8b78aSgm89044 				}
73488f8b78aSgm89044 			}
73588f8b78aSgm89044 			break;
73688f8b78aSgm89044 
73788f8b78aSgm89044 		case 128:
73888f8b78aSgm89044 			for (i = 0; i < 4; i++) {
73988f8b78aSgm89044 				des_ctx->dr_ctx.key[i] = 0;
74088f8b78aSgm89044 				for (j = 0; j < 4; j++) {
74188f8b78aSgm89044 					des_ctx->dr_ctx.key[i] <<= 8;
74288f8b78aSgm89044 					des_ctx->dr_ctx.key[i] |= *value;
74388f8b78aSgm89044 					value++;
74488f8b78aSgm89044 				}
74588f8b78aSgm89044 			}
74688f8b78aSgm89044 			des_ctx->dr_ctx.key[4] = des_ctx->dr_ctx.key[0];
74788f8b78aSgm89044 			des_ctx->dr_ctx.key[5] = des_ctx->dr_ctx.key[1];
74888f8b78aSgm89044 			break;
74988f8b78aSgm89044 
75088f8b78aSgm89044 		default:
75188f8b78aSgm89044 			DBG(NULL, DWARN, "Incorrect 3DES keysize (%d)", len);
75288f8b78aSgm89044 			dca_3desctxfree(ctx);
75388f8b78aSgm89044 			return (CRYPTO_KEY_SIZE_RANGE);
75488f8b78aSgm89044 		}
75588f8b78aSgm89044 	} else {
75688f8b78aSgm89044 		/* single DES */
75788f8b78aSgm89044 		if (len != 64) {
75888f8b78aSgm89044 			DBG(NULL, DWARN, "Incorrect DES keysize (%d)", len);
75988f8b78aSgm89044 			dca_3desctxfree(ctx);
76088f8b78aSgm89044 			return (CRYPTO_KEY_SIZE_RANGE);
76188f8b78aSgm89044 		}
7624b56a003SDaniel Anderson 
7634b56a003SDaniel Anderson #ifdef UNALIGNED_POINTERS_PERMITTED
7644b56a003SDaniel Anderson 		value32 = (uint32_t *)value;
7654b56a003SDaniel Anderson 		des_ctx->dr_ctx.key[0] = htonl(value32[0]);
7664b56a003SDaniel Anderson 		des_ctx->dr_ctx.key[1] = htonl(value32[1]);
7674b56a003SDaniel Anderson #else
76888f8b78aSgm89044 		des_ctx->dr_ctx.key[0] =
76988f8b78aSgm89044 		    value[0]<<24 | value[1]<<16 | value[2]<<8 | value[3];
77088f8b78aSgm89044 		des_ctx->dr_ctx.key[1] =
77188f8b78aSgm89044 		    value[4]<<24 | value[5]<<16 | value[6]<<8 | value[7];
7724b56a003SDaniel Anderson #endif	/* UNALIGNED_POINTERS_PERMITTED */
7734b56a003SDaniel Anderson 
77488f8b78aSgm89044 		/* for single des just repeat des key */
77588f8b78aSgm89044 		des_ctx->dr_ctx.key[4] =
77688f8b78aSgm89044 		    des_ctx->dr_ctx.key[2] = des_ctx->dr_ctx.key[0];
77788f8b78aSgm89044 		des_ctx->dr_ctx.key[5] =
77888f8b78aSgm89044 		    des_ctx->dr_ctx.key[3] = des_ctx->dr_ctx.key[1];
77988f8b78aSgm89044 	}
78088f8b78aSgm89044 
78188f8b78aSgm89044 	/*
78288f8b78aSgm89044 	 * Setup the context here so that we do not need to setup it up
78388f8b78aSgm89044 	 * for every update
78488f8b78aSgm89044 	 */
78588f8b78aSgm89044 	PUTCTX16(des_ctx, CTX_LENGTH, CTX_3DES_LENGTH);
78688f8b78aSgm89044 	PUTCTX16(des_ctx, CTX_CMD, CMD_3DES);
78788f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESDIRECTION,
78888f8b78aSgm89044 	    flags & DR_ENCRYPT ? CTX_3DES_ENCRYPT : CTX_3DES_DECRYPT);
78988f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY1HI, des_ctx->dr_ctx.key[0]);
79088f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY1LO, des_ctx->dr_ctx.key[1]);
79188f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY2HI, des_ctx->dr_ctx.key[2]);
79288f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY2LO, des_ctx->dr_ctx.key[3]);
79388f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY3HI, des_ctx->dr_ctx.key[4]);
79488f8b78aSgm89044 	PUTCTX32(des_ctx, CTX_3DESKEY3LO, des_ctx->dr_ctx.key[5]);
79588f8b78aSgm89044 
79688f8b78aSgm89044 	return (CRYPTO_SUCCESS);
79788f8b78aSgm89044 }
798