From 12e99bfdc4dd8c67bb9361ef7327cf9b06a4c7d4 Mon Sep 17 00:00:00 2001 From: Konstantin Kroschewski Date: Thu, 14 Jul 2022 11:19:59 +0200 Subject: [PATCH] If the tc_cmac_update() function is called and fills the internal leftover cache completely, the following tc_cmac_final() call will produce a wrong token. If the tc_cmac_update() is called with a data length which fills up the internal leftover cache completely, the leftover data will be processed instantly and is left empty. This is not the right behavior, because tc_cmac_final() requires that the last block is still in the leftover cache and not processed, because it need special treatment. Bug reproduction code: ~~~c #include "tinycrypt/cmac_mode.h" #include "tinycrypt/aes.h" #include "tinycrypt/utils.h" #include "tinycrypt/constants.h" #include #include #define ASSERT_TRUE(cond) if (!(cond)) {printf("Test failed!\n"); return -1;} const uint8_t testData[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; const uint8_t key[TC_AES_KEY_SIZE] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x12 }; uint8_t token1[TC_AES_BLOCK_SIZE]; uint8_t token2[TC_AES_BLOCK_SIZE]; int main() { { struct tc_cmac_struct ctx; struct tc_aes_key_sched_struct sched; ASSERT_TRUE(tc_cmac_init(&ctx) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_setup(&ctx, key, &sched) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_update(&ctx, testData, sizeof(testData)) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_final(token1, &ctx) == TC_CRYPTO_SUCCESS); } { const size_t splitOffset = 8; struct tc_cmac_struct ctx; struct tc_aes_key_sched_struct sched; ASSERT_TRUE(tc_cmac_init(&ctx) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_setup(&ctx, key, &sched) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_update(&ctx, testData, splitOffset) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_update(&ctx, &testData[splitOffset] , TC_AES_BLOCK_SIZE - splitOffset) == TC_CRYPTO_SUCCESS); ASSERT_TRUE(tc_cmac_final(token2, &ctx) == TC_CRYPTO_SUCCESS); } ASSERT_TRUE(memcmp(token1, token2, TC_AES_BLOCK_SIZE) == 0); //will fail, tokens do not match printf("Test ok!\n"); } ~~~ --- lib/source/cmac_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/source/cmac_mode.c b/lib/source/cmac_mode.c index 22adf20..ed51542 100644 --- a/lib/source/cmac_mode.c +++ b/lib/source/cmac_mode.c @@ -179,13 +179,13 @@ int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length) /* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */ size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset; - if (data_length < remaining_space) { + if (data_length <= remaining_space) { /* still not enough data to encrypt this time either */ _copy(&s->leftover[s->leftover_offset], data_length, data, data_length); s->leftover_offset += data_length; return TC_CRYPTO_SUCCESS; } - /* leftover block is now full; encrypt it first */ + /* leftover block is now full and there is addidional data; encrypt block first */ _copy(&s->leftover[s->leftover_offset], remaining_space, data,