From 0346c37cbeb60faf335e59e7cd19074049b35e01 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 27 May 2016 23:09:08 +0200 Subject: [PATCH] sm: use AES CMAC Engine to calculate f5 for dhkey check verification --- src/ble/sm.c | 213 ++++++++++++++++++++++++++++++--------------------- src/hci.h | 6 ++ 2 files changed, 132 insertions(+), 87 deletions(-) diff --git a/src/ble/sm.c b/src/ble/sm.c index da310aef7..05b0584e3 100644 --- a/src/ble/sm.c +++ b/src/ble/sm.c @@ -269,6 +269,7 @@ typedef struct sm_setup_context { sm_key_t sm_local_dhkey_check; sm_key_t sm_ra; sm_key_t sm_rb; + sm_key_t sm_t; // used for f5 sm_key_t sm_mackey; uint8_t sm_passkey_bit; #endif @@ -622,39 +623,6 @@ static void aes_cmac(sm_key_t aes_cmac, const sm_key_t key, const uint8_t * data aes128_calc_cyphertext(key, sm_cmac_y, aes_cmac); } -const sm_key_t f5_salt = { 0x6C ,0x88, 0x83, 0x91, 0xAA, 0xF5, 0xA5, 0x38, 0x60, 0x37, 0x0B, 0xDB, 0x5A, 0x60, 0x83, 0xBE}; -const uint8_t f5_key_id[] = { 0x62, 0x74, 0x6c, 0x65 }; -const uint8_t f5_length[] = { 0x01, 0x00}; -static void f5(sm_key256_t res, const sm_key256_t w, const sm_key_t n1, const sm_key_t n2, const sm_key56_t a1, const sm_key56_t a2){ - // T = AES-CMACSAL_T(W) - sm_key_t t; - aes_cmac(t, f5_salt, w, 32); - // f5(W, N1, N2, A1, A2) = AES-CMACT (Counter = 0 || keyID || N1 || N2|| A1|| A2 || Length = 256) -- this is the MacKey - uint8_t buffer[53]; - buffer[0] = 0; - memcpy(buffer+01, f5_key_id, 4); - memcpy(buffer+05, n1, 16); - memcpy(buffer+21, n2, 16); - memcpy(buffer+37, a1, 7); - memcpy(buffer+44, a2, 7); - memcpy(buffer+51, f5_length, 2); - log_info("f5 DHKEY"); - log_info_hexdump(w, 32); - log_info("f5 key"); - log_info_hexdump(t, 16); - log_info("f5 message for MacKey"); - log_info_hexdump(buffer, sizeof(buffer)); - aes_cmac(res, t, buffer, sizeof(buffer)); - // hexdump2(res, 16); - // || AES-CMACT (Counter = 1 || keyID || N1 || N2|| A1|| A2 || Length = 256) -- this is the LTK - buffer[0] = 1; - // hexdump2(buffer, sizeof(buffer)); - log_info("f5 message for LTK"); - log_info_hexdump(buffer, sizeof(buffer)); - aes_cmac(res+16, t, buffer, sizeof(buffer)); - // hexdump2(res+16, 16); -} - // g2(U, V, X, Y) = AES-CMACX(U || V || Y) mod 2^32 // - U is 256 bits // - V is 256 bits @@ -1044,9 +1012,10 @@ static void sm_cmac_handle_encryption_result(sm_key_t data){ break; case CMAC_W4_MLAST: // done + log_info("Setting CMAC Engine to IDLE"); + sm_cmac_state = CMAC_IDLE; log_info_key("CMAC", data); sm_cmac_done_handler(data); - sm_cmac_state = CMAC_IDLE; break; default: log_info("sm_cmac_handle_encryption_result called in state %u", sm_cmac_state); @@ -1419,11 +1388,23 @@ static void sm_sc_cmac_done(uint8_t * hash){ break; case SM_SC_W4_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK: if (0 != memcmp(hash, setup->sm_peer_dhkey_check, 16) ){ - sm_pairing_error(sm_conn, SM_REASON_DHKEY_CHECK_FAILED); + sm_pairing_error(sm_cmac_connection, SM_REASON_DHKEY_CHECK_FAILED); break; } - sm_sc_state_after_receiving_dhkey_check(sm_conn); + sm_sc_state_after_receiving_dhkey_check(sm_cmac_connection); break; + case SM_SC_W4_CALCULATE_F5_SALT: + memcpy(setup->sm_t, hash, 16); + sm_cmac_connection->sm_engine_state = SM_SC_W2_CALCULATE_F5_MACKEY; + break; + case SM_SC_W4_CALCULATE_F5_MACKEY: + memcpy(setup->sm_mackey, hash, 16); + sm_cmac_connection->sm_engine_state = SM_SC_W2_CALCULATE_F5_LTK; + break; + case SM_SC_W4_CALCULATE_F5_LTK: + memcpy(setup->sm_ltk, hash, 16); + sm_cmac_connection->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK; + break; default: log_error("sm_sc_cmac_done in state %u", sm_cmac_connection->sm_engine_state); break; @@ -1445,6 +1426,92 @@ static void f4_engine(sm_connection_t * sm_conn, const sm_key256_t u, const sm_k sm_cmac_general_start(x, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done); } +static const sm_key_t f5_salt = { 0x6C ,0x88, 0x83, 0x91, 0xAA, 0xF5, 0xA5, 0x38, 0x60, 0x37, 0x0B, 0xDB, 0x5A, 0x60, 0x83, 0xBE}; +static const uint8_t f5_key_id[] = { 0x62, 0x74, 0x6c, 0x65 }; +static const uint8_t f5_length[] = { 0x01, 0x00}; + +static void sm_sc_calculate_dhkey(sm_key256_t dhkey){ +#ifdef USE_MBEDTLS_FOR_ECDH + // da * Pb + mbedtls_ecp_group grp; + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + mbedtls_ecp_point Q; + mbedtls_ecp_point_init( &Q ); + mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32); + mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32); + mbedtls_mpi_read_string(&Q.Z, 16, "1" ); + mbedtls_ecp_point DH; + mbedtls_ecp_point_init( &DH ); + mbedtls_ecp_mul(&grp, &DH, &le_keypair.d, &Q, NULL, NULL); + mbedtls_mpi_write_binary(&DH.X, dhkey, 32); +#endif + log_info("dhkey"); + log_info_hexdump(dhkey, 32); +} + +static void f5_calculate_salt(sm_connection_t * sm_conn){ + // calculate DHKEY + sm_key256_t dhkey; + sm_sc_calculate_dhkey(dhkey); + + // calculate salt for f5 + const uint16_t message_len = 32; + sm_cmac_connection = sm_conn; + memcpy(sm_cmac_sc_buffer, dhkey, message_len); + sm_cmac_general_start(f5_salt, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done); +} + +static inline void f5_mackkey(sm_connection_t * sm_conn, sm_key_t t, const sm_key_t n1, const sm_key_t n2, const sm_key56_t a1, const sm_key56_t a2){ + const uint16_t message_len = 53; + sm_cmac_connection = sm_conn; + + // f5(W, N1, N2, A1, A2) = AES-CMACT (Counter = 0 || keyID || N1 || N2|| A1|| A2 || Length = 256) -- this is the MacKey + sm_cmac_sc_buffer[0] = 0; + memcpy(sm_cmac_sc_buffer+01, f5_key_id, 4); + memcpy(sm_cmac_sc_buffer+05, n1, 16); + memcpy(sm_cmac_sc_buffer+21, n2, 16); + memcpy(sm_cmac_sc_buffer+37, a1, 7); + memcpy(sm_cmac_sc_buffer+44, a2, 7); + memcpy(sm_cmac_sc_buffer+51, f5_length, 2); + log_info("f5 key"); + log_info_hexdump(t, 16); + log_info("f5 message for MacKey"); + log_info_hexdump(sm_cmac_sc_buffer, message_len); + sm_cmac_general_start(t, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done); +} + +static void f5_calculate_mackey(sm_connection_t * sm_conn){ + sm_key56_t bd_addr_master, bd_addr_slave; + bd_addr_master[0] = setup->sm_m_addr_type; + bd_addr_slave[0] = setup->sm_s_addr_type; + memcpy(&bd_addr_master[1], setup->sm_m_address, 6); + memcpy(&bd_addr_slave[1], setup->sm_s_address, 6); + if (sm_conn->sm_role){ + // responder + f5_mackkey(sm_conn, setup->sm_t, setup->sm_peer_nonce, setup->sm_local_nonce, bd_addr_master, bd_addr_slave); + } else { + // initiator + f5_mackkey(sm_conn, setup->sm_t, setup->sm_local_nonce, setup->sm_peer_nonce, bd_addr_master, bd_addr_slave); + } +} + +// note: must be called right after f5_mackey, as sm_cmac_buffer[1..52] will be reused +static inline void f5_ltk(sm_connection_t * sm_conn, sm_key_t t){ + const uint16_t message_len = 53; + sm_cmac_connection = sm_conn; + sm_cmac_sc_buffer[0] = 1; + // 1..52 setup before + log_info("f5 key"); + log_info_hexdump(t, 16); + log_info("f5 message for LTK"); + log_info_hexdump(sm_cmac_sc_buffer, message_len); + sm_cmac_general_start(t, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done); +} +static void f5_calculate_ltk(sm_connection_t * sm_conn){ + f5_ltk(sm_conn, setup->sm_t); +} + static void f6_engine(sm_connection_t * sm_conn, const sm_key_t w, const sm_key_t n1, const sm_key_t n2, const sm_key_t r, const sm_key24_t io_cap, const sm_key56_t a1, const sm_key56_t a2){ const uint16_t message_len = 65; sm_cmac_connection = sm_conn; @@ -1491,50 +1558,15 @@ static void sm_sc_calculate_remote_confirm(sm_connection_t * sm_conn){ f4_engine(sm_conn, setup->sm_peer_qx, local_qx, setup->sm_peer_nonce, z); } -static void sm_sc_calculate_dhkey(sm_key256_t dhkey){ -#ifdef USE_MBEDTLS_FOR_ECDH - // da * Pb - mbedtls_ecp_group grp; - mbedtls_ecp_group_init( &grp ); - mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); - mbedtls_ecp_point Q; - mbedtls_ecp_point_init( &Q ); - mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32); - mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32); - mbedtls_mpi_read_string(&Q.Z, 16, "1" ); - mbedtls_ecp_point DH; - mbedtls_ecp_point_init( &DH ); - mbedtls_ecp_mul(&grp, &DH, &le_keypair.d, &Q, NULL, NULL); - mbedtls_mpi_write_binary(&DH.X, dhkey, 32); -#endif - log_info("dhkey"); - log_info_hexdump(dhkey, 32); -} +static void sm_sc_prepare_dhkey_check(sm_connection_t * sm_conn){ -static void sm_sc_calculate_f5_for_dhkey_check(sm_connection_t * sm_conn){ - // calculate DHKEY - sm_key256_t dhkey; - sm_sc_calculate_dhkey(dhkey); + sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_SALT; - // calculate LTK + MacKey - sm_key256_t ltk_mackey; - sm_key56_t bd_addr_master, bd_addr_slave; - bd_addr_master[0] = setup->sm_m_addr_type; - bd_addr_slave[0] = setup->sm_s_addr_type; - memcpy(&bd_addr_master[1], setup->sm_m_address, 6); - memcpy(&bd_addr_slave[1], setup->sm_s_address, 6); - if (sm_conn->sm_role){ - // responder - f5(ltk_mackey, dhkey, setup->sm_peer_nonce, setup->sm_local_nonce, bd_addr_master, bd_addr_slave); - } else { - // initiator - f5(ltk_mackey, dhkey, setup->sm_local_nonce, setup->sm_peer_nonce, bd_addr_master, bd_addr_slave); - } - // store LTK - memcpy(setup->sm_ltk, <k_mackey[16], 16); + // TODO: use AES CMAC Engine + // sm_sc_calculate_f5_for_dhkey_check(sm_conn); - // store macckey - memcpy(setup->sm_mackey, <k_mackey[0], 16); + // second part + // sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK; } static void sm_sc_calculate_f6_for_dhkey_check(sm_connection_t * sm_conn){ @@ -1586,15 +1618,6 @@ static void sm_sc_calculate_f6_to_verify_dhkey_check(sm_connection_t * sm_conn){ } } -static void sm_sc_prepare_dhkey_check(sm_connection_t * sm_conn){ - - // TODO: use AES CMAC Engine - sm_sc_calculate_f5_for_dhkey_check(sm_conn); - - // second part - sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK; -} - #endif static void sm_run(void){ @@ -1880,7 +1903,19 @@ static void sm_run(void){ break; case SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK: connection->sm_engine_state = SM_SC_W4_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK; - sm_sc_calculate_f6_to_verify_dhkey_check(sm_conn); + sm_sc_calculate_f6_to_verify_dhkey_check(connection); + break; + case SM_SC_W2_CALCULATE_F5_SALT: + connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_SALT; + f5_calculate_salt(connection); + break; + case SM_SC_W2_CALCULATE_F5_MACKEY: + connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_MACKEY; + f5_calculate_mackey(connection); + break; + case SM_SC_W2_CALCULATE_F5_LTK: + connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_LTK; + f5_calculate_ltk(connection); break; #endif // initiator side @@ -3342,6 +3377,8 @@ void sm_just_works_confirm(hci_con_handle_t con_handle){ } #endif } + +#ifdef ENABLE_LE_SECURE_CONNECTIONS if (sm_conn->sm_engine_state == SM_SC_W4_USER_RESPONSE){ if (sm_conn->sm_role){ // responder @@ -3351,6 +3388,8 @@ void sm_just_works_confirm(hci_con_handle_t con_handle){ // TODO handle intiator role } } +#endif + sm_run(); } diff --git a/src/hci.h b/src/hci.h index a499f93de..49e6d2ec5 100644 --- a/src/hci.h +++ b/src/hci.h @@ -313,6 +313,12 @@ typedef enum { SM_SC_W4_CONFIRMATION, SM_SC_SEND_PAIRING_RANDOM, SM_SC_W4_PAIRING_RANDOM, + SM_SC_W2_CALCULATE_F5_SALT, + SM_SC_W4_CALCULATE_F5_SALT, + SM_SC_W2_CALCULATE_F5_MACKEY, + SM_SC_W4_CALCULATE_F5_MACKEY, + SM_SC_W2_CALCULATE_F5_LTK, + SM_SC_W4_CALCULATE_F5_LTK, SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK, SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK, SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK,