Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_crypto_core_cmac_v2.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 10 KB Fix file modes.
/***************************************************************************//**
* \file cy_crypto_core_cmac_v2.c
* \version 2.40
*
* \brief
*  This file provides the source code to the API for the CMAC method
*  in the Crypto block driver.
*
*  Implementation is done in accordance with information from this weblink:
*  nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf
*
********************************************************************************
* Copyright 2016-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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 "cy_device.h"

#if defined (CY_IP_MXCRYPTO)

#include "cy_crypto_core_cmac_v2.h"

#if defined(__cplusplus)
extern "C" {
#endif

#if (CPUSS_CRYPTO_AES == 1)

#include "cy_crypto_core_aes_v2.h"
#include "cy_crypto_core_hw_v2.h"
#include "cy_syslib.h"

/* The bit string used to generate sub-keys */
#define CY_CRYPTO_CMAC_RB  (0x87u)

/* The structure to define used memory buffers */
typedef struct
{
    cy_stc_crypto_v2_cmac_state_t cmacState;
    uint8_t k[CY_CRYPTO_AES_BLOCK_SIZE];
} cy_stc_crypto_v2_cmac_buffers_t;

static void Cy_Crypto_Core_V2_Cmac_CalcSubKey(uint8_t *srcDstPtr);

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac_CalcSubKey
****************************************************************************//**
*
* Calculates the sub-key for the CMAC algorithm
* according to the NIST publication 800-38B, page 7.
*
* \param srcDstPtr
* The pointer to the source data for sub-key calculation, see 800-38B.
*
*******************************************************************************/
static void Cy_Crypto_Core_V2_Cmac_CalcSubKey(uint8_t *srcDstPtr)
{
    int32_t i;
    uint32_t c;
    uint32_t msb = 0UL;

    for (i = (int32_t)((int32_t)CY_CRYPTO_AES_BLOCK_SIZE - 1); i >= 0; i--)
    {
        c = (uint32_t)srcDstPtr[i];
        c = (c << 1U) | msb;
        srcDstPtr[i] = (uint8_t) c;
        msb = (c >> 8U) & 1UL;
    }

    if (0UL != msb)
    {
        /* Just one byte is valuable, the rest are zeros */
        srcDstPtr[(uint8_t)(CY_CRYPTO_AES_BLOCK_SIZE - 1U)] ^= CY_CRYPTO_CMAC_RB;
    }
}

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac_Init
****************************************************************************//**
*
* The function for initialization of CMAC operation.
*
* \param cmacState
* The pointer to the structure which stores the CMAC context.
*
* \param k
* The pointer to the sub-key.

*******************************************************************************/
void Cy_Crypto_Core_V2_Cmac_Init(cy_stc_crypto_v2_cmac_state_t* cmacState, uint8_t* k)
{
    cmacState->k = k;
}

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac_Start
****************************************************************************//**
*
* Starts CMAC calculation.
*
* \param base
* The pointer to the CRYPTO instance.
*
* \param cmacState
* The pointer to the structure which stores the CMAC context.
*
*******************************************************************************/
void Cy_Crypto_Core_V2_Cmac_Start(CRYPTO_Type *base,
                               cy_stc_crypto_v2_cmac_state_t *cmacState)
{
    cmacState->block_idx = 0U;

    /* Calculate the K1 sub-key */
    Cy_Crypto_Core_V2_BlockXor(base, CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_V2_RB_BLOCK0,
                                     CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_RunAes(base);
    Cy_Crypto_Core_V2_FFStart (base, CY_CRYPTO_V2_RB_FF_STORE, cmacState->k, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_BlockMov(base, CY_CRYPTO_V2_RB_FF_STORE, CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_Sync(base);

    Cy_Crypto_Core_V2_Cmac_CalcSubKey(cmacState->k);

    Cy_Crypto_Core_V2_BlockXor(base, CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_V2_RB_BLOCK1,
                                     CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_AES_BLOCK_SIZE);
}

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac_Update
****************************************************************************//**
*
* Calculates CMAC on a message.
*
* \param base
* The pointer to the CRYPTO instance.
*
* \param cmacState
* The pointer to the structure which stores the CMAC context.
*
* \param message
* The pointer to the message whose CMAC is being computed.
*
* \param messageSize
* The size of the message whose CMAC is being computed.
*
*******************************************************************************/
void Cy_Crypto_Core_V2_Cmac_Update(CRYPTO_Type *base,
                                cy_stc_crypto_v2_cmac_state_t *cmacState,
                                uint8_t const *message,
                                uint32_t  messageSize)
{
    uint32_t myBlockIdx = cmacState->block_idx + messageSize;

    Cy_Crypto_Core_V2_FFContinue(base, CY_CRYPTO_V2_RB_FF_LOAD0, message, messageSize);

    while (myBlockIdx > CY_CRYPTO_AES_BLOCK_SIZE)
    {
        Cy_Crypto_Core_V2_BlockXor(base, CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_V2_RB_FF_LOAD0,
                                         CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_AES_BLOCK_SIZE);
        Cy_Crypto_Core_V2_RunAes(base);

        myBlockIdx -= CY_CRYPTO_AES_BLOCK_SIZE;
    }

    cmacState->block_idx = myBlockIdx;
}

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac_Finish
****************************************************************************//**
*
* Completes CMAC calculation.
*
* \param base
* The pointer to the CRYPTO instance.
*
* \param cmacState
* The pointer to the structure which stores the CMAC context.
*
* \param cmac
* The pointer to the computed CMAC value.
*
*******************************************************************************/
void Cy_Crypto_Core_V2_Cmac_Finish(CRYPTO_Type *base,
                                cy_stc_crypto_v2_cmac_state_t *cmacState,
                                uint8_t* cmac)
{
    uint8_t  const p_padding[16] =
    {
        0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
        0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u
    };

    uint8_t* myK = cmacState->k;
    uint32_t myBlockIdx = cmacState->block_idx;

    Cy_Crypto_Core_V2_FFContinue(base, CY_CRYPTO_V2_RB_FF_LOAD0, p_padding, CY_CRYPTO_AES_BLOCK_SIZE - myBlockIdx);
    Cy_Crypto_Core_V2_BlockXor  (base, CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_V2_RB_FF_LOAD0,
                                       CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_AES_BLOCK_SIZE);

    if (myBlockIdx < CY_CRYPTO_AES_BLOCK_SIZE)
    {
        Cy_Crypto_Core_V2_Cmac_CalcSubKey(myK);        /* calculate "k2" */
    }

    Cy_Crypto_Core_V2_FFContinue(base, CY_CRYPTO_V2_RB_FF_LOAD0, myK, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_BlockXor  (base, CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_V2_RB_FF_LOAD0,
                                       CY_CRYPTO_V2_RB_BLOCK0, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_RunAes(base);

    Cy_Crypto_Core_V2_FFStart   (base, CY_CRYPTO_V2_RB_FF_STORE, cmac, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_BlockMov  (base, CY_CRYPTO_V2_RB_FF_STORE, CY_CRYPTO_V2_RB_BLOCK1, CY_CRYPTO_AES_BLOCK_SIZE);
    Cy_Crypto_Core_V2_Sync(base);
}

/*******************************************************************************
* Function Name: Cy_Crypto_Core_V2_Cmac
****************************************************************************//**
*
* Performs CMAC(Cipher-based Message Authentication Code) operation
* on a message to produce message authentication code using AES.
*
* \param base
* The pointer to the CRYPTO instance.
*
* \param message
* The pointer to a source plain text. Must be 4-byte aligned.
*
* \param messageSize
* The size of a source plain text.
*
* \param key
* The pointer to the encryption key. Must be 4-byte aligned.
*
* \param keyLength
* \ref cy_en_crypto_aes_key_length_t
*
* \param cmac
* The pointer to the calculated CMAC.
*
* \param aesState
* The pointer to the AES state structure allocated by the user. The user
* must not modify anything in this structure.
*
* \return
* \ref cy_en_crypto_status_t
*
*******************************************************************************/
cy_en_crypto_status_t Cy_Crypto_Core_V2_Cmac(CRYPTO_Type *base,
                                          uint8_t const *message,
                                          uint32_t messageSize,
                                          uint8_t  const *key,
                                          cy_en_crypto_aes_key_length_t keyLength,
                                          uint8_t *cmac,
                                          cy_stc_crypto_aes_state_t *aesState)
{
    /* Allocate space for the structure which stores the CMAC context */
    cy_stc_crypto_aes_buffers_t      aesBuffersData  = {{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }};
    cy_stc_crypto_v2_cmac_buffers_t  cmacBuffersData = {{0UL, NULL}, { 0 }};
    cy_stc_crypto_v2_cmac_buffers_t *cmacBuffers  = &cmacBuffersData;
    cy_stc_crypto_v2_cmac_state_t   *cmacStateLoc = &cmacBuffers->cmacState;

    CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 18.6','No valid data expected after funtion return');
    (void)Cy_Crypto_Core_V2_Aes_Init(base, key, keyLength, aesState, &aesBuffersData);
    Cy_Crypto_Core_V2_Aes_LoadEncKey(base, aesState);

    Cy_Crypto_Core_V2_Cmac_Init  (cmacStateLoc, cmacBuffers->k);
    Cy_Crypto_Core_V2_Cmac_Start (base, cmacStateLoc);
    Cy_Crypto_Core_V2_Cmac_Update(base, cmacStateLoc, message, messageSize);
    Cy_Crypto_Core_V2_Cmac_Finish(base, cmacStateLoc, cmac);

    return (CY_CRYPTO_SUCCESS);
}

#endif /* #if (CPUSS_CRYPTO_AES == 1) */

#if defined(__cplusplus)
}
#endif

#endif /* CY_IP_MXCRYPTO */


/* [] END OF FILE */