netbsd/sys/dev/pci/n8/common/api/n8_cryptographic.c
2013-04-06 16:48:33 +02:00

1869 lines
76 KiB
C

/*-
* Copyright (C) 2001-2003 by NBMK Encryption Technologies.
* All rights reserved.
*
* NBMK Encryption Technologies provides no support of any kind for
* this software. Questions or concerns about it may be addressed to
* the members of the relevant open-source community at
* <tech-crypto@netbsd.org>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static char const n8_id[] = "$Id: n8_cryptographic.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
/*****************************************************************************/
/** @file n8_cryptographic.c
* @brief Contains packet functions.
*
* Functions:
* N8_EncryptInitialize - Initializes the encrypt object object.
* N8_EncryptPartial - Perform a partial encryption.
* N8_EncryptEnd - Complete an in-progress partial encryption.
* N8_Encrypt - Perform a complete encryption.
* N8_DecryptPartial - Perform a partial decryption.
* N8_DecryptEnd - Complete an in-progress partial decryption.
* N8_Decrypt - Perform a complete decryption.
*
*****************************************************************************/
/*****************************************************************************
* Revision history:
* 06/06/03 brr Move n8_enums to public include as n8_pub_enums.
* 05/27/03 brr Removed N8_preamble call since N8_PacketInitialize must be
* called prior to Encrypt/Decrypt operations.
* 05/20/03 brr Remove include of obsolete n8_contextM.h & n8_cryptographic.h.
* 09/23/02 bac Fixed bug #870 by initializing residualLength to zero.
* 06/18/02 bac When Encrypt and EncryptEnd were adding padding, the portion
* added was not being set to 0x0. (Bug #808)
* 06/15/02 brr Check message length ptr in N8_EncryptPartial & N8_EncryptEnd.
* 06/11/02 bac Check for null context in N8_EncryptInitialize when using
* ARC4. Return N8_UNALLOCATED_CONTEXT when the magic number is
* not correct. (Bug #776)
* 06/11/02 bac Check for invalid unit in N8_EncryptInitialize. (Bug #777)
* 06/10/02 bac Fixed N8_Decrypt and N8_DecryptEnd to return
* N8_INVALID_INPUT_SIZE instead of padding. (Bug #775)
* 05/22/02 brr Check message length ptr in N8_DecryptPartial & N8_DecryptEnd.
* 05/20/02 brr Free the request for all error conditions.
* 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support.
* 03/26/02 brr Allocate the data buffer as part of the API request.
* 02/28/02 brr Do not include any QMgr include files.
* 02/25/02 brr Removed last references to the QMgr.
* 01/31/02 brr Eliminated the memory allocation for postProcessingData.
* 12/18/01 mel Deleted illegal operations with contextHandle
* 11/28/01 mel Fixed bug #381: EncryptInitialize needs to force parity before
* DES weakkeys check.
* 11/27/01 bac Removed unnecessary CHECK_RETURNs after QUEUE_AND_CHECKs.
* 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files.
* 11/09/01 hml Added structure verification code.
* 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers.
* 09/28/01 bac Clean up regarding use of const in parameter lists.
* 09/28/01 bac Further development changes. Fixes to work for context use.
* 09/24/01 hml Added unit specifer for multi-chip.
* 09/21/01 bac Fixed bug to prevent request from being freed twice.
* 09/20/01 bac Continued development. Massive changes.
* 09/18/01 bac Substantial re-write to properly use kernel memory, event
* processing, and async support.
* 09/14/01 mel Added event parameter to N8_FreeContext.
* 09/06/01 bac Fixed doxygen groupings.
* 07/31/01 bac Added call to N8_preamble for all public interfaces.
* 06/07/01 mel Original version.
****************************************************************************/
/** @defgroup crypto Cryptographic API Packet-Level functions
*/
#include "n8_common.h" /* common definitions */
#include "n8_pub_errors.h" /* Errors definition */
#include "n8_enqueue_common.h" /* common definitions for enqueue */
#include "n8_cb_ea.h"
#include "n8_util.h"
#include "n8_key_works.h"
#include "n8_packet.h"
#include "n8_API_Initialize.h"
#include "n8_pub_enums.h"
#include <opencrypto/cryptodev.h>
#define NO_CALLBACK_FCN NULL
/*
* Local structures used only for transfering data to the call back functions.
*/
typedef struct
{
unsigned int *encryptedMsgLen_p;
N8_EncryptObject_t *encryptObject_p;
uint32_t *nextIV_p;
} encryptData_t;
/*
* Local functions
*/
static N8_Status_t verifyInputLength(const unsigned int len)
{
N8_Status_t ret = N8_STATUS_OK;
if (len > N8_MAX_MESSAGE_LENGTH)
{
DBG(("Message length is out of range\n"));
ret = N8_INVALID_INPUT_SIZE;
}
return ret;
}
static N8_Status_t checkCipher(N8_Cipher_t cipher)
{
N8_Status_t ret = N8_STATUS_OK;
switch (cipher)
{
case N8_CIPHER_ARC4:
case N8_CIPHER_DES:
break;
default:
ret = N8_INVALID_CIPHER;
break;
}
return ret;
}
static void performCopyBack(API_Request_t* req_p)
{
if (req_p->copyBackSize > 0 &&
req_p->copyBackFrom_p != NULL &&
(req_p->copyBackTo_p != NULL || req_p->copyBackTo_uio != NULL))
{
#if N8DEBUG
DBG(("copyBackSize = %d\n", req_p->copyBackSize));
DBG(("results: "));
printN8Buffer((N8_Buffer_t *) req_p->copyBackFrom_p, req_p->copyBackSize);
#endif
if (req_p->copyBackTo_p != NULL) {
#if N8DEBUG
DBG(("memcpy\n"));
#endif
memcpy(req_p->copyBackTo_p,
req_p->copyBackFrom_p,
req_p->copyBackSize);
} else {
#if N8DEBUG
DBG(("cuio_copyback\n"));
#endif
cuio_copyback(req_p->copyBackTo_uio, 0,
req_p->copyBackSize,
req_p->copyBackFrom_p);
}
}
else
{
DBG(("no copy back given\n"));
}
}
static void resultHandler(API_Request_t* req_p)
{
char title[] = "N8_cryptographic result handler";
encryptData_t *callBackData_p = (encryptData_t *) req_p->postProcessingData_p;
if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
{
DBG(("%s called with success\n", title));
performCopyBack(req_p);
if (callBackData_p != NULL)
{
N8_EncryptObject_t *encryptObject_p = callBackData_p->encryptObject_p;
/* update IVs for DES*/
if (encryptObject_p->cipher == N8_CIPHER_DES &&
callBackData_p->nextIV_p != NULL)
{
memcpy(encryptObject_p->cipherInfo.key.keyDES.IV,
callBackData_p->nextIV_p, N8_DES_BLOCK_LENGTH);
#if N8DEBUG
DBG(("IV[ms]: "));
printN8Buffer((N8_Buffer_t *) encryptObject_p->cipherInfo.key.keyDES.IV,
N8_DES_BLOCK_LENGTH);
#endif
}
/* set the returned value for the encrypted message length */
*(callBackData_p->encryptedMsgLen_p) = req_p->copyBackSize;
}
}
else
{
RESULT_HANDLER_WARNING(title, req_p);
}
} /* resultHandler */
/*
* External functions
*/
/*****************************************************************************
* N8_EncryptInitialize
*****************************************************************************/
/** @ingroup crypto
* @brief Initializes (makes ready for use in encrypt and decrypt operations)
* the encrypt object specified by EncryptObject.
*
* An encryption object can be initialized for use with ARC4 or DES encryption /
* decryption. The encryption algorithm is specified by the enumerated value
* Cipher. The two permissible values for Cipher are ARC4 and DES. If Cipher is
* ARC4, then EncryptObject is initialized for use with ARC4 encryption /
* decryption. ARC4 operations require context memory, so ContextHandle must
* specify a valid context entry allocated by N8_AllocateContext that will be
* made part of EncryptObject. CipherInfo specifies the ARC4 key to use. The
* context entry denoted by ContextHandle is loaded with this key and will be
* used in subsequent N8_Encrypt or N8_Decrypt calls made with EncryptObject.
* If Cipher is DES, then EncryptObject is initialized for use with DES
* encryption / decryption. DES operations do not require context memory.
* ContextHandle may be null or may specify a valid context entry allocated by
* N8_AllocateContext that will be made part of EncryptObject. CipherInfo
* specifies the DES key material to use (including the initialization
* vector). If ContextHandle is null, then EncryptObject is initialized with the
* key material and can be used in subsequent N8_Encrypt or N8_Decrypt calls. If
* ContextHandle is non-null and valid, the context entry denoted by
* ContextHandle is loaded with this key material and will be used in subsequent
* N8_Encrypt or N8_Decrypt calls made with EncryptObject. DES keys will be
* checked for weak and semi-weak keys and such keys will be rejected. DES keys
* will not be checked for correct parity; the parity bits are ignored. (Before
* use in the hardware the parity will be set correctly so that hardware
* generated parity errors do not occur.)
*
* @param encryptObject_p WO: The encrypt object to be initialized with the
* specified information. The returned object can
* be used in subsequent N8_Encrypt or N8_Decrypt *
* calls
*
* @param contextHandle_p RO: A valid context handle as returned by
* N8_AllocateContext, if Cipher = ARC4. Optional
* (may be null), if Cipher = DES. The
* corresponding context memory entry is loaded for
* use in subsequent N8_Encrypt of Decrypt calls.
*
* @param cipher RO: One of the values ARC4 or DES.
*
* @param cipherInfo_p RO: The specific information to be used in the
* initialization. Its type and contents depend on
* the value of ContextType, as specified above.
*
*
* @return
* encryptObject_p - initialized encrypt object.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - packet object is zero, couldn't write to unspecified
* address<BR>
* N8_INVALID_CIPHER - The value of Cipher is not one of the legal values
* ARC4 or DES.<BR>
* N8_INVALID_VALUE - The value of ContextIndex is not a valid context
* index, or ContextIndex is null but a context index
* is required because ARC4 is specified or the
* unit value specified is invalid.<BR>
* N8_UNALLOCATED_CONTEXT - ContextIndex denotes a context memory index that
* has not been allocated by N8_AllocateContext.<BR>
* N8_INVALID_KEY_SIZE - The size of the key specified in CipherInfo_p is
* outside the valid range for the encryption algorithm
* specified in Cipher, or the size of an HMAC key
* specified in CipherInfo_p is outside the valid range
* for the hash algorithm specified in HashAlgorithm.<BR>
* N8_INCONSISTENT - The information in CipherInfo_p and/or its type is
* different than or inconsistent with the type
* specified by Cipher or HashAlgorithm, or the
* combination of values specified by Protocol, Cipher,
* and HashAlgorithm is invalid (for example, SSL is
* specified with HMAC-MD5, or IPSec is specified with ARC4).<BR>
* N8_MALLOC_FAILED - memory allocation failed
* N8_HARDWARE_ERROR - couldn't write to context memory
*
*
* @par Assumptions:
* Context entries (and hence ContextHandles) can only be used to hold one
* context at a time. The context entry specified in this call should not
* be in use with any other current encrypt object or packet object. This
* condition is not checked for; incorrect / indeterminate and / or errors
* are likely in this situation.
*****************************************************************************/
N8_Status_t N8_EncryptInitialize(N8_EncryptObject_t *encryptObject_p,
const N8_ContextHandle_t *contextHandle_p,
const N8_Cipher_t cipher,
N8_EncryptCipher_t *cipherInfo_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or
* ERROR */
int i;
API_Request_t *req_p = NULL; /* request buffer */
key_cblock_t key1, key2, key3; /* keys to be checked */
DBG(("N8_EncryptInitialize\n"));
do
{
ret = N8_preamble();
CHECK_RETURN(ret);
/* verify packet object */
CHECK_OBJECT(encryptObject_p, ret);
/* verify cipher object */
CHECK_OBJECT(cipherInfo_p, ret);
/* since we are initializing the object, set the residual length to
* zero. */
encryptObject_p->residualLength = 0;
/* if we are given a context handle */
if (contextHandle_p != NULL)
{
/* Make sure the context struct is valid */
if (contextHandle_p->structureID != N8_CONTEXT_STRUCT_ID)
{
ret = N8_UNALLOCATED_CONTEXT;
break;
}
/* copy the contents into our encryption object and set the context in
* use flag to true */
memcpy(&encryptObject_p->contextHandle,
contextHandle_p,
sizeof(N8_ContextHandle_t));
encryptObject_p->unitID = contextHandle_p->unitID;
encryptObject_p->contextHandle.inUse = N8_TRUE;
}
else
{
encryptObject_p->contextHandle.inUse = N8_FALSE;
encryptObject_p->contextHandle.index = 0xFFFF;
encryptObject_p->unitID = cipherInfo_p->unitID;
}
/* validate the unit */
if (n8_validateUnit(encryptObject_p->unitID) == N8_FALSE)
{
return N8_INVALID_UNIT;
break;
}
/* verify cipher */
switch (cipher)
{
case N8_CIPHER_ARC4:
/* verify that a valid context has been passed */
if (contextHandle_p == NULL)
{
ret = N8_INVALID_OBJECT;
break;
}
/* verify key size */
if((cipherInfo_p->keySize < 1) ||
(cipherInfo_p->keySize > ARC4_KEY_SIZE_BYTES_MAX))
{
DBG(("Key size specified for ARC4 "
"is outside the valid range: %d\n",
cipherInfo_p->keySize));
DBG(("N8_EncryptInitialize - return Error\n"));
ret = N8_INVALID_KEY_SIZE;
break;
}
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_LOADARC4KEYONLY_NUMCMDS,
NO_CALLBACK_FCN,
sizeof(EA_SSL30_CTX));
CHECK_RETURN(ret);
/* Initialize for use with ARC4 encryption/decryption */
ret = cb_ea_loadARC4keyOnly(req_p,
req_p->EA_CommandBlock_ptr,
&(encryptObject_p->contextHandle),
cipherInfo_p);
break;
case N8_CIPHER_DES:
/* verify key size */
if(cipherInfo_p->keySize != DES_KEY_SIZE_BYTES)
{
DBG(("Key size specified for DES "
"is outside the valid range: %d\n",
cipherInfo_p->keySize));
DBG(("N8_EncryptInitialize - return Error\n"));
ret = N8_INVALID_KEY_SIZE;
break;
}
/* build keys for parity verification */
/* force key parity */
for (i=0 ; i < sizeof(key_cblock_t); i++)
{
key1[i] = cipherInfo_p->key.keyDES.key1[i];
key2[i] = cipherInfo_p->key.keyDES.key2[i];
key3[i] = cipherInfo_p->key.keyDES.key3[i];
}
if (checkKeyParity(&key1) == N8_FALSE)
{
forceParity(&key1);
for (i=0 ; i < sizeof(key_cblock_t); i++)
{
cipherInfo_p->key.keyDES.key1[i] = key1[i];
}
}
if (checkKeyParity(&key2) == N8_FALSE)
{
forceParity(&key2);
for (i=0 ; i < sizeof(key_cblock_t); i++)
{
cipherInfo_p->key.keyDES.key2[i] = key2[i];
}
}
if (checkKeyParity(&key3) == N8_FALSE)
{
forceParity(&key3);
for (i=0 ; i < sizeof(key_cblock_t); i++)
{
cipherInfo_p->key.keyDES.key3[i] = key3[i];
}
}
if (checkKeyForWeakness(&key1) ||
checkKeyForWeakness(&key2) ||
checkKeyForWeakness(&key3))
{
ret = N8_WEAK_KEY;
break;
}
if (contextHandle_p != NULL)
{
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_LOADDESKEYONLY_NUMCMDS,
NO_CALLBACK_FCN,
sizeof(EA_SSL30_CTX));
CHECK_RETURN(ret);
/* DES context memory */
ret = cb_ea_loadDESkeyOnly(req_p,
req_p->EA_CommandBlock_ptr,
&(encryptObject_p->contextHandle),
cipherInfo_p);
}
break;
default:
/* invalid cipher */
DBG(("Invalid cipher\n"));
DBG(("N8_EncryptInitialize - return Error\n"));
ret = N8_INVALID_CIPHER;
break;
}
CHECK_RETURN(ret);
/* finish initialize packet object with protocol related values */
/* cipher info */
memcpy(&encryptObject_p->cipherInfo, cipherInfo_p, sizeof(N8_EncryptCipher_t));
/* encryption algorithm */
encryptObject_p->cipher = cipher;
if (req_p != NULL)
{
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
}
else
{
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_EA);
}
}
} while(FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
else
{
/* set the structure pointer to the correct state */
encryptObject_p->structureID = N8_ENCRYPT_STRUCT_ID;
}
DBG(("N8_EncryptInitialize - FINISHED\n"));
return ret;
} /* N8_EncryptInitialize */
/******************************************************************************
* N8_Encrypt
*****************************************************************************/
/** @ingroup crypto
* @brief Encrypts message.
*
* Using the encryption algorithm and context (keys, etc.) contained in
* EncryptObject, encrypt the plain text bytes in Message whose length is
* MessageLength bytes, returning the resulting cipher text bytes (including
* any pad bytes added during encryption) in EncryptedMessage. The length of
* EncryptedMessage will depend on the encryption algorithm and the size of Message.
*
* @param encryptObject_p RW: The encryption object to use, defining the
* encryption algorithm (DES or ARC4), the keys, etc.
* The state in EncryptObject will be updated
* appropriately as part of the call.<BR>
* @param message_p RO: The bytes to be encrypted<BR>
* @param messageLength RO Length of Message in bytes, from 0 to 18 KBytes
* inclusive. A length of 0 is legal, but no bytes
* will actually be encrypted or returned in
* EncryptedMessage<BR>
* @param encryptedMessage_p WO: The result of encrypting the given Message
* with the specified encryption algorithm and keys
* etc in EncryptObject. This includes any pad bytes
* added by the encryption algorithm. (DES will pad
* as necessary, ARC4 never will.)<BR>
* @param event_p RW: On input, if null the call is synchronous and no
* event is returned. The operation is complete when
* the call returns. If non-null, then the call is
* asynchronous; an event is returned that can be used
* to determine when the operation completes.<BR>
*
* @return
* encryptObject_p - The state in PacketObject will be updated if necessary as
* part of the call.
* encryptedMessage_p - The encrypted data.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - object is zero, couldn't write/read unspecified
* address<BR>
* N8_INVALID_INPUT_SIZE - The value of message length is less than 0 or bigger
* then 18 KBytes.
* N8_UNIMPLEMENTED_FUNCTION - not supported protocol configuration requested
* N8_HARDWARE_ERROR - couldn't write to context memory
*
*
* @par Assumptions:
* The caller must ensure that EncryptedMessage is of the required size.
* (This will never be more than MessageLength + 7 for
* DES, and will always be exactly MessageLength for ARC4.)
*****************************************************************************/
N8_Status_t N8_Encrypt(N8_EncryptObject_t *encryptObject_p,
const N8_Buffer_t *message_p,
const unsigned int messageLength,
N8_Buffer_t *encryptedMessage_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *plain_p = NULL;
uint32_t plain_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int paddedMessageLength;
unsigned int nBytes;
DBG(("N8_Encrypt\n"));
do
{
/* verify data length */
ret = verifyInputLength(messageLength);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
paddedMessageLength = messageLength;
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
unsigned int remainder;
/* pad message if necessary. the message length must be a multiple of
* N8_DES_BLOCK_LENGTH */
if ((remainder = messageLength % N8_DES_BLOCK_LENGTH))
{
paddedMessageLength += N8_DES_BLOCK_LENGTH - remainder;
}
}
nBytes = 2 * NEXT_WORD_SIZE(paddedMessageLength);
/* create request buffer */
ret = createEARequestBuffer(&req_p, encryptObject_p->unitID,
N8_CB_EA_ENCRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
plain_a = res_a + NEXT_WORD_SIZE(paddedMessageLength);
plain_p = res_p + NEXT_WORD_SIZE(paddedMessageLength);
/* copy the user message into the kernel memory buffer */
memcpy(plain_p, message_p, messageLength);
/* set the padding bytes to 0x0 */
memset(&plain_p[messageLength], 0x0, paddedMessageLength - messageLength);
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = encryptedMessage_p;
req_p->copyBackSize = paddedMessageLength;
ret = cb_ea_encrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
plain_a,
res_a,
paddedMessageLength);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
DBG(("N8_Encrypt - FINISHED\n"));
return ret;
} /* N8_Encrypt */
/* same as above, but for uio iovec i/o */
N8_Status_t N8_Encrypt_uio(N8_EncryptObject_t *encryptObject_p,
struct uio *message_p,
const unsigned int messageLength,
struct uio *encryptedMessage_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *plain_p = NULL;
uint32_t plain_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int paddedMessageLength;
unsigned int nBytes;
DBG(("N8_Encrypt\n"));
do
{
/* verify data length */
ret = verifyInputLength(messageLength);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
paddedMessageLength = messageLength;
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
unsigned int remainder;
/* pad message if necessary. the message length must be a multiple of
* N8_DES_BLOCK_LENGTH */
if ((remainder = messageLength % N8_DES_BLOCK_LENGTH))
{
paddedMessageLength += N8_DES_BLOCK_LENGTH - remainder;
}
}
nBytes = 2 * NEXT_WORD_SIZE(paddedMessageLength);
/* create request buffer */
ret = createEARequestBuffer(&req_p, encryptObject_p->unitID,
N8_CB_EA_ENCRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
plain_a = res_a + NEXT_WORD_SIZE(paddedMessageLength);
plain_p = res_p + NEXT_WORD_SIZE(paddedMessageLength);
/* copy the user message into the kernel memory buffer */
cuio_copydata(message_p, 0, messageLength, plain_p);
/* set the padding bytes to 0x0 */
memset(&plain_p[messageLength], 0x0, paddedMessageLength - messageLength);
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = NULL;
req_p->copyBackTo_uio = encryptedMessage_p;
req_p->copyBackSize = paddedMessageLength;
ret = cb_ea_encrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
plain_a,
res_a,
paddedMessageLength);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
DBG(("N8_Encrypt - FINISHED\n"));
return ret;
} /* N8_Encrypt */
/******************************************************************************
* N8_EncryptPartial
*****************************************************************************/
/** @ingroup crypto
* @brief Encrypts message.
*
* Using the encryption algorithm and context (keys, etc.) contained in
* EncryptObject, encrypt the plain text bytes in Message whose length is
* MessageLength bytes, returning the resulting cipher text bytes (including
* any pad bytes added during encryption) in EncryptedMessage. The length of
* EncryptedMessage will depend on the encryption algorithm and the size of Message.
*
* @param encryptObject_p WO: The encryption object to use, defining the
* encryption algorithm (DES or ARC4), the keys, etc.
* The state in EncryptObject will be updated
* appropriately as part of the call.<BR>
* @param message_p RO: The bytes to be encrypted<BR>
* @param messageLength RO Length of Message in bytes, from 0 to 18 KBytes
* inclusive. A length of 0 is legal, but no bytes
* will actually be encrypted or returned in
* EncryptedMessage<BR>
* @param encryptedMessage_p WO: The result of encrypting the given Message
* with the specified encryption algorithm and keys
* etc in EncryptObject. This includes any pad bytes
* added by the encryption algorithm. (DES will pad
* as necessary, ARC4 never will.)<BR>
* @param encryptedMsgLen_p WO: The length of the encrypted message.
* @param event_p RW: On input, if null the call is synchronous and no
* event is returned. The operation is complete when
* the call returns. If non-null, then the call is
* asynchronous; an event is returned that can be used
* to determine when the operation completes.<BR>
*
* @return
* packetObject_p - The state in PacketObject will be updated if necessary as
* part of the call.
* encryptedMessage_p - The encrypted data.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - object is NULL, couldn't write/read unspecified
* address<BR>
* N8_INVALID_INPUT_SIZE - The value of messageLength is less than 0 or bigger
* then 18 KBytes.
* N8_UNIMPLEMENTED_FUNCTION - not supported protocol configuration requested
* N8_HARDWARE_ERROR - couldn't write to context memory
*
*
* @par Assumptions:
* The caller must ensure that EncryptedMessage is of the required size.
* (This will never be more than MessageLength + 7 for
* DES, and will always be exactly MessageLength for ARC4.)
*****************************************************************************/
N8_Status_t N8_EncryptPartial(N8_EncryptObject_t *encryptObject_p,
const N8_Buffer_t *message_p,
const unsigned int messageLength,
N8_Buffer_t *encryptedMessage_p,
unsigned int *encryptedMsgLen_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *plain_p = NULL; /* virtual address of message to be
* encrypted this time. */
N8_Buffer_t *res_p = NULL; /* virtual address of encrypted
* message. */
uint32_t plain_a; /* physical address of message to be
* encrypted. */
uint32_t res_a; /* physical address of encrypted
* message. */
unsigned int totalLength = 0; /* total length of this message plus
* any residual from previous
* calls. */
unsigned int msgLen = 0; /* the length of the message to be
* encrypted in this call. */
unsigned int nextResidualLength = 0; /* amount leftover from this
* call. */
unsigned int fromThisMessageLength = 0; /* amount of taken from this
* message */
unsigned int nBytes;
encryptData_t *callBackData_p = NULL;
DBG(("N8_EncryptPartial\n"));
do
{
/* verify data length */
ret = verifyInputLength(messageLength);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_OBJECT(encryptedMsgLen_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
/* sanity check the residual length */
if (encryptObject_p->residualLength >= N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
/* set the value for the returned encrypted message length to zero. it
* will be set finally in the callback at the completion of the call (sync
* or async). */
*encryptedMsgLen_p = 0;
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
totalLength = encryptObject_p->residualLength + messageLength;
nextResidualLength = totalLength % N8_DES_BLOCK_LENGTH;
msgLen = totalLength - nextResidualLength;
fromThisMessageLength = messageLength - nextResidualLength;
}
else if (encryptObject_p->cipher == N8_CIPHER_ARC4)
{
fromThisMessageLength = msgLen = messageLength;
}
else
{
ret = N8_INVALID_CIPHER;
break;
}
/* check to ensure we actually have some message to encrypt this go
* round. */
if (msgLen == 0)
{
/* copy the input to the end of the residual */
memcpy(&encryptObject_p->residual_p[encryptObject_p->residualLength],
message_p,
messageLength);
encryptObject_p->residualLength += messageLength;
/* if this was an asynchronous call, set the status to finished */
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_EA);
}
break;
}
nBytes = 2 * NEXT_WORD_SIZE(msgLen);
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_ENCRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
plain_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
plain_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = plain_p + NEXT_WORD_SIZE(msgLen);
res_a = plain_a + NEXT_WORD_SIZE(msgLen);
/* copy any previous residual to the m-t-b-e buffer */
if (encryptObject_p->residualLength > 0)
{
memcpy(plain_p,
encryptObject_p->residual_p,
encryptObject_p->residualLength);
/* advance the message pointer */
plain_p += encryptObject_p->residualLength;
}
/* copy the new message portion to the end of the m-t-b-e buffer */
if (fromThisMessageLength > 0)
{
memcpy(plain_p,
message_p,
fromThisMessageLength);
}
/* copy leftovers to the residual */
if (nextResidualLength > 0)
{
/* not necessary, but let's zero out the remaining message buffer */
memset(encryptObject_p->residual_p, 0x0,
N8_DES_BLOCK_LENGTH);
memcpy(encryptObject_p->residual_p,
&message_p[fromThisMessageLength],
nextResidualLength);
}
encryptObject_p->residualLength = nextResidualLength;
/* set the copy back parameters for returning the results to the user.
* the main data is represented by the copy back structures in the request
* and the extra data is in the post-processing data. */
callBackData_p = (encryptData_t *)&req_p->postProcessBuffer;
req_p->postProcessingData_p = (void *) callBackData_p;
callBackData_p->encryptedMsgLen_p = encryptedMsgLen_p;
callBackData_p->encryptObject_p = encryptObject_p;
if (encryptObject_p->contextHandle.inUse == N8_FALSE)
{
callBackData_p->nextIV_p = (uint32_t *) (res_p + msgLen -
N8_DES_BLOCK_LENGTH);
}
else
{
callBackData_p->nextIV_p = NULL;
}
req_p->copyBackSize = msgLen;
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = encryptedMessage_p;
ret = cb_ea_encrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
plain_a,
res_a,
msgLen);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
}
DBG(("N8_EncryptPartial - FINISHED\n"));
return ret;
} /* N8_EncryptPartial */
/******************************************************************************
* N8_EncryptEnd
*****************************************************************************/
/** @ingroup crypto
* @brief Encrypts message.
*
* Using the encryption algorithm and context (keys, etc.) contained in
* EncryptObject, encrypt the plain text bytes in Message whose length is
* MessageLength bytes, returning the resulting cipher text bytes (including
* any pad bytes added during encryption) in EncryptedMessage. The length of
* EncryptedMessage will depend on the encryption algorithm and the size of Message.
*
* @param encryptObject_p WO: The encryption object to use, defining the
* encryption algorithm (DES or ARC4), the keys, etc.
* The state in EncryptObject will be updated
* appropriately as part of the call.<BR>
* @param message_p RO: The bytes to be encrypted<BR>
* @param messageLength RO Length of Message in bytes, from 0 to 18 KBytes
* inclusive. A length of 0 is legal, but no bytes
* will actually be encrypted or returned in
* EncryptedMessage<BR>
* @param encryptedMessage_p WO: The result of encrypting the given Message
* with the specified encryption algorithm and keys
* etc in EncryptObject. This includes any pad bytes
* added by the encryption algorithm. (DES will pad
* as necessary, ARC4 never will.)<BR>
* @param event_p RW: On input, if null the call is synchronous and no
* event is returned. The operation is complete when
* the call returns. If non-null, then the call is
* asynchronous; an event is returned that can be used
* to determine when the operation completes.<BR>
*
*
* @return
* packetObject_p - The state in PacketObject will be updated if necessary as
* part of the call.
* encryptedMessage_p - The encrypted data.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - object is zero, couldn't write/read unspecified
* address<BR>
* N8_UNIMPLEMENTED_FUNCTION - not supported protocol configuration requested
* N8_HARDWARE_ERROR - couldn't write to context memory
*
*
* @par Assumptions:
* The caller must ensure that EncryptedMessage is of the required size.
* (This will never be more than MessageLength + 7 for
* DES, and will always be exactly MessageLength for ARC4.)
*****************************************************************************/
N8_Status_t N8_EncryptEnd(N8_EncryptObject_t *encryptObject_p,
N8_Buffer_t *encryptedMessage_p,
unsigned int *encryptedMsgLen_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *plain_p = NULL;
uint32_t plain_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int paddedMessageLength = 0;
unsigned int nBytes;
encryptData_t *callBackData_p = NULL;
DBG(("N8_EncryptEnd\n"));
do
{
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_OBJECT(encryptedMsgLen_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
/* sanity check the residual length */
if (encryptObject_p->residualLength >= N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
*encryptedMsgLen_p = 0;
/* check to see if there is no work to be done. */
if (encryptObject_p->residualLength == 0)
{
/* if this was an asynchronous call, set the status to finished */
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_EA);
}
break;
}
paddedMessageLength = encryptObject_p->residualLength;
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
/* pad message */
paddedMessageLength =
CEIL(encryptObject_p->residualLength, N8_DES_BLOCK_LENGTH) *
N8_DES_BLOCK_LENGTH;
}
nBytes = 2 * NEXT_WORD_SIZE(paddedMessageLength);
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_ENCRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
plain_a = res_a + NEXT_WORD_SIZE(paddedMessageLength);
plain_p = res_p + NEXT_WORD_SIZE(paddedMessageLength);
/* copy the residual message into the kernel memory buffer */
memcpy(plain_p,
encryptObject_p->residual_p,
encryptObject_p->residualLength);
/* set the padding bytes to 0x0 */
memset(&plain_p[encryptObject_p->residualLength],
0x0,
paddedMessageLength - encryptObject_p->residualLength);
/* set the copy back parameters for returning the results to the user.
* the main data is represented by the copy back structures in the request
* and the extra data is in the post-processing data. */
callBackData_p = (encryptData_t *)&req_p->postProcessBuffer;
req_p->postProcessingData_p = (void *) callBackData_p;
callBackData_p->encryptedMsgLen_p = encryptedMsgLen_p;
callBackData_p->encryptObject_p = encryptObject_p;
callBackData_p->nextIV_p = NULL;
req_p->copyBackSize = paddedMessageLength;
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = encryptedMessage_p;
encryptObject_p->residualLength = 0;
ret = cb_ea_encrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
plain_a,
res_a,
paddedMessageLength);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
}
DBG(("N8_EncryptEnd - FINISHED\n"));
return ret;
} /* N8_EncryptEnd */
/******************************************************************************
* N8_Decrypt
*****************************************************************************/
/** @ingroup crypto
* @brief Decrypts message.
*
* Using the algorithm and context (keys, etc.) contained in EncryptObject,
* decrypt the cipher text bytes in EncryptedMessage whose length is
* EncryptedMessageLength bytes, returning the resulting plain text bytes
* (including any pad bytes added during encryption) in EncryptedMessage.
* The length of Message will always be EncryptedMessageLength. Either DES
* or ARC4 encryption can be specified in EncryptObject. DES encryption pads
* if necessary so Message may contain pad bytes; ARC4 decrypted messages will
* never contain pad bytes.
*
* @param encryptObject_p WR: The encryption object to use, defining
* the encryption algorithm (DES or
* ARC4), the keys, etc. The state in
* EncryptObject will be updated
* appropriately as part of the call. For
* example, an ARC4 object would
* have its key information updated.<BR>
* @param encryptedMessage_p RO: The bytes to be decrypted.<BR>
* @param encryptedMsgLen_p RO: Length of EncryptedMessage in bytes,
* from 0 to 18 KBytes inclusive. A
* length of 0 is legal, but no bytes will
* actually be decrypted or returned in
* EncryptedMessage. For DES,
* EncryptedMessageLength must be a
* multiple of 8, the DES block size.
* @param message_p WO: The result of decrypting the given
* EncryptedMessage with the specified
* algorithm and keys etc in EncryptObject.
* This includes any pad bytes
* added by the encryption algorithm.
* (DES will pad as necessary, ARC4 never will.)
* Thus Message is always of size MessageLength,
* the caller must ensure that Message is of at
* least this size.<BR>
* @param event_p RW: On input, if null the call is synchronous and no
* event is returned. The operation is complete when
* the call returns. If non-null, then the call is
* asynchronous; an event is returned that can be used
* to determine when the operation completes.
*
*
* @return
* encryptObject_p - The state in PacketObject will be updated if necessary as
* part of the call.
* message_p - The encrypted data.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - encrypt object is zero, couldn't write to unspecified
* address<BR>
* N8_INVALID_INPUT_SIZE - The value of message length is less than 0 or bigger
* then 18 KBytes.
* N8_HARDWARE_ERROR - couldn't decrypt
*
* N8_MALLOC_FAILED - memory allocation failed
*
* @par Assumptions:
*****************************************************************************/
N8_Status_t N8_Decrypt(N8_EncryptObject_t *encryptObject_p,
const N8_Buffer_t *encryptedMessage_p,
const unsigned int encryptedMsgLen,
N8_Buffer_t *message_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *enc_p = NULL;
uint32_t enc_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int nBytes;
DBG(("N8_Decrypt\n"));
do {
/* verify data length */
ret = verifyInputLength(encryptedMsgLen);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
/* Check to ensure the message length is a multiple of
* N8_DES_BLOCK_LENGTH. Return an error if not.
*/
if (encryptedMsgLen % N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_INPUT_SIZE;
break;
}
}
nBytes = 2 * NEXT_WORD_SIZE(encryptedMsgLen);
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_DECRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
enc_a = res_a + NEXT_WORD_SIZE(encryptedMsgLen);
enc_p = res_p + NEXT_WORD_SIZE(encryptedMsgLen);
/* copy the encrypted message into the kernel memory buffer */
memcpy(enc_p, encryptedMessage_p, encryptedMsgLen);
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = message_p;
req_p->copyBackSize = encryptedMsgLen;
ret = cb_ea_decrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
enc_a,
res_a,
encryptedMsgLen);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
DBG(("N8_Decrypt - FINISHED\n"));
return ret;
} /* N8_Decrypt */
/* same as above, but for uio iovec i/o */
N8_Status_t N8_Decrypt_uio(N8_EncryptObject_t *encryptObject_p,
struct uio *encryptedMessage_p,
const unsigned int encryptedMsgLen,
struct uio *message_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *enc_p = NULL;
uint32_t enc_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int nBytes;
DBG(("N8_Decrypt\n"));
do {
/* verify data length */
ret = verifyInputLength(encryptedMsgLen);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
/* Check to ensure the message length is a multiple of
* N8_DES_BLOCK_LENGTH. Return an error if not.
*/
if (encryptedMsgLen % N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_INPUT_SIZE;
break;
}
}
nBytes = 2 * NEXT_WORD_SIZE(encryptedMsgLen);
/* create request buffer */
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_DECRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
enc_a = res_a + NEXT_WORD_SIZE(encryptedMsgLen);
enc_p = res_p + NEXT_WORD_SIZE(encryptedMsgLen);
/* copy the encrypted message into the kernel memory buffer */
cuio_copydata(encryptedMessage_p, 0, encryptedMsgLen, enc_p);
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = NULL;
req_p->copyBackTo_uio = message_p;
req_p->copyBackSize = encryptedMsgLen;
ret = cb_ea_decrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
enc_a,
res_a,
encryptedMsgLen);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
DBG(("N8_Decrypt - FINISHED\n"));
return ret;
} /* N8_Decrypt */
/******************************************************************************
* N8_DecryptPartial
*****************************************************************************/
/** @ingroup crypto
* @brief Decrypts partial message.
* For stream decryption algorithms (ARC4), this function is identical to
* N8_Decrypt called with the same parameters, with the additional output
* parameter MessageLength always set equal to EncryptedMessageLength on return.
*
* For block decryption algorithms (DES), this function starts or continues,
* but does not complete, decrypting the bytes given in EncryptedMessage.
* The partial message in EncryptedMessage can be any number of bytes from 0
* to 18 KBytes inclusive, its size is specified in EncryptedMessageLength.
* The EncryptObject specifies the decryption algorithm to use, and must have
* been initialized by a call to N8_EncryptInitialize prior to the first call
* to N8_DecryptPartial. If this is the first call to this routine since the
* EncryptObject was initialized, then the call starts the decryption of a message.
* Subsequent calls to N8_DecryptPartial with the same EncryptObject with additional
* bytes in EncryptedMessage allow the decryption to be continued, and a final
* call to N8_DecryptEnd finishes the computation and returns the final decrypted
* result. Note that for block decryption algorithms, only whole message blocks
* will be decrypted and returned to the caller on each call to N8_DecryptPartial.
* Any message bytes left over (i.e., not forming a complete decryption block)
* will be accumulated in the EncryptObject and added to the message bytes in
* the next N8_DecryptPartial call. For this reason, the number of bytes
* decrypted and returned in Message may be different than the number of input
* bytes specified in EncryptedMessageLength. The actual number of bytes
* decrypted will always be an integral multiple of the block size of the
* encryption algorithm (8 bytes for DES) and is returned in MessageLength.
* Note in particular that this value can be 0, and it can be larger than the
* input length by as much as one less than the block size (8 - 1 = 7 for DES).
* That is, the maximum result length is the next multiple of the block size
* that is larger than EncryptedMessageLength-1
* (maximum length = ((EncryptedMessageLength / block size) + 1) * block size).
* The caller is responsible for ensuring that Message can hold a message
* of the required size. Note that while this call does not require that
* EncryptedMessageLength be a multiple of the block size, if the length of
* the entire message to be decrypted over multiple calls is not a multiple
* of the block size, an error will occur eventually
*
* @param encryptObject_p RW: The encryption object to use, defining
* the encryption algorithm (DES or
* ARC4), the keys, etc. The state in
* EncryptObject will be updated
* appropriately as part of the call.
* For example, an ARC4 object would have
* its key information updated.
* @param encryptedMessage_p RO: The bytes to be decrypted.
* @param encryptedMsgLen_p RO: Length of EncryptedMessage in bytes,
* from 0 to 18 KBytes inclusive. A
* length of 0 is legal, but no bytes will
* actually be decrypted or returned in
* message.
* @param message_p WO: The partial result of decrypting the
* given EncryptedMessage with the
* specified encryption algorithm and keys
* etc in EncryptObject. The caller must
* ensure that Message is of the required
* size. (This will never be more than
* EncryptedMessageLength + 7 for DES.
* @param messageLength WO: The number of bytes encrypted by this call and
* returned in Message. Always a multiple of
* the block size (8 for DES). This value may
* be 0 and may be as large as the next multiple
* of the block size that is greater than
* EncryptedMessageLength. For stream algorithms
* this will always equal MessageLength and will
* always be exactly MessageLength for * ARC4.)
* @param event_p RW: On input, if null the call is synchronous and
* no event is returned. The operation is
* complete when the call returns. If
* non-null, then the call is asynchronous; an
* event is returned that can be used to
* determine when the operation completes.<BR>
*
* @return
* Message WO: The partial result of decrypting the
* given EncryptedMessage with the
* specified encryption algorithm and keys
* etc in EncryptObject.
* MessageLength WO: The number of bytes encrypted by this call
* and returned in Message.
* @par Errors:
* N8_INVALID_OBJECT - encrypt object is zero, couldn't write to unspecified
* address<BR>
* N8_INVALID_INPUT_SIZE - The value of message length is less than 0 or bigger
* then 18 KBytes.
* N8_HARDWARE_ERROR - couldn't decrypt
* N8_MALLOC_FAILED - memory allocation failed
*
* @par Assumptions:
*****************************************************************************/
N8_Status_t N8_DecryptPartial(N8_EncryptObject_t *encryptObject_p,
const N8_Buffer_t *encryptedMessage_p,
const unsigned int encryptedMsgLen,
N8_Buffer_t *message_p,
unsigned int *messageLength_p,
N8_Event_t *event_p)
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *enc_p = NULL;
N8_Buffer_t *cipherText_p = NULL;
uint32_t enc_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int totalLength = 0; /* total length of this message plus
* any residual from previous
* calls. */
unsigned int msgLen = 0; /* the length of the message to be
* encrypted in this call. */
unsigned int nextResidualLength = 0; /* amount leftover from this
* call. */
unsigned int fromThisMessageLength = 0; /* amount of taken from this
* message */
encryptData_t *callBackData_p = NULL;
unsigned int nBytes;
DBG(("N8_DecryptPartial\n"));
do
{
/* verify data length */
ret = verifyInputLength(encryptedMsgLen);
CHECK_RETURN(ret);
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(messageLength_p, ret);
CHECK_OBJECT(encryptedMessage_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
/* sanity check the residual length */
if (encryptObject_p->residualLength >= N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
/* set the value for the returned decrypted message length to zero. it
* will be set finally in the callback at the completion of the call (sync
* or async). */
*messageLength_p = 0;
switch (encryptObject_p->cipher)
{
case N8_CIPHER_DES:
{
totalLength = encryptObject_p->residualLength + encryptedMsgLen;
nextResidualLength = totalLength % N8_DES_BLOCK_LENGTH;
msgLen = totalLength - nextResidualLength;
fromThisMessageLength = encryptedMsgLen - nextResidualLength;
break;
}
case N8_CIPHER_ARC4:
{
fromThisMessageLength = msgLen = encryptedMsgLen;
break;
}
}
/* check to ensure we actually have some message to encrypt this go
* round. */
if (msgLen == 0)
{
/* copy the input to the end of the residual */
memcpy(&encryptObject_p->residual_p[encryptObject_p->residualLength],
encryptedMessage_p,
encryptedMsgLen);
encryptObject_p->residualLength += encryptedMsgLen;
/* if this was an asynchronous call, set the status to finished */
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_EA);
}
break;
}
nBytes = 2 * NEXT_WORD_SIZE(msgLen);
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_DECRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
enc_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
enc_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = enc_p + NEXT_WORD_SIZE(msgLen);
res_a = enc_a + NEXT_WORD_SIZE(msgLen);
cipherText_p = enc_p;
/* copy any previous residual to the m-t-b-e buffer */
if (encryptObject_p->residualLength > 0)
{
memcpy(cipherText_p,
encryptObject_p->residual_p,
encryptObject_p->residualLength);
/* advance the message pointer */
cipherText_p += encryptObject_p->residualLength;
}
/* copy the new message portion to the end of the m-t-b-e buffer */
if (fromThisMessageLength > 0)
{
memcpy(cipherText_p,
encryptedMessage_p,
fromThisMessageLength);
}
/* copy leftovers to the residual */
if (nextResidualLength > 0)
{
/* not necessary, but let's zero out the remaining message buffer */
memset(encryptObject_p->residual_p, 0x0,
N8_DES_BLOCK_LENGTH);
memcpy(encryptObject_p->residual_p,
&encryptedMessage_p[fromThisMessageLength],
nextResidualLength);
}
encryptObject_p->residualLength = nextResidualLength;
/* set the copy back parameters for returning the results to the user.
* the main data is represented by the copy back structures in the request
* and the extra data is in the post-processing data. */
callBackData_p = (encryptData_t *)&req_p->postProcessBuffer;
req_p->postProcessingData_p = (void *) callBackData_p;
callBackData_p->encryptedMsgLen_p = messageLength_p;
callBackData_p->encryptObject_p = encryptObject_p;
if (encryptObject_p->contextHandle.inUse == N8_FALSE)
{
callBackData_p->nextIV_p = (uint32_t *) (enc_p + msgLen -
N8_DES_BLOCK_LENGTH);
}
else
{
callBackData_p->nextIV_p = NULL;
}
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = message_p;
req_p->copyBackSize = msgLen;
ret = cb_ea_decrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
enc_a,
res_a,
msgLen);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
/* free the request */
freeRequest(req_p);
}
DBG(("N8_DecryptPartial - FINISHED\n"));
return ret;
} /* N8_DecryptPartial */
/******************************************************************************
* N8_DecryptEnd
*****************************************************************************/
/** @ingroup crypto
* @brief Decrypts message.
*
* Completes a sequence of partial decrypt operations by encrypting any residual
* message bytes in EncryptObject, returning the resulting MessageLength bytes
* in Message.
* For stream encryption algorithms (ARC4), this function does nothing as there
* will never be residual message bytes in EncryptObject after an
* N8_DecryptPartial operation. MessageLength will be 0 on return and no
* decrypted bytes will be returned in Message.
* For block encryption algorithms (DES), this completes decrypting any message
* bytes remaining in EncryptObject from previous N8_DecryptPartial calls.
* The EncryptObject specifies the decryption algorithm to use, and must have
* been initialized by a call to N8_EncryptInitialize prior to the first call
* to N8_DecryptPartial; it may have been used in one or more N8_DecryptPartial
* calls to process previous parts of the message. If this is the first call made
* with EncryptObject since it was initialized, then the call does nothing; 0 is
* returned in MessageLength and no bytes are written to Message. If previous
* calls to N8_DecryptPartial with EncryptObject were made, then this final
* call to N8_DecryptEnd finishes the computation and returns the final decrypted
* result. Note that for block decryption algorithms, this final decryption must
* result in a total length over all N8_DecryptPartial & N8_DecryptEnd calls that
* is a multiple of the block size. This means that if there are any residual
* message bytes accumulated in the EncryptObject as a result of previous
* N8_DecryptPartial calls that the total length is not a multiple of the block
* size, and an error will result. Thus, a successful call will never result in
* any bytes being decrypted. The actual number of bytes decrypted will always be 0.
* The caller is responsible for ensuring that Message can hold a message of this
* required size.
*
* @param encryptObject_p WR: The encryption object to use, defining
* the encryption algorithm (DES or
* ARC4), the keys, etc. The state in
* EncryptObject will be updated
* appropriately as part of the call. For
* example, an ARC4 object would
* have its key information updated.<BR>
* @param MessageLength RO: The number of bytes decrypted by this call and
* returned in Message. Should always a
* multiple of the block size (8 for DES).
* This value may be 0 and may be as large as
* (EncryptedMessageLength + block size - 1)
* mod (block size). For stream algorithms
* this will always equal MessageLength
* @param message_p WO: The result of decrypting the given
* EncryptedMessage with the specified
* algorithm and keys etc in EncryptObject.
* This includes any pad bytes
* added by the encryption algorithm.
* (DES will pad as necessary, ARC4 never will.)
* Thus Message is always of size MessageLength,
* the caller must ensure that Message is of at
* least this size.<BR>
* @param event_p RW: On input, if null the call is synchronous and no
* event is returned. The operation is complete when
* the call returns. If non-null, then the call is
* asynchronous; an event is returned that can be used
* to determine when the operation completes.
*
*
* @return
* encryptObject_p - The state in encryptObject_p will be updated if necessary as
* part of the call.
* message_p - The decrypted data.
* ret - returns N8_STATUS_OK if successful or Error value.
*
* @par Errors:
* N8_INVALID_OBJECT - packet object is zero, couldn't write to unspecified
* address<BR>
* N8_MALLOC_FAILED - memory allocation failed
* N8_HARDWARE_ERROR - couldn't write to context memory
*
*
* @par Assumptions:
* packetObject_p was initialized and all parameters checked.<BR>
*****************************************************************************/
N8_Status_t N8_DecryptEnd(N8_EncryptObject_t *encryptObject_p,
N8_Buffer_t *message_p,
unsigned int *messageLength_p,
N8_Event_t *event_p )
{
N8_Status_t ret = N8_STATUS_OK; /* the return status: OK or ERROR */
API_Request_t *req_p = NULL; /* request buffer */
N8_Buffer_t *enc_p = NULL;
uint32_t enc_a;
N8_Buffer_t *res_p = NULL;
uint32_t res_a;
unsigned int nBytes;
encryptData_t *callBackData_p = NULL;
DBG(("N8_DecryptEnd\n"));
do
{
/* verify objects */
CHECK_OBJECT(encryptObject_p, ret);
CHECK_OBJECT(message_p, ret);
CHECK_OBJECT(messageLength_p, ret);
CHECK_STRUCTURE(encryptObject_p->structureID, N8_ENCRYPT_STRUCT_ID, ret);
ret = checkCipher(encryptObject_p->cipher);
CHECK_RETURN(ret);
/* sanity check the residual length */
if (encryptObject_p->residualLength >= N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_OBJECT;
break;
}
*messageLength_p = 0;
/* check to see if there is no work to be done. */
if (encryptObject_p->residualLength == 0)
{
/* if this was an asynchronous call, set the status to finished */
if (event_p != NULL)
{
N8_SET_EVENT_FINISHED(event_p, N8_EA);
}
break;
}
if (encryptObject_p->cipher == N8_CIPHER_DES)
{
if (encryptObject_p->residualLength % N8_DES_BLOCK_LENGTH)
{
ret = N8_INVALID_INPUT_SIZE;
break;
}
}
/* create request buffer */
nBytes = 2 * NEXT_WORD_SIZE(encryptObject_p->residualLength);
ret = createEARequestBuffer(&req_p,
encryptObject_p->unitID,
N8_CB_EA_DECRYPT_NUMCMDS,
resultHandler, nBytes);
CHECK_RETURN(ret);
res_a = req_p->qr.physicalAddress + req_p->dataoffset;
res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
enc_a = res_a + NEXT_WORD_SIZE(encryptObject_p->residualLength);
enc_p = res_p + NEXT_WORD_SIZE(encryptObject_p->residualLength);
/* copy the residual message into the kernel memory buffer */
memcpy(enc_p,
encryptObject_p->residual_p,
encryptObject_p->residualLength);
/* set the copy back parameters for returning the results to the user.
* the main data is represented by the copy back structures in the request
* and the extra data is in the post-processing data. */
callBackData_p = (encryptData_t *)&req_p->postProcessBuffer;
req_p->postProcessingData_p = (void *) callBackData_p;
callBackData_p->encryptedMsgLen_p = messageLength_p;
callBackData_p->encryptObject_p = encryptObject_p;
callBackData_p->nextIV_p = NULL;
req_p->copyBackSize = encryptObject_p->residualLength;
req_p->copyBackFrom_p = res_p;
req_p->copyBackTo_p = message_p;
encryptObject_p->residualLength = 0;
ret = cb_ea_decrypt(req_p,
req_p->EA_CommandBlock_ptr,
encryptObject_p,
enc_a,
res_a,
encryptObject_p->residualLength);
CHECK_RETURN(ret);
QUEUE_AND_CHECK(event_p, req_p, ret);
HANDLE_EVENT(event_p, req_p, ret);
} while (FALSE);
/*
* Deallocate the request if we arrived from an error condition.
*/
if (ret != N8_STATUS_OK)
{
freeRequest(req_p);
}
DBG(("N8_DecryptEnd - FINISHED\n"));
return ret;
} /* N8_DecryptEnd */