initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
@@ -0,0 +1,136 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief AES and random number security service implemented using HCI.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "hci_api.h"
#include "util/calc128.h"
/**************************************************************************************************
External Variables
**************************************************************************************************/
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Returns the next token.
*
* \return Token value.
*/
/*************************************************************************************************/
static uint8_t getNextToken()
{
uint8_t token = secCb.token++;
if (token == SEC_TOKEN_INVALID)
{
token = secCb.token++;
}
return token;
}
/*************************************************************************************************/
/*!
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
* sent to the specified handler. This function returns a token value that
* the client can use to match calls to this function with messages.
*
* \param pKey Pointer to 16 byte key.
* \param pPlaintext Pointer to 16 byte plaintext.
* \param handlerId WSF handler ID.
* \param param Client-defined parameter returned in message.
* \param event Event for client's WSF handler.
*
* \return Token value.
*/
/*************************************************************************************************/
uint8_t SecAes(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
/* allocate a buffer */
if ((pBuf = WsfMsgAlloc(sizeof(secQueueBuf_t))) != NULL)
{
pBuf->msg.hdr.status = getNextToken();
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pBuf->type = SEC_TYPE_AES;
/* queue buffer */
WsfMsgEnq(&secCb.aesEncQueue, handlerId, pBuf);
/* call HCI encrypt function */
HciLeEncryptCmd(pKey, pPlaintext);
return pBuf->msg.hdr.status;
}
return SEC_TOKEN_INVALID;
}
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for AES operations.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecAesHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
secAes_t *pAes = (secAes_t *) &pBuf->msg;
/* set encrypted data pointer and copy */
pAes->pCiphertext = pBuf->ciphertext;
Calc128Cpy(pAes->pCiphertext, pEvent->leEncryptCmdCmpl.data);
/* send message */
WsfMsgSend(handlerId, pAes);
}
/*************************************************************************************************/
/*!
* \brief Called to initialize AES secuirity.
*
* \param none.
*
* \return none.
*/
/*************************************************************************************************/
void SecAesInit()
{
secCb.hciCbackTbl[SEC_TYPE_AES] = SecAesHciCback;
}
@@ -0,0 +1,137 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief AES and random number security service implemented using HCI.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "util/wstr.h"
/**************************************************************************************************
External Variables
**************************************************************************************************/
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Returns the next token.
*
* \return Token value.
*/
/*************************************************************************************************/
static uint8_t getNextToken()
{
uint8_t token = secCb.token++;
if (token == SEC_TOKEN_INVALID)
{
token = secCb.token++;
}
return token;
}
/*************************************************************************************************/
/*!
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
* sent to the specified handler. This function returns a token value that
* the client can use to match calls to this function with messages. Note this version
* reverses the key and plaintext bytes.
*
* \param pKey Pointer to 16 byte key.
* \param pPlaintext Pointer to 16 byte plaintext.
* \param handlerId WSF handler ID.
* \param param Client-defined parameter returned in message.
* \param event Event for client's WSF handler.
*
* \return Token value.
*/
/*************************************************************************************************/
uint8_t SecAesRev(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
/* allocate a buffer */
if ((pBuf = WsfMsgAlloc(sizeof(secQueueBuf_t))) != NULL)
{
pBuf->msg.hdr.status = getNextToken();
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pBuf->type = SEC_TYPE_AES_REV;
/* call HCI encrypt function */
SecLeEncryptCmd(pKey, pPlaintext, pBuf, handlerId);
return pBuf->msg.hdr.status;
}
return SEC_TOKEN_INVALID;
}
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for AES operations. Note this version reverses the
* ciphertext bytes.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecAesRevHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
secAes_t *pAes = (secAes_t *) &pBuf->msg;
/* set encrypted data pointer and copy */
pAes->pCiphertext = pBuf->ciphertext;
Calc128Cpy(pAes->pCiphertext, pEvent->leEncryptCmdCmpl.data);
/* send message */
WsfMsgSend(handlerId, pAes);
}
/*************************************************************************************************/
/*!
* \brief Called to initialize AES secuirity.
*
* \param none.
*
* \return none.
*/
/*************************************************************************************************/
void SecAesRevInit()
{
secCb.hciCbackTbl[SEC_TYPE_AES_REV] = SecAesRevHciCback;
}
@@ -0,0 +1,595 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Counter with CBC-MAC (CCM) mode security - HCI AES.
*
* Copyright (c) 2018-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "sec_api.h"
#include "sec_main.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "util/wstr.h"
#ifndef SEC_CCM_CFG
#define SEC_CCM_CFG SEC_CCM_CFG_HCI
#endif
#if SEC_CCM_CFG == SEC_CCM_CFG_HCI
/**************************************************************************************************
Constants
**************************************************************************************************/
/* State machine states */
enum
{
SEC_CCM_STATE_XI_HDR,
SEC_CCM_STATE_XI_MSG,
SEC_CCM_STATE_S0,
SEC_CCM_STATE_SI,
SEC_CCM_STATE_MIC_COMPLETE,
};
/**************************************************************************************************
External Variables
**************************************************************************************************/
/* Global security control block */
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Exclusive-or two 128-bit integers and return the result in pDst.
*
* \param pDst Pointer to destination.
* \param pSrc Pointer to source.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmCalcXor(uint8_t *pDst, uint8_t *pSrc, uint8_t size)
{
uint8_t i;
for (i = 0; i < size; i++)
{
*pDst++ ^= *pSrc++;
}
}
/*************************************************************************************************/
/*!
* \fn secCcmBlockEncrypt
*
* \brief Perform a 16-byte block encryption (HCI AES)
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param pText Pointer to text to encrypt (16 bytes).
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmBlockEncrypt(secQueueBuf_t *pBuf, uint8_t *pText)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
SecLeEncryptCmd(pCcm->key, pText, pBuf, pCcm->handlerId);
}
/*************************************************************************************************/
/*!
* \fn secCcmGenX0
*
* \brief Generate X_0 := E(K, B_0)
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenX0(secQueueBuf_t *pBuf)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
/* Scratch buffer contains nonce, add flags and message length */
pCcm->scratch[0] = (SEC_CCM_L - 1) | (((pCcm->micLen - 2) / 2) << 3) | ((pCcm->clearLen > 0? 1:0) << 6);
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->textLen >> 8;
pCcm->scratch[SEC_BLOCK_LEN - 1] = pCcm->textLen & 0xFF;
pCcm->state = pCcm->clearLen > 0 ? SEC_CCM_STATE_XI_HDR : SEC_CCM_STATE_XI_MSG;
pCcm->position = 0;
/* AES Operation */
secCcmBlockEncrypt(pBuf, pCcm->scratch);
}
/*************************************************************************************************/
/*!
* \fn secCcmGenXiHdr
*
* \brief Generate X_i header if clear text (additional data) is present.
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param pPriorX 16 byte buffer containing X_i-1.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenXiHdr(secQueueBuf_t *pBuf, uint8_t *pPriorX)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
uint8_t b_i[SEC_BLOCK_LEN];
uint16_t remaining;
uint16_t offset = 0;
if (pCcm->position == 0)
{
/* Copy additional data into working buffer */
memcpy(pCcm->pWorking, pCcm->pClear, pCcm->clearLen);
/* First two bytes of b_0 contain length of additional data */
b_i[0] = pCcm->clearLen >> 8;
b_i[1] = pCcm->clearLen & 0xFF;
pCcm->position = offset = 2;
}
remaining = (int16_t) pCcm->clearLen - pCcm->position + 2;
/* Copy additional to b_i */
if (remaining >= SEC_BLOCK_LEN - offset)
{
memcpy(b_i + offset, pCcm->pClear + pCcm->position - 2, SEC_BLOCK_LEN - offset);
pCcm->position += SEC_BLOCK_LEN - offset;
if (remaining == SEC_BLOCK_LEN - offset)
{
pCcm->state = SEC_CCM_STATE_XI_MSG;
pCcm->position = 0;
}
}
else
{
memcpy(b_i + offset, pCcm->pClear + pCcm->position - 2, remaining);
memset(b_i + offset + remaining, 0, SEC_BLOCK_LEN - remaining - offset);
pCcm->state = SEC_CCM_STATE_XI_MSG;
pCcm->position = 0;
}
/* X_i XOR B_i */
Calc128Xor(b_i, pPriorX);
/* AES Operation */
secCcmBlockEncrypt(pBuf, b_i);
}
/*************************************************************************************************/
/*!
* \fn secCcmGenXiMsg
*
* \brief Generate X_i for the message text.
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param pPriorX 16 byte buffer containing X_i-1.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenXiMsg(secQueueBuf_t *pBuf, uint8_t *pPriorX)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
uint8_t b_i[SEC_BLOCK_LEN];
uint16_t remaining = (int16_t) pCcm->textLen - pCcm->position;
/* Copy data to b_i */
if (remaining >= SEC_BLOCK_LEN)
{
Calc128Cpy(b_i, pCcm->pText + pCcm->position);
pCcm->position += SEC_BLOCK_LEN;
if (remaining == SEC_BLOCK_LEN)
{
pCcm->state = SEC_CCM_STATE_S0;
}
}
else
{
memcpy(b_i, pCcm->pText + pCcm->position, remaining);
memset(b_i + remaining, 0, SEC_BLOCK_LEN - remaining);
pCcm->state = SEC_CCM_STATE_S0;
}
/* X_i XOR B_i */
Calc128Xor(b_i, pPriorX);
/* AES Operation */
secCcmBlockEncrypt(pBuf, b_i);
}
/*************************************************************************************************/
/*!
* \fn secCcmGenS0
*
* \brief Generate S_0 := E(K, A_0)
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param x_n 16 byte buffer containing X_n (containing T).
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenS0(secQueueBuf_t *pBuf, uint8_t *x_n)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
uint16_t offset = pCcm->textLen + pCcm->clearLen;
/* Copy T to working buffer */
memcpy(pCcm->pWorking + offset, x_n, pCcm->micLen);
/* Scratch buffer contains nonce, add flags and counter */
pCcm->scratch[0] = (SEC_CCM_L - 1);
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->scratch[SEC_BLOCK_LEN - 1] = 0;
pCcm->state = SEC_CCM_STATE_MIC_COMPLETE;
/* AES Operation */
secCcmBlockEncrypt(pBuf, pCcm->scratch);
}
/*************************************************************************************************/
/*!
* \fn secCcmGenS1
*
* \brief Generate S_1 := E(K, A_1)
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenS1(secQueueBuf_t *pBuf)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
/* Set counter. */
pCcm->counter = 1;
/* Scratch buffer contains nonce, add flags and counter. */
pCcm->scratch[0] = (SEC_CCM_L - 1);
pCcm->scratch[SEC_BLOCK_LEN - 2] = 0;
pCcm->scratch[SEC_BLOCK_LEN - 1] = 1;
/* Change state to S_i state. */
pCcm->state = SEC_CCM_STATE_SI;
/* AES Operation. */
secCcmBlockEncrypt(pBuf, pCcm->scratch);
}
/*************************************************************************************************/
/*!
* \fn secCcmMicComplete
*
* \brief Called when MIC calculation is complete.
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param s_0 16 byte buffer containing S_0.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmMicComplete(secQueueBuf_t *pBuf, uint8_t *s_0)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
int16_t micOffset;
/* MIC = s_0 XOR T (store in result buffer). */
micOffset = pCcm->textLen + pCcm->clearLen;
secCcmCalcXor(pCcm->pWorking + micOffset, s_0, pCcm->micLen);
if (pCcm->operation == SEC_CCM_OP_ENCRYPT)
{
/* When encrypting, continue S_i calculations */
secCcmGenS1(pBuf);
}
else
{
/* Decryption complete. Send notification. */
secCcmDecMsg_t *pMsg = (secCcmDecMsg_t *) &pBuf->msg;
/* Verify MIC value */
if (memcmp(pCcm->pRcvMic, pCcm->pWorking + micOffset, pCcm->micLen) == 0)
{
pMsg->pText = pCcm->pWorking + pCcm->clearLen;
pMsg->textLen = pCcm->textLen;
pMsg->success = TRUE;
}
else
{
pMsg->pText = NULL;
pMsg->textLen = 0;
pMsg->success = FALSE;
}
WsfMsgSend(pCcm->handlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn secCcmGenSi
*
* \brief Generate S_i := E(K, A_i)
*
* \param pBuf Security queue buffer containing CCM algorithm control block.
* \param pPriorS 16 byte buffer containing S_i-1.
*
* \return None.
*/
/*************************************************************************************************/
static void secCcmGenSi(secQueueBuf_t *pBuf, uint8_t *pPriorS)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
int16_t resultOffset = 0;
uint16_t len;
/* Determine length of XOR operation. */
len = pCcm->textLen - ((pCcm->counter - 1) * SEC_BLOCK_LEN);
len = len > SEC_BLOCK_LEN? SEC_BLOCK_LEN : len;
/* m_i XOR s_i+1. */
resultOffset = (pCcm->counter - 1) * SEC_BLOCK_LEN + pCcm->clearLen;
secCcmCalcXor(pCcm->pWorking + resultOffset, pPriorS, (uint8_t) len);
if (pCcm->counter * SEC_BLOCK_LEN >= pCcm->textLen)
{
if (pCcm->operation == SEC_CCM_OP_ENCRYPT)
{
/* Encription complete. Send notification. */
secCcmEncMsg_t *pMsg = (secCcmEncMsg_t *) &pBuf->msg;
pMsg->pCiphertext = pCcm->pWorking;
pMsg->textLen = pCcm->textLen + pCcm->clearLen + pCcm->micLen;
WsfMsgSend(pCcm->handlerId, pMsg);
}
else
{
/* Set pText to point to the decrypted result in pWorking */
pCcm->pText = pCcm->pWorking + pCcm->clearLen;
/* Begin calculating the MIC */
secCcmGenX0(pBuf);
}
}
else
{
/* Update counter. */
pCcm->counter++;
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->counter >> 8;
pCcm->scratch[SEC_BLOCK_LEN - 1] = pCcm->counter & 0xFF;
/* AES Operation. */
secCcmBlockEncrypt(pBuf, pCcm->scratch);
}
}
/*************************************************************************************************/
/*!
* \fn SecCcmBlockEncryptCmpl
*
* \brief Called when a block encryption operation completes.
*
* \param pParam Pointer to security control block.
* \param pCypherText Pointer to encrypt result.
*
* \return none.
*/
/*************************************************************************************************/
void SecCcmHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) pBuf->pCb;
switch (pCcm->state)
{
case SEC_CCM_STATE_XI_HDR:
secCcmGenXiHdr(pBuf, pEvent->leEncryptCmdCmpl.data);
break;
case SEC_CCM_STATE_XI_MSG:
secCcmGenXiMsg(pBuf, pEvent->leEncryptCmdCmpl.data);
break;
case SEC_CCM_STATE_S0:
secCcmGenS0(pBuf, pEvent->leEncryptCmdCmpl.data);
break;
case SEC_CCM_STATE_SI:
secCcmGenSi(pBuf, pEvent->leEncryptCmdCmpl.data);
break;
case SEC_CCM_STATE_MIC_COMPLETE:
secCcmMicComplete(pBuf, pEvent->leEncryptCmdCmpl.data);
break;
}
}
/*************************************************************************************************/
/*!
* \fn SecCcmEnc
*
* \brief Execute the CCM-Mode encryption algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pPlainText Pointer to text to encrypt.
* \param textLen Length of pPlainText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCcmSecCb_t);
WSF_ASSERT(clearLen < SEC_CCM_MAX_ADDITIONAL_LEN);
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) (pBuf + 1);
/* Setup queue buffer */
pBuf->pCb = pCcm;
pBuf->type = SEC_TYPE_CCM;
pBuf->msg.hdr.status = secCb.token++;
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pCcm->handlerId = handlerId;
pCcm->pText = pPlainText;
pCcm->textLen = textLen;
pCcm->pClear = pClear;
pCcm->pWorking = pResult;
pCcm->clearLen = clearLen;
pCcm->micLen = micLen;
pCcm->counter = 0;
memcpy(pCcm->pWorking + clearLen, pPlainText, textLen);
memcpy(&pCcm->scratch[1], pNonce, SEC_CCM_NONCE_LEN);
Calc128Cpy(pCcm->key, (uint8_t *) pKey);
pCcm->operation = SEC_CCM_OP_ENCRYPT;
/* Begin encryption of text by generation of X_0 */
secCcmGenX0(pBuf);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \fn SecCcmDec
*
* \brief Execute the CCM-Mode verify and decrypt algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pCypherText Pointer to text to decrypt.
* \param textLen Length of pCypherText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param pMic Pointer to authentication digest.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCcmSecCb_t);
WSF_ASSERT(clearLen < SEC_CCM_MAX_ADDITIONAL_LEN);
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
{
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) (pBuf + 1);
/* Setup queue buffer */
pBuf->pCb = pCcm;
pBuf->type = SEC_TYPE_CCM;
pBuf->msg.hdr.status = secCb.token++;
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pCcm->handlerId = handlerId;
pCcm->pClear = pClear;
pCcm->pRcvMic = pMic;
pCcm->pWorking = pResult;
pCcm->textLen = textLen;
pCcm->clearLen = clearLen;
pCcm->micLen = micLen;
pCcm->counter = 0;
/* Prepare the working buffer */
memcpy(pCcm->pWorking, pClear, clearLen);
memcpy(pCcm->pWorking + clearLen, pCypherText, textLen);
memcpy(pCcm->pWorking + clearLen + textLen, pMic, micLen);
memcpy(&pCcm->scratch[1], pNonce, SEC_CCM_NONCE_LEN);
Calc128Cpy(pCcm->key, (uint8_t *) pKey);
pCcm->operation = SEC_CCM_OP_DECRYPT;
/* Begin decryption of text by generation of S_1 */
secCcmGenS1(pBuf);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \fn SecCcmInit
*
* \brief Called to initialize CCM-Mode security.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void SecCcmInit(void)
{
secCb.hciCbackTbl[SEC_TYPE_CCM] = SecCcmHciCback;
}
#endif /* SEC_CCM_CFG */
@@ -0,0 +1,323 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief AES and random number security service implemented using HCI.
*
* Copyright (c) 2010-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "util/wstr.h"
#ifndef SEC_CMAC_CFG
#define SEC_CMAC_CFG SEC_CMAC_CFG_HCI
#endif
#if SEC_CMAC_CFG == SEC_CMAC_CFG_HCI
enum
{
SEC_CMAC_STATE_SUBKEY,
SEC_CMAC_STATE_BLOCK,
SEC_CMAC_STATE_COMPLETE,
};
/**************************************************************************************************
External Variables
**************************************************************************************************/
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Continue the execution of the CMAC algorithm over the next message block.
*
* \param pBuf Security queue buffer containing CMAC algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCmacProcessBlock(secQueueBuf_t *pBuf)
{
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
uint8_t text[SEC_BLOCK_LEN];
uint8_t *pMn = pCmac->pPlainText + pCmac->position;
int16_t remaining = (int16_t) pCmac->len - pCmac->position;
/* Check for Last Block */
if (remaining <= SEC_BLOCK_LEN)
{
memcpy(text, pMn, remaining);
/* Pad the message if necessary */
if (remaining != SEC_BLOCK_LEN)
{
memset(text + remaining, 0, SEC_BLOCK_LEN - remaining);
text[remaining] = 0x80;
}
/* XOr the subkey */
Calc128Xor(text, pCmac->subkey);
pCmac->state = SEC_CMAC_STATE_COMPLETE;
}
else
{
/* Copy the block to the buffer */
Calc128Cpy(text, pMn);
}
if (pCmac->position != 0)
{
/* Except for first block, XOr the previous AES calculation */
Calc128Xor(text, pBuf->ciphertext);
}
pCmac->position += SEC_BLOCK_LEN;
SecLeEncryptCmd(pCmac->key, text, pBuf, pCmac->handlerId);
}
/*************************************************************************************************/
/*!
* \brief Step 1 to generate the subkey used in the CMAC algorithm.
*
* \param pBuf Security queue buffer containing CMAC algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCmacGenSubkey1(secQueueBuf_t *pBuf)
{
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
uint8_t buf[SEC_BLOCK_LEN];
/* Perform aes on the key with a constant zero */
memset(buf, 0, SEC_BLOCK_LEN);
SecLeEncryptCmd(pCmac->key, buf, pBuf, pCmac->handlerId);
}
/*************************************************************************************************/
/*!
* \brief Left shift a buffer of WSF_CMAC_KEY_LEN bytes by N bits.
*
* \param pBuf Buffer to left shift.
* \param shift Number of bits to shift.
*
* \return The overflow of the operaiton.
*/
/*************************************************************************************************/
static uint8_t secCmacKeyShift(uint8_t *pBuf, uint8_t shift)
{
uint8_t overflow, i;
uint8_t finalOverflow = pBuf[0] >> (8 - shift);
for (i = 0; i < SEC_CMAC_KEY_LEN; i++)
{
/* store shifted bits for next byte */
if (i < SEC_CMAC_KEY_LEN-1)
{
overflow = pBuf[i+1] >> (8 - shift);
}
else
{
overflow = 0;
}
/* shift byte and OR in shifted bits from previous byte */
pBuf[i] = (pBuf[i] << shift) | overflow;
}
return finalOverflow;
}
/*************************************************************************************************/
/*!
* \brief Complete generation of the subkey used in the CMAC algorithm.
*
* \param pBuf Security queue buffer containing CMAC algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCmacGenSubkey2(secQueueBuf_t *pBuf)
{
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
uint8_t overflow;
/* Copy the result of the AES oepration */
Calc128Cpy(pCmac->subkey, pBuf->ciphertext);
/* Calculate the K1 subkey */
overflow = secCmacKeyShift(pCmac->subkey, 1);
if (overflow)
{
pCmac->subkey[SEC_BLOCK_LEN-1] ^= SEC_CMAC_RB;
}
if (pCmac->len % SEC_BLOCK_LEN != 0)
{
/* If the message len is not a multiple of SEC_BLOCK_LEN */
/* Continue with generation of the K2 subkey based on the K1 key */
overflow = secCmacKeyShift(pCmac->subkey, 1);
if (overflow)
{
pCmac->subkey[SEC_BLOCK_LEN-1] ^= SEC_CMAC_RB;
}
}
/* Begin CMAC calculation */
pCmac->state = SEC_CMAC_STATE_BLOCK;
secCmacProcessBlock(pBuf);
}
/*************************************************************************************************/
/*!
* \brief Send a message to the handler with CMAC result.
*
* \param pBuf Security queue buffer containing CMAC algorithm control block.
*
* \return None.
*/
/*************************************************************************************************/
static void secCmacComplete(secQueueBuf_t *pBuf)
{
/* CMAC is complete, copy and send result to handler */
secCmacMsg_t *pMsg = (secCmacMsg_t *) &pBuf->msg;
secCmacSecCb_t *pCmac = (secCmacSecCb_t *) pBuf->pCb;
pMsg->pCiphertext = pBuf->ciphertext;
pMsg->pPlainText = pCmac->pPlainText;
WsfMsgSend(pCmac->handlerId, pMsg);
}
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for CMAC operations.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecCmacHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
secCmacSecCb_t *pCmac = (secCmacSecCb_t *) pBuf->pCb;
if (pCmac)
{
Calc128Cpy(pBuf->ciphertext, pEvent->leEncryptCmdCmpl.data);
switch (pCmac->state)
{
case SEC_CMAC_STATE_SUBKEY:
secCmacGenSubkey2(pBuf);
break;
case SEC_CMAC_STATE_BLOCK:
secCmacProcessBlock(pBuf);
break;
case SEC_CMAC_STATE_COMPLETE:
secCmacComplete(pBuf);
break;
}
}
}
/*************************************************************************************************/
/*!
* \brief Execute the CMAC algorithm.
*
* \param pKey Key used in CMAC operation.
* \param pPlainText Data to perform CMAC operation over
* \param len Size of pPlaintext in bytes.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCmac(const uint8_t *pKey, uint8_t *pPlainText, uint16_t textLen, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCmacSecCb_t);
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
{
secCmacSecCb_t *pCmacCb = (secCmacSecCb_t *) (pBuf + 1);
/* Setup queue buffer */
pBuf->pCb = pCmacCb;
pBuf->type = SEC_TYPE_CMAC;
pBuf->msg.hdr.status = secCb.token++;
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pCmacCb->pPlainText = pPlainText;
pCmacCb->len = textLen;
pCmacCb->position = 0;
pCmacCb->handlerId = handlerId;
pCmacCb->state = SEC_CMAC_STATE_SUBKEY;
/* Copy key */
Calc128Cpy(pCmacCb->key, (uint8_t *) pKey);
/* Start the CMAC process by calculating the subkey */
secCmacGenSubkey1(pBuf);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Called to initialize CMAC security.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void SecCmacInit()
{
secCb.hciCbackTbl[SEC_TYPE_CMAC] = SecCmacHciCback;
}
#endif /* SEC_CMAC_CFG */
@@ -0,0 +1,160 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Security ECC implementation using debug keys.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "util/calc128.h"
#ifndef SEC_ECC_CFG
#define SEC_ECC_CFG SEC_ECC_CFG_DEBUG
#endif
#if SEC_ECC_CFG == SEC_ECC_CFG_DEBUG
/* Debug Keys */
static const uint8_t debugPrivateKey[] = {0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38,
0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99,
0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd};
static const uint8_t debugPublicKeyX[] = {0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
static const uint8_t debugPublicKeyY[] = {0xdc, 0x80, 0x9c, 0x49, 0x65, 0x2a, 0xeb, 0x6d,
0x63, 0x32, 0x9a, 0xbf, 0x5a, 0x52, 0x15, 0x5c,
0x76, 0x63, 0x45, 0xc2, 0x8f, 0xed, 0x30, 0x24,
0x74, 0x1c, 0x8e, 0xd0, 0x15, 0x89, 0xd2, 0x8b};
static const uint8_t debugSharedSecret[] = {0x49, 0x4c, 0xfd, 0x99, 0x6f, 0x40, 0x17, 0xf5,
0xb5, 0x48, 0xba, 0x66, 0x99, 0x60, 0x64, 0x08,
0x62, 0x75, 0xd5, 0x1f, 0xe0, 0x8e, 0x56, 0x36,
0xb9, 0x36, 0xd1, 0xe4, 0x57, 0x46, 0x4b, 0xed};
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for ECC operations.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
if (pMsg)
{
/* Generate the keys */
memcpy(pMsg->data.key.pubKey_x, debugPublicKeyX, SEC_ECC_KEY_LEN);
memcpy(pMsg->data.key.pubKey_y, debugPublicKeyY, SEC_ECC_KEY_LEN);
memcpy(pMsg->data.key.privKey, debugPrivateKey, SEC_ECC_KEY_LEN);
/* Send shared secret to handler */
pMsg->hdr.event = event;
pMsg->hdr.param = param;
pMsg->hdr.status = HCI_SUCCESS;
WsfMsgSend(handlerId, pMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param pKey ECC Key structure.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
if (pMsg)
{
memcpy(pMsg->data.sharedSecret.secret, debugSharedSecret, SEC_ECC_KEY_LEN);
/* Send shared secret to handler */
pMsg->hdr.event = event;
pMsg->hdr.param = param;
pMsg->hdr.status = HCI_SUCCESS;
WsfMsgSend(handlerId, pMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Called to initialize ECC security.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void SecEccInit()
{
}
#endif /* SEC_ECC_CFG */
@@ -0,0 +1,183 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief WSF Security ECC implementation using HCI.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "util/wstr.h"
#ifndef SEC_ECC_CFG
#define SEC_ECC_CFG SEC_ECC_CFG_HCI
#endif
#if SEC_ECC_CFG == SEC_ECC_CFG_HCI
/**************************************************************************************************
External Variables
**************************************************************************************************/
extern secCb_t secCb;
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for ECC operations.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
secEccMsg_t *pMsg = (secEccMsg_t *) &pBuf->msg;
if (pEvent->hdr.event == HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT)
{
/* Reverse copy the public key (to big endian) */
WStrReverseCpy(pMsg->data.key.pubKey_x, pEvent->leP256.key, SEC_ECC_KEY_LEN);
WStrReverseCpy(pMsg->data.key.pubKey_y, pEvent->leP256.key + SEC_ECC_KEY_LEN, SEC_ECC_KEY_LEN);
/* Send shared secret to handler */
pMsg->hdr.status = pEvent->leP256.status;
WsfMsgSend(handlerId, pMsg);
}
else if (pEvent->hdr.event == HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT)
{
/* Reverse copy the DH key (to big endian) */
WStrReverseCpy(pMsg->data.sharedSecret.secret, pEvent->leGenDHKey.key, SEC_ECC_KEY_LEN);
/* Send shared secret to handler */
pMsg->hdr.status = pEvent->leGenDHKey.status;
WsfMsgSend(handlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secEccMsg_t);
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
{
/* Record the event and parameter for use in the HCI response */
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pBuf->type = SEC_TYPE_DH;
/* queue buffer */
WsfMsgEnq(&secCb.pubKeyQueue, handlerId, pBuf);
/* Request the local public key via HCI */
HciLeReadLocalP256PubKey();
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param pKey ECC Key structure.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secQueueBuf_t *pBuf;
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secEccMsg_t);
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
{
uint8_t pubKeyX[SEC_ECC_KEY_LEN];
uint8_t pubKeyY[SEC_ECC_KEY_LEN];
/* Record the event and parameter for use in the HCI response */
pBuf->msg.hdr.param = param;
pBuf->msg.hdr.event = event;
pBuf->type = SEC_TYPE_DH;
/* queue buffer */
WsfMsgEnq(&secCb.dhKeyQueue, handlerId, pBuf);
/* Reverse keys (to little endian) */
WStrReverseCpy(pubKeyX, pKey->pubKey_x, SEC_ECC_KEY_LEN);
WStrReverseCpy(pubKeyY, pKey->pubKey_y, SEC_ECC_KEY_LEN);
/* Request the DH Key via HCI */
HciLeGenerateDHKey(pubKeyX, pubKeyY);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Called to initialize ECC security.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void SecEccInit()
{
secCb.hciCbackTbl[SEC_TYPE_DH] = SecEccHciCback;
}
#endif /* SEC_ECC_CFG */
@@ -0,0 +1,195 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Security service implemented using HCI.
*
* Copyright (c) 2010-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "sec_api.h"
#include "sec_main.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "util/wstr.h"
// #include "pal_crypto.h"
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/* Security Control block */
secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption and random number events.
*
* \return None.
*/
/*************************************************************************************************/
static void secHciCback(hciEvt_t *pEvent)
{
secQueueBuf_t *pBuf = NULL;
wsfHandlerId_t handlerId = 0;
/* Handle random number event. */
switch (pEvent->hdr.event)
{
case HCI_LE_RAND_CMD_CMPL_CBACK_EVT:
/* Copy new data to circular buffer of random data. */
memcpy(&secCb.rand[HCI_RAND_LEN * secCb.randTop], pEvent->leRandCmdCmpl.randNum, HCI_RAND_LEN);
secCb.randTop = (secCb.randTop >= SEC_HCI_RAND_MULT - 1) ? 0 : secCb.randTop + 1;
break;
case HCI_LE_ENCRYPT_CMD_CMPL_CBACK_EVT:
pBuf = WsfMsgDeq(&secCb.aesEncQueue, &handlerId);
WSF_ASSERT(pBuf != NULL);
/* note: pBuf should never be NULL and is checked by assert above. */
/* coverity[dereference] */
if (pBuf->type == SEC_TYPE_CCM || pBuf->type == SEC_TYPE_CMAC || pBuf->type == SEC_TYPE_AES_REV)
{
WStrReverse(pEvent->leEncryptCmdCmpl.data, HCI_ENCRYPT_DATA_LEN);
}
break;
case HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT:
pBuf = WsfMsgDeq(&secCb.pubKeyQueue, &handlerId);
break;
case HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT:
pBuf = WsfMsgDeq(&secCb.dhKeyQueue, &handlerId);
break;
default:
break;
}
if (pBuf)
{
WSF_ASSERT(secCb.hciCbackTbl[pBuf->type]);
secCb.hciCbackTbl[pBuf->type](pBuf, pEvent, handlerId);
}
}
/*************************************************************************************************/
/*!
* \brief Initialize the security service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecInit(void)
{
WSF_QUEUE_INIT(&secCb.aesEncQueue);
WSF_QUEUE_INIT(&secCb.pubKeyQueue);
WSF_QUEUE_INIT(&secCb.dhKeyQueue);
secCb.token = 0;
/* Register callback with HCI */
HciSecRegister(secHciCback);
}
/*************************************************************************************************/
/*!
* \brief Initialize the random number service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecRandInit(void)
{
int8_t i;
/* get new random numbers */
for (i=0; i<SEC_HCI_RAND_MULT; i++)
{
HciLeRandCmd();
}
}
/*************************************************************************************************/
/*!
* \brief This function returns up to HCI_RAND_LEN * SEC_HCI_RAND_MULT bytes of random data to
* a buffer provided by the client.
*
* \param pRand Pointer to returned random data.
* \param randLen Length of random data.
*
* \return None.
*/
/*************************************************************************************************/
void SecRand(uint8_t *pRand, uint8_t randLen)
{
int8_t count = (randLen + HCI_RAND_LEN - 1) / HCI_RAND_LEN;
uint8_t index = secCb.randBtm * HCI_RAND_LEN;
WSF_ASSERT(randLen <= SEC_RAND_DATA_LEN);
/* Copy from circular buffer of random data. */
while (randLen--)
{
*pRand++ = secCb.rand[index];
index = (index == SEC_RAND_DATA_LEN - 1) ? 0 : index + 1;
}
while (count--)
{
/* Request more random data. */
HciLeRandCmd();
/* Update copy index. */
secCb.randBtm = (secCb.randBtm >= SEC_HCI_RAND_MULT - 1) ? 0 : secCb.randBtm + 1;
}
}
/*************************************************************************************************/
/*!
* \brief Queue callback and call LE encrypt given most significant byte ordered key and data.
*
* \param pKey Pointer to key.
* \param pText Pointer to text to encrypt.
* \param pBuf Pointer to queue block.
* \param handlerId Handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void SecLeEncryptCmd(uint8_t *pKey, uint8_t *pText, void *pBuf, wsfHandlerId_t handlerId)
{
uint8_t revKey[HCI_KEY_LEN];
uint8_t revText[HCI_ENCRYPT_DATA_LEN];
WStrReverseCpy(revKey, pKey, HCI_KEY_LEN);
WStrReverseCpy(revText, pText, HCI_ENCRYPT_DATA_LEN);
WsfMsgEnq(&secCb.aesEncQueue, handlerId, pBuf);
HciLeEncryptCmd(revKey, revText);
}
@@ -0,0 +1,162 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Internal security service structures.
*
* Copyright (c) 2010-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef SEC_MAIN_H
#define SEC_MAIN_H
#include "hci_api.h"
// #include "pal_crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! AES, CMAC and HCI algorithm block length */
#define SEC_BLOCK_LEN 16
/* CMAC constant Rb */
#define SEC_CMAC_RB 0x87
/*! Number or random bytes to keep in the secCb_t rand data buffer */
#define SEC_RAND_DATA_LEN 32
/*! Multiple of HCI_RAND_LEN kept in the secCb_t rand data buffer */
#define SEC_HCI_RAND_MULT (SEC_RAND_DATA_LEN / HCI_RAND_LEN)
/*! Compile time ECC configuration */
#define SEC_ECC_CFG_DEBUG 0
#define SEC_ECC_CFG_UECC 1
#define SEC_ECC_CFG_HCI 2
/*! Compile time CMAC configuration */
#define SEC_CMAC_CFG_PLATFORM 0
#define SEC_CMAC_CFG_HCI 1
/*! Compile time CCM configuration */
#define SEC_CCM_CFG_PLATFORM 0
#define SEC_CCM_CFG_HCI 1
/*! CCM Operation (Encryption or Decryption) */
#define SEC_CCM_OP_ENCRYPT 0
#define SEC_CCM_OP_DECRYPT 1
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! Enumeration of security operation types */
enum
{
SEC_TYPE_AES,
SEC_TYPE_CMAC,
SEC_TYPE_DH,
SEC_TYPE_CCM,
SEC_TYPE_AES_REV,
SEC_NUM_TYPES
};
/*! Security queue element for CMAC operations */
typedef struct
{
uint8_t *pPlainText;
uint8_t key[SEC_CMAC_KEY_LEN];
uint8_t subkey[SEC_CMAC_KEY_LEN];
uint16_t position;
uint16_t len;
wsfHandlerId_t handlerId;
uint8_t state;
} secCmacSecCb_t;
/*! Security queue element for CCM-Mode operations */
typedef struct
{
uint8_t operation;
uint8_t *pText;
uint8_t *pClear;
uint8_t *pRcvMic;
uint16_t textLen;
uint16_t clearLen;
uint8_t micLen;
uint8_t key[SEC_CCM_KEY_LEN];
uint8_t scratch[SEC_BLOCK_LEN];
uint16_t counter;
uint16_t position;
wsfHandlerId_t handlerId;
uint8_t state;
uint8_t *pWorking;
} secCcmSecCb_t;
/*! Security queue element */
typedef struct
{
secMsg_t msg;
uint8_t ciphertext[SEC_BLOCK_LEN];
uint8_t reserved[SEC_BLOCK_LEN];
void *pCb;
uint8_t type;
} secQueueBuf_t;
typedef void secHciCback_t(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId);
typedef secHciCback_t *pSecHciCback_t;
/* Control block */
typedef struct
{
uint8_t rand[SEC_RAND_DATA_LEN]; /* Random data buffer */
wsfQueue_t aesEncQueue; /* Queue for AES encrypt requests */
wsfQueue_t pubKeyQueue; /* Queue for read p256 public key requests */
wsfQueue_t dhKeyQueue; /* Queue for generate dh key requests */
uint8_t token; /* Token value */
uint8_t randTop; /* Random buffer insert point (HCI_RAND_LEN bytes) */
uint8_t randBtm; /* Random buffer copy point (HCI_RAND_LEN bytes) */
pSecHciCback_t hciCbackTbl[SEC_NUM_TYPES];
} secCb_t;
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Queue callback and call LE encrypt given most significant byte ordered key and data.
*
* \param pKey Pointer to key.
* \param pText Pointer to text to encrypt.
* \param pBuf Pointer to queue block.
* \param handlerId Handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void SecLeEncryptCmd(uint8_t *pKey, uint8_t *pText, void *pBuf, wsfHandlerId_t handlerId);
#ifdef __cplusplus
};
#endif
#endif /* SEC_MAIN_H */
@@ -0,0 +1,174 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Counter with CBC-MAC (CCM) mode security - Native AES.
*
* Copyright (c) 2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_buf.h"
#include "wsf_msg.h"
#include "sec_api.h"
#include "sec_main.h"
#ifndef SEC_CCM_CFG
#define SEC_CCM_CFG SEC_CCM_CFG_PLATFORM
#endif
#if SEC_CCM_CFG == SEC_CCM_CFG_PLATFORM
/**************************************************************************************************
External Variables
**************************************************************************************************/
/* Global security control block */
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Execute the CCM-Mode encryption algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pPlainText Pointer to text to encrypt.
* \param textLen Length of pPlainText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secCcmEncMsg_t *pCcmMsg;
if ((pCcmMsg = WsfMsgAlloc(sizeof(secCcmEncMsg_t))) != NULL)
{
/* Encrypt. */
PalCryptoCcmEnc(pKey, pNonce, pPlainText, textLen, pClear, clearLen, micLen, pResult,
handlerId, param, event);
memcpy(pResult, pClear, clearLen);
/* Send notification of encryption complete. */
pCcmMsg->hdr.status = secCb.token++;
pCcmMsg->hdr.param = param;
pCcmMsg->hdr.event = event;
pCcmMsg->pCiphertext = pResult;
pCcmMsg->textLen = textLen + clearLen + micLen;
WsfMsgSend(handlerId, pCcmMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \fn SecCcmDec
*
* \brief Execute the CCM-Mode verify and decrypt algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pCypherText Pointer to text to decrypt.
* \param textLen Length of pCypherText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param pMic Pointer to authentication digest.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secCcmDecMsg_t *pCcmMsg;
if ((pCcmMsg = WsfMsgAlloc(sizeof(secCcmDecMsg_t))) != NULL)
{
/* Decrypt. */
uint32_t error;
error = PalCryptoCcmDec(pKey, pNonce, pCypherText, textLen, pClear, clearLen, pMic, micLen,
pResult, handlerId, param, event);
/* Send notification of decryption complete. */
pCcmMsg->hdr.status = secCb.token++;
pCcmMsg->hdr.param = param;
pCcmMsg->hdr.event = event;
/* Compare MIC with computed MIC. */
if (error)
{
/* MIC not authentic. */
pCcmMsg->success = FALSE;
pCcmMsg->pResult = NULL;
pCcmMsg->pText = NULL;
pCcmMsg->textLen = 0;
}
else
{
/* MIC authentic. */
pCcmMsg->success = TRUE;
pCcmMsg->pResult = pResult;
pCcmMsg->pText = pResult;
pCcmMsg->textLen = textLen;
}
WsfMsgSend(handlerId, pCcmMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Called to initialize CCM-Mode security.
*
* \return None.
*/
/*************************************************************************************************/
void SecCcmInit()
{
PalCryptoInit();
secCb.hciCbackTbl[SEC_TYPE_CCM] = NULL;
}
#endif /* SEC_CCM_CFG */
@@ -0,0 +1,171 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Security ECC implementation using uECC.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "sec_api.h"
#include "sec_main.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "util/calc128.h"
#include "uECC.h"
#ifndef SEC_ECC_CFG
#define SEC_ECC_CFG SEC_ECC_CFG_UECC
#endif
#if SEC_ECC_CFG == SEC_ECC_CFG_UECC
/**************************************************************************************************
External Variables
**************************************************************************************************/
extern secCb_t secCb;
/*************************************************************************************************/
/*!
* \brief Random number generator used by uECC.
*
* \param p_dest Buffer to hold random number
* \param p_size Size of p_dest in bytes .
*
* \return TRUE if successful.
*/
/*************************************************************************************************/
static int secEccRng(uint8_t *p_dest, unsigned p_size)
{
SecRand(p_dest, p_size);
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Callback for HCI encryption for ECC operations.
*
* \param pBuf Pointer to sec queue element.
* \param pEvent Pointer to HCI event.
* \param handlerId WSF handler ID.
*
* \return none.
*/
/*************************************************************************************************/
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
{
/* TBD */
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
if (pMsg)
{
/* Generate the keys */
uECC_make_key(pMsg->data.key.pubKey_x, pMsg->data.key.privKey);
/* Send shared secret to handler */
pMsg->hdr.event = event;
pMsg->hdr.param = param;
pMsg->hdr.status = HCI_SUCCESS;
WsfMsgSend(handlerId, pMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param pKey ECC Key structure.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
{
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
if (pMsg)
{
bool_t keyValid = uECC_valid_public_key(pKey->pubKey_x);
if (keyValid)
{
uECC_shared_secret(pKey->pubKey_x, pKey->privKey, pMsg->data.sharedSecret.secret);
}
else
{
memset(pMsg->data.sharedSecret.secret, 0xFF, SEC_ECC_KEY_LEN);
}
/* Send shared secret to handler. */
pMsg->hdr.event = event;
pMsg->hdr.param = param;
pMsg->hdr.status = keyValid ? HCI_SUCCESS : HCI_ERR_INVALID_PARAM;
WsfMsgSend(handlerId, pMsg);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Called to initialize ECC security.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void SecEccInit()
{
//srand((unsigned int)time(NULL));
uECC_set_rng(secEccRng);
}
#endif /* SEC_ECC_CFG */