From f88ad41f77f7f7380cf4f30f10a5f0edb26f8233 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Sat, 12 Jan 2019 12:32:45 +0100 Subject: [PATCH] btstack_crypto/aes-ccm: add support for Additional Authenticated Data (AAD) --- src/btstack_crypto.c | 109 ++++++++++++++++++++++++++++++++++++- src/btstack_crypto.h | 21 ++++++- test/crypto/aes_ccm.c | 26 +++++++++ test/crypto/aes_ccm_test.c | 74 ++++++++++++++++++++++++- 4 files changed, 222 insertions(+), 8 deletions(-) diff --git a/src/btstack_crypto.c b/src/btstack_crypto.c index 3d5a04eaf..b2b59346d 100644 --- a/src/btstack_crypto.c +++ b/src/btstack_crypto.c @@ -341,7 +341,7 @@ static void btstack_crypto_ccm_setup_a_i(btstack_crypto_ccm_t * btstack_crypto_c memcpy(&btstack_crypto_ccm_s[1], btstack_crypto_ccm->nonce, 13); big_endian_store_16(btstack_crypto_ccm_s, 14, counter); #ifdef DEBUG_CCM - printf("tstack_crypto_ccm_setup_a_%u\n", counter); + printf("ststack_crypto_ccm_setup_a_%u\n", counter); printf("%16s: ", "ai"); printf_hexdump(btstack_crypto_ccm_s, 16); #endif @@ -373,7 +373,8 @@ static void btstack_crypto_ccm_setup_a_i(btstack_crypto_ccm_t * btstack_crypto_c static void btstack_crypto_ccm_setup_b_0(btstack_crypto_ccm_t * btstack_crypto_ccm, uint8_t * b0){ uint8_t m_prime = (btstack_crypto_ccm->auth_len - 2) / 2; - b0[0] = (m_prime << 3) | 1 ; // Adata = 0, M', L' = L - 1 + uint8_t Adata = btstack_crypto_ccm->aad_len ? 1 : 0; + b0[0] = (Adata << 6) | (m_prime << 3) | 1 ; // Adata, M', L' = L - 1 memcpy(&b0[1], btstack_crypto_ccm->nonce, 13); big_endian_store_16(b0, 14, btstack_crypto_ccm->message_len); #ifdef DEBUG_CCM @@ -548,6 +549,55 @@ static void btstack_crypto_ccm_calc_xn(btstack_crypto_ccm_t * btstack_crypto_ccm } #endif +static void btstack_crypto_ccm_calc_aad_xn(btstack_crypto_ccm_t * btstack_crypto_ccm){ + // store length + if (btstack_crypto_ccm->aad_offset == 0){ + uint8_t len_buffer[2]; + big_endian_store_16(len_buffer, 0, btstack_crypto_ccm->aad_len); + btstack_crypto_ccm->x_i[0] ^= len_buffer[0]; + btstack_crypto_ccm->x_i[1] ^= len_buffer[1]; + btstack_crypto_ccm->aad_remainder_len += 2; + btstack_crypto_ccm->aad_offset += 2; + } + + // fill from input + uint16_t bytes_free = 16 - btstack_crypto_ccm->aad_remainder_len; + uint16_t bytes_to_copy = btstack_min(bytes_free, btstack_crypto_ccm->block_len); + printf("btstack_crypto_ccm_calc_aad_xn: bytes to copy %u\n", bytes_to_copy); + while (bytes_to_copy){ + btstack_crypto_ccm->x_i[btstack_crypto_ccm->aad_remainder_len++] ^= *btstack_crypto_ccm->input++; + btstack_crypto_ccm->aad_offset++; + btstack_crypto_ccm->block_len--; + bytes_to_copy--; + bytes_free--; + } + + // if last block, fill with zeros + printf("btstack_crypto_ccm_calc_aad_xn: aad_len %u, aad_offset %u. aad_remainder_len %u, bytes_free %u\n", + btstack_crypto_ccm->aad_len, btstack_crypto_ccm->aad_offset, btstack_crypto_ccm->aad_remainder_len, bytes_free); + + if (btstack_crypto_ccm->aad_offset == (btstack_crypto_ccm->aad_len + 2)){ + printf("btstack_crypto_ccm_calc_aad_xn: fill from %u, %u bytes\n", btstack_crypto_ccm->aad_remainder_len, bytes_free); + // memset(&btstack_crypto_ccm->b_i[btstack_crypto_ccm->aad_remainder_len], 0, bytes_free); + btstack_crypto_ccm->aad_remainder_len = 16; + } + // if not full, notify done + if (btstack_crypto_ccm->aad_remainder_len < 16){ + btstack_crypto_done(&btstack_crypto_ccm->btstack_crypto); + return; + } + + // encrypt block +#ifdef DEBUG_CCM + printf("%16s: ", "Xn XOR Bn (aad)"); + printf_hexdump(btstack_crypto_ccm->x_i, 16); +#endif + + btstack_crypto_ccm->aad_remainder_len = 0; + btstack_crypto_ccm->state = CCM_W4_AAD_XN; + btstack_crypto_aes128_start(btstack_crypto_ccm->key, btstack_crypto_ccm->x_i); +} + static void btstack_crypto_ccm_handle_s0(btstack_crypto_ccm_t * btstack_crypto_ccm, const uint8_t * data){ // data is little-endian, flip on the fly int i; @@ -634,6 +684,7 @@ static void btstack_crypto_run(void){ } break; + case BTSTACK_CRYPTO_CCM_DIGEST_BLOCK: case BTSTACK_CRYPTO_CCM_ENCRYPT_BLOCK: case BTSTACK_CRYPTO_CCM_DECRYPT_BLOCK: #ifdef USE_BTSTACK_AES128 @@ -642,6 +693,9 @@ static void btstack_crypto_run(void){ #else btstack_crypto_ccm = (btstack_crypto_ccm_t *) btstack_crypto; switch (btstack_crypto_ccm->state){ + case CCM_CALCULATE_AAD_XN: + btstack_crypto_ccm_calc_aad_xn(btstack_crypto_ccm); + break; case CCM_CALCULATE_X1: btstack_crypto_ccm_calc_x1(btstack_crypto_ccm); break; @@ -772,6 +826,36 @@ static void btstack_crypto_handle_encryption_result(const uint8_t * data){ reverse_128(data, result); btstack_crypto_cmac_handle_encryption_result(btstack_crypto_cmac, result); break; + case BTSTACK_CRYPTO_CCM_DIGEST_BLOCK: + btstack_crypto_ccm = (btstack_crypto_ccm_t*) btstack_linked_list_get_first_item(&btstack_crypto_operations); + switch (btstack_crypto_ccm->state){ + case CCM_W4_X1: + reverse_128(data, btstack_crypto_ccm->x_i); +#ifdef DEBUG_CCM + printf("%16s: ", "X1"); + printf_hexdump(btstack_crypto_ccm->x_i, 16); +#endif + btstack_crypto_ccm->aad_remainder_len = 0; + btstack_crypto_ccm->state = CCM_CALCULATE_AAD_XN; + break; + case CCM_W4_AAD_XN: + reverse_128(data, btstack_crypto_ccm->x_i); +#ifdef DEBUG_CCM + printf("%16s: ", "Xn+1 AAD"); + printf_hexdump(btstack_crypto_ccm->x_i, 16); +#endif + // more aad? + if (btstack_crypto_ccm->aad_offset < (btstack_crypto_ccm->aad_len + 2)){ + btstack_crypto_ccm->state = CCM_CALCULATE_AAD_XN; + } else { + // done + btstack_crypto_done(btstack_crypto); + } + break; + default: + break; + } + break; case BTSTACK_CRYPTO_CCM_ENCRYPT_BLOCK: btstack_crypto_ccm = (btstack_crypto_ccm_t*) btstack_linked_list_get_first_item(&btstack_crypto_operations); switch (btstack_crypto_ccm->state){ @@ -1058,15 +1142,28 @@ int btstack_crypto_ecc_p256_validate_public_key(const uint8_t * public_key){ } #endif -void btstack_crypo_ccm_init(btstack_crypto_ccm_t * request, const uint8_t * key, const uint8_t * nonce, uint16_t message_len, uint8_t auth_len){ +void btstack_crypo_ccm_init(btstack_crypto_ccm_t * request, const uint8_t * key, const uint8_t * nonce, uint16_t message_len, uint16_t additional_authenticated_data_len, uint8_t auth_len){ request->key = key; request->nonce = nonce; request->message_len = message_len; + request->aad_len = additional_authenticated_data_len; + request->aad_offset = 0; request->auth_len = auth_len; request->counter = 1; request->state = CCM_CALCULATE_X1; } +void btstack_crypo_ccm_digest(btstack_crypto_ccm_t * request, uint8_t * additional_authenticated_data, uint16_t additional_authenticated_data_len, void (* callback)(void * arg), void * callback_arg){ + // not implemented yet + request->btstack_crypto.context_callback.callback = callback; + request->btstack_crypto.context_callback.context = callback_arg; + request->btstack_crypto.operation = BTSTACK_CRYPTO_CCM_DIGEST_BLOCK; + request->block_len = additional_authenticated_data_len; + request->input = additional_authenticated_data; + btstack_linked_list_add_tail(&btstack_crypto_operations, (btstack_linked_item_t*) request); + btstack_crypto_run(); +} + void btstack_crypo_ccm_get_authentication_value(btstack_crypto_ccm_t * request, uint8_t * authentication_value){ memcpy(authentication_value, request->x_i, request->auth_len); } @@ -1081,6 +1178,9 @@ void btstack_crypto_ccm_encrypt_block(btstack_crypto_ccm_t * request, uint16_t b request->block_len = block_len; request->input = plaintext; request->output = ciphertext; + if (request->state != CCM_CALCULATE_X1){ + request->state = CCM_CALCULATE_XN; + } btstack_linked_list_add_tail(&btstack_crypto_operations, (btstack_linked_item_t*) request); btstack_crypto_run(); } @@ -1092,6 +1192,9 @@ void btstack_crypto_ccm_decrypt_block(btstack_crypto_ccm_t * request, uint16_t b request->block_len = block_len; request->input = ciphertext; request->output = plaintext; + if (request->state != CCM_CALCULATE_X1){ + request->state = CCM_CALCULATE_SN; + } btstack_linked_list_add_tail(&btstack_crypto_operations, (btstack_linked_item_t*) request); btstack_crypto_run(); } diff --git a/src/btstack_crypto.h b/src/btstack_crypto.h index 97c2a6750..7d4daf236 100644 --- a/src/btstack_crypto.h +++ b/src/btstack_crypto.h @@ -60,6 +60,7 @@ typedef enum { BTSTACK_CRYPTO_CMAC_MESSAGE, BTSTACK_CRYPTO_ECC_P256_GENERATE_KEY, BTSTACK_CRYPTO_ECC_P256_CALCULATE_DHKEY, + BTSTACK_CRYPTO_CCM_DIGEST_BLOCK, BTSTACK_CRYPTO_CCM_ENCRYPT_BLOCK, BTSTACK_CRYPTO_CCM_DECRYPT_BLOCK, } btstack_crypto_operation_t; @@ -102,6 +103,8 @@ typedef struct { typedef enum { CCM_CALCULATE_X1, CCM_W4_X1, + CCM_CALCULATE_AAD_XN, + CCM_W4_AAD_XN, CCM_CALCULATE_XN, CCM_W4_XN, CCM_CALCULATE_S0, @@ -118,10 +121,13 @@ typedef struct { const uint8_t * input; uint8_t * output; uint8_t x_i[16]; + uint16_t aad_offset; + uint16_t aad_len; uint16_t message_len; - uint16_t block_len; uint16_t counter; + uint16_t block_len; uint8_t auth_len; + uint8_t aad_remainder_len; } btstack_crypto_ccm_t; /** @@ -220,9 +226,10 @@ int btstack_crypto_ecc_p256_validate_public_key(const uint8_t * public_key); * @param nonce * @param key * @param message_len + * @param additional_authenticated_data_len must be smaller than 0xff00 * @param auth_len */ -void btstack_crypo_ccm_init(btstack_crypto_ccm_t * request, const uint8_t * key, const uint8_t * nonce, uint16_t message_len, uint8_t auth_len); +void btstack_crypo_ccm_init(btstack_crypto_ccm_t * request, const uint8_t * key, const uint8_t * nonce, uint16_t message_len, uint16_t additional_authenticated_data_len, uint8_t auth_len); /** * Get authentication value after encrypt or decrypt operation @@ -231,6 +238,16 @@ void btstack_crypo_ccm_init(btstack_crypto_ccm_t * request, const uint8_t * key, */ void btstack_crypo_ccm_get_authentication_value(btstack_crypto_ccm_t * request, uint8_t * authentication_value); +/** + * Digest Additional Authentication Data - can be called multipled times up to total additional_authenticated_data_len specified in btstack_crypo_ccm_init + * @param request + * @param additional_authenticated_data + * @param additional_authenticated_data_len + * @param callback + * @param callback_arg + */ +void btstack_crypo_ccm_digest(btstack_crypto_ccm_t * request, uint8_t * additional_authenticated_data, uint16_t additional_authenticated_data_len, void (* callback)(void * arg), void * callback_arg); + /** * Encrypt block - can be called multiple times. len must be a multiply of 16 for all but the last call * @param request diff --git a/test/crypto/aes_ccm.c b/test/crypto/aes_ccm.c index 5770a60ac..be91881cb 100644 --- a/test/crypto/aes_ccm.c +++ b/test/crypto/aes_ccm.c @@ -115,6 +115,11 @@ int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], pmsg[i] = Xn[i]; } +#ifdef LOG_XN + printf("%16s: ", "Xn XOR bn"); + printf_hexdump(pmsg, 16); +#endif + err = bt_encrypt_be(key, pmsg, Xn); if (err) { return err; @@ -323,10 +328,21 @@ int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], aad_len -= 16; i = 0; +#ifdef LOG_XN + printf("%16s: ", "Xn XOR bn (aad)"); + printf_hexdump(pmsg, 16); +#endif + err = bt_encrypt_be(key, pmsg, Xn); if (err) { return err; } + +#ifdef LOG_XN + printf("%16s: ", "Xn+1 AAD"); + printf_hexdump(Xn, 16); +#endif + } for (i = 0; i < aad_len; i++, j++) { @@ -337,10 +353,20 @@ int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], pmsg[i] = Xn[i]; } +#ifdef LOG_XN + printf("%16s: ", "Xn XOR bn (aad)"); + printf_hexdump(pmsg, 16); +#endif + err = bt_encrypt_be(key, pmsg, Xn); if (err) { return err; } +#ifdef LOG_XN + printf("%16s: ", "Xn+1 AAD"); + printf_hexdump(Xn, 16); +#endif + } last_blk = msg_len % 16; diff --git a/test/crypto/aes_ccm_test.c b/test/crypto/aes_ccm_test.c index f51629d14..0d360666c 100644 --- a/test/crypto/aes_ccm_test.c +++ b/test/crypto/aes_ccm_test.c @@ -29,7 +29,73 @@ static void ccm_done(void * arg){ } -static void message_24(void){ +static void message_24_upper_transport_encrypt(void){ + printf("[+] Upper transport encrypt\n"); + DEFINE_KEY(label_uuid, "f4a002c7fb1e4ca0a469a021de0db875"); + DEFINE_KEY(app_key, "63964771734fbd76e3b40519d1d94a48"); + + uint8_t app_nonce[13]; + parse_hex(app_nonce, "010007080d1234973612345677"); + printf("%16s: ", "app_nonce"); printf_hexdump(app_nonce, 13); + + uint8_t plaintext[8]; + parse_hex(plaintext, "ea0a00576f726c64"); + printf("%16s: ", "plaintext"); printf_hexdump(plaintext, sizeof(plaintext)); + + printf("Reference:\n"); + uint8_t ciphertext[8+8]; + bt_mesh_ccm_encrypt(app_key, app_nonce, plaintext, sizeof(plaintext), label_uuid, sizeof(label_uuid), ciphertext, 8); + printf("%16s: ", "ciphertext"); printf_hexdump(ciphertext, 8); + printf("%16s: ", "TransMIC"); printf_hexdump(&ciphertext[8], 8); + + // btstack_crypto + printf("btstack_crypto:\n"); + uint8_t trans_mic[8]; + btstack_crypto_init(); + btstack_crypto_ccm_t btstack_crypto_ccm; + btstack_crypo_ccm_init(&btstack_crypto_ccm, app_key, app_nonce, sizeof(plaintext), sizeof(label_uuid), sizeof(trans_mic)); + btstack_crypo_ccm_digest(&btstack_crypto_ccm, label_uuid, 16, &ccm_done, NULL); + btstack_crypto_ccm_encrypt_block(&btstack_crypto_ccm, sizeof(plaintext), plaintext, ciphertext, &ccm_done, NULL); + btstack_crypo_ccm_get_authentication_value(&btstack_crypto_ccm, trans_mic); + printf("%16s: ", "ciphertext"); printf_hexdump(ciphertext, 8); + printf("%16s: ", "TransMIC"); printf_hexdump(trans_mic, 8); +} + +static void message_24_upper_transport_decrypt(void){ + printf("[+] Upper transport decrypt\n"); + DEFINE_KEY(label_uuid, "f4a002c7fb1e4ca0a469a021de0db875"); + DEFINE_KEY(app_key, "63964771734fbd76e3b40519d1d94a48"); + + uint8_t app_nonce[13]; + parse_hex(app_nonce, "010007080d1234973612345677"); + printf("%16s: ", "app_nonce"); printf_hexdump(app_nonce, 13); + + + uint8_t ciphertext[8]; + parse_hex(ciphertext, "DE1547118463123E"); + printf("%16s: ", "ciphertext"); printf_hexdump(ciphertext, sizeof(ciphertext)); + + printf("Reference:\n"); + uint8_t plaintext[8+8]; + bt_mesh_ccm_decrypt(app_key, app_nonce, ciphertext, sizeof(ciphertext), label_uuid, sizeof(label_uuid), plaintext, 8); + printf("%16s: ", "plaintext"); printf_hexdump(plaintext, 8); + printf("%16s: ", "TransMIC"); printf_hexdump(&plaintext[8], 8); + + // btstack_crypto + printf("btstack_crypto:\n"); + uint8_t trans_mic[8]; + btstack_crypto_init(); + btstack_crypto_ccm_t btstack_crypto_ccm; + btstack_crypo_ccm_init(&btstack_crypto_ccm, app_key, app_nonce, sizeof(ciphertext), sizeof(label_uuid), sizeof(trans_mic)); + btstack_crypo_ccm_digest(&btstack_crypto_ccm, label_uuid, 16, &ccm_done, NULL); + btstack_crypto_ccm_decrypt_block(&btstack_crypto_ccm, sizeof(ciphertext), ciphertext, plaintext, &ccm_done, NULL); + btstack_crypo_ccm_get_authentication_value(&btstack_crypto_ccm, trans_mic); + printf("%16s: ", "plaintext"); printf_hexdump(plaintext, 8); + printf("%16s: ", "TransMIC"); printf_hexdump(trans_mic, 8); +} + +static void message_24_lower_transport_segment_0(void){ + printf("[+] Lower Transport Segment 0\n"); DEFINE_KEY(encryption_key, "0953fa93e7caac9638f58820220a398e"); uint8_t network_nonce[13]; @@ -51,7 +117,7 @@ static void message_24(void){ uint8_t net_mic[4]; btstack_crypto_init(); btstack_crypto_ccm_t btstack_crypto_ccm; - btstack_crypo_ccm_init(&btstack_crypto_ccm, encryption_key, network_nonce, sizeof(plaintext), 4); + btstack_crypo_ccm_init(&btstack_crypto_ccm, encryption_key, network_nonce, sizeof(plaintext), 0, 4); btstack_crypto_ccm_encrypt_block(&btstack_crypto_ccm, sizeof(plaintext), plaintext, ciphertext, &ccm_done, NULL); btstack_crypo_ccm_get_authentication_value(&btstack_crypto_ccm, net_mic); printf("%16s: ", "ciphertext"); printf_hexdump(ciphertext, 18); @@ -59,6 +125,8 @@ static void message_24(void){ } int main(void){ - message_24(); + message_24_upper_transport_encrypt(); + message_24_upper_transport_decrypt(); + message_24_lower_transport_segment_0(); return 0; }