xref: /onnv-gate/usr/src/uts/common/crypto/io/dca_3des.c (revision 906:1b5a12bcb15b)
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