/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Deimos - cryptographic acceleration based upon Broadcom 582x.
*/
#include <sys/byteorder.h>
#define UNALIGNED_POINTERS_PERMITTED
#endif
/*
* 3DES implementation.
*/
static void dca_3desdone(dca_request_t *, int);
int
{
int len;
int rv;
(void) dca_free_context(ctx);
if (flags & DR_DECRYPT) {
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
} else {
return (CRYPTO_DATA_LEN_RANGE);
}
}
/*
* If cd_miscdata non-null then this contains the IV.
*/
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
}
/* Do not free the context since the app will call again */
return (CRYPTO_BUFFER_TOO_SMALL);
}
(void) dca_free_context(ctx);
return (rv);
}
/* special handling for null-sized input buffers */
if (len == 0) {
(void) dca_free_context(ctx);
return (CRYPTO_SUCCESS);
}
/*
* Make a local copy of the input crypto_data_t structure. This
* allows it to be manipulated locally and for dealing with in-place
* data (ie in == out). Note that "nin" has been pre-allocated,
* and only fields are copied, not actual data.
*/
(void) dca_free_context(ctx);
return (rv);
}
/* Set output to zero ready to take the processed data */
/* Context will be freed in the kCF callback function otherwise */
(void) dca_free_context(ctx);
}
return (rv);
}
void
{
return;
else
/* Return it to the pool */
}
int
{
int len;
int rawlen;
int rv;
/*
* If cd_miscdata non-null then this contains the IV.
*/
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
}
/* Do not free the context since the app will call again */
return (CRYPTO_BUFFER_TOO_SMALL);
}
(void) dca_free_context(ctx);
return (rv);
}
/*
* From here on out, we are committed.
*/
if (len == 0) {
/*
* No blocks being encrypted, so we just accumulate the
* input for the next pass and return.
*/
"dca_3desupdate: dca_getbufbytes() failed for residual only pass");
return (rv);
}
/*
* Do not free the context here since it will be done
* in the final function
*/
return (CRYPTO_SUCCESS);
}
/*
* Set up rbuf for previous residual data.
*/
}
/*
* Locate and save residual data for next encrypt_update.
*/
(void) dca_free_context(ctx);
return (rv);
}
/* Calculate new residual length. */
/*
* Make a local copy of the input crypto_data_t structure. This
* allows it to be manipulated locally and for dealing with in-place
* data (ie in == out).
*/
(void) dca_free_context(ctx);
return (rv);
}
/* Set output to zero ready to take the processed data */
/*
* As this is multi-part the context is cleared on success
* (CRYPTO_QUEUED) in dca_3desfinal().
*/
(void) dca_free_context(ctx);
}
return (rv);
}
int
{
/*
* There must be no unprocessed ciphertext/plaintext.
* This happens if the length of the last data is
* not a multiple of the DES block length.
*/
if (mode & DR_DECRYPT) {
} else {
}
}
(void) dca_free_context(ctx);
return (rv);
}
int
{
int rv;
/*
* Input must be a multiple of the block size. This test only
* works for non-padded mechanisms when the blocksize is 2^N.
*/
if (mode & DR_DECRYPT) {
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
} else {
return (CRYPTO_DATA_LEN_RANGE);
}
}
if (rv != CRYPTO_SUCCESS) {
return (rv);
}
/*
* Set the atomic flag so that the hardware callback function
* will free the context.
*/
/* check for inplace ops */
|= DR_INPLACE;
}
}
/*
* The features of dca_3desfinal() are implemented within
* dca_3desdone() due to the asynchronous nature of dca_3des().
*/
/*
* The context will be freed in the hardware callback function if it
* is queued
*/
if (rv != CRYPTO_QUEUED)
return (rv);
}
int
{
int rv;
/*
* Preconditions:
* 1) in and out point to the "right" buffers.
* 2) in->b_bcount - in->b_resid == initial offset
* 3) likewise for out
* 4) there is enough space in the output
* 5) we perform a block for block encrypt
*/
/* collect IVs for this pass */
/*
* And also, for decrypt, collect the IV for the next pass. For
* decrypt, the IV must be collected BEFORE decryption, or else
* we will lose it. (For encrypt, we grab the IV AFTER encryption,
* in dca_3desdone.
*/
if (flags & DR_DECRYPT) {
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
/* get last 8 bytes of ciphertext for IV of next op */
/*
* If we're processing only a DESBLOCKS worth of data
* and there is active residual present then it will be
* needed for the IV also.
*/
/* Bring the active residual into play */
} else {
}
if (rv != CRYPTO_SUCCESS) {
"dca_3desstart: dca_getbufbytes() failed");
return (rv);
}
/* store as a pair of native 32-bit values */
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
}
/* For now we force a pullup. Add direct DMA later. */
}
/* Try to do direct DMA. */
} else {
"dca_3desstart: dca_bindchains() failed");
return (CRYPTO_DEVICE_ERROR);
}
}
/* gather the data into the device */
if (rv != CRYPTO_SUCCESS) {
"dca_3desstart: dca_resid_gather() failed");
return (rv);
}
/*
* Setup for scattering the result back out
* The output buffer is a multi-entry chain for x86 and
* a single entry chain for Sparc.
* Use the actual length if the first entry is sufficient.
*/
DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
return (CRYPTO_DEVICE_ERROR);
}
else
}
/*
* Setup for scattering the result back out
* The output buffer is a multi-entry chain for x86 and
* a single entry chain for Sparc.
* Use the actual length if the first entry is sufficient.
*/
else
}
/* write out the context structure */
/* schedule the work by doing a submit */
}
void
{
if (errno == CRYPTO_SUCCESS) {
/*
* Save the offset: this has to be done *before* dca_scatter
* modifies the buffer. We take the initial offset into the
* first buf, and add that to the total packet size to find
* the end of the packet.
*/
DDI_SUCCESS) {
goto errout;
}
if (errno != CRYPTO_SUCCESS) {
"dca_3desdone: dca_scatter() failed");
goto errout;
}
} else {
/* we've processed some more data */
}
/*
* For encryption only, we have to grab the IV for the
* next pass AFTER encryption.
*/
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
/* get last 8 bytes for IV of next op */
if (errno != CRYPTO_SUCCESS) {
"dca_3desdone: dca_getbufbytes() failed");
goto errout;
}
/* store as a pair of native 32-bit values */
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
}
/*
* If there is more to do, then reschedule another
* pass.
*/
reqp);
if (errno == CRYPTO_QUEUED) {
return;
}
}
}
/*
* If this is an atomic operation perform the final function
* tasks (equivalent to to dca_3desfinal()).
*/
"dca_3desdone: invalid nonzero residual");
} else {
}
}
}
/* notify framework that request is completed */
"dca_3desdone: returning %d to the kef via crypto_op_notification",
errno);
/* This has to be done after notifing the framework */
else
}
}
/* ARGSUSED */
int
{
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
unsigned len;
int i, j;
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
"dca_3desctxinit: parameter(IV) length not %d (%d)",
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
return (CRYPTO_HOST_MEMORY);
}
/*
* Identify and store the IV as a pair of native 32-bit words.
*
* If cm_param == NULL then the IV comes from the cd_miscdata field
* in the crypto_data structure.
*/
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
}
"dca_3desctxinit: only raw crypto key type support with DES/3DES");
return (CRYPTO_KEY_TYPE_INCONSISTENT);
}
/* 3DES */
switch (len) {
case 192:
for (i = 0; i < 6; i++) {
for (j = 0; j < 4; j++) {
value++;
}
}
break;
case 128:
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
value++;
}
}
break;
default:
return (CRYPTO_KEY_SIZE_RANGE);
}
} else {
/* single DES */
if (len != 64) {
return (CRYPTO_KEY_SIZE_RANGE);
}
#ifdef UNALIGNED_POINTERS_PERMITTED
#else
#endif /* UNALIGNED_POINTERS_PERMITTED */
/* for single des just repeat des key */
}
/*
* Setup the context here so that we do not need to setup it up
* for every update
*/
return (CRYPTO_SUCCESS);
}