Пример #1
0
/** @ingroup ipsec_packet
 * @brief Decrypt and verify an entire IPSec record.
 *
 * Decrypt and verify an entire IPSec record. PacketObject is a packet object 
 * previously initialized by a call to N8_PacketInitialize specifying IPSec 
 * as the packet protocol to use. PacketObject provides encryption and 
 * authentication information to be used in the call. The decryption algorithm 
 * can only be DES as specified when PacketObject was initialized. The 
 * authentication algorithm can be HMAC-MD5-96 or HMAC-SHA-1-96 as specified 
 * when PacketObject was initialized. Thus, two combinations of 
 * decryption/verification can be performed: DES/HMAC-MD5-96 and DES/HMAC-SHA-1-96. 
 * The SPI parameter specifies the IPSec Security Parameter Index of the message. 
 * The SPI is used along with the sequence number and the DES initialization 
 * vector (taken from PacketObject) in the authentication computation. The 
 * message contents of the encrypted and authenticated IPSec packet is given 
 * in EncryptedData; its length in bytes must be specified in encryptedPacketLength. 
 * Note that EncryptedData must end with the unencrypted12-byte authentication 
 * value as required by the IPSec specification. The byte length of EncryptedData 
 * including the 12 byte authentication value is specified in encryptedPacketLength. 
 * encryptedPacketLength must be at least 20 (i.e., EncryptedData must consist of 
 * at least one DES block to be decrypted plus the mandatory 12 byte 
 * authentication value), and must be of the form 12 + n*8 for n > 0. The decrypted 
 * EncryptedData is returned in Result, including the decrypted  data followed by 
 * the 12 bytes of authentication data. Result is always encryptedPacketLength 
 * bytes in length. The caller is responsible for ensuring that Result is at  
 * least this size.  This call also calculates the authentication value on the 
 * EncryptedData and compares this calculated value to the value at the end of 
 * EncryptedData. If these two values are equal, the verification succeeds and 
 * True is returned in Verify, otherwise False is returned in Verify.
 *  
 *
 * @param packetObject_p RW:    The  object denoting the decryption and 
 *                              verification computation to be done. PacketObject
 *                              must have been initialized for use with IPSec. 
 *                              The state in PacketObject will be updated if 
 *                              necessary as part of the call. <BR> 
 * @param encryptedPacket_p RO:   The message portion / contents of the IPSec packet.<BR>
 * @param encryptedPacketLength RO:  The length of EncryptedData, in bytes, 
 *                              from 20 bytes - 18 KBytes inclusive. A length 
 *                              less than 20 or not of the form 12+n*8 is illegal
 *                              and results in an error.<BR>
 * @param Verify         WO:    Returned as True if the computed authentication 
 *                              value on EncryptedData matches the authentication 
 *                              value contained at the end of EncryptedData; 
 *                              otherwise False is returned. If Verify is False, 
 *                              the contents of Result may be gibberish and/or 
 *                              have been altered.<BR>
 * @param result_p       WO:    The decrypted / authenticated data, complete 
 *                              with authentication data. Result must be of 
 *                              sufficient size to hold the decrypted & 
 *                              authenticated message; its size must be at least 
 *                              EncryptedDataLeng.<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 
 *    packetObject_p - The state in PacketObject will be updated if necessary as 
 *                     part of the call.
 *    result_p       - The encrypted / authenticated data, complete with 
 *                     authentication 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_INVALID_INPUT_SIZE - The value of packetLength is < 20 or > 18 KBytes or 
 *                          is not of the form 12 + n*8; no operation is 
 *                          performed and no result is  returned.
 *    N8_UNIMPLEMENTED_FUNCTION - not supported protocol configuration requested
 *    N8_HARDWARE_ERROR   - couldn't write to context memory
 *   
 *
 * @par Assumptions:
 *      packetObject_p was initialized and all parameters checked.
 *****************************************************************************/
N8_Status_t N8_IPSecDecryptVerify( N8_Packet_t   *packetObject_p, 
                                   N8_IPSecPacket_t *encryptedPacket_p, 
                                   int               encryptedPacketLength,
                                   N8_Buffer_t      *computedHMAC_p,
                                   N8_Boolean_t     *verify_p,
                                   N8_IPSecPacket_t *result_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 */
   EA_CMD_BLOCK_t *next_cb_p = NULL;
   int dataLength;
   unsigned long pack_a;
   N8_Buffer_t *pack_p = NULL;
   unsigned long res_a;
   N8_Buffer_t *res_p = NULL;
   N8_Buffer_t *ctx_p = NULL;
   uint32_t     ctx_a;
   int nBytes;
   int numCommands;
   int numCtxBytes = 0;
   ipsecVerifyPostDataStruct_t *postData_p = NULL;
   n8_ctxLoadFcn_t    ctxLoadFcn;

   DBG(("N8_IPSecDecryptVerify\n"));
   do
   {
      *verify_p = N8_FALSE;
      /* verify data length */
      if ((encryptedPacketLength < IPSEC_DECRYPTED_DATA_LENGTH_MIN) ||
          (encryptedPacketLength > IPSEC_DATA_LENGTH_MAX))
      {
         DBG(("Data length is out of range\n"));
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }
    
      if ((encryptedPacketLength - IPSEC_AUTHENTICATION_DATA_LENGTH) % IPSEC_DATA_BLOCK_SIZE)
      {
         DBG(("Data length is not a multiple of %d\n", IPSEC_DATA_BLOCK_SIZE));
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }
      /* verify packet object */
      CHECK_OBJECT(packetObject_p, ret);
      CHECK_STRUCTURE(packetObject_p->structureID, N8_PACKET_STRUCT_ID, ret);
      /* verify encrypted data object */
      CHECK_OBJECT(encryptedPacket_p, ret);
      /* verify result object */
      CHECK_OBJECT(result_p, ret);
#ifdef NO_MAC_COPYBACK
      CHECK_OBJECT(computedHMAC_p, ret);
#endif 

      dataLength = encryptedPacketLength - IPSEC_PACKET_HEADER_LENGTH;

      numCommands = N8_CB_EA_IPSECDECRYPTVERIFY_NUMCMDS;
      if (packetObject_p->contextLoadNeeded == N8_TRUE)
      {
         numCommands += packetObject_p->ctxLoadCmds;
         numCtxBytes = NEXT_WORD_SIZE(sizeof(EA_ARC4_CTX));
      }

      /* compute the space needed for the chip to place the result */
      nBytes = NEXT_WORD_SIZE(HMAC_LENGTH) + numCtxBytes; /* context to load */
      if (packetObject_p->mode == N8_PACKETMEMORY_NONE)
      {
         nBytes += NEXT_WORD_SIZE(dataLength * 2);
      }

      /* create request buffer */
      ret = createEARequestBuffer(&req_p,
                                  packetObject_p->unitID,
                                  numCommands,
                                  resultHandlerIPSecVerify,
                                  nBytes);
      CHECK_RETURN(ret);

      req_p->copyBackCommandBlock = N8_TRUE;

      /* Compute the addresses for the context. */
      ctx_a = req_p->qr.physicalAddress + req_p->dataoffset;
      ctx_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);

      /* Compute the addresses for the packet and result buffer. */
      if (packetObject_p->mode == N8_PACKETMEMORY_NONE)
      {
         /* The data must be copied to this kernel before the chip can operate  */
         /* on it, compute the addresses within the kernel buffer and copy in   */
         /* the packet.                                                         */
         pack_a = ctx_a + numCtxBytes;
         pack_p = ctx_p + numCtxBytes;

         res_a = pack_a + NEXT_WORD_SIZE(dataLength);
         res_p = pack_p + NEXT_WORD_SIZE(dataLength);

         memcpy(pack_p, encryptedPacket_p + IPSEC_DATA_OFFSET, dataLength); 
      
      }
      else
      {
         /* The chip can access the data directly, compute the */
         /* physical addresses of the packet & result buffer.  */
         pack_a = N8_VirtToPhys(encryptedPacket_p + IPSEC_DATA_OFFSET);
         res_a =  N8_VirtToPhys(result_p + IPSEC_DATA_OFFSET);
      }

      next_cb_p = req_p->EA_CommandBlock_ptr;

      /* generate the command blocks necessary to load the context, if required */
      if (packetObject_p->contextLoadNeeded == N8_TRUE)
      {
         /* Generate the command blocks for the Context Load */
         ctxLoadFcn = (n8_ctxLoadFcn_t)packetObject_p->ctxLoadFcn;
         ret = ctxLoadFcn(req_p,
                          next_cb_p,
                          packetObject_p,
                          &packetObject_p->cipherInfo,
                          packetObject_p->packetHashAlgorithm,
                          ctx_p,
                          ctx_a,
                          &next_cb_p);
         CHECK_RETURN(ret);

         packetObject_p->contextLoadNeeded = N8_FALSE;
      }

      memcpy(&packetObject_p->cipherInfo.IV[0], encryptedPacket_p+8,8);
      packetObject_p->cipherInfo.key.IPsecKeyDES.sequence_number =
         IPSEC_EXTRACT_SEQUENCE_NIMBER(encryptedPacket_p);

      cb_ea_IPsec(next_cb_p,
                  packetObject_p,
                  pack_a, 
                  res_a,
                  dataLength,
                  IPSEC_EXTRACT_SPI(encryptedPacket_p),
                  packetObject_p->decOpCode);

      postData_p = (ipsecVerifyPostDataStruct_t *)req_p->postProcessBuffer;
      postData_p->computedHMAC_p = computedHMAC_p;
      postData_p->data_p = result_p + IPSEC_DATA_OFFSET;
      postData_p->res_p = res_p;
      postData_p->dataLength = dataLength;
      postData_p->verify_p = verify_p;
      postData_p->hashAlgorithm = packetObject_p->packetHashAlgorithm;

      /* setup post processing buffer pointer */
      req_p->postProcessingData_p = (void *) postData_p;

      /* decrypt data */
      QUEUE_AND_CHECK(event_p, req_p, ret)
      HANDLE_EVENT(event_p, req_p, ret);
      /* compare authentication values */

      memcpy(result_p, encryptedPacket_p, IPSEC_PACKET_HEADER_LENGTH); 
      if (*verify_p == N8_TRUE)
      {
         packetObject_p->cipherInfo.key.IPsecKeyDES.sequence_number =
            IPSEC_EXTRACT_SEQUENCE_NIMBER(encryptedPacket_p);
         memcpy(&packetObject_p->cipherInfo.IV[0],
                encryptedPacket_p+IPSEC_IV_OFFSET,
                N8_DES_KEY_LENGTH);

      }

   } while (FALSE);

   if (ret != N8_STATUS_OK)
   {
      freeRequest(req_p);
   }
   DBG(("N8_IPSecDecryptVerify - FINISHED\n"));
   return ret;
} /* N8_IPSecDecryptVerify */
Пример #2
0
/** @ingroup ipsec_packet
 * @brief Encrypt and authenticate an entire IPSec record.
 *
 * Encrypt and authenticate an entire IPSec record.  PacketObject is a packet 
 * object previously initialized by a call to N8_PacketInitialize specifying 
 * IPSec as the packet protocol to use. PacketObject provides encryption and 
 * authentication information to be used in the call. The decryption algorithm 
 * can only be DES as specified when PacketObject was initialized. The 
 * authentication algorithm can be HMAC-MD5-96 or HMACSHA-1-96 as specified 
 * when PacketObject was initialized. Thus, two combinations of 
 * encryption/authentication can be performed: DES/HMAC-MD5-96 and 
 * DES/HMAC-SHA-1-96. The SPI parameter specifies the IPSec Security Parameter 
 * Index of the message. The SPI is used along with the sequence number and 
 * the DES initialization vector (taken from information specified in the
 * PacketObject) in the authentication computation. The message contents of the
 * IPSec packet is given in Data; its length in bytes must be specified in
 * packetLength. Note that Data must include all of the information to be
 * encrypted according to the IPSec specification; this includes the TCP and
 * IP headers if present (the IP header is only present in tunnel mode) and must
 * also include the terminating pad, pad length and next header fields.
 * The byte length of Data is specified in packetLength and must also include all
 * of these fields. packetLength must be a multiple of 8. The fully encrypted and
 * authenticated Data is returned in Result, including the encrypted  data
 * followed by the HMAC-MD5-96 or HMAC-SHA-1-96 authentication value. 
 *
 * @param packetObject_p RW:    The  object denoting the decryption and
 *                              verification computation to be done.  PacketObject
 *                              must have been initialized for use with IPSec. 
 *                              The state in PacketObject will be updated if 
 *                              necessary as part of the call. <BR> 
 * @param packet_p       RO:    The ESP packet beginning with the Security 
 *                              Parameter Index,  Sequence Number and data payload
 *                              including DES initialization vector and ending 
 *                              with the pad, pad length, and next header fields 
 *                              as specified by the IPSec protocol.<BR>
 * @param packetLength     RO:    The length of Data, in bytes, from 8 bytes - 17 KBytes 
 *                              inclusive. A length < 8 or not a multiple of 8 is 
 *                              illegal and results in an error.<BR>
 * @param result_p       WO:    The encrypted / authenticated data, complete with 
 *                              authentication data. Result must be of sufficient 
 *                              size to hold the fully encrypted & authenticated 
 *                              message; its size must be at least packetLength +
 *                              IPSEC_AUTHENTICATION_DATA_LENGTH  
 *                              (hash size for all hash algorithms).<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 
 *    packetObject_p - The state in PacketObject will be updated if necessary as 
 *                     part of the call.
 *    result_p       - The encrypted / authenticated data, complete with 
 *                     authentication 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_INVALID_INPUT_SIZE - The value of packetLength is less then 8 or bigger 
 *                            then 17 KBytes or is not a multiple of 8.
 *    N8_UNIMPLEMENTED_FUNCTION - not supported protocol configuration requested
 *    N8_HARDWARE_ERROR   - couldn't write to context memory
 *   
 *
 * @par Assumptions:
 *      packetObject_p was initialized and all parameters checked.<BR>
 *      For IPSec, the authentication data is always
 *      12 (IPSEC_AUTHENTICATION_DATA_LENGTH) bytes (the 12 most  
 *      significant bytes of the standard 16 byte MD5 or 20 byte SHA-1 value) and
 *      is not encrypted. Result is always packetLength + 12 bytes in length. 
 *      The caller is responsible for ensuring that Result is this size.
 *****************************************************************************/
N8_Status_t N8_IPSecEncryptAuthenticate(N8_Packet_t       *packetObject_p, 
                                        N8_IPSecPacket_t  *packet_p, 
                                        int                packetLength,  
                                        N8_IPSecPacket_t  *result_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 */
   EA_CMD_BLOCK_t *next_cb_p = NULL;
   int dataLength;
   unsigned long pack_a;
   N8_Buffer_t *pack_p = NULL;
   unsigned long res_a;
   N8_Buffer_t *res_p = NULL;
   N8_Buffer_t *ctx_p = NULL;
   uint32_t     ctx_a;
   int nBytes;
   int numCommands;
   int numCtxBytes = 0;
   void *callbackFcn = NULL;
   n8_ctxLoadFcn_t    ctxLoadFcn;
   DBG(("N8_IPSecEncryptAuthenticate\n"));     
   do
   {
      /* verify data length */
      if ((packetLength < IPSEC_DATA_LENGTH_MIN) || (packetLength > IPSEC_DATA_LENGTH_MAX))
      {
         DBG(("Data length is out of range\n"));
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      if (packetLength % IPSEC_DATA_BLOCK_SIZE)
      {
         DBG(("Data length is not a multiple of %d\n", IPSEC_DATA_BLOCK_SIZE));
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      /* verify packet object */
      CHECK_OBJECT(packetObject_p, ret);
      CHECK_STRUCTURE(packetObject_p->structureID, N8_PACKET_STRUCT_ID, ret);
      /* verify data object */
      CHECK_OBJECT(packet_p, ret);
      /* verify result object */
      CHECK_OBJECT(result_p, ret);

      dataLength = packetLength - IPSEC_PACKET_HEADER_LENGTH;
      numCommands = N8_CB_EA_IPSECENCRYPTAUTHENTICATE_NUMCMDS;
      if (packetObject_p->contextLoadNeeded == N8_TRUE)
      {
         numCommands += packetObject_p->ctxLoadCmds;
         numCtxBytes = NEXT_WORD_SIZE(EA_CTX_Record_Byte_Length);
      }

      /* compute the space needed for the size of context load, if required */ 
      nBytes = NEXT_WORD_SIZE(HMAC_LENGTH) + numCtxBytes;              

      /* If the data must be copied to a kernel before the chip can operate  */
      /* on it, compute the additional space required and setup the callback */
      /* function to copy the result once the operation has completed.       */
      if (packetObject_p->mode == N8_PACKETMEMORY_NONE)
      {
         nBytes += NEXT_WORD_SIZE(dataLength) + /* packet data length pack_p  */
                   NEXT_WORD_SIZE(packetLength);/* result packet length res_p */
         callbackFcn = resultHandlerGeneric;
      }

      /* create request buffer */
      ret = createEARequestBuffer(&req_p,
                                  packetObject_p->unitID,
                                  numCommands,
                                  callbackFcn,
                                  nBytes);
      CHECK_RETURN(ret);

      /* Compute the context memory pointers. */
      ctx_a = req_p->qr.physicalAddress + req_p->dataoffset;
      ctx_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);

      /* Compute the addresses for the packet and result buffer. */
      if (packetObject_p->mode == N8_PACKETMEMORY_NONE)
      {
         /* The data must be copied to this kernel before the chip can operate  */
         /* on it, compute the addresses within the kernel buffer and copy in   */
         /* the packet.                                                         */
         pack_a = ctx_a + numCtxBytes;
         pack_p = ctx_p + numCtxBytes;

         res_a = pack_a + NEXT_WORD_SIZE(dataLength);
         res_p = pack_p + NEXT_WORD_SIZE(dataLength);

         memcpy(pack_p, &packet_p[IPSEC_DATA_OFFSET], dataLength);
      
      }
      else
      {
         /* The chip can access the data directly, compute the */
         /* physical addresses of the packet & result buffer.  */
         pack_a = N8_VirtToPhys(&packet_p[IPSEC_DATA_OFFSET]);
         res_a =  N8_VirtToPhys(&result_p[IPSEC_DATA_OFFSET]);
      }


      next_cb_p = req_p->EA_CommandBlock_ptr;
      
      memcpy(result_p, packet_p, IPSEC_PACKET_HEADER_LENGTH);

      packetObject_p->cipherInfo.key.IPsecKeyDES.sequence_number =
         IPSEC_EXTRACT_SEQUENCE_NIMBER(packet_p);

      /* generate the command blocks necessary to load the context, if required */
      if (packetObject_p->contextLoadNeeded == N8_TRUE)
      {
         /* Generate the command blocks for the Context Load */
         ctxLoadFcn = (n8_ctxLoadFcn_t)packetObject_p->ctxLoadFcn;
         ret = ctxLoadFcn(req_p,
                          next_cb_p,
                          packetObject_p,
                          &packetObject_p->cipherInfo,
                          packetObject_p->packetHashAlgorithm,
                          ctx_p,
                          ctx_a,
                          &next_cb_p);
         CHECK_RETURN(ret);

         packetObject_p->contextLoadNeeded = N8_FALSE;
      }

      memcpy(&packetObject_p->cipherInfo.IV[0], packet_p+IPSEC_IV_OFFSET,
             N8_DES_KEY_LENGTH); 

      cb_ea_IPsec(next_cb_p,
                  packetObject_p,
                  pack_a, 
                  res_a,
                  dataLength,
                  IPSEC_EXTRACT_SPI(packet_p),
                  packetObject_p->encOpCode);


      req_p->copyBackTo_p   = result_p + IPSEC_DATA_OFFSET;
      req_p->copyBackFrom_p = res_p;
      req_p->copyBackSize   = dataLength + HMAC_LENGTH;

      QUEUE_AND_CHECK(event_p, req_p, ret)
      HANDLE_EVENT(event_p, req_p, ret);
   } while (FALSE);

   if (ret != N8_STATUS_OK)
   {
      freeRequest(req_p);
   }
   DBG(("N8_IPSecEncryptAuthenticate - FINISHED\n"));
   return ret;
} /* N8_IPSecEncryptAuthenticate */
Пример #3
0
/** @ingroup dh
 * @brief Computes a Diffie-Hellman exponentiation as required to compute
 * Diffie-Hellman public values from a secret value and a Diffie-Hellman
 * key (or group).  
 *
 * Description:
 * The key or group is specified by DHKeyObject which must have been
 * previously initialized with the appropriate group generator g, modulus p,
 * and modulus size by a call to N8_DHInitializeKey. The DH secret value
 * used as the exponent is specified in XValue, and must be of the same
 * size as the modulus size in DHKeyObject. GValue specifies the value
 * to be exponentiated and must also be the same size as the modulus. 
 * GValue may be null, in which case the generator g from DHKeyObject is
 * used as the GValue. The result of the calculation is returned in
 * GXValue and is the same size as the modulus.  The value computed is
 * GXValue = ( GValue ** XValue ) mod p. Thus this routine computes a
 * modular exponentiation.
 * This call can be used to compute from a private x value the value
 * X = g**x mod p that is the public X value sent to the other respondent
 * in a Diffie-Hellman exchange.  (In this case the GValue is set to null,
 * and x is used for XValue.)  When the respondent's corresponding Y value
 * (Y = g**y mod p, y = the respondent's private y) is received, this call
 * can then be used to compute the common shared secret XY = g**(xy) = YX by
 * using X for the GValue and the received Y as the XValue. 
 * 
 * Parameters:
 * @param key_p         RO:     The caller supplied DHKeyObject containing
 *                              the appropriate Diffie-Hellman values
 *                              and pre-computed DH constants.
 * @param gValue        RO:     The value to be raised to a power. 
 *                              If null, then the generator g value from
 *                              DHKeyObject is used. GValue must be the
 *                              same size as the modulus p from DHKeyObject.
 * @param xValue        RO:     The exponent. Must be supplied. XValue
 *                              must be the same size as the
 *                              modulus p from DHKeyObject
 * @param gxValue       WO:     GValue raised to the XValue power, mod p.  
 *                              GXValue will be the same
 *                              size as the modulus p from DHKeyObject.
 * @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 
 *    ret - returns N8_STATUS_OK if successful or Error value.
 *
 * @par Errors:
 *          N8_INVALID_OBJECT   -   context request object is NULL<BR>
 *          N8_INVALID_KEY      -   The DHKeyObject is not a valid key
 *                                  object 
 *                                  for this operation.
 *
 * @par Assumptions:
 **********************************************************************/
N8_Status_t N8_DHCompute(N8_DH_KeyObject_t  *key_p,
                         N8_Buffer_t        *gValue_p,
                         N8_Buffer_t        *xValue_p,
                         N8_Buffer_t        *gxValue_p,
                         N8_Event_t         *event_p)
{
   N8_Status_t    ret = N8_STATUS_OK;
   API_Request_t *req_p = NULL;
   unsigned int   nBytes;

   N8_Buffer_t    *g_p;
   N8_Buffer_t    *x_p;
   N8_Buffer_t    *res_p;

   uint32_t        g_a;
   uint32_t        x_a;
   uint32_t        res_a;

   unsigned int    g_len;
   unsigned int    x_len;
   unsigned int    res_len;
   
   N8_Boolean_t       useShortCommandBlock = N8_FALSE;
   do
   {
      ret = N8_preamble();
      CHECK_RETURN(ret);
      
      CHECK_OBJECT(key_p, ret);
      CHECK_OBJECT(xValue_p, ret);
      CHECK_OBJECT(gxValue_p, ret);
      CHECK_STRUCTURE(key_p->structureID, N8_DH_STRUCT_ID, ret);

      /* compute the lengths of all of the parameters as a convenience */
      g_len      = key_p->modulusLength;
      x_len      = key_p->modulusLength;
      res_len    = key_p->modulusLength;

      nBytes = (NEXT_WORD_SIZE(x_len) +
                NEXT_WORD_SIZE(res_len));

      /* gValue_p is allowed to be NULL.  if so, use the g from the key object. */
      if (gValue_p == NULL)
      {
         useShortCommandBlock = N8_TRUE;

         /* allocate user-space buffer */
         ret = createPKRequestBuffer(&req_p,
                                     key_p->unitID,
                                     N8_CB_COMPUTE_G_XMODP_NUMCMDS_SHORT,
                                     resultHandlerGeneric, nBytes); 
      }
      else
      {
         nBytes += NEXT_WORD_SIZE(g_len);

         /* allocate user-space buffer */
         ret = createPKRequestBuffer(&req_p,
                                     key_p->unitID,
                                     N8_CB_COMPUTE_G_XMODP_NUMCMDS_LONG,
                                     resultHandlerGeneric, nBytes); 
      }

      CHECK_RETURN(ret);

      /* set up the addressing for the pointers */
      x_p =  (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
      x_a =                  req_p->qr.physicalAddress + req_p->dataoffset;
      res_p    = x_p + NEXT_WORD_SIZE(x_len);
      res_a    = x_a + NEXT_WORD_SIZE(x_len);

      memcpy(x_p, xValue_p, x_len);
      
      req_p->copyBackSize = x_len;
      req_p->copyBackFrom_p = res_p;
      req_p->copyBackTo_p = gxValue_p;

      if (useShortCommandBlock == N8_TRUE)
      {
         ret = cb_computeGXmodp_short(req_p,
                                      x_a,
                                      key_p->p_a,
                                      key_p->cp_a,
                                      key_p->gRmodP_a,
                                      res_a,
                                      key_p->modulusLength,
                                      req_p->PK_CommandBlock_ptr);
      }
      else
      {
         /* gValue_p is not NULL, copy the user-space */
         /* data into our kernel space buffers        */
         g_p    = res_p + NEXT_WORD_SIZE(res_len);
         g_a    = res_a + NEXT_WORD_SIZE(res_len);
         memcpy(g_p, gValue_p, g_len);

         ret = cb_computeGXmodp_long(req_p,
                                     g_a,
                                     x_a,
                                     key_p->p_a,
                                     key_p->cp_a,
                                     key_p->RmodP_a,
                                     res_a,
                                     key_p->modulusLength,
                                     req_p->PK_CommandBlock_ptr);
      }

      CHECK_RETURN(ret);

      QUEUE_AND_CHECK(event_p, req_p, ret);
      HANDLE_EVENT(event_p, req_p, ret);

   } while (FALSE);
   DBG(("DH computed\n"));

   /*
    * Deallocate the request if we arrived from an error condition.
    */
   if (ret != N8_STATUS_OK)
   {
      freeRequest(req_p);
   }
  
   return ret;
} /* N8_DHCompute */
Пример #4
0
/** @ingroup dh
 * @brief Initializes the specified DHKeyObject so that it can be used
 * in Diffie-Hellman operations. The KeyMaterial object (structure)
 * contains the appropriate group generator g, modulus p,  and modulus size.
 *
 * Description:
 * This call pre-computes various constant values from the supplied
 * parameters and initializes DHKeyObject with these values.  By
 * pre-computing these values, Diffie-Hellman computations can be done
 * faster than if these constants must be computed on each operation. 
 * Once a DHKeyObject has been initialized, it can be used repeatedly
 * in multiple DH operations. It does not ever need to be re-initialized,
 * unless the actual key value(s) change (i.e., unless the key itself
 * changes).
 * 
 * @param key_p         RW: The caller allocated DHKeyObject, initialized
 *                          by this call with the appropriate DH key 
 *                          material and pre-computed DH constants 
 *                          depending on the value of the KeyType parameter
 * @param material_p    RO: Pointer to the key material to use in initializing
 *                          DHKeyObject. 
 *
 * @return 
 *    ret - returns N8_STATUS_OK if successful or Error value.
 *
 * @par Errors:
 *          N8_INVALID_OBJECT   -   DH key or key material object is NULL<BR>
 *
 * @par Assumptions:
 *      None.
 **********************************************************************/
N8_Status_t N8_DHInitializeKey(N8_DH_KeyObject_t     *key_p,
                               N8_DH_KeyMaterial_t   *material_p,
                               N8_Event_t            *event_p)
{
   N8_Status_t     ret = N8_STATUS_OK;
   int             nBytes;
   API_Request_t  *req_p = NULL;

   do
   {
      ret = N8_preamble();
      CHECK_RETURN(ret);

      CHECK_OBJECT(key_p, ret);
      CHECK_OBJECT(material_p, ret);

      key_p->unitID = material_p->unitID;

      /* check the modulus size to ensure it is 1 <= ms <= 512.  return
       * N8_INVALID_SIZE if not. */
      if (material_p->modulusSize < N8_DH_MIN_MODULUS_SIZE ||
          material_p->modulusSize > N8_DH_MAX_MODULUS_SIZE)
      {
         ret = N8_INVALID_KEY_SIZE;
         break;
      }

      /* Allocate space for the initialized key.  we must compute 'R mod p' and 'cp'
       * for use in subsequent DHComputes. */
      key_p->modulusLength = material_p->modulusSize;
      nBytes = (NEXT_WORD_SIZE(key_p->modulusLength) +    /* g */
                NEXT_WORD_SIZE(key_p->modulusLength) +    /* p */
                NEXT_WORD_SIZE(key_p->modulusLength) +    /* R mod p */
                NEXT_WORD_SIZE(key_p->modulusLength) +    /* g R mod p */
                NEXT_WORD_SIZE(PK_DH_CP_Byte_Length));/* cp */

      /* Allocate a kernel buffer to hold data accessed by the NSP2000 */
      key_p->kmem_p = N8_KMALLOC_PK(nBytes);
      CHECK_OBJECT(key_p->kmem_p, ret);
      memset(key_p->kmem_p->VirtualAddress, 0, nBytes);

      /* Compute virtual addresses within the kernel buffer */
      key_p->g        = (N8_Buffer_t *) key_p->kmem_p->VirtualAddress;
      key_p->p        = key_p->g        + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->R_mod_p  = key_p->p        + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->gR_mod_p = key_p->R_mod_p  + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->cp       = key_p->gR_mod_p + NEXT_WORD_SIZE(key_p->modulusLength);

      /* Compute physical addresses within the kernel buffer */
      key_p->g_a      = key_p->kmem_p->PhysicalAddress;
      key_p->p_a      = key_p->g_a      + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->RmodP_a  = key_p->p_a      + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->gRmodP_a = key_p->RmodP_a  + NEXT_WORD_SIZE(key_p->modulusLength);
      key_p->cp_a     = key_p->gRmodP_a + NEXT_WORD_SIZE(key_p->modulusLength);

      /* Set up the memory for p and g and copy from the key material */
      memcpy(key_p->p, material_p->p, material_p->modulusSize);
      memcpy(key_p->g, material_p->g, material_p->modulusSize);

      /* Set the structure ID */
      key_p->structureID = N8_DH_STRUCT_ID;

      /* allocate user-space command buffer */
      ret = createPKRequestBuffer(&req_p, key_p->unitID,
                                  N8_CB_PRECOMPUTE_DHVALUES_NUMCMDS,
                                  NULL, 0);

      CHECK_RETURN(ret);

      ret = cb_precomputeDHValues(req_p, key_p->g_a, key_p->p_a, 
		                  key_p->RmodP_a, key_p->gRmodP_a, key_p->cp_a,
                                  key_p->modulusLength,
                                  req_p->PK_CommandBlock_ptr,
                                  key_p->unitID);
      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);
      /* free the key also, if it has been allocated */
      if (key_p != NULL)
      {
         /* ignore the return code as we want to return the original anyway */
         (void) N8_DHFreeKey(key_p);
      }
   }
  
   return ret;
} /* N8_DHInitializeKey */
Пример #5
0
/** @ingroup n8_ssltls
 * @brief Decrypt and verify an entire SSL or TLS message.
 *
 * Decrypt an verify a SSL or TLS message.  If the verification fails, it will
 * be noted in the return value.
 *
 *  @param packetObj_p         RW:  Pre-initialized packet object.
 *  @param packet_p            RO:  A complete, encrypted SSL or TLS packet
 *                                  including the header.
 *  @param computedMAC_p       RW:  Pointer to result space for the MAC
 *                                  computation output.
 *  @param verify_p:           WO:  Pointer to a verify flag.  If the MAC's
 *                                  match, the verify flag will be set to N8_TRUE.
 *  @param result_p            RW:  Pointer to result space for the decrypted
 *                                  result. 
 *  @param request             RW:  Kernel request buffer used when mode =
 *                                  N8_PACKETMEMORY_REQUEST.
 *  @param event_p             RW:  Asynchronous event pointer.
 *
 * @par Externals
 *    None
 *
 * @return
 *    Error condition if raised.
 *
 * @par Errors
 *    N8_MALLOC_FAILED<br>
 *    N8_INVALID_INPUT_SIZE - the value in the packet header is too large or too
 *                            small.<br>
 *    N8_INCONSISTENT       - the version number in the packet header does not
 *                            match the designation in the packet object.<br>
 *    N8_INVALID_OBJECT     - packet object is not a valid object initialized
 *                            for SSL or TLS<br>
 *    N8_INVALID_VALUE      - the value of the type field in the packet header
 *                            is not one of the legal values for SSL or TLS.<br>
 *
 * @par Assumptions
 *    The result_p and computedMAC_p pointers refer to pre-allocated space of
 * sufficient size.  The calling program retains responsibility for freeing this
 * memory. 
 *****************************************************************************/
N8_Status_t 
N8_SSLTLSDecryptVerifyMemory(N8_Packet_t             *packetObj_p,
                             const N8_SSLTLSPacket_t *packet_p,
                             N8_Buffer_t             *computedMAC_p,
                             N8_Boolean_t            *verify_p,
                             N8_SSLTLSPacket_t       *result_p,
                             N8_RequestHandle_t       request,
                             N8_Event_t              *event_p)
{

   N8_Status_t ret = N8_STATUS_OK;
   API_Request_t *req_p = NULL;
   EA_CMD_BLOCK_t *next_cb_p = NULL;
   N8_SSL_Post_Decrypt_Data_t *postData_p = NULL;
   uint16_t length;
   short int encLen;
   int nBytes;
   N8_Buffer_t *res_p = NULL;
   uint32_t     res_a;
   N8_Buffer_t *input_p = NULL;
   uint32_t     input_a;
   N8_Buffer_t *ctx_p = NULL;
   uint32_t     ctx_a = 0;
   unsigned int numCommands = 0;
   unsigned int numCtxBytes = 0;
   N8_MemoryHandle_t *request_p;
   n8_ctxLoadFcn_t  ctxLoadFcn;
   n8_SSLTLSFcn_t   decryptFcn;
   do
   {
      /* ensure none of the pointers we're given are null */
      CHECK_OBJECT(packetObj_p, ret);
      CHECK_STRUCTURE(packetObj_p->structureID, N8_PACKET_STRUCT_ID, ret);
      CHECK_OBJECT(packet_p, ret);
#ifdef N8_MAC_COPYBACK
      CHECK_OBJECT(computedMAC_p, ret);
#endif
      CHECK_OBJECT(result_p, ret);

      request_p = (N8_MemoryHandle_t *) request;

      /* Check that request_p & mode are consistent */
      if (request_p == NULL)
      {
         if (packetObj_p->mode != N8_PACKETMEMORY_NONE)
         {
            /* No request_p means mode should be "none" */
            ret = N8_INCONSISTENT;
            break;
         }
      }
      else if (packetObj_p->mode != N8_PACKETMEMORY_REQUEST)
      {
         /* They said they would give us a request and they didn't */
         ret = N8_INCONSISTENT;
         break;
      }

      /*
       * convert the length from network order to host order
       */
      length  = ntohs(*((uint16_t *) &packet_p[SSLTLS_LENGTH_OFFSET]));

      /* verify the length is not greater than the max */
      if (length > N8_SSLTLS_MAX_DATA_SIZE_DECRYPT)
      {
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      numCommands = packetObj_p->decCommands;
      if (packetObj_p->contextLoadNeeded == N8_TRUE)
      {
         numCommands += packetObj_p->ctxLoadCmds;
         numCtxBytes = NEXT_WORD_SIZE(sizeof(EA_ARC4_CTX));
      }

      encLen = N8_ComputeEncryptedLength(length, 
                                         packetObj_p->hashPacket.hashSize,
                                         packetObj_p->packetCipher);

      /* kernel space is needed for the data portion of the incoming packet plus
       * the hash and padding.  the exact amount is needed for the return
       * packet. */
      /* Note that if the in packet is NULL, we don't check the out packet */
      if (request_p == NULL)
      {
         nBytes = NEXT_WORD_SIZE(length) * 2 + numCtxBytes;
         /* create an API request buffer */
         ret = createEARequestBuffer(&req_p,
                                     packetObj_p->unitID,
                                     numCommands,
                                     resultHandlerSSLTLSDecrypt,
                                     nBytes); 
         CHECK_RETURN(ret);
         /* User has not provided any buffers */
         res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
         res_a = req_p->qr.physicalAddress + req_p->dataoffset;

         input_p = res_p + NEXT_WORD_SIZE(length);
         input_a = res_a + NEXT_WORD_SIZE(length);

         ctx_p = input_p + NEXT_WORD_SIZE(encLen);
         ctx_a = input_a + NEXT_WORD_SIZE(encLen);
      }
      else
      {
         /* User has provided a request packet, which must contain enough
            space for the input and output packets. The user may
            reuse the input pointer for the output. */

         /* The user has given us a request structure.  We just need to
            initialize it. */
         req_p = (API_Request_t *) request_p->VirtualAddress;
         initializeEARequestBuffer(req_p,
                                   request_p,
                                   packetObj_p->unitID,
                                   numCommands,
                                   resultHandlerSSLTLSDecrypt,
                                   N8_TRUE);

         /* Initialize input_p and input_a to the beginning of
            data area in the request */
         input_p = (N8_Buffer_t *)((unsigned long) packet_p + SSLTLS_DATA_OFFSET);
         input_a = N8_VirtToPhys(input_p);


         res_p = result_p + SSLTLS_DATA_OFFSET;
         res_a = N8_VirtToPhys(res_p);

         /* If we are loading context memory, we load it at the last 
            N8_CTX_BYTES before the data section */
         if (numCtxBytes > 0)
         {
            ctx_p = (N8_Buffer_t *)((unsigned long) req_p + sizeof(API_Request_t) + N8_COMMAND_BLOCK_BYTES);
            ctx_a = N8_VirtToPhys(ctx_p);
         }
      }

      next_cb_p = req_p->EA_CommandBlock_ptr;

      /* generate the command blocks necessary to load the context, if required */
      if (packetObj_p->contextLoadNeeded == N8_TRUE)
      {
         /* Generate the command blocks for the Context Load */
         ctxLoadFcn = (n8_ctxLoadFcn_t)packetObj_p->ctxLoadFcn;
         ret = ctxLoadFcn(req_p, 
                          req_p->EA_CommandBlock_ptr,
                          packetObj_p,
                          &packetObj_p->cipherInfo, 
                          packetObj_p->packetHashAlgorithm,
                          ctx_p,
                          ctx_a,
                          &next_cb_p);
         CHECK_RETURN(ret);
         packetObj_p->contextLoadNeeded = N8_FALSE;
      }

      /* copy the data portion of the incoming packet into the input kernel
       * buffer */
      if (request_p == NULL)
      {
         memcpy(input_p, &packet_p[SSLTLS_DATA_OFFSET], length);
      }

      /* use the post processing structure in the API Request */
      postData_p = (N8_SSL_Post_Decrypt_Data_t *)&req_p->postProcessBuffer;

      /* now check the length */
      if (length < packetObj_p->minLength)
      {
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      /* if des, ensure the length is a multiple of N8_DES_BLOCK_MULTIPLE */
      if ((packetObj_p->packetCipher == N8_CIPHER_DES) &&
          ((length % N8_DES_BLOCK_MULTIPLE) != 0))
      {
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      /* set up the copy back for the result packet.  we only copy back the data
       * portion which we get from the kernel buffer. */
      req_p->copyBackTo_p = &result_p[SSLTLS_DATA_OFFSET];
      req_p->copyBackFrom_p = res_p;
      /* the length the decrypted data is not known until after the operation is
       * run.  we will calculate it in the resultHandler.  set the copyBackSize
       * to zero as a safe thing to do.*/
      req_p->copyBackSize = 0;

      if (packetObj_p->contextHandle.inUse == N8_FALSE)
      {
         /* This sets up the offset for the start of the copy back of the IV. 
            This case can only occur if the cipher is DES, not ARC4 */
         memcpy(&postData_p->nextIV, 
                &(packet_p[5 - N8_DES_KEY_LENGTH + length]),
                N8_DES_KEY_LENGTH);
      }

      /* set up the post processing data */
      postData_p->macLength = packetObj_p->macLength;
      postData_p->computedMAC_p = computedMAC_p;
      postData_p->packetObj_p = packetObj_p;
      postData_p->verify_p = verify_p;
      postData_p->encryptedLength = length;
      if (request_p == NULL)
      {
         postData_p->copyData = N8_TRUE;
      }
      else
      {
         postData_p->copyData = N8_FALSE;
      }
      postData_p->resultPacket_p = result_p;

      /* tell the Queue Manager to copy back the command block results */
      req_p->copyBackCommandBlock = N8_TRUE;
      req_p->postProcessingData_p = (void *) postData_p;

      /* Generate the command blocks for the Decrypt */
      decryptFcn = (n8_SSLTLSFcn_t)packetObj_p->SSLTLScmdFcn;
      ret = decryptFcn(next_cb_p,
                       packetObj_p,
                       packet_p,
                       input_a,
                       res_a,
                       packetObj_p->decOpCode);
      CHECK_RETURN(ret);

      /* set up the return packet 
       * again, recall we cannot set the length in the result packet now and
       * will have to do it in the result handler. */
      memcpy(&result_p[SSLTLS_TYPE_OFFSET],
             &packet_p[SSLTLS_TYPE_OFFSET],
             sizeof(uint8_t) + sizeof(uint16_t));

      QUEUE_AND_CHECK(event_p, req_p, ret);
      HANDLE_EVENT(event_p, req_p, ret);
   } while (FALSE);

   /* clean up if necessary.  note that if there is no error condition, the post
    * data and request will be de-allocated in the result handler. */
   if (ret != N8_STATUS_OK)
   {
      freeRequest(req_p);
   }
   return ret;
} /* N8_SSLTLSDecryptVerify */
Пример #6
0
/** @ingroup n8_ssltls
 * @brief Encrypt/Authenticate an SSL or TLS message
 *
 * An entire SSL or TLS record is encrypted/authenticated.
 *
 *  @param packetObj_p         RW:  Pointer to a packet object which was
 *                                  previously initialized for SSL or TLS
 *  @param packet_p            RO:  Pointer to packet
 *  @param result_p            RW:  Pointer to pre-allocated buffer where the
 *                                  results will be stored.
 *  @param request             RW:  Kernel request buffer used when mode =
 *                                  N8_PACKETMEMORY_REQUEST.
 *  @param event_p             RW:  Asynchronous event pointer.
 *
 * @par Externals
 *    None
 *
 * @return
 *    Error condition if raised.
 *
 * @par Errors
 *    None
 *
 * @par Assumptions
 *    None
 *****************************************************************************/
N8_Status_t 
N8_SSLTLSEncryptAuthenticateMemory(N8_Packet_t             *packetObj_p,
                                   const N8_SSLTLSPacket_t *packet_p,
                                   N8_SSLTLSPacket_t       *result_p,
                                   N8_RequestHandle_t       request,
                                   N8_Event_t              *event_p)
{

   N8_Status_t ret = N8_STATUS_OK;
   API_Request_t *req_p = NULL;
   EA_CMD_BLOCK_t *next_cb_p = NULL;
   uint16_t length;
   short int encLen;
   short int packetLen;
   N8_Buffer_t *res_p = NULL;
   uint32_t     res_a;
   N8_Buffer_t *input_p = NULL;
   uint32_t     input_a;
   N8_Buffer_t *ctx_p = NULL;
   uint32_t     ctx_a = 0;
   int          nBytes;
   unsigned int numCommands = 0;
   unsigned int numCtxBytes = 0;
   N8_MemoryHandle_t *request_p;
   n8_ctxLoadFcn_t    ctxLoadFcn;
   n8_SSLTLSFcn_t     encryptFcn;

   do
   {
      /* verify the pointers passed in are not null */
      CHECK_OBJECT(packetObj_p, ret);
      CHECK_STRUCTURE(packetObj_p->structureID, N8_PACKET_STRUCT_ID, ret);
      CHECK_OBJECT(packet_p, ret);
      CHECK_OBJECT(result_p, ret);

      request_p = (N8_MemoryHandle_t *) request;

      /* Check that request_p & mode are consistent */
      if (request_p == NULL)
      {
         if (packetObj_p->mode != N8_PACKETMEMORY_NONE)
         {
            /* No request_p means mode should be "none" */
            ret = N8_INCONSISTENT;
            break;
         }
      }
      else if (packetObj_p->mode != N8_PACKETMEMORY_REQUEST)
      {
         /* They said they would give us a request and they didn't */
         ret = N8_INCONSISTENT;
         break;
      }

      /*
       * convert the length from network order to host order
       */
      length = SSLTLS_EXTRACT_LENGTH(packet_p);
      /* check to see the data length is within range
       * [0..N8_SSLTLS_MAX_DATA_SIZE_ENCRYPT] 
       */
      if (length > N8_SSLTLS_MAX_DATA_SIZE_ENCRYPT)
      {
         ret = N8_INVALID_INPUT_SIZE;
         break;
      }

      numCommands = packetObj_p->encCommands;
      if (packetObj_p->contextLoadNeeded == N8_TRUE)
      {
         numCommands += packetObj_p->ctxLoadCmds;
         numCtxBytes = NEXT_WORD_SIZE(sizeof(EA_ARC4_CTX));
      }

      /* create a kernel memory structure for temporarily storing the results */
      /* compute the lengths for the result packet */
      encLen = N8_ComputeEncryptedLength(length,
                                         packetObj_p->hashPacket.hashSize,
                                         packetObj_p->packetCipher); 
      packetLen = encLen + SSLTLS_HEADER_LEN;

      /* compute the total number of bytes in kernel space we need to allocate.
       * note we round up to the next word boundary. */
      /* Note that if the in packet is NULL, we don't check the out packet */
      if (request_p == NULL)
      {
         nBytes = (NEXT_WORD_SIZE(length) + /* input */
                   NEXT_WORD_SIZE(encLen) + /* output */
                   numCtxBytes);            /* size of context, if needed */
         /* create an API request buffer */
         ret = createEARequestBuffer(&req_p,
                                     packetObj_p->unitID,
                                     numCommands,
                                     resultHandlerSSLTLSEncrypt,
                                     nBytes); 
         CHECK_RETURN(ret);
         /* User has not provided a request buffer */
         res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
         res_a = req_p->qr.physicalAddress + req_p->dataoffset;

         input_p = res_p + NEXT_WORD_SIZE(length);
         input_a = res_a + NEXT_WORD_SIZE(length);

         ctx_p = input_p + NEXT_WORD_SIZE(encLen);
         ctx_a = input_a + NEXT_WORD_SIZE(encLen);
      }
      else
      {
         /* The user has given us a request structure.  We just need to
            initialize it. */
         req_p = (API_Request_t *) request_p->VirtualAddress;
         initializeEARequestBuffer(req_p,
                                   request_p,
                                   packetObj_p->unitID,
                                   numCommands,
                                   resultHandlerSSLTLSEncrypt,
                                   N8_TRUE);

         /* User has provided a request packet, which must contain enough
            space for the input and output packets. The user may
            reuse the input pointer for the output. */
         input_p = (N8_Buffer_t *)((unsigned long) packet_p + SSLTLS_DATA_OFFSET);
         input_a = N8_VirtToPhys(input_p);

         res_p = (N8_Buffer_t *)((unsigned long) result_p + SSLTLS_DATA_OFFSET);
         res_a = N8_VirtToPhys(res_p);
         /* If we are loading context memory, we load it at the last 
            N8_CTX_BYTES before the data section */
         if (numCtxBytes > 0)
         {
            ctx_p = (N8_Buffer_t *)((unsigned long) req_p + sizeof(API_Request_t) + N8_COMMAND_BLOCK_BYTES);
            ctx_a = N8_VirtToPhys(ctx_p);
         }
      }

      next_cb_p = req_p->EA_CommandBlock_ptr;

      /* generate the command blocks necessary to load the context, if required */
      if (packetObj_p->contextLoadNeeded == N8_TRUE)
      {
         /* Generate the command blocks for the Context Load */
         ctxLoadFcn = (n8_ctxLoadFcn_t)packetObj_p->ctxLoadFcn;
         ret = ctxLoadFcn(req_p, 
                          next_cb_p,
                          packetObj_p,
                          &packetObj_p->cipherInfo, 
                          packetObj_p->packetHashAlgorithm,
                          ctx_p,
                          ctx_a,
                          &next_cb_p);
         CHECK_RETURN(ret);
         packetObj_p->contextLoadNeeded = N8_FALSE;
      }

      req_p->copyBackFrom_p = res_p;
      req_p->postProcessingData_p = (void *) packetObj_p;
      /* This sets up the offset for the start of the copy back of the IV */
      req_p->postProcessBuffer[0] = encLen - N8_DES_KEY_LENGTH;

      if (request_p == NULL)
      {
         memcpy(input_p, &packet_p[SSLTLS_DATA_OFFSET], length);
         req_p->copyBackTo_p = &result_p[SSLTLS_DATA_OFFSET];
         req_p->copyBackSize = encLen;
      }
      else
      {
         req_p->copyBackSize = 0;
      }

      /* Generate the command blocks for the Encrypt */
      encryptFcn = (n8_SSLTLSFcn_t)packetObj_p->SSLTLScmdFcn;
      ret = encryptFcn(next_cb_p,
                       packetObj_p,
                       packet_p,
                       input_a,
                       res_a,
                       packetObj_p->encOpCode);
      CHECK_RETURN(ret);

      /* set up the return packet.  note that this can be done before the
       * command is executed as it is only constant header information. */
      memcpy(&result_p[SSLTLS_TYPE_OFFSET],
             &packet_p[SSLTLS_TYPE_OFFSET],
             sizeof(uint8_t) + sizeof(uint16_t)); 
      SSLTLS_SET_LENGTH(result_p, encLen);

      QUEUE_AND_CHECK(event_p, req_p, ret);
      HANDLE_EVENT(event_p, req_p, ret);
   } while (FALSE);

   /* clean up if necessary.  note that if there is no error condition, the
    * request will be de-allocated in the result handler. */ 
   if (ret != N8_STATUS_OK)
   {
      freeRequest(req_p);
   }
   return ret;

} /* N8_SSLEncryptAuthenticateMemory */