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.

LP-MSPM0G3519: AES CMAC 40-byte Message Validation – Firmware Output Mismatch

Part Number: LP-MSPM0G3519
Other Parts Discussed in Thread: MSPM0G3519

Hi TI Team,

I am validating AES CMAC generation using the AESADV hardware accelerator on MSPM0G3519.

For 16-byte and 32-byte messages, the CMAC output from firmware matches perfectly with the NIST SP800-38B test vectors.
However, for a 40-byte message (non-multiple of 16), the CMAC output from firmware does not match the expected value.

Below are my detailed observations and test setup.

AES Key          : 2b7e151628aed2a6abf7158809cf4f3c
AES-ECB(Zero) L  : 7df76b0c1ab899b33e42f047b91b546f
Derived K1       : fbeed618357133667c85e08f7236a8de
Derived K2       : f7ddac306ae266ccf90bc11ee46d513b

Message (40 bytes):
6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c
9eb76fac45af8e5130c81c46a35ce411

Partial (un-padded) last 8 bytes : 30c81c46a35ce411
Padded block (before XOR K2)     : 30c81c46a35ce4118000000000000000
K2                               : f7ddac306ae266ccf90bc11ee46d513b
Final block (padded ^ K2)        : c715b076c9be82dd790bc11ee46d513b

Expected CMAC (NIST SP800-38B):

dfa66747de9ae63030ca32611497c827

Firmware CMAC (Observed): 

465AF15ED86DBF7223C13C77682B884D

Keys are loaded using: 

DL_AESADV_setKeySize(AESADV, DL_AESADV_KEY_SIZE_128);
DL_AESADV_setKey(AESADV, (uint32_t *)aes_key);

Firmware Function Used

void generate_cmac(uint8_t *msg, uint32_t msgLen, uint8_t *tagOut)
{
__attribute__((aligned(4))) uint8_t lastBlock[16] = {0};

if ((msg == NULL_PTR) || (tagOut == NULL_PTR) || (msgLen == 0U))
return;

DL_AESADV_Config config = {
.mode = DL_AESADV_MODE_CMAC,
.direction = DL_AESADV_DIR_ENCRYPT,
.k1 = rub_output_subkey1,
.k2 = rub_output_subkey2,
.lowerCryptoLength = msgLen,
.upperCryptoLength = 0U,
.aadLength = 0U,
.iv = NULL,
.nonce = NULL
};

DL_AESADV_initCMAC(AESADV, &config);

uint32_t fullBlocks = msgLen / 16U;
uint32_t remBytes = msgLen % 16U;

for (uint32_t i = 0; i < fullBlocks; i++)
{
while (!DL_AESADV_isInputReady(AESADV)) {;}
DL_AESADV_STATUS st = DL_AESADV_loadInputData(AESADV, msg + (i * 16U));
if (st != DL_AESADV_STATUS_SUCCESS) { __BKPT(0); return; }
}

if (remBytes > 0U)
{
memcpy(lastBlock, msg + (fullBlocks * 16U), remBytes);
lastBlock[remBytes] = 0x80;

for (int i = 0; i < 16; i++)
lastBlock[i] ^= rub_output_subkey2[i];

while (!DL_AESADV_isInputReady(AESADV)) {;}
DL_AESADV_loadInputDataAligned(AESADV, (uint32_t *)lastBlock);
}

while (!DL_AESADV_isSavedOutputContextReady(AESADV)) {;}
DL_AESADV_STATUS st = DL_AESADV_readTAG(AESADV, tagOut);
if (st != DL_AESADV_STATUS_SUCCESS) { __BKPT(0); return; }

memset(lastBlock, 0, sizeof(lastBlock));
}

Clarifications Requested

Could you please confirm the following points:

  1. Does DL_AESADV_MODE_CMAC automatically handle padding and subkey (K1/K2) XOR internally,
    or should firmware manually apply the XOR and padding before calling DL_AESADV_loadInputDataAligned()?

  2. Does AESADV support CMAC generation for non-multiple-of-16 message lengths (like 7 or 40 bytes)?
    I observed that when msgLen is not a multiple of 16, the CMAC is incorrect.
    Also, passing 0 bytes as length results in no valid output.

  3. Is it expected that only multiples of 16 bytes are supported for CMAC operation?
    If not, are there additional configuration steps to enable partial-block processing?


Best regards,
Kasirajan C

  • Hi Kasirajan,

    1. It will not handle the padding and subkey XOR automatically.

    2. According to the TRM, I believe the following figure can answer you the rest of two questions, the input data should be 16x bytes and length must be more than 0.

    Thanks!

    Best Regards,
    Peter

  • Hi Peter, 

    Please correct me if I’m wrong — as per my understanding from above reponse, AES CMAC input to AESADV must be a multiple of 16 bytes (16, 32, 48, etc.). If the message isn’t a multiple of 16, firmware should pad with 0x80 followed by zeros until it reaches 16 bytes, then XOR the final block with K2.I applied this rule for a 40-byte message:

    6BC1BEE22E409F96E93D7E117393172A
    AE2D8A571E03AC9C9EB76FAC45AF8E51
    C715B076C9BE82DD790BC11EE46D513B ← padded ⊕ K2

    However, the CMAC output from DL_AESADV_readTAG() is:
    465AF15ED86DBF7223C13C77682B884D

    But the expected CMAC (per RFC 4493 / NIST SP800-38B) is:
    DFA66747DE9AE63030CA32611497C827

    Why is the hardware returning an incorrect CMAC even though the last block and padding are correct?

    Thanks,
    Kasirajan

  • Hi Kasirajan,

    Let me clarify more information about CMAC based on AESADV:

    • If the input data is not 16bytes aligned, customer need to manually pad the input buffer with 0b1000... stream (as you said 0x80 followed by zeros) to make sure the input buffer is 16 bytes aligned.
    • The CMAC final step (XOR with K1/K2) is achieve by AESADV module itself by hardware, so no need to calculate in FW for this step.
    • If the input data is not 16 bytes aligned, you also need to set the C_LENGTH_0 register (.lowerCryptoLength field in CMAC configuration) as the actual length (40 in your example). 

    Best Regards,

    Pengfei

  • Thanking you for your response.