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