diff --git a/esb_illegalmod/nrf_esb_illegalmod.c b/esb_illegalmod/nrf_esb_illegalmod.c index 7ccaf1c..722a1a2 100644 --- a/esb_illegalmod/nrf_esb_illegalmod.c +++ b/esb_illegalmod/nrf_esb_illegalmod.c @@ -2599,43 +2599,49 @@ uint32_t nrf_esb_update_channel_frequency_table(uint8_t * values, uint8_t length // reset frequency to first channel m_esb_addr.rf_channel = 0; - //NRF_LOG_INFO("New channel table with length %d", length); + NRF_LOG_INFO("New channel table with length %d", length); return NRF_SUCCESS; } uint32_t nrf_esb_update_channel_frequency_table_unifying() { uint8_t unifying_frequencies[25] = { 5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,77 }; uint8_t unifying_frequencies_len = 25; + NRF_LOG_INFO("Using channel table 'Unifying'"); return nrf_esb_update_channel_frequency_table(unifying_frequencies, unifying_frequencies_len); } uint32_t nrf_esb_update_channel_frequency_table_lightspeed() { uint8_t unifying_frequencies[12] = { 1,49,56,41,79,80,81,24,89,78,26,3 }; uint8_t unifying_frequencies_len = 12; + NRF_LOG_INFO("Using channel table 'Lightspeed'"); return nrf_esb_update_channel_frequency_table(unifying_frequencies, unifying_frequencies_len); } uint32_t nrf_esb_update_channel_frequency_table_unifying_reduced() { uint8_t unifying_frequencies[12] = { 5,8,14,17,32,35,41,44,62,65,71,74 }; uint8_t unifying_frequencies_len = 12; + NRF_LOG_INFO("Using channel table 'Unifying reduced'"); return nrf_esb_update_channel_frequency_table(unifying_frequencies, unifying_frequencies_len); } uint32_t nrf_esb_update_channel_frequency_table_unifying_pairing() { uint8_t unifying_frequencies[11] = { 62,8,35,65,14,41,71,17,44,74,5 }; uint8_t unifying_frequencies_len = 11; + NRF_LOG_INFO("Using channel table 'Unifying pairing'"); return nrf_esb_update_channel_frequency_table(unifying_frequencies, unifying_frequencies_len); } uint32_t nrf_esb_update_channel_frequency_table_lightspeed_pairing() { uint8_t unifying_frequencies[12] = { 26,41,79,3,1,80,81,56,49,89,25,82 }; uint8_t unifying_frequencies_len = 12; + NRF_LOG_INFO("Using channel table 'Lightspeed pairing'"); return nrf_esb_update_channel_frequency_table(unifying_frequencies, unifying_frequencies_len); } uint32_t nrf_esb_update_channel_frequency_table_all() { uint8_t all_frequencies[100] = { 0 }; for (uint8_t i=0; ilast_used_aes_ctr); break; + case UNIFYING_RF_REPORT_ENCRYPTED_HIDPP_LONG: + if (len != 30) return NRF_ERROR_INVALID_DATA; + p_device->caps |= LOGITACKER_DEVICE_CAPS_UNIFYING_COMPATIBLE; + p_device->report_types |= LOGITACKER_DEVICE_REPORT_TYPES_LONG_HIDPP; + break; case UNIFYING_RF_REPORT_HIDPP_LONG: //ToDo: check if HID++ reports provide additional information (f.e. long version of device name is exchanged) if (len != 22) return NRF_ERROR_INVALID_DATA; diff --git a/logitacker/logitacker_processor_passive_enum.c b/logitacker/logitacker_processor_passive_enum.c index e1e17e7..4f77a9d 100644 --- a/logitacker/logitacker_processor_passive_enum.c +++ b/logitacker/logitacker_processor_passive_enum.c @@ -34,6 +34,7 @@ static logitacker_processor_t m_processor = {0}; static logitacker_processor_passive_enum_ctx_t m_static_passive_enum_ctx; //we reuse the same context, alternatively an malloc'ed ctx would allow separate instances static char addr_str_buff[LOGITACKER_DEVICE_ADDR_STR_LEN] = {0}; static uint8_t m_keyboard_report_decryption_buffer[8] = { 0 }; +static uint8_t m_hidpp_long_report_decryption_buffer[23] = { 0 }; void processor_passive_enum_init_func(logitacker_processor_t *p_processor); void processor_passive_enum_init_func_(logitacker_processor_passive_enum_ctx_t *self); @@ -315,6 +316,31 @@ void passive_enum_process_rx(logitacker_processor_passive_enum_ctx_t *self) { } + if (unifying_report_type == UNIFYING_RF_REPORT_ENCRYPTED_HIDPP_LONG) { + if (p_device != NULL && p_device->key_known) { + if (logitacker_unifying_crypto_decrypt_encrypted_hidpp_frame(m_hidpp_long_report_decryption_buffer, p_device->key, &self->tmp_rx_payload) == NRF_SUCCESS) { + if (g_logitacker_global_config.passive_enum_pass_through_hidraw) { + // generate decrypted pseudo frame for hidraw pass trough + // 07 C1 00 4E 00 00 00 00 00 EA + nrf_esb_payload_t pseudo_frame; + pseudo_frame.rssi = self->tmp_rx_payload.rssi; + pseudo_frame.pid = self->tmp_rx_payload.pid; + pseudo_frame.rx_channel = self->tmp_rx_payload.rx_channel; + pseudo_frame.data[0] = self->tmp_rx_payload.data[0]; + pseudo_frame.data[1] = 0x51; //HID++ long with keep alive bit + memcpy(&pseudo_frame.data[2], m_hidpp_long_report_decryption_buffer, 19); + logitacker_unifying_payload_update_checksum(pseudo_frame.data, 22); + pseudo_frame.length = 22; + pseudo_frame.validated_promiscuous_frame = false; + + if (logitacker_usb_write_hidraw_input_report_rf_frame(LOGITACKER_MODE_PASSIVE_ENUMERATION, addr, &pseudo_frame) != NRF_SUCCESS) { + NRF_LOG_ERROR("Failed wirting decrypted frame to hidraw"); + } + } + } + } + } + if (unifying_report_type == UNIFYING_RF_REPORT_ENCRYPTED_KEYBOARD) { // check if device key is known if (p_device != NULL && p_device->key_known) { diff --git a/logitacker/logitacker_unifying.c b/logitacker/logitacker_unifying.c index f39cf95..eb7c152 100644 --- a/logitacker/logitacker_unifying.c +++ b/logitacker/logitacker_unifying.c @@ -102,6 +102,9 @@ void logitacker_unifying_frame_classify_log(nrf_esb_payload_t frame) { case UNIFYING_RF_REPORT_HIDPP_LONG: NRF_LOG_INFO("%sHID++ long", UNIFYING_CLASSIFY_LOG_PREFIX); return; + case UNIFYING_RF_REPORT_ENCRYPTED_HIDPP_LONG: + NRF_LOG_INFO("%sENCRYPTED HID++ long", UNIFYING_CLASSIFY_LOG_PREFIX); + return; case UNIFYING_RF_REPORT_ENCRYPTED_KEYBOARD: //counter = frame.data[10] << 24 | frame.data[11] << 16 | frame.data[12] << 8 | frame.data[13]; counter = 0; diff --git a/logitacker/logitacker_unifying.h b/logitacker/logitacker_unifying.h index 31008ba..347b2f9 100644 --- a/logitacker/logitacker_unifying.h +++ b/logitacker/logitacker_unifying.h @@ -17,6 +17,7 @@ #define UNIFYING_RF_REPORT_HIDPP_SHORT 0x10 #define UNIFYING_RF_REPORT_HIDPP_LONG 0x11 #define UNIFYING_RF_REPORT_ENCRYPTED_KEYBOARD 0x13 +#define UNIFYING_RF_REPORT_ENCRYPTED_HIDPP_LONG 0x1b #define UNIFYING_RF_REPORT_PAIRING 0x1f #define UNIFYING_RF_REPORT_BIT_KEEP_ALIVE 0x40 diff --git a/logitacker/logitacker_unifying_crypto.c b/logitacker/logitacker_unifying_crypto.c index fe1ae51..7c09fa0 100644 --- a/logitacker/logitacker_unifying_crypto.c +++ b/logitacker/logitacker_unifying_crypto.c @@ -84,6 +84,78 @@ uint32_t logitacker_unifying_crypto_decrypt_encrypted_keyboard_frame(uint8_t * r return NRF_SUCCESS; } +uint32_t logitacker_unifying_crypto_decrypt_encrypted_hidpp_frame(uint8_t * result, uint8_t * device_key, nrf_esb_payload_t * rf_frame) { + /* + * app: Unifying RF frame: ENCRYPTED HID++ long + LOGITACKER_PROCESSOR_PASIVE_ENUM: 00 5B 5F BF 8C 1A 86 A6|.[_..... + LOGITACKER_PROCESSOR_PASIVE_ENUM: 4F 0A 94 51 74 16 EE 20|O..Qt.. + LOGITACKER_PROCESSOR_PASIVE_ENUM: 9F C0 21 37 9A B6 85 B1|..!7.... + LOGITACKER_PROCESSOR_PASIVE_ENUM: 29 12 17 45 0C FF |)..E.. + LOGITACKER_PROCESSOR_PASIVE_ENUM: frame RX in passive enumeration mode (addr C6:1B:34:4A:26, len: 30, ch idx 17, raw ch 56) + app: Unifying RF frame: ENCRYPTED HID++ long + LOGITACKER_PROCESSOR_PASIVE_ENUM: 00 5B F2 B2 8B 04 60 BA|.[....`. + LOGITACKER_PROCESSOR_PASIVE_ENUM: E8 EF 06 61 75 D2 D7 BA|...au... + LOGITACKER_PROCESSOR_PASIVE_ENUM: E2 FA 29 A7 84 C5 32 AF|..)...2. + LOGITACKER_PROCESSOR_PASIVE_ENUM: 9D 14 17 45 0C 53 |...E.S + + */ + + + // validate frame + VERIFY_PARAM_NOT_NULL(result); + VERIFY_PARAM_NOT_NULL(device_key); + VERIFY_PARAM_NOT_NULL(rf_frame); + VERIFY_TRUE(rf_frame->length == 30, NRF_ERROR_INVALID_DATA); + VERIFY_TRUE((rf_frame->data[1] & 0x1f) == UNIFYING_RF_REPORT_ENCRYPTED_HIDPP_LONG, NRF_ERROR_INVALID_DATA); //encrypted keyboard frame + + ret_code_t ret_val; + + //two successive counters are used to calculate two keys + + // extract counter + uint8_t counter[4] = { 0 }; + uint8_t counter2[4] = { 0 }; + memcpy(counter, &rf_frame->data[0x19], 4); + + uint32_t tmp_counter = * ((uint32_t *) counter); + uint32_t tmp_counter2 = tmp_counter; + tmp_counter2++; + memcpy(counter2, &tmp_counter2, 4); + + NRF_LOG_INFO("COUNTER1: %08x", tmp_counter) + NRF_LOG_INFO("COUNTER1: %08x", tmp_counter2) + + //generate frame key1 + uint8_t frame_key1[16] = { 0 }; + ret_val = logitacker_unifying_crypto_calculate_frame_key(frame_key1, device_key, counter); + VERIFY_SUCCESS(ret_val); + //generate frame key2 + uint8_t frame_key2[16] = { 0 }; + ret_val = logitacker_unifying_crypto_calculate_frame_key(frame_key2, device_key, counter2); + VERIFY_SUCCESS(ret_val); + + NRF_LOG_INFO("Frame key1:"); + NRF_LOG_HEXDUMP_INFO(frame_key1,16); + NRF_LOG_INFO("Frame key2:"); + NRF_LOG_HEXDUMP_INFO(frame_key2,16); + + //copy cipher part to result + memcpy(result, &rf_frame->data[2], 23); + + // xor decrypt with relevant part of AES key (yes, only half of the key - generated from high-entropy input data - is used) + for (int i=0; i<16; i++) { + result[i] ^= frame_key1[i]; + } + for (int i=0; i<7; i++) { + result[16+i] ^= frame_key2[i]; + } + + NRF_LOG_INFO("Decrypt:"); + NRF_LOG_HEXDUMP_INFO(result,23); + + return NRF_SUCCESS; +} + uint32_t logitacker_unifying_crypto_encrypt_keyboard_frame(nrf_esb_payload_t * result_rf_frame, uint8_t * plain_payload, logitacker_device_unifying_device_key_t device_key, uint32_t counter) { // validate frame VERIFY_PARAM_NOT_NULL(plain_payload); diff --git a/logitacker/logitacker_unifying_crypto.h b/logitacker/logitacker_unifying_crypto.h index c71dbe8..277987e 100644 --- a/logitacker/logitacker_unifying_crypto.h +++ b/logitacker/logitacker_unifying_crypto.h @@ -11,5 +11,5 @@ uint32_t logitacker_unifying_crypto_decrypt_encrypted_keyboard_frame(uint8_t * r uint32_t logitacker_unifying_crypto_encrypt_keyboard_frame(nrf_esb_payload_t *result_rf_frame, uint8_t *plain_payload, logitacker_device_unifying_device_key_t device_key, uint32_t counter); - +uint32_t logitacker_unifying_crypto_decrypt_encrypted_hidpp_frame(uint8_t * result, uint8_t * device_key, nrf_esb_payload_t * rf_frame); #endif //LOGITACKER_UNIFYING_CRYPTO_H diff --git a/logitacker/logitacker_usb.c b/logitacker/logitacker_usb.c index bc3e992..569e386 100644 --- a/logitacker/logitacker_usb.c +++ b/logitacker/logitacker_usb.c @@ -167,7 +167,7 @@ static void usbd_hid_generic_event_handler(app_usbd_class_inst_t const *p_inst, } case APP_USBD_HID_USER_EVT_IN_REPORT_DONE: { - NRF_LOG_DEBUG("report sent successfully") + NRF_LOG_INFO("HID raw report sent successfully") m_current_hidraw_in_report_buf_read++; m_current_hidraw_in_report_buf_read &= (HIDRAW_IN_REPORT_BUF_COUNT-1); m_current_hidraw_in_report_buf_enqueued--;