diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index ff9f487ac..9730b92a4 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -20,6 +20,9 @@ ADD_SCENE(subghz, set_type, SetType) ADD_SCENE(subghz, set_fix, SetFix) ADD_SCENE(subghz, set_cnt, SetCnt) ADD_SCENE(subghz, set_seed, SetSeed) +ADD_SCENE(subghz, set_fix_bft, SetFixBft) +ADD_SCENE(subghz, set_cnt_bft, SetCntBft) +ADD_SCENE(subghz, set_seed_bft, SetSeedBft) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, read_raw, ReadRAW) ADD_SCENE(subghz, more_raw, MoreRAW) diff --git a/applications/subghz/scenes/subghz_scene_set_cnt_bft.c b/applications/subghz/scenes/subghz_scene_set_cnt_bft.c new file mode 100644 index 000000000..d58409a7e --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_set_cnt_bft.c @@ -0,0 +1,46 @@ +#include "../subghz_i.h" + +#define TAG "SubGhzSetCntBft" + +void subghz_scene_set_cnt_bft_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_cnt_bft_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter COUNTER in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_cnt_bft_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->cnt, + 2); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_cnt_bft_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeedBft); + consumed = true; + } + } + return consumed; +} + +void subghz_scene_set_cnt_bft_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(subghz->byte_input, ""); +} diff --git a/applications/subghz/scenes/subghz_scene_set_fix_bft.c b/applications/subghz/scenes/subghz_scene_set_fix_bft.c new file mode 100644 index 000000000..8153fa2a0 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_set_fix_bft.c @@ -0,0 +1,46 @@ +#include "../subghz_i.h" + +#define TAG "SubGhzSetFixBft" + +void subghz_scene_set_fix_bft_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_fix_bft_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter FIX in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_fix_bft_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->fix, + 4); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_fix_bft_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCntBft); + consumed = true; + } + } + return consumed; +} + +void subghz_scene_set_fix_bft_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(subghz->byte_input, ""); +} \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_set_seed_bft.c b/applications/subghz/scenes/subghz_scene_set_seed_bft.c new file mode 100644 index 000000000..0caa04a4b --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_set_seed_bft.c @@ -0,0 +1,99 @@ +#include "../subghz_i.h" +#include +#include + +#define TAG "SubGhzSetSeedBft" + +void subghz_scene_set_seed_bft_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_seed_bft_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter SEED in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_seed_bft_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->seed, + 4); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_seed_bft_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + bool generated_protocol = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + + uint32_t fix_part = subghz->txrx->secure_data->fix[0] << 24 | subghz->txrx->secure_data->fix[1] << 16 | + subghz->txrx->secure_data->fix[2] << 8 | subghz->txrx->secure_data->fix[3]; + + uint16_t cnt = subghz->txrx->secure_data->cnt[0] << 8 | subghz->txrx->secure_data->cnt[1]; + + uint32_t seed = subghz->txrx->secure_data->seed[0] << 24 | subghz->txrx->secure_data->seed[1] << 16 | + subghz->txrx->secure_data->seed[2] << 8 | subghz->txrx->secure_data->seed[3]; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + fix_part & 0x0FFFFFFF, + fix_part >> 28, + cnt, + seed, + "BFT", + 433920000, + FuriHalSubGhzPresetOok650Async); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + FURI_LOG_I(TAG, "SEED: %8X\n", seed); + + generated_protocol = true; + } else { + generated_protocol = false; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + if(!generated_protocol) { + string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + consumed = true; + } + + if(generated_protocol) { + subghz_file_name_clear(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzAddManually); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + return true; + } + } + return consumed;; +} + +void subghz_scene_set_seed_bft_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(subghz->byte_input, ""); +} diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index 198cd0fd0..96a8d24d2 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -12,6 +12,7 @@ enum SubmenuIndex { SubmenuIndexFaacSLH, + SubmenuIndexBFT, SubmenuIndexPricenton, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, @@ -89,6 +90,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexFaacSLH, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "BFT Mitto", + SubmenuIndexBFT, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "Princeton_433", @@ -183,6 +190,9 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexFaacSLH: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); break; + case SubmenuIndexBFT: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft); + break; case SubmenuIndexPricenton: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 if(subghz_scene_set_type_submenu_gen_data_protocol( diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 871a4375b..b50ff949d 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -78,8 +78,6 @@ const SubGhzProtocol subghz_protocol_faac_slh = { .encoder = &subghz_protocol_faac_slh_encoder, }; -//static uint32_t seed_global; - /** * Analysis of received data * @param instance Pointer to a SubGhzBlockGeneric* instance @@ -163,20 +161,19 @@ bool subghz_protocol_faac_slh_create_data( const char* manufacture_name, uint32_t frequency, FuriHalSubGhzPreset preset) { - furi_assert(context); - SubGhzProtocolEncoderFaacSLH* instance = context; - instance->generic.serial = serial; - instance->generic.btn = btn; - instance->generic.cnt = cnt; - instance->generic.seed = seed; - //seed_global = instance->generic.seed; - instance->manufacture_name = manufacture_name; - instance->generic.data_count_bit = 64; - bool res = subghz_protocol_faac_slh_gen_data(instance); - if(res) { - res = subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); - } - return res; + furi_assert(context); + SubGhzProtocolEncoderFaacSLH* instance = context; + instance->generic.serial = serial; + instance->generic.btn = btn; + instance->generic.cnt = cnt; + instance->generic.seed = seed; + instance->manufacture_name = manufacture_name; + instance->generic.data_count_bit = 64; + bool res = subghz_protocol_faac_slh_gen_data(instance); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); + } + return res; } /** @@ -399,7 +396,7 @@ static void subghz_protocol_faac_slh_check_remote_controller (SubGhzBlockGeneric* instance, SubGhzKeystore* keystore, const char** manufacture_name) { - //instance->seed = seed_global; + FURI_LOG_I(TAG, "seed check = %8X", instance->seed); uint32_t code_fix = instance->data >> 32; uint32_t code_hop = instance->data & 0xFFFFFFFF; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index e61bc4ed7..64d3e59dd 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -141,16 +141,22 @@ static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instanc break; case KEELOQ_LEARNING_NORMAL: //Simple Learning - man = - subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); + break; + case KEELOQ_LEARNING_SECURE: + //Secure Learning + man = subghz_protocol_keeloq_common_secure_learning(fix, instance->generic.seed, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); break; case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: + //Magic XOR type-1 Learning man = subghz_protocol_keeloq_common_magic_xor_type1_learning( instance->generic.serial, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); break; case KEELOQ_LEARNING_UNKNOWN: + //KeeLoq Replay Attack (sends just the captured key) code_found_reverse = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); hop = code_found_reverse & 0x00000000ffffffff; @@ -176,18 +182,42 @@ bool subghz_protocol_keeloq_create_data( const char* manufacture_name, uint32_t frequency, FuriHalSubGhzPreset preset) { - furi_assert(context); - SubGhzProtocolEncoderKeeloq* instance = context; - instance->generic.serial = serial; - instance->generic.cnt = cnt; - instance->manufacture_name = manufacture_name; - instance->generic.data_count_bit = 64; - bool res = subghz_protocol_keeloq_gen_data(instance, btn); - if(res) { - res = - subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); - } - return res; + furi_assert(context); + SubGhzProtocolEncoderKeeloq* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->manufacture_name = manufacture_name; + instance->generic.data_count_bit = 64; + bool res = subghz_protocol_keeloq_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); + } + return res; +} + +bool subghz_protocol_keeloq_bft_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name, + uint32_t frequency, + FuriHalSubGhzPreset preset) { + furi_assert(context); + SubGhzProtocolEncoderKeeloq* instance = context; + instance->generic.serial = serial; + instance->generic.btn = btn; + instance->generic.cnt = cnt; + instance->generic.seed = seed; + instance->manufacture_name = manufacture_name; + instance->generic.data_count_bit = 64; + bool res = subghz_protocol_keeloq_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); + } + return res; } /** @@ -266,6 +296,16 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl FURI_LOG_E(TAG, "Deserialize error"); break; } + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (instance->generic.seed >> i * 8) & 0xFF; + } + if(!flipper_format_read_hex(flipper_format, "Seed", seed_data, sizeof(uint32_t))) { + FURI_LOG_E(TAG, "Missing Seed"); + break; + } + instance->generic.seed = seed_data[0] << 24 | seed_data[1] << 16 | seed_data[2] << 8 | seed_data[3] ; + FURI_LOG_I(TAG, "encoder seed = %8X", instance->generic.seed); subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); @@ -474,7 +514,6 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( uint8_t btn = (uint8_t)(fix >> 28); uint32_t decrypt = 0; uint64_t man; - uint32_t seed = 0; for M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { @@ -499,7 +538,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( break; case KEELOQ_LEARNING_SECURE: man = subghz_protocol_keeloq_common_secure_learning( - fix, seed, manufacture_code->key); + fix, instance->seed, manufacture_code->key); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = string_get_cstr(manufacture_code->name); @@ -554,7 +593,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( // Secure Learning man = subghz_protocol_keeloq_common_secure_learning( - fix, seed, manufacture_code->key); + fix, instance->seed, manufacture_code->key); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = string_get_cstr(manufacture_code->name); @@ -562,7 +601,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( } // Check for mirrored man - man = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev); + man = subghz_protocol_keeloq_common_secure_learning(fix, instance->seed, man_rev); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = string_get_cstr(manufacture_code->name); @@ -633,11 +672,23 @@ bool subghz_protocol_decoder_keeloq_serialize( FuriHalSubGhzPreset preset) { furi_assert(context); SubGhzProtocolDecoderKeeloq* instance = context; - subghz_protocol_keeloq_check_remote_controller( - &instance->generic, instance->keystore, &instance->manufacture_name); bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (instance->generic.seed >> i * 8) & 0xFF; + } + if(res && !flipper_format_write_hex(flipper_format, "Seed", seed_data, sizeof(uint32_t))) { + FURI_LOG_E(TAG, "Unable to add Seed"); + res = false; + } + instance->generic.seed = seed_data[0] << 24 | seed_data[1] << 16 | seed_data[2] << 8 | seed_data[3] ; + FURI_LOG_I(TAG, "decoder seed = %8X", instance->generic.seed); + + subghz_protocol_keeloq_check_remote_controller( + &instance->generic, instance->keystore, &instance->manufacture_name); if(res && !flipper_format_write_string_cstr( flipper_format, "Manufacture", instance->manufacture_name)) { @@ -656,6 +707,20 @@ bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* fl FURI_LOG_E(TAG, "Deserialize error"); break; } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (instance->generic.seed >> i * 8) & 0xFF; + } + if(!flipper_format_read_hex(flipper_format, "Seed", seed_data, sizeof(uint32_t))) { + FURI_LOG_E(TAG, "Missing Seed"); + break; + } + instance->generic.seed = seed_data[0] << 24 | seed_data[1] << 16 | seed_data[2] << 8 | seed_data[3] ; + FURI_LOG_I(TAG, "decoder seed = %8X", instance->generic.seed); res = true; } while(false); @@ -676,7 +741,27 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) { uint32_t code_found_reverse_hi = code_found_reverse >> 32; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + if (strcmp(instance->generic.protocol_name, "BFT") == 0) { + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04X\r\n" + "Hop:0x%08lX Btn:%01lX\r\n" + "MF:%s Sd:%08lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->generic.cnt, + code_found_reverse_lo, + instance->generic.btn, + instance->manufacture_name, + instance->generic.seed); + } else { + string_cat_printf( output, "%s %dbit\r\n" "Key:%08lX%08lX\r\n" @@ -693,4 +778,5 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) { instance->generic.btn, instance->manufacture_name, instance->generic.serial); + } } diff --git a/lib/subghz/protocols/keeloq.h b/lib/subghz/protocols/keeloq.h index 8031998f8..9750439fe 100644 --- a/lib/subghz/protocols/keeloq.h +++ b/lib/subghz/protocols/keeloq.h @@ -46,6 +46,30 @@ bool subghz_protocol_keeloq_create_data( uint32_t frequency, FuriHalSubGhzPreset preset); +/** + * Key generation for BFT. + * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 28 bit + * @param btn Button number, 4 bit + * @param cnt Counter value, 16 bit + * @param seed Seed value, 32 bit + * @param manufacture_name Name of manufacturer's key + * @param frequency Transmission frequency, Hz + * @param preset Modulation, FuriHalSubGhzPreset + * @return true On success + */ +bool subghz_protocol_keeloq_bft_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name, + uint32_t frequency, + FuriHalSubGhzPreset preset); + /** * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance