cancel
Showing results for 
Search instead for 
Did you mean: 

STSAFE-A110 with mbedTLS and local envelope API

Michael98006
Associate III

I'm using an STSAFE-A110 chip with SPL02 profile on a custom board and trying to get StSafeA_WrapLocalEnvelope() function working. I've already successfully paired my chip with my MCU/FW by writing the default host MAC key from the ST examples to the STSAFE chip:

{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}.
I generated envelope slot keys and checked for them with the StSafeA_LocalEnvelopeKeySlotQuery() function, and both key 0 and 1 slots have the envelope keys.
A call to StSafeA_WrapLocalEnvelope(gStsafeHandle, keySlot, dataIn, dataInSize, &localEnvelopeInfo, STSAFEA_MAC_HOST_CMAC, STSAFEA_ENCRYPTION_NONE) returns STSAFEA_INVALID_CMAC. I don't know why that means and I'm looking to find out what this error code might mean. And perhaps more importantly, how do I debug this issue?  @Benjamin BARATTE 
 
I'm on the Nordic nRF52832 platform using Nordic SDK and the version of mbedTLS they provided, so my implementation of StSafeA_AES_MAC_*() functions looks like this:

 

// Call nrf_crypto_init() at start-up.
//
// Return value checks are omitted below for brivity, but
// the original code had them in place and no errors were detected.


void StSafeA_AES_MAC_Start(void **ppAesMacCtx)
{
    uint8_t iv[NRF_CRYPTO_MBEDTLS_AES_IV_SIZE] = {0};

    *ppAesMacCtx = &cbc_mac_128_ctx;
    nrf_crypto_aes_init(*ppAesMacCtx,
                        &g_nrf_crypto_aes_cbc_mac_128_pad_pkcs7_info,
                        NRF_CRYPTO_MAC_CALCULATE);
    
    nrf_crypto_aes_key_set(*ppAesMacCtx, (uint8_t*)gHostMacKey);
    nrf_crypto_aes_iv_set(*ppAesMacCtx, iv);
}

void StSafeA_AES_MAC_Update(uint8_t *pInData, uint16_t InDataLength, void *pAesMacCtx)
{
    uint8_t  mac[16] = {0};

    nrf_crypto_aes_update(pAesMacCtx,
                          (uint8_t *)pInData,
                          InDataLength,
                          (uint8_t *)mac);
}

static uint8_t gMac[16] = {0};

__weak void StSafeA_AES_MAC_LastUpdate(uint8_t *pInData, uint16_t InDataLength, void *pAesMacCtx)
{
    size_t outLen = sizeof(gMac);
    
    nrf_crypto_aes_finalize(pAesMacCtx,
                            (uint8_t *)pInData,
                            InDataLength,
                            (uint8_t *)gMac,
                            &outLen);
}

__weak void StSafeA_AES_MAC_Final(uint8_t *pOutMac, void **ppAesMacCtx)
{
    memcpy(pOutMac, gMac, sizeof(gMac));

    nrf_crypto_aes_uninit(*ppAesMacCtx);
    *ppAesMacCtx = NULL;
}

 

Thank you!

3 REPLIES 3
Benjamin BARATTE
ST Employee

Hi @Michael98006 ,

The error you are reporting is typical when the CMAC implementation is not correct.

Be aware that after 50 invalid CMAC in a row, the Pairing key will be blocked.

To avoid, blindly testing the CMAC implementation please find below some test vectors :

 

Test mac key : 00112233445566778899AABBCCDDEEFF

test vector 1 : 0102030405060708090A0B0C0D0E0F
MAC result    : DE1419BBDD340EC3A0E0D5F113C91D39

test vector 2 : 00000100800000000000000000000000 00b4000101
Mac result    : 025F67E6EF77607DA7DB05528C3444C3

 

 

You can use the Test Vector 1 :

 

void *ctx;

uint8_t test_vector1[] = {
  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
  0x0d, 0x0e, 0x0f
};

uint8_t mac[16];

StSafeA_AES_MAC_Start(&ctx);

StSafeA_AES_MAC_LastUpdate(test_vector1, sizeof(test_vector1), ctx);

StSafeA_AES_MAC_Final(mac, &ctx);

 

you can use the Test Vector 2 : 

 

void *ctx;

uint8_t test_vector2_1[] = {
  0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00
};

uint8_t test_vector2_2[] = {
  0x00, 0xb4, 0x00, 0x01, 0x01
};
uint8_t mac[16];

StSafeA_AES_MAC_Start(&ctx);

StSafeA_AES_MAC_Update(test_vector2_1, sizeof(test_vector2_1), ctx);

StSafeA_AES_MAC_LastUpdate(test_vector2_2, sizeof(test_vector2_2), ctx);

StSafeA_AES_MAC_Final(mac, &ctx);

 

regarding your configuration, I'm not family with NRF AES API but I have seen that you can use g_nrf_crypto_aes_cbc_mac_128_info  for AES CBC MAC 128 without padding. We don't use padding, so this could be the source of your issue.

Best Regards,

Benjamin

 

 

Michael98006
Associate III

Hi @Benjamin BARATTE ,

Thank you for your response!  I'm still not getting the correct output. I was wondering if you could clarify this for me:

1. CBC MAC encryption seems to require multiples of 16-byte (128-bit) input data packets; otherwise, padding to 16-bute boundary seems to be required. Not sure how encryption of the second vector would work without padding.

2. The first vector is only 15 bytes. It seems like it should have been aligned to a 16-byte boundary, and I was expecting to see a test vector resembling something like 

uint8_t test_vector1[] = {
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
  0x0d, 0x0e, 0x0f
};

Could you check the first vector for correct number of bytes?

Thanks again!

Hi @Michael98006 ,

The CMAC operation doesn't requires 16 bytes alignment and you are right normally, you should use the  g_nrf_crypto_aes_cbc_mac_128_pad_pkcs7_info option as this is the CMAC algorithm that mandates PKCS7 padding.

Therefore, the size of the input is not important as there is a padding done during the CMAC operation.

if you look at the mbedtls cmac function, you will see that you don't have constraint on the alignment of the input block.

Therefore my test vector are valid as the input size is not an issue.

If you are not able to get the test vector right, this means you have an issue with the CMAC implementation.

Also, I see that you use the call to nrf_crypto_aes_iv_set(*ppAesMacCtx, iv); even if the algo is AES CBC MAC, there is no AES CBC below and the IV is not necessary.

If you have difficulties to use the Nordic API, you can use the NIST test vector as per in the RFC4493

if the output is not compliant with the RFC, you can ask your support at Nordic why the API is not output the expected value for the NIST Test Vector.

If you have direct access to mbedtls, then you can use the example implementation from the X-CUBE-SAFEA1 package :

/**
  * @brief   StSafeA_AES_MAC_Start
  *          Start AES MAC computation
  * @note    This is a weak function that MUST be implemented at application interface level.
  *          A specific example template stsafea_crypto_xxx_interface_template.c is provided with this BSP
  *
  * @param   ppAesMacCtx : AES MAC context
  * @retval  None
  */
void StSafeA_AES_MAC_Start(void **ppAesMacCtx)
{

#if defined MBEDTLS_AES_C & defined MBEDTLS_CIPHER_MODE_CBC
  *ppAesMacCtx = &cipher_ctx;

  mbedtls_cipher_init(*ppAesMacCtx);
  (void)mbedtls_cipher_setup(*ppAesMacCtx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB));
  (void)mbedtls_cipher_cmac_starts(*ppAesMacCtx, aHostMacKey, STSAFEA_HOST_KEY_LENGTH * 8U);
#endif /* MBEDTLS_AES_C - MBEDTLS_CIPHER_MODE_CBC */
}

/**
  * @brief   StSafeA_AES_MAC_Update
  *          Update / Add data to MAC computation
  * @note    This is a weak function that MUST be implemented at application interface level.
  *          A specific example template stsafea_crypto_xxx_interface_template.c is provided with this BSP
  *
  * @param   pInData : data buffer
  * @param   InDataLength : data buffer length
  * @param   pAesMacCtx : AES MAC context
  * @retval  None
  */
void StSafeA_AES_MAC_Update(uint8_t *pInData, uint16_t InDataLength, void *pAesMacCtx)
{

#if defined MBEDTLS_AES_C & defined MBEDTLS_CIPHER_MODE_CBC
  (void)mbedtls_cipher_cmac_update(pAesMacCtx, pInData, InDataLength);
#endif /* MBEDTLS_AES_C - MBEDTLS_CIPHER_MODE_CBC */
}

/**
  * @brief   StSafeA_AES_MAC_LastUpdate
  *          Update / Add data to MAC computation
  * @note    This is a weak function that MUST be implemented at application interface level.
  *          A specific example template stsafea_crypto_xxx_interface_template.c is provided with this BSP
  *
  * @param   pInData : data buffer
  * @param   InDataLength : data buffer length
  * @param   pAesMacCtx : AES MAC context
  * @retval  None
  */
void StSafeA_AES_MAC_LastUpdate(uint8_t *pInData, uint16_t InDataLength, void *pAesMacCtx)
{
StSafeA_AES_MAC_Update(pInData, InDataLength, pAesMacCtx);
}

/**
  * @brief   StSafeA_AES_MAC_Final
  *          Finalize AES MAC computation
  * @note    This is a weak function that MUST be implemented at application interface level.
  *          A specific example template stsafea_crypto_xxx_interface_template.c is provided with this BSP
  *
  * @param   pOutMac : calculated MAC
  * @param   ppAesMacCtx : AES MAC context
  * @retval  None
  */
void StSafeA_AES_MAC_Final(uint8_t *pOutMac, void **ppAesMacCtx)
{

#if defined MBEDTLS_AES_C & defined MBEDTLS_CIPHER_MODE_CBC
  (void)mbedtls_cipher_cmac_finish(*ppAesMacCtx, pOutMac);
  mbedtls_cipher_free(*ppAesMacCtx);
  *ppAesMacCtx = NULL;
#endif /* MBEDTLS_AES_C - MBEDTLS_CIPHER_MODE_CBC */
}

Best Regards,

 

Benjamin