mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-05-14 21:25:04 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20a95b2fec | |||
| 3605669cc5 |
@@ -1,11 +1,15 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
|
#include "../helpers/subghz_txrx_i.h"
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
#include <lib/subghz/protocols/keeloq_common.h>
|
#include <lib/subghz/protocols/keeloq_common.h>
|
||||||
|
#include <lib/subghz/environment.h>
|
||||||
|
#include <lib/subghz/subghz_keystore.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <bt/bt_service/bt.h>
|
#include <bt/bt_service/bt.h>
|
||||||
|
|
||||||
#define KL_DECRYPT_EVENT_DONE (0xD2)
|
#define KL_DECRYPT_EVENT_DONE (0xD2)
|
||||||
#define KL_TOTAL_KEYS 0x100000000ULL
|
#define KL_DECRYPT_EVENT_CANDIDATE (0xD3)
|
||||||
|
#define KL_TOTAL_KEYS 0x100000000ULL
|
||||||
|
|
||||||
#define KL_MSG_BF_REQUEST 0x10
|
#define KL_MSG_BF_REQUEST 0x10
|
||||||
#define KL_MSG_BF_PROGRESS 0x11
|
#define KL_MSG_BF_PROGRESS 0x11
|
||||||
@@ -54,16 +58,12 @@ static void kl_ble_data_received(uint8_t* data, uint16_t size, void* context) {
|
|||||||
|
|
||||||
} else if(data[0] == KL_MSG_BF_RESULT && size >= 26) {
|
} else if(data[0] == KL_MSG_BF_RESULT && size >= 26) {
|
||||||
uint8_t found = data[1];
|
uint8_t found = data[1];
|
||||||
uint64_t mfkey = 0;
|
|
||||||
uint64_t devkey = 0;
|
|
||||||
uint32_t cnt = 0;
|
|
||||||
uint32_t elapsed_ms = 0;
|
|
||||||
memcpy(&mfkey, data + 2, 8);
|
|
||||||
memcpy(&devkey, data + 10, 8);
|
|
||||||
memcpy(&cnt, data + 18, 4);
|
|
||||||
memcpy(&elapsed_ms, data + 22, 4);
|
|
||||||
|
|
||||||
if(found == 1) {
|
if(found == 1) {
|
||||||
|
uint64_t mfkey = 0;
|
||||||
|
uint32_t cnt = 0;
|
||||||
|
memcpy(&mfkey, data + 2, 8);
|
||||||
|
memcpy(&cnt, data + 18, 4);
|
||||||
uint16_t learn_type = (size >= 27) ? data[26] : 6;
|
uint16_t learn_type = (size >= 27) ? data[26] : 6;
|
||||||
|
|
||||||
ctx->candidate_count++;
|
ctx->candidate_count++;
|
||||||
@@ -74,47 +74,13 @@ static void kl_ble_data_received(uint8_t* data, uint16_t size, void* context) {
|
|||||||
subghz_view_keeloq_decrypt_update_candidates(
|
subghz_view_keeloq_decrypt_update_candidates(
|
||||||
ctx->subghz->subghz_keeloq_decrypt, ctx->candidate_count);
|
ctx->subghz->subghz_keeloq_decrypt, ctx->candidate_count);
|
||||||
|
|
||||||
if(!ctx->subghz->keeloq_keys_manager) {
|
view_dispatcher_send_custom_event(
|
||||||
ctx->subghz->keeloq_keys_manager = subghz_keeloq_keys_alloc();
|
ctx->subghz->view_dispatcher, KL_DECRYPT_EVENT_CANDIDATE);
|
||||||
}
|
|
||||||
char key_name[32];
|
|
||||||
snprintf(key_name, sizeof(key_name), "BF_%07lX_%lu", ctx->serial, ctx->candidate_count);
|
|
||||||
subghz_keeloq_keys_add(
|
|
||||||
ctx->subghz->keeloq_keys_manager,
|
|
||||||
mfkey,
|
|
||||||
learn_type,
|
|
||||||
key_name);
|
|
||||||
subghz_keeloq_keys_save(ctx->subghz->keeloq_keys_manager);
|
|
||||||
|
|
||||||
} else if(found == 2) {
|
} else if(found == 2) {
|
||||||
ctx->success = (ctx->candidate_count > 0);
|
ctx->success = (ctx->candidate_count > 0);
|
||||||
|
view_dispatcher_send_custom_event(
|
||||||
if(ctx->candidate_count > 0) {
|
ctx->subghz->view_dispatcher, KL_DECRYPT_EVENT_DONE);
|
||||||
furi_string_printf(
|
|
||||||
ctx->result,
|
|
||||||
"Found %lu candidate(s)\n"
|
|
||||||
"Last: %08lX%08lX\n"
|
|
||||||
"Type:%u Cnt:%04lX\n"
|
|
||||||
"Saved to user keys",
|
|
||||||
ctx->candidate_count,
|
|
||||||
(uint32_t)(ctx->recovered_mfkey >> 32),
|
|
||||||
(uint32_t)(ctx->recovered_mfkey & 0xFFFFFFFF),
|
|
||||||
ctx->recovered_type,
|
|
||||||
ctx->recovered_cnt);
|
|
||||||
|
|
||||||
FlipperFormat* fff = subghz_txrx_get_fff_data(ctx->subghz->txrx);
|
|
||||||
flipper_format_rewind(fff);
|
|
||||||
|
|
||||||
char mf_str[20];
|
|
||||||
snprintf(mf_str, sizeof(mf_str), "BF_%07lX", ctx->serial);
|
|
||||||
flipper_format_insert_or_update_string_cstr(fff, "Manufacture", mf_str);
|
|
||||||
|
|
||||||
uint32_t cnt_val = ctx->recovered_cnt;
|
|
||||||
flipper_format_rewind(fff);
|
|
||||||
flipper_format_insert_or_update_uint32(fff, "Cnt", &cnt_val, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(ctx->subghz->view_dispatcher, KL_DECRYPT_EVENT_DONE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,16 +179,68 @@ bool subghz_scene_keeloq_decrypt_on_event(void* context, SceneManagerEvent event
|
|||||||
if(!ctx) return false;
|
if(!ctx) return false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == KL_DECRYPT_EVENT_DONE) {
|
if(event.event == KL_DECRYPT_EVENT_CANDIDATE) {
|
||||||
|
if(!subghz->keeloq_keys_manager) {
|
||||||
|
subghz->keeloq_keys_manager = subghz_keeloq_keys_alloc();
|
||||||
|
}
|
||||||
|
char key_name[24];
|
||||||
|
snprintf(key_name, sizeof(key_name), "BF_%07lX", ctx->serial);
|
||||||
|
subghz_keeloq_keys_add(
|
||||||
|
subghz->keeloq_keys_manager,
|
||||||
|
ctx->recovered_mfkey,
|
||||||
|
ctx->recovered_type,
|
||||||
|
key_name);
|
||||||
|
subghz_keeloq_keys_save(subghz->keeloq_keys_manager);
|
||||||
|
|
||||||
|
SubGhzKeystore* env_ks = subghz_environment_get_keystore(
|
||||||
|
subghz->txrx->environment);
|
||||||
|
SubGhzKeyArray_t* env_arr = subghz_keystore_get_data(env_ks);
|
||||||
|
SubGhzKey* entry = SubGhzKeyArray_push_raw(*env_arr);
|
||||||
|
entry->name = furi_string_alloc_set(key_name);
|
||||||
|
entry->key = ctx->recovered_mfkey;
|
||||||
|
entry->type = ctx->recovered_type;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if(event.event == KL_DECRYPT_EVENT_DONE) {
|
||||||
kl_ble_cleanup(ctx);
|
kl_ble_cleanup(ctx);
|
||||||
subghz->keeloq_bf2.sig1_loaded = false;
|
subghz->keeloq_bf2.sig1_loaded = false;
|
||||||
subghz->keeloq_bf2.sig2_loaded = false;
|
subghz->keeloq_bf2.sig2_loaded = false;
|
||||||
|
|
||||||
if(ctx->success) {
|
if(ctx->success) {
|
||||||
subghz_save_protocol_to_file(
|
furi_string_printf(
|
||||||
subghz,
|
ctx->result,
|
||||||
subghz_txrx_get_fff_data(subghz->txrx),
|
"Found %lu candidate(s)\n"
|
||||||
furi_string_get_cstr(subghz->file_path));
|
"Last: %08lX%08lX\n"
|
||||||
|
"Type:%u Cnt:%04lX\n"
|
||||||
|
"Saved to user keys",
|
||||||
|
ctx->candidate_count,
|
||||||
|
(uint32_t)(ctx->recovered_mfkey >> 32),
|
||||||
|
(uint32_t)(ctx->recovered_mfkey & 0xFFFFFFFF),
|
||||||
|
ctx->recovered_type,
|
||||||
|
ctx->recovered_cnt);
|
||||||
|
|
||||||
|
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||||
|
flipper_format_rewind(fff);
|
||||||
|
|
||||||
|
char mf_str[20];
|
||||||
|
snprintf(mf_str, sizeof(mf_str), "BF_%07lX", ctx->serial);
|
||||||
|
flipper_format_insert_or_update_string_cstr(fff, "Manufacture", mf_str);
|
||||||
|
|
||||||
|
uint32_t cnt_val = ctx->recovered_cnt;
|
||||||
|
flipper_format_rewind(fff);
|
||||||
|
flipper_format_insert_or_update_uint32(fff, "Cnt", &cnt_val, 1);
|
||||||
|
|
||||||
|
if(ctx->hop2 != 0) {
|
||||||
|
flipper_format_rewind(fff);
|
||||||
|
flipper_format_insert_or_update_uint32(fff, "Hop2", &ctx->hop2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subghz_path_is_file(subghz->file_path)) {
|
||||||
|
subghz_save_protocol_to_file(
|
||||||
|
subghz,
|
||||||
|
subghz_txrx_get_fff_data(subghz->txrx),
|
||||||
|
furi_string_get_cstr(subghz->file_path));
|
||||||
|
}
|
||||||
|
|
||||||
subghz_view_keeloq_decrypt_set_result(
|
subghz_view_keeloq_decrypt_set_result(
|
||||||
subghz->subghz_keeloq_decrypt, true, furi_string_get_cstr(ctx->result));
|
subghz->subghz_keeloq_decrypt, true, furi_string_get_cstr(ctx->result));
|
||||||
@@ -242,13 +260,8 @@ bool subghz_scene_keeloq_decrypt_on_event(void* context, SceneManagerEvent event
|
|||||||
uint8_t cancel_msg = KL_MSG_BF_CANCEL;
|
uint8_t cancel_msg = KL_MSG_BF_CANCEL;
|
||||||
bt_custom_data_tx(bt, &cancel_msg, 1);
|
bt_custom_data_tx(bt, &cancel_msg, 1);
|
||||||
furi_record_close(RECORD_BT);
|
furi_record_close(RECORD_BT);
|
||||||
kl_ble_cleanup(ctx);
|
|
||||||
}
|
}
|
||||||
ctx->cancel = true;
|
ctx->cancel = true;
|
||||||
furi_string_free(ctx->result);
|
|
||||||
free(ctx);
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
subghz->scene_manager, SubGhzSceneKeeloqDecrypt, 0);
|
|
||||||
scene_manager_previous_scene(subghz->scene_manager);
|
scene_manager_previous_scene(subghz->scene_manager);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
|
uint32_t fix;
|
||||||
uint32_t hop;
|
uint32_t hop;
|
||||||
|
uint32_t hop2;
|
||||||
uint8_t btn;
|
uint8_t btn;
|
||||||
uint16_t disc;
|
uint16_t disc;
|
||||||
size_t bf_indices[32];
|
size_t bf_indices[32];
|
||||||
@@ -12,7 +14,7 @@ typedef struct {
|
|||||||
size_t valid_count;
|
size_t valid_count;
|
||||||
} KlCleanupCtx;
|
} KlCleanupCtx;
|
||||||
|
|
||||||
static bool kl_cleanup_validate_key(uint64_t key, uint32_t hop, uint8_t btn, uint16_t disc) {
|
static bool kl_cleanup_validate_hop(uint64_t key, uint32_t hop, uint8_t btn, uint16_t disc) {
|
||||||
uint32_t dec = subghz_protocol_keeloq_common_decrypt(hop, key);
|
uint32_t dec = subghz_protocol_keeloq_common_decrypt(hop, key);
|
||||||
if((dec >> 28) != btn) return false;
|
if((dec >> 28) != btn) return false;
|
||||||
uint16_t dec_disc = (dec >> 16) & 0x3FF;
|
uint16_t dec_disc = (dec >> 16) & 0x3FF;
|
||||||
@@ -21,6 +23,18 @@ static bool kl_cleanup_validate_key(uint64_t key, uint32_t hop, uint8_t btn, uin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool kl_cleanup_validate_key(uint64_t key, uint32_t hop1, uint32_t hop2, uint8_t btn, uint16_t disc) {
|
||||||
|
if(!kl_cleanup_validate_hop(key, hop1, btn, disc)) return false;
|
||||||
|
if(hop2 == 0) return true;
|
||||||
|
if(!kl_cleanup_validate_hop(key, hop2, btn, disc)) return false;
|
||||||
|
uint32_t dec1 = subghz_protocol_keeloq_common_decrypt(hop1, key);
|
||||||
|
uint32_t dec2 = subghz_protocol_keeloq_common_decrypt(hop2, key);
|
||||||
|
uint16_t cnt1 = dec1 & 0xFFFF;
|
||||||
|
uint16_t cnt2 = dec2 & 0xFFFF;
|
||||||
|
int diff = (int)cnt2 - (int)cnt1;
|
||||||
|
return (diff >= 1 && diff <= 256);
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
@@ -32,15 +46,19 @@ void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
|||||||
|
|
||||||
uint8_t key_data[8] = {0};
|
uint8_t key_data[8] = {0};
|
||||||
if(flipper_format_read_hex(fff, "Key", key_data, 8)) {
|
if(flipper_format_read_hex(fff, "Key", key_data, 8)) {
|
||||||
uint32_t fix = ((uint32_t)key_data[0] << 24) | ((uint32_t)key_data[1] << 16) |
|
ctx->fix = ((uint32_t)key_data[0] << 24) | ((uint32_t)key_data[1] << 16) |
|
||||||
((uint32_t)key_data[2] << 8) | key_data[3];
|
((uint32_t)key_data[2] << 8) | key_data[3];
|
||||||
ctx->hop = ((uint32_t)key_data[4] << 24) | ((uint32_t)key_data[5] << 16) |
|
ctx->hop = ((uint32_t)key_data[4] << 24) | ((uint32_t)key_data[5] << 16) |
|
||||||
((uint32_t)key_data[6] << 8) | key_data[7];
|
((uint32_t)key_data[6] << 8) | key_data[7];
|
||||||
ctx->serial = fix & 0x0FFFFFFF;
|
ctx->serial = ctx->fix & 0x0FFFFFFF;
|
||||||
ctx->btn = fix >> 28;
|
ctx->btn = ctx->fix >> 28;
|
||||||
ctx->disc = ctx->serial & 0x3FF;
|
ctx->disc = ctx->serial & 0x3FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx->hop2 = 0;
|
||||||
|
flipper_format_rewind(fff);
|
||||||
|
flipper_format_read_uint32(fff, "Hop2", &ctx->hop2, 1);
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneKlBfCleanup, (uint32_t)(uintptr_t)ctx);
|
subghz->scene_manager, SubGhzSceneKlBfCleanup, (uint32_t)(uintptr_t)ctx);
|
||||||
|
|
||||||
@@ -48,9 +66,8 @@ void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
|||||||
subghz->keeloq_keys_manager = subghz_keeloq_keys_alloc();
|
subghz->keeloq_keys_manager = subghz_keeloq_keys_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
char prefix[16];
|
char bf_name[24];
|
||||||
snprintf(prefix, sizeof(prefix), "BF_%07lX_", ctx->serial);
|
snprintf(bf_name, sizeof(bf_name), "BF_%07lX", ctx->serial);
|
||||||
size_t prefix_len = strlen(prefix);
|
|
||||||
|
|
||||||
size_t user_count = subghz_keeloq_keys_user_count(subghz->keeloq_keys_manager);
|
size_t user_count = subghz_keeloq_keys_user_count(subghz->keeloq_keys_manager);
|
||||||
ctx->bf_count = 0;
|
ctx->bf_count = 0;
|
||||||
@@ -60,9 +77,9 @@ void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
|||||||
SubGhzKey* k = subghz_keeloq_keys_get(subghz->keeloq_keys_manager, i);
|
SubGhzKey* k = subghz_keeloq_keys_get(subghz->keeloq_keys_manager, i);
|
||||||
if(!k || !k->name) continue;
|
if(!k || !k->name) continue;
|
||||||
const char* name = furi_string_get_cstr(k->name);
|
const char* name = furi_string_get_cstr(k->name);
|
||||||
if(strncmp(name, prefix, prefix_len) == 0) {
|
if(strcmp(name, bf_name) == 0) {
|
||||||
ctx->bf_indices[ctx->bf_count] = i;
|
ctx->bf_indices[ctx->bf_count] = i;
|
||||||
if(kl_cleanup_validate_key(k->key, ctx->hop, ctx->btn, ctx->disc)) {
|
if(kl_cleanup_validate_key(k->key, ctx->hop, ctx->hop2, ctx->btn, ctx->disc)) {
|
||||||
ctx->valid_indices[ctx->valid_count++] = i;
|
ctx->valid_indices[ctx->valid_count++] = i;
|
||||||
}
|
}
|
||||||
ctx->bf_count++;
|
ctx->bf_count++;
|
||||||
@@ -83,26 +100,11 @@ void subghz_scene_kl_bf_cleanup_on_enter(void* context) {
|
|||||||
deleted++;
|
deleted++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char new_name[24];
|
|
||||||
snprintf(new_name, sizeof(new_name), "BF_%07lX", ctx->serial);
|
|
||||||
|
|
||||||
size_t new_user_count = subghz_keeloq_keys_user_count(subghz->keeloq_keys_manager);
|
|
||||||
for(size_t i = 0; i < new_user_count; i++) {
|
|
||||||
SubGhzKey* k = subghz_keeloq_keys_get(subghz->keeloq_keys_manager, i);
|
|
||||||
if(!k || !k->name) continue;
|
|
||||||
const char* n = furi_string_get_cstr(k->name);
|
|
||||||
if(strncmp(n, prefix, prefix_len) == 0) {
|
|
||||||
subghz_keeloq_keys_set(
|
|
||||||
subghz->keeloq_keys_manager, i, k->key, k->type, new_name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subghz_keeloq_keys_save(subghz->keeloq_keys_manager);
|
subghz_keeloq_keys_save(subghz->keeloq_keys_manager);
|
||||||
|
|
||||||
furi_string_printf(msg,
|
furi_string_printf(msg,
|
||||||
"Cleaned %u keys.\nKept valid key:\n%s",
|
"Cleaned %u keys.\nKept valid key:\n%s",
|
||||||
deleted, new_name);
|
deleted, bf_name);
|
||||||
} else if(ctx->valid_count == 0) {
|
} else if(ctx->valid_count == 0) {
|
||||||
furi_string_printf(msg,
|
furi_string_printf(msg,
|
||||||
"%u BF keys found\nbut none validates\nhop. Kept all.",
|
"%u BF keys found\nbut none validates\nhop. Kept all.",
|
||||||
|
|||||||
Reference in New Issue
Block a user