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