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