Part Number: TMS320F28P650DH
Other Parts Discussed in Thread: C2000WARE
Hi Experts,
Could you please help checkinf if the AES-CMAC in F28P65 fully compliant to the RFC4493 standard?
Regards,
Hang
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: TMS320F28P650DH
Other Parts Discussed in Thread: C2000WARE
Hi Experts,
Could you please help checkinf if the AES-CMAC in F28P65 fully compliant to the RFC4493 standard?
Regards,
Hang
Please look at C2000ware AEC CMAC block implementation example, it tests the same NIST vectors mentioned in RFC.
No, we are talking about RFC4493, please refer to this article "RFC 4493 - The AES-CMAC Algorithm", we test the example "c:/ti/c2000/C2000Ware_6_00_00_00/driverlib/f28p65x/examples/c28x/aes/aes_ex7_cmac_auth.c", the result of TI's CMAC engine is different from mbedtls and openssl, while these two libraries do fully comply with RFC4493.
I checked this article "RFC 4492: Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)", I found out that RFC4492 is not related with CMAC.
Hi Hang,
After looking into the issue, we have identified the problem with the code. Please try with this .c file. You can use this .c file directly in the example C2000Ware_6_00_00_00/driverlib/f28p65x/examples/c28x/aes/aes_ex7_cmac_auth.c. We have verified it with NIST Test Vectors for AES CMAC 128 bit and 256 bit. You can verify the testStatusGlobal variable in the code, it will get set to TEST_PASS (0xABCDABCD) if the test passes i.e if the calculated Tag matches the NIST expected Tag.
//#############################################################################
//
// FILE: aes_ex7_cmac_auth.c
//
// TITLE: AES CBCMAC Encryption
//
//! \addtogroup driver_example_list
//! <h1>AES CMAC Authentication Example </h1>
//!
//! This example encrypts block cipher-text using AES128 and AES256 in CMAC mode and authenticates the result. It does
//! the encryption first without uDMA and then with uDMA. The results are
//! checked after each operation.
//!
//! \b External \b Connections \n
//! - None
//!
//! \b Watch \b Variables \n
//! - \b errCountGlobal - Error Counter. It should be zero.
//! - \b testStatusGlobal - Test status. It should be equal to PASS.
//!
//
//#############################################################################
//
//
//
// C2000Ware v6.00.01.00
//
// Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################
//
// Included Files
//
#include <string.h>
#include "driverlib.h"
#include "device.h"
//
// Defines
//
#define TEST_PASS 0xABCDABCD
#define TEST_FAIL 0xDEADDEAD
#define BURST_SIZE 0x8
#define BURST_SRCSTEP 0x2
#define BURST_DESTSTEP 0x2
#define TRANSFER_SIZE 0x4
#define TRANSFER_SRCSTEP 0x2
#define TRANSFER_DESTSTEP 0x2
#define SRCWRAPSIZE 0x100
#define WRAP_SRCSTEP 0x10
#define DESTWRAPSIZE 0x100
#define WRAP_DESTSTEP 0x10
//
// Global Variables
//
//
// Global error counter & status
//
uint16_t errCountGlobal = 0;
uint32_t testStatusGlobal;
//
// Output tag-out array
//
#pragma DATA_SECTION(TagOutArray,"ramgs0");
uint32_t TagOutArray[4];
//
// Global interrupt status
//
static volatile uint32_t intStatus = 0;
//
// The AES interrupt handler and interrupt flags.
//
static volatile bool contextInIntFlag;
static volatile bool dataInIntFlag;
static volatile bool contextOutIntFlag;
static volatile bool dataOutIntFlag;
static volatile bool contextInDMADoneIntFlag;
static volatile bool dataInDMADoneIntFlag;
static volatile bool contextOutDMADoneIntFlag;
static volatile bool dataOutDMADoneIntFlag;
//
// Structure for NIST AES CBCMAC tests
//
typedef struct
{
AES_KeySize keySize;
uint32_t cmackey[8];
uint32_t dataLength;
uint32_t iv[4];
uint32_t plainTextArray[16];
uint32_t ExpectedTagOutArray[16];
} testVectorCBCMAC;
//
// Test Cases from NIST ECB Revised Spec.
//
#pragma DATA_SECTION(testVectorCBCMACArray,"ramgs0");
testVectorCBCMAC testVectorCBCMACArray[] =
{
//
// Test Case #1 with 128 bit key
//
{
.keySize = AES_KEY_SIZE_128BIT,
.cmackey = { 0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09 },
.dataLength = 64U,
.iv = { 0x00000000,0x00000000,0x00000000,0x00000000 },
.plainTextArray = { 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a,
0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6 },
.ExpectedTagOutArray = { 0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679 },
},
//
// Test Case #2 with 256 bit key
//
{
.keySize = AES_KEY_SIZE_256BIT,
.cmackey = { 0x10eb3d60,0xbe71ca15,0xf0ae732b,0x81777d85, 0x072c351f,0xd708613b,0xa310982d,0xf4df1409 },
.dataLength = 64U,
.iv = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
.plainTextArray = { 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373,
0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45,
0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a,
0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6 },
.ExpectedTagOutArray = { 0x902199e1, 0xd56e9f54, 0x052c6a69, 0x1054316c}
}
};
//
// Function Prototypes
//
void performCMACAuthentication(AES_KeySize keySize, uint32_t *srcArray,
uint32_t *dstTagArray, uint32_t *cmackey,
uint32_t *iv, uint32_t dataLength, bool useDMA);
void performECBEncryption(AES_KeySize keySize, uint32_t *srcArray,
uint32_t *dstArray, uint32_t *keyArray,
uint32_t dataLength);
void generateSubKey(AES_KeySize keySize, uint32_t *cmackey, uint32_t *iv, uint32_t* subKey1, uint32_t* subKey2);
void array_shift_and_generate(const uint32_t input[], uint32_t output[]);
void array_xor_inplace_generic(uint32_t* data, const uint32_t* xor, uint32_t size);
uint32_t roundUpDataLength(uint32_t dataLength);
void initializeDMACH1(void);
void initializeDMACH2(void);
void configureDMACH1(const void *src, const void *dst, uint32_t transferSize);
void configureDMACH2(const void *src, const void *dst, uint32_t transferSize);
void configurreDMAInterruptCH1(void);
void configureDMAInteruptCH2(void);
void initilizeAES(void);
void startAES(void);
interrupt void AESDMADataInISR(void)
{
AES_disableDMARequest(AESA_BASE, AES_DMA_EN_DATA_IN);
dataInDMADoneIntFlag = true;
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}
interrupt void AESDMADataOutISR(void)
{
AES_disableDMARequest(AESA_BASE, AES_DMA_EN_CONTEXT_OUT );
dataOutDMADoneIntFlag = true;
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}
void initializeDMACH1(void)
{
DMA_disableTrigger(DMA_CH1_BASE);
DMA_clearTriggerFlag(DMA_CH1_BASE);
DMA_clearErrorFlag(DMA_CH1_BASE);
}
void initializeDMACH2(void)
{
DMA_disableTrigger(DMA_CH2_BASE);
DMA_clearTriggerFlag(DMA_CH2_BASE);
DMA_clearErrorFlag(DMA_CH2_BASE);
}
void configureDMACH1(const void *src, const void *dst, uint32_t transferSize)
{
//
//Configure DMA Channel 1 as needed
//
DMA_configAddresses(DMA_CH1_BASE,dst,src);
//
// Burst configuration with 4 32 bit words/burst. Destination is not moving.
//
DMA_configBurst(DMA_CH1_BASE,BURST_SIZE,BURST_SRCSTEP,0);
//
// Transfer configuration with 4 bursts/transfer. Destination is not moving.
//
DMA_configTransfer(DMA_CH1_BASE,transferSize,TRANSFER_SRCSTEP,0);
//
// Wrap condition enabled if more than 256 bursts/transfer
//
DMA_configWrap(DMA_CH1_BASE,SRCWRAPSIZE,WRAP_SRCSTEP,DESTWRAPSIZE,WRAP_DESTSTEP);
DMA_configMode(DMA_CH1_BASE,DMA_TRIGGER_AESA_DATAIN,DMA_CFG_ONESHOT_DISABLE |
DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_32BIT);
DMA_enableTrigger(DMA_CH1_BASE);
}
void configureDMACH2(const void *src, const void *dst, uint32_t transferSize)
{
//
//Configure DMA Channel 2 as needed
//
DMA_configAddresses(DMA_CH2_BASE,dst,src);
//
// Burst configuration with 4 32 words/burst. Source is moving.
//
DMA_configBurst(DMA_CH2_BASE,16,1,1);
//
// Transfer configuration with 4 bursts/transfer. Source is not moving.
//
DMA_configTransfer(DMA_CH2_BASE,transferSize,0,TRANSFER_DESTSTEP);
//
// Wrap condition enabled if more than 256 bursts/transfer
//
DMA_configWrap(DMA_CH2_BASE,SRCWRAPSIZE,WRAP_SRCSTEP,DESTWRAPSIZE,WRAP_DESTSTEP);
DMA_configMode(DMA_CH2_BASE,DMA_TRIGGER_AESA_CONTEXTOUT,DMA_CFG_ONESHOT_DISABLE |
DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_32BIT);
DMA_enableTrigger(DMA_CH2_BASE);
}
void configureDMAInterruptCH1(void)
{
//
// Register the interrupt handler.
//
Interrupt_register(INT_DMA_CH1, AESDMADataInISR);
//
// Enable the DMA interrupt.
//
Interrupt_enable(INT_DMA_CH1);
Interrupt_enableGlobal();
DMA_enableInterrupt(DMA_CH1_BASE);
//
// generate the interrupt at the end of the transfer.
//
DMA_setInterruptMode(DMA_CH1_BASE,DMA_INT_AT_END);
}
void configureDMAInterruptCH2(void)
{
//
// Register the interrupt handler.
//
Interrupt_register(INT_DMA_CH2, AESDMADataOutISR);
//
// Enable the DMA interrupt.
//
Interrupt_enable(INT_DMA_CH2);
Interrupt_enableGlobal();
DMA_enableInterrupt(DMA_CH2_BASE);
//
// generate the interrupt at the end of the transfer.
//
DMA_setInterruptMode(DMA_CH2_BASE,DMA_INT_AT_END);
}
void initilizeAES(void)
{
Interrupt_disableGlobal();
AES_disableGlobalInterrupt(AESA_SS_BASE);
AES_performSoftReset(AESA_BASE);
}
void startAES(void)
{
//
//start the DMA Channel and wait for the trigger event.
//
DMA_startChannel(DMA_CH1_BASE);
//
//start the DMA Channel and wait for the trigger event.
//
DMA_startChannel(DMA_CH2_BASE);
AES_enableDMARequest(AESA_BASE, AES_DMA_EN_DATA_IN | AES_DMA_EN_CONTEXT_OUT);
}
//
// Main
//
void main(void)
{
uint32_t errCountLocal, cnt;
uint32_t *cmackey, dataLength;
uint32_t *ExpectedTagOutArray, *plainTextArray;
uint32_t vectorCnt;
uint32_t *iv;
AES_KeySize keySize;
//
// Initialize device clock and peripherals
//
Device_init();
//
// Initialize GPIO and configure the GPIO pin as a push-pull output
//
Device_initGPIO();
//
// Disable global interrupts.
//
DINT;
//
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
//
Interrupt_initModule();
//
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
//
Interrupt_initVectorTable();
//
// Initialize local variables.
//
errCountLocal = 0;
//
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
//
EINT;
ERTM;
//
// Loop through all the given vectors.
//
for(vectorCnt = 0;
(vectorCnt < (sizeof(testVectorCBCMACArray) /
sizeof(testVectorCBCMACArray[0]))); vectorCnt++)
{
//
// Get the current vector's data members.
//
keySize = testVectorCBCMACArray[vectorCnt].keySize;
cmackey = testVectorCBCMACArray[vectorCnt].cmackey ;
dataLength = testVectorCBCMACArray[vectorCnt].dataLength;
plainTextArray = testVectorCBCMACArray[vectorCnt].plainTextArray;
ExpectedTagOutArray = testVectorCBCMACArray[vectorCnt].ExpectedTagOutArray;
iv = testVectorCBCMACArray[vectorCnt].iv;
//
// Clear the array containing the Tag.
//
for(cnt = 0; cnt < 4; cnt++)
{
TagOutArray[cnt] = 0;
}
//
// Perform Encryption without DMA.
performCMACAuthentication(keySize, plainTextArray, TagOutArray, cmackey, iv, dataLength, true);
//
// Check the results
//
for(cnt = 0; cnt < 4U; cnt++)
{
if(TagOutArray[cnt] != ExpectedTagOutArray[cnt])
{
errCountLocal++;
}
}
//
// Update the global error counter.
//
if(errCountLocal > 0)
{
errCountGlobal++;
}
//
// Clear the local error counter.
//
errCountLocal = 0;
}
//
// Clean up AES Data registers
//
AES_performSoftReset(AESA_BASE);
//
// Update test status variable
//
if(errCountGlobal == 0)
{
testStatusGlobal = TEST_PASS;
}
else
{
testStatusGlobal = TEST_FAIL;
}
//
// Infinite Loop to keep the core running
//
while(1)
{
asm(" ESTOP0");
}
}
//
// Perform an AES-CBCMAC encryption operation.
//
void performCMACAuthentication(AES_KeySize keySize, uint32_t *srcArray,
uint32_t *dstTagArray, uint32_t *cmackey,
uint32_t *iv, uint32_t dataLength, bool useDMA)
{
//
// Clear the interrupt flags.
//
contextInIntFlag = false;
dataInIntFlag = false;
contextOutIntFlag = false;
dataOutIntFlag = false;
contextInDMADoneIntFlag = false;
dataInDMADoneIntFlag = false;
contextOutDMADoneIntFlag = false;
dataOutDMADoneIntFlag = false;
uint32_t subKey1[4] = {0};
uint32_t subKey2[4] = {0};
bool dataSizeAligned = true;// Set this to false if data is not 16 byte aligned. Padding with 0x80 is required.
uint32_t lastBlockBackup[4];
uint32_t *lastBlock = srcArray + ((dataLength/4U) - 4U);
// Make a backup of the last block
lastBlockBackup[0] = lastBlock[0];
lastBlockBackup[1] = lastBlock[1];
lastBlockBackup[2] = lastBlock[2];
lastBlockBackup[3] = lastBlock[3];
generateSubKey(keySize, cmackey, iv, subKey1, subKey2);
if(dataSizeAligned)
{
//array_xor_inplace_generic(srcArray + ((dataLength/4U) - 4U), subKey1, 4U );
array_xor_inplace_generic(lastBlock, subKey1, 4U);
}
else
{
//array_xor_inplace_generic(srcArray + ((dataLength/4U) - 4U), subKey2, 4U );
array_xor_inplace_generic(lastBlock, subKey2, 4U);
}
//
// Clear the interrupt flags.
//
contextInIntFlag = false;
dataInIntFlag = false;
contextOutIntFlag = false;
dataOutIntFlag = false;
//
// Perform a soft reset.
//
initilizeAES();
//
// Configure the AES module.
//
AES_ConfigParams aesConfig;
memset(&aesConfig, 0, sizeof(AES_ConfigParams));
aesConfig.direction = AES_DIRECTION_ENCRYPT;
aesConfig.keySize = keySize;
aesConfig.opMode = AES_OPMODE_CBCMAC;
aesConfig.ctrWidth = AES_CTR_WIDTH_32BIT;
aesConfig.ccmLenWidth = AES_CCM_L_1;
aesConfig.ccmAuthLenWidth = AES_CCM_M_16;
AES_configureModule(AESA_BASE, &aesConfig);
//
// Write the initialization value
//
AES_setInitializationVector(AESA_BASE, iv);
//
// Write the keys.
//
AES_setKey1(AESA_BASE,cmackey,keySize);
//
// Enable all interrupts.
//
if(useDMA)
{
DMA_initController();
initializeDMACH1();
configureDMACH1((const void*)srcArray,
(const void*)(AESA_BASE + AES_O_DATA_IN_OUT_0),
(roundUpDataLength(dataLength) / 16U));
configureDMAInterruptCH1();
initializeDMACH2();
configureDMACH2((const void*)(AESA_BASE + AES_O_TAG_OUT_0),
(const void*)TagOutArray,
1);
configureDMAInterruptCH2();
AES_setDataLength(AESA_BASE, dataLength);
/*trigger dma*/
startAES();
//
// Wait for the data in DMA done interrupt.
//
while(!dataInDMADoneIntFlag)
{
}
//
// Wait for the data out DMA done interrupt.
//
while(!dataOutDMADoneIntFlag)
{
}
lastBlock[0] = lastBlockBackup[0];
lastBlock[1] = lastBlockBackup[1];
lastBlock[2] = lastBlockBackup[2];
lastBlock[3] = lastBlockBackup[3];
}
else
{
AES_enableInterrupt(AESA_BASE, (AES_INT_CONTEXT_IN |
AES_INT_CONTEXT_OUT | AES_INT_DATA_IN |
AES_INT_DATA_OUT));
//
// Perform the authentication.
//
AES_authenticateData(AESA_BASE, srcArray, dataLength, dstTagArray);
lastBlock[0] = lastBlockBackup[0];
lastBlock[1] = lastBlockBackup[1];
lastBlock[2] = lastBlockBackup[2];
lastBlock[3] = lastBlockBackup[3];
}
AES_performSoftReset(AESA_BASE);
AES_disableDMARequest(AESA_BASE, AES_DMA_EN_DATA_IN | AES_DMA_EN_CONTEXT_OUT);
}
uint32_t roundUpDataLength(uint32_t dataLength) {
uint32_t remainder;
remainder = dataLength % 16U;
if (remainder == 0U) {
return (dataLength);
} else {
return (dataLength + (16U - remainder));
}
}
//
// roundUpDataLength - Round up length to nearest 16 byte boundary. This is
// needed because all four data registers must be written at once. This is
// handled in the AES driver, but if using uDMA, the length must rounded up.
//
void performECBEncryption(AES_KeySize keySize, uint32_t *srcArray,
uint32_t *dstArray, uint32_t *keyArray,
uint32_t dataLength)
{
//
// Clear the interrupt flags.
//
contextInIntFlag = false;
dataInIntFlag = false;
contextOutIntFlag = false;
dataOutIntFlag = false;
//
// Perform a soft reset.
//
initilizeAES();
//
// Configure the AES module.
//
AES_ConfigParams aesConfig;
memset(&aesConfig, 0, sizeof(AES_ConfigParams));
aesConfig.direction = AES_DIRECTION_ENCRYPT;
aesConfig.keySize = keySize;
aesConfig.opMode = AES_OPMODE_ECB;
aesConfig.ctrWidth = AES_CTR_WIDTH_32BIT;
aesConfig.ccmLenWidth = AES_CCM_L_1;
aesConfig.ccmAuthLenWidth = AES_CCM_M_0;
AES_configureModule(AESA_BASE, &aesConfig);
//
// Write the key.
//
AES_setKey1(AESA_BASE, keyArray, keySize);
//
//
// Enable all interrupts.
//
AES_enableInterrupt(AESA_BASE, (AES_INT_CONTEXT_IN |
AES_INT_CONTEXT_OUT | AES_INT_DATA_IN |
AES_INT_DATA_OUT));
//
// Perform the encryption.
//
AES_processData(AESA_BASE, srcArray, dstArray, dataLength);
}
void generateSubKey(AES_KeySize keySize, uint32_t *cmackey, uint32_t *iv, uint32_t* subKey1, uint32_t* subKey2){
uint32_t L[4];
performECBEncryption(keySize, iv, L, cmackey, 16U);
array_shift_and_generate(L, subKey1);
array_shift_and_generate(subKey1, subKey2);
}
void array_shift_and_generate(const uint32_t input[], uint32_t output[]) {
uint32_t temp[4];
uint32_t carry = 0;
int i;
uint32_t msbCheck = 0x80;
uint32_t Rb = 0x87;
// Copy and convert endianness
for (i = 0; i < 4; i++) {
temp[i] = ((input[i] & 0xFF000000) >> 24) |
((input[i] & 0x00FF0000) >> 8) |
((input[i] & 0x0000FF00) << 8) |
((input[i] & 0x000000FF) << 24);
}
// Left shift the entire 128-bit value by 1
for (i = 3; i >= 0; i--) {
uint32_t next_carry = (temp[i] & 0x80000000U) ? 1U : 0U;
temp[i] = (temp[i] << 1) | carry;
carry = next_carry;
}
if((input[0] & msbCheck) == msbCheck){
temp[3] = temp[3] ^ Rb;
}
// Convert back to original endianness
for (i = 0; i < 4; i++) {
output[i] = ((temp[i] & 0xFF000000) >> 24) |
((temp[i] & 0x00FF0000) >> 8) |
((temp[i] & 0x0000FF00) << 8) |
((temp[i] & 0x000000FF) << 24);
}
}
void array_xor_inplace_generic(uint32_t* array1, const uint32_t* array2, uint32_t size) {
uint32_t i;
for (i = 0; i < size; i++) {
array1[i] ^= array2[i];
}
}
Thanks,
Ira
Yes, you add some extra functions to generate subkey, so the result is compatible with the RFC4493 specification. But, I test the CMAC result of secure boot, it is not equal to the result of mbedtls and openssl, as the F28P65x technical reference manual said "The CMAC calculation requires a user-defined 128-bit
key programmed in the CPU User OTP Zone 1 Header OTP CMACKEY bit field. Additionally, the user must
calculate the golden CMAC tag based on the 16-KB Flash memory range and store the tag along with the
user code at a hardcoded address in Flash. " I use openssl calculate the 16kb of executable binary, the result is different from the CCS hex utility calculation result.
The CMAC key is:
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
the example is "boot_ex1_cpu1_secure_flash_cpu1.c"
Please clarify does secure boot CMAC has the ability to generate subkey. If not, it will be hard to meet the secure-boot requirement.
Hi Ira,
Thanks for the response! Could you please help looking if the secure boot (ROM) has the same issue too?
Regards,
Hang
Hi Hang Yang xuliang ren ,
I can confirm that ROM has the code to generate subkeys and use them to compute CMAC.
Secure Boot should *not* have the same bug as the example
Thanks,
Ronak
[MK] Edited reply to fix typo
What do you mean? If so, secure boot is correct or not?
I can confirm that ROM has the code to generate subkeys and use them to compute CMAC.
How can we fix this bug? Because secure boot is essential nowadays, if the secure boot is not compatible with the standard(RFC4493), how can we convince our end customer that our product meets the requirement, such as IECC62443.
Hi This bug is not present in secure boot, we have validated it internally.
Can you please let me know what steps did you try with implementing the secure boot
Hi Nilabh,
I believe Xuliang's issue is not about running secure boot but not being able to convince end customer that the secure boot complies to IEC62443.
Is it possible to check if IEC62442 requires a secure boot with compliance to RFC4493 as mandatory? Or any secure boot can work?
Regards,
Hang.
IEC 62443 Does NOT Specify:
✗ Specific cryptographic algorithms (like RFC 4493 CMAC)
✗ Particular secure boot implementations
✗ Specific technical methods for achieving integrity/authenticity
Answer to Your Question:
IEC 62443 does NOT mandate RFC 4493 compliance or any specific secure boot implementation. The standard is technology-agnostic and focuses on the security objectives (integrity and authenticity verification) rather than prescribing specific cryptographic methods.
Any secure boot implementation that achieves the required integrity and authenticity verification would be compliant, whether it uses:
Hi Nilabh,
Thanks for the information, which has help us addressed the concerns!
In the meantime Ira Thete is it possible for us to add the changes to ROM in next products?
The problems is that customer will assume we follows RFC 4493 as we said "CMAC", and will tries to using 3-P CMAC tools for signature generation, only to find it does not work.
Now they can only use TI tools to do the job.
Regards,
Hang
I test the CCS Hex utility, it calculated the CMAC result, but the result does not compatible with the OpenSSL or mbedtls result, furthermore, the CCS result does not compatible with the method in C2000Ware_6_00_00_00/driverlib/f28p65x/examples/c28x/aes/aes_ex7_cmac_auth.c
To point out, if the secure boot of F28P65x device is compatible with the standard or best practices(ECDSA or CMAC RFC 4493, etc), it will be more convenient and persuasive.
Meanwhile, as the documentation said the authentication algorithm is CMAC, so it should compatible with its definition.
As you mentioned, "This is already present in ROM code", can you provide a description file to tell us how to use the example "boot_ex1_cpu1_secure_flash_cpu1.c", currently, the documentation on this aspect is rare, which is very confusing.
Hi Xuliang,
The team has mentioned that the implementation is correct in the ROM code. Can you please confirm if you have accounted for the little endianness of the C2000 architecture. Please note the default format OpenSSL expects is big endian. Please let us know if you can get the same CMAC tag calculation.
Regards,
Ozino
Could you please provide an example with inter-operatability, which means, a CCS example and an OpenSSL command to generate the same tag.
I consider the endianness, and I use the following command:
echo "generate big endian binary:"
${CG_TOOL_HEX} -q -b -image -map primary_boot_summary_be.map -o primary_boot_be.bin --order LS ${PROJECT_LOC}/primary_boot_roms_directive_file.txt ${BuildArtifactFileBaseName}.out
echo "generate little endian binary:"
${CG_TOOL_HEX} -q -b -image -map primary_boot_summary_le.map -o primary_boot_le.bin --order MS ${PROJECT_LOC}/primary_boot_roms_directive_file.txt ${BuildArtifactFileBaseName}.out
openssl enc -aes-128-cbc -in primary_boot_be.bin -out primary_boot_be_enc.bin -K FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -iv 00000000000000000000000000000000
openssl enc -aes-128-cbc -in primary_boot_le.bin -out primary_boot_le_enc.bin -K FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -iv 00000000000000000000000000000000
echo "generate big endian encrypted binary:"
xxd -s -16 -l 16 -p -u primary_boot_be_enc.bin
echo "generate little endian encrypted binary:"
xxd -s -16 -l 16 -p -u primary_boot_le_enc.bin
echo "big endian input, tag:"
openssl mac -cipher AES-128-CBC -macopt hexkey:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -in primary_boot_be.bin CMAC
echo "little endian input, tag:"
openssl mac -cipher AES-128-CBC -macopt hexkey:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -in primary_boot_le.bin CMAC
But none of the above result is compatible with the CCS hex utility result.
Hi TI Experts,
I have tested the CMAC implementation on F28P65 extensively, but cannot reproduce the TI-generated CMAC tag using OpenSSL (RFC4493 compliant). I have moved beyond basic checks like endianness.
Core Logic Analysis
For a typical secure boot scenario:
Protected region: `0x80000~0x823FF`
- CMAC stored at: `0x823F4~0x823FF` (16-byte tag + 8-byte padding)
- At generation: CMAC area contains zeros

What I have verified:
- Method A (CMAC area treated as zeros) → **does NOT match TI**
- Method C (exclude CMAC area) → **does NOT match TI**
- Both tested with little/big endian → still no match
Since both logically consistent methods fail, the TI toolchain must be using a **different input data assembly** than what I extract from the final binary.
My request:
Can you clearly specify:
1. Which logic model (A, B, or C) does the secure boot ROM/Hex2000 tool use?
A simple CCS example that can be verified with an OpenSSL one-liner would be the best proof.
Hi Hang,
Is the data 128 bit aligned?
ROM expects an aligned image to calculate CMAC on.
Thanks
Ronak
Hi Ronak,
I believe the problem we have is the on the generation method, especially on how CMAC area is filled.
Customer's request:
Can you clearly specify:
1. Which logic model (A, B, or C) does the secure boot ROM/Hex2000 tool use?
2. A simple CCS example that can be verified with an OpenSSL one-liner (Or any other 3P tool) would be the best proof.
Hello,
We are verifying this internally, but referencing the TRM:

Best,
Matt