mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Compare commits
10 Commits
41098b04f8
...
64c2b52aca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64c2b52aca | ||
|
|
5c539d2346 | ||
|
|
3bfeea9962 | ||
|
|
0a7eb30a15 | ||
|
|
caad1ef268 | ||
|
|
d10a601109 | ||
|
|
32a182c439 | ||
|
|
1f676cffea | ||
|
|
a28b2477f9 | ||
|
|
c08cb33a76 |
@@ -7,11 +7,14 @@
|
||||
* SubGHz: Add IL-100 Smart support for Add manually
|
||||
* SubGHz: Add **experimental counter overflow mode** (OFEX), replicates how some key duplicators work, DO NOT USE if you don't know what you are doing, it will reset your counter value! (accesible with debug on in radio settings - counter incr.)
|
||||
* SubGHz: **Return Honeywell Sec** with fixes and improvements (by htotoo & LiQuiDz & xMasterX)
|
||||
* NFC: Keys found in key cache are now used in Nested attacks, deleting key cache is no longer required (by @noproto)
|
||||
* NFC: MFKey 4.0, MIFARE Classic Static Encrypted Nested attacks run 10x faster (by @noproto)
|
||||
* NFC: **Add Saflok MFUL Parser Support** (by @aaronjamt)
|
||||
* NFC: **Add MFUL counters to Info page** (by @aaronjamt)
|
||||
* OFW: Fix Felica standard loading from nfc file
|
||||
* Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
|
||||
## Other changes
|
||||
* SubGHz: OFEX support for SecPlus v1 and v2, various fixes (by @Dmitry422 & xMasterX)
|
||||
* SubGHz Remote: Add default remote and clear slot features (by @jknlsn)
|
||||
* Fix typo in README warning about scammers (PR #931 | by @koterba)
|
||||
* Bad USB: Colemak keyboard layout (by @Ashe-Sterling)
|
||||
|
||||
@@ -40,8 +40,6 @@ void nfc_render_mf_ultralight_pwd_pack(const MfUltralightData* data, FuriString*
|
||||
}
|
||||
|
||||
nfc_render_mf_ultralight_pages_count(data, str);
|
||||
|
||||
nfc_render_mf_ultralight_counters(data, str);
|
||||
}
|
||||
|
||||
void nfc_render_mf_ultralight_info(
|
||||
@@ -51,6 +49,8 @@ void nfc_render_mf_ultralight_info(
|
||||
nfc_render_iso14443_3a_info(data->iso14443_3a_data, format_type, str);
|
||||
|
||||
nfc_render_mf_ultralight_pages_count(data, str);
|
||||
|
||||
nfc_render_mf_ultralight_counters(data, str);
|
||||
}
|
||||
|
||||
void nfc_render_mf_ultralight_dump(const MfUltralightData* data, FuriString* str) {
|
||||
|
||||
@@ -113,6 +113,9 @@ typedef struct {
|
||||
uint16_t nested_target_key;
|
||||
uint16_t msb_count;
|
||||
bool enhanced_dict;
|
||||
uint16_t current_key_idx; // Current key index for CUID dictionary mode
|
||||
uint8_t*
|
||||
cuid_key_indices_bitmap; // Bitmap of key indices present in CUID dictionary (256 bits = 32 bytes)
|
||||
} NfcMfClassicDictAttackContext;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -2,12 +2,22 @@
|
||||
|
||||
#include <bit_lib/bit_lib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#define TAG "NfcMfClassicDictAttack"
|
||||
#define TAG "NfcMfClassicDictAttack"
|
||||
#define BIT(x, n) ((x) >> (n) & 1)
|
||||
|
||||
// TODO FL-3926: Fix lag when leaving the dictionary attack view after Hardnested
|
||||
// TODO FL-3926: Re-enters backdoor detection between user and system dictionary if no backdoor is found
|
||||
|
||||
// KeysDict structure definition for inline CUID dictionary allocation
|
||||
struct KeysDict {
|
||||
Stream* stream;
|
||||
size_t key_size;
|
||||
size_t key_size_symbols;
|
||||
size_t total_keys;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DictAttackStateCUIDDictInProgress,
|
||||
DictAttackStateUserDictInProgress,
|
||||
@@ -31,11 +41,22 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
instance->nfc_dict_context.is_card_present = false;
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardLost);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
bool is_cuid_dict = (state == DictAttackStateCUIDDictInProgress);
|
||||
|
||||
const MfClassicData* mfc_data =
|
||||
nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic);
|
||||
mfc_event->data->poller_mode.mode = (instance->nfc_dict_context.enhanced_dict) ?
|
||||
MfClassicPollerModeDictAttackEnhanced :
|
||||
MfClassicPollerModeDictAttackStandard;
|
||||
|
||||
// Select mode based on dictionary type
|
||||
if(is_cuid_dict) {
|
||||
mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttackCUID;
|
||||
} else if(instance->nfc_dict_context.enhanced_dict) {
|
||||
mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttackEnhanced;
|
||||
} else {
|
||||
mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttackStandard;
|
||||
}
|
||||
|
||||
mfc_event->data->poller_mode.data = mfc_data;
|
||||
instance->nfc_dict_context.sectors_total =
|
||||
mf_classic_get_total_sectors_num(mfc_data->type);
|
||||
@@ -46,12 +67,57 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
bool is_cuid_dict = (state == DictAttackStateCUIDDictInProgress);
|
||||
|
||||
MfClassicKey key = {};
|
||||
if(keys_dict_get_next_key(
|
||||
instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
|
||||
bool key_found = false;
|
||||
|
||||
if(is_cuid_dict) {
|
||||
// CUID dictionary: read 7 bytes (1 byte key_idx + 6 bytes key) and filter by exact key_idx
|
||||
uint16_t target_key_idx = instance->nfc_dict_context.current_key_idx;
|
||||
|
||||
// Check if this key index exists in the bitmap (only valid for 0-255)
|
||||
if(target_key_idx < 256 &&
|
||||
BIT(instance->nfc_dict_context.cuid_key_indices_bitmap[target_key_idx / 8],
|
||||
target_key_idx % 8)) {
|
||||
uint8_t key_with_idx[sizeof(MfClassicKey) + 1];
|
||||
|
||||
while(keys_dict_get_next_key(
|
||||
instance->nfc_dict_context.dict, key_with_idx, sizeof(MfClassicKey) + 1)) {
|
||||
// Extract key_idx from first byte
|
||||
uint8_t key_idx = key_with_idx[0];
|
||||
|
||||
instance->nfc_dict_context.dict_keys_current++;
|
||||
|
||||
// Only use key if it matches the exact current key index
|
||||
if(key_idx == (uint8_t)target_key_idx) {
|
||||
// Copy the actual key (starts at byte 1)
|
||||
memcpy(key.data, &key_with_idx[1], sizeof(MfClassicKey));
|
||||
key_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Standard dictionary: read 12 bytes
|
||||
if(keys_dict_get_next_key(
|
||||
instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
|
||||
key_found = true;
|
||||
instance->nfc_dict_context.dict_keys_current++;
|
||||
}
|
||||
}
|
||||
|
||||
if(key_found) {
|
||||
mfc_event->data->key_request_data.key = key;
|
||||
// In CUID mode, set key_type based on key_idx (odd = B, even = A)
|
||||
if(is_cuid_dict) {
|
||||
uint16_t target_key_idx = instance->nfc_dict_context.current_key_idx;
|
||||
mfc_event->data->key_request_data.key_type =
|
||||
(target_key_idx % 2 == 0) ? MfClassicKeyTypeA : MfClassicKeyTypeB;
|
||||
}
|
||||
mfc_event->data->key_request_data.key_provided = true;
|
||||
instance->nfc_dict_context.dict_keys_current++;
|
||||
if(instance->nfc_dict_context.dict_keys_current % 10 == 0) {
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
@@ -72,10 +138,27 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
bool is_cuid_dict = (state == DictAttackStateCUIDDictInProgress);
|
||||
|
||||
keys_dict_rewind(instance->nfc_dict_context.dict);
|
||||
instance->nfc_dict_context.dict_keys_current = 0;
|
||||
instance->nfc_dict_context.current_sector =
|
||||
mfc_event->data->next_sector_data.current_sector;
|
||||
|
||||
// In CUID mode, increment the key index and calculate sector from it
|
||||
if(is_cuid_dict) {
|
||||
instance->nfc_dict_context.current_key_idx++;
|
||||
// Calculate sector from key_idx (each sector has 2 keys: A and B)
|
||||
instance->nfc_dict_context.current_sector =
|
||||
instance->nfc_dict_context.current_key_idx / 2;
|
||||
// Write back to event data so poller can read it
|
||||
mfc_event->data->next_sector_data.current_sector =
|
||||
instance->nfc_dict_context.current_sector;
|
||||
} else {
|
||||
instance->nfc_dict_context.current_sector =
|
||||
mfc_event->data->next_sector_data.current_sector;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyA) {
|
||||
@@ -153,18 +236,51 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
|
||||
break;
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.dict = keys_dict_alloc(
|
||||
furi_string_get_cstr(cuid_dict_path),
|
||||
KeysDictModeOpenExisting,
|
||||
sizeof(MfClassicKey));
|
||||
// Manually create KeysDict and scan once to count + populate bitmap
|
||||
KeysDict* dict = malloc(sizeof(KeysDict));
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
dict->stream = buffered_file_stream_alloc(storage);
|
||||
dict->key_size = sizeof(MfClassicKey) + 1;
|
||||
dict->key_size_symbols = dict->key_size * 2 + 1;
|
||||
dict->total_keys = 0;
|
||||
|
||||
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
if(!buffered_file_stream_open(
|
||||
dict->stream,
|
||||
furi_string_get_cstr(cuid_dict_path),
|
||||
FSAM_READ_WRITE,
|
||||
FSOM_OPEN_EXISTING)) {
|
||||
buffered_file_stream_close(dict->stream);
|
||||
free(dict);
|
||||
state = DictAttackStateUserDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
// Allocate and populate bitmap of key indices present in CUID dictionary
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap = malloc(32);
|
||||
memset(instance->nfc_dict_context.cuid_key_indices_bitmap, 0, 32);
|
||||
|
||||
// Scan dictionary once to count keys and populate bitmap
|
||||
uint8_t key_with_idx[dict->key_size];
|
||||
while(keys_dict_get_next_key(dict, key_with_idx, dict->key_size)) {
|
||||
uint8_t key_idx = key_with_idx[0];
|
||||
// Set bit for this key index
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap[key_idx / 8] |=
|
||||
(1 << (key_idx % 8));
|
||||
dict->total_keys++;
|
||||
}
|
||||
keys_dict_rewind(dict);
|
||||
|
||||
if(dict->total_keys == 0) {
|
||||
keys_dict_free(dict);
|
||||
free(instance->nfc_dict_context.cuid_key_indices_bitmap);
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap = NULL;
|
||||
state = DictAttackStateUserDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.dict = dict;
|
||||
dict_attack_set_header(instance->dict_attack, "MF Classic CUID Dictionary");
|
||||
instance->nfc_dict_context.current_key_idx = 0; // Initialize key index for CUID mode
|
||||
} while(false);
|
||||
|
||||
furi_string_free(cuid_dict_path);
|
||||
@@ -265,6 +381,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
if(instance->nfc_dict_context.cuid_key_indices_bitmap) {
|
||||
free(instance->nfc_dict_context.cuid_key_indices_bitmap);
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap = NULL;
|
||||
}
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
@@ -309,6 +429,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
if(instance->nfc_dict_context.cuid_key_indices_bitmap) {
|
||||
free(instance->nfc_dict_context.cuid_key_indices_bitmap);
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap = NULL;
|
||||
}
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
@@ -366,6 +490,12 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
|
||||
// Free CUID bitmap if allocated
|
||||
if(instance->nfc_dict_context.cuid_key_indices_bitmap) {
|
||||
free(instance->nfc_dict_context.cuid_key_indices_bitmap);
|
||||
instance->nfc_dict_context.cuid_key_indices_bitmap = NULL;
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.current_sector = 0;
|
||||
instance->nfc_dict_context.sectors_total = 0;
|
||||
instance->nfc_dict_context.sectors_read = 0;
|
||||
@@ -381,6 +511,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||
instance->nfc_dict_context.nested_target_key = 0;
|
||||
instance->nfc_dict_context.msb_count = 0;
|
||||
instance->nfc_dict_context.enhanced_dict = false;
|
||||
instance->nfc_dict_context.current_key_idx = 0;
|
||||
|
||||
// Clean up temporary files used for nested dictionary attack
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH)) {
|
||||
|
||||
@@ -55,7 +55,7 @@ const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = {
|
||||
10,
|
||||
50,
|
||||
65535,
|
||||
65534,
|
||||
-2147483647,
|
||||
0,
|
||||
-1,
|
||||
-2,
|
||||
|
||||
@@ -13,6 +13,8 @@ static uint32_t counter32 = 0x0;
|
||||
static uint16_t counter16 = 0x0;
|
||||
static uint8_t byte_count = 0;
|
||||
static uint8_t* byte_ptr = NULL;
|
||||
static uint8_t hex_char_lenght = 0;
|
||||
static FuriString* byte_input_text;
|
||||
|
||||
#define COUNTER_MODE_COUNT 7
|
||||
static const char* const counter_mode_text[COUNTER_MODE_COUNT] = {
|
||||
@@ -50,11 +52,61 @@ static Protocols protocols[] = {
|
||||
|
||||
#define PROTOCOLS_COUNT (sizeof(protocols) / sizeof(Protocols));
|
||||
|
||||
// our special case function based on strint_to_uint32 from strint.c
|
||||
StrintParseError strint_to_uint32_base16(const char* str, uint32_t* out, uint8_t* lenght) {
|
||||
// skip whitespace
|
||||
while(((*str >= '\t') && (*str <= '\r')) || *str == ' ') {
|
||||
str++;
|
||||
}
|
||||
|
||||
// read digits
|
||||
uint32_t limit = UINT32_MAX;
|
||||
uint32_t mul_limit = limit / 16;
|
||||
uint32_t result = 0;
|
||||
int read_total = 0;
|
||||
|
||||
while(*str != 0) {
|
||||
int digit_value;
|
||||
if(*str >= '0' && *str <= '9') {
|
||||
digit_value = *str - '0';
|
||||
} else if(*str >= 'A' && *str <= 'Z') {
|
||||
digit_value = *str - 'A' + 10;
|
||||
} else if(*str >= 'a' && *str <= 'z') {
|
||||
digit_value = *str - 'a' + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if(digit_value >= 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(result > mul_limit) return StrintParseOverflowError;
|
||||
result *= 16;
|
||||
if(result > limit - digit_value) return StrintParseOverflowError; //-V658
|
||||
result += digit_value;
|
||||
|
||||
read_total++;
|
||||
str++;
|
||||
}
|
||||
|
||||
if(read_total == 0) {
|
||||
result = 0;
|
||||
*lenght = 0;
|
||||
return StrintParseAbsentError;
|
||||
}
|
||||
|
||||
if(out) *out = result;
|
||||
if(lenght) *lenght = read_total;
|
||||
return StrintParseNoError;
|
||||
}
|
||||
|
||||
void subghz_scene_signal_settings_counter_mode_changed(VariableItem* item) {
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, counter_mode_text[index]);
|
||||
counter_mode = counter_mode_value[index];
|
||||
}
|
||||
|
||||
void subghz_scene_signal_settings_byte_input_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone);
|
||||
@@ -62,11 +114,15 @@ void subghz_scene_signal_settings_byte_input_callback(void* context) {
|
||||
|
||||
void subghz_scene_signal_settings_variable_item_list_enter_callback(void* context, uint32_t index) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// when we click OK on "Edit counter" item
|
||||
if(index == 1) {
|
||||
furi_string_cat_printf(byte_input_text, "%i", hex_char_lenght * 4);
|
||||
furi_string_cat_str(byte_input_text, "-bit counter in HEX");
|
||||
|
||||
// Setup byte_input view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter counter in HEX");
|
||||
byte_input_set_header_text(byte_input, furi_string_get_cstr(byte_input_text));
|
||||
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
@@ -75,7 +131,6 @@ void subghz_scene_signal_settings_variable_item_list_enter_callback(void* contex
|
||||
subghz,
|
||||
byte_ptr,
|
||||
byte_count);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +149,7 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
FuriString* tmp_string = furi_string_alloc();
|
||||
FuriString* tmp_text = furi_string_alloc_set_str("");
|
||||
|
||||
uint32_t tmp_counter_mode = 0;
|
||||
counter_mode = 0xff;
|
||||
@@ -106,10 +161,10 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
} else {
|
||||
flipper_format_read_string(fff_data_file, "Protocol", tmp_string);
|
||||
flipper_format_read_string(fff_data_file, "Protocol", tmp_text);
|
||||
// compare available protocols names, load CounterMode value from file and setup variable_item_list values_count
|
||||
for(uint8_t i = 0; i < PROTOCOLS_COUNT i++) {
|
||||
if(!strcmp(furi_string_get_cstr(tmp_string), protocols[i].name)) {
|
||||
if(!strcmp(furi_string_get_cstr(tmp_text), protocols[i].name)) {
|
||||
mode_count = protocols[i].mode_count;
|
||||
if(flipper_format_read_uint32(fff_data_file, "CounterMode", &tmp_counter_mode, 1)) {
|
||||
counter_mode = (uint8_t)tmp_counter_mode;
|
||||
@@ -121,39 +176,15 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
||||
}
|
||||
FURI_LOG_D(TAG, "Current CounterMode value %li", counter_mode);
|
||||
|
||||
furi_string_free(tmp_string);
|
||||
flipper_format_file_close(fff_data_file);
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
//Create and Enable/Disable variable_item_list depent from current CounterMode value
|
||||
VariableItemList* variable_item_list = subghz->variable_item_list;
|
||||
int32_t value_index;
|
||||
VariableItem* item;
|
||||
|
||||
variable_item_list_set_selected_item(subghz->variable_item_list, 0);
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list,
|
||||
subghz_scene_signal_settings_variable_item_list_enter_callback,
|
||||
subghz);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Counter Mode",
|
||||
mode_count,
|
||||
subghz_scene_signal_settings_counter_mode_changed,
|
||||
subghz);
|
||||
value_index = value_index_int32(counter_mode, counter_mode_value, mode_count);
|
||||
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, counter_mode_text[value_index]);
|
||||
variable_item_set_locked(item, (counter_mode == 0xff), "Not available\nfor this\nprotocol !");
|
||||
|
||||
// ### Counter edit section ###
|
||||
FuriString* tmp_text = furi_string_alloc_set_str("");
|
||||
FuriString* textCnt = furi_string_alloc_set_str("");
|
||||
byte_input_text = furi_string_alloc_set_str("Enter ");
|
||||
furi_string_reset(tmp_text);
|
||||
|
||||
bool counter_not_available = true;
|
||||
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
||||
|
||||
@@ -171,46 +202,97 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
||||
|
||||
int8_t place = furi_string_search_str(tmp_text, "Cnt:??", 0);
|
||||
if(place > 0) {
|
||||
FURI_LOG_D(TAG, "Founded Cnt:???? - counter not available for this protocol");
|
||||
counter_mode = 0xff;
|
||||
FURI_LOG_D(
|
||||
TAG, "Founded Cnt:???? - Counter mode and edit not available for this protocol");
|
||||
} else {
|
||||
place = furi_string_search_str(tmp_text, "Cnt:", 0);
|
||||
if(place > 0) {
|
||||
furi_string_set_n(textCnt, tmp_text, place + 4, 8);
|
||||
FURI_LOG_D(
|
||||
TAG, "Found 8 bytes string starting with Cnt:%s", furi_string_get_cstr(textCnt));
|
||||
counter_not_available = false;
|
||||
|
||||
// trim and convert 8 simbols string to uint32 by base 16 (hex) by strint_to_uint32();
|
||||
// later we use loaded_counter in subghz_scene_signal_settings_on_event to check is there 0 or not - special case
|
||||
strint_to_uint32(furi_string_get_cstr(textCnt), NULL, &loaded_counter32, 16);
|
||||
|
||||
// Check it there counter 2 (less than 65535) or 4 (more than 65535) hex bytes long and use corresponding variable for ByteInput
|
||||
// To show hex value we must revert bytes for ByteInput view and display 2 or 4 hex bytes to edit
|
||||
if(counter32 > 0xFFFF) {
|
||||
byte_count = 4;
|
||||
counter32 = loaded_counter32;
|
||||
furi_string_printf(tmp_text, "%08lX", counter32);
|
||||
FURI_LOG_D(TAG, "Byte count %i", byte_count);
|
||||
FURI_LOG_D(TAG, "Counter DEC %li, HEX %lX", counter32, counter32);
|
||||
counter32 = __bswap32(counter32);
|
||||
byte_ptr = (uint8_t*)&counter32;
|
||||
} else {
|
||||
counter16 = loaded_counter32;
|
||||
byte_count = 2;
|
||||
furi_string_printf(tmp_text, "%04X", counter16);
|
||||
FURI_LOG_D(TAG, "Byte count %i", byte_count);
|
||||
FURI_LOG_D(TAG, "Counter DEC %i, HEX %X", counter16, counter16);
|
||||
counter16 = __bswap16(counter16);
|
||||
byte_ptr = (uint8_t*)&counter16;
|
||||
// defence from memory leaks. Check can we take 8 symbols after 'Cnt:' ?
|
||||
// if from current place to end of stirngs more than 8 symbols - ok, if not - just take symbols from current place to end of string.
|
||||
// +4 - its 'Cnt:' lenght
|
||||
uint8_t n_symbols_taken = 8;
|
||||
if(sizeof(tmp_text) - (place + 4) < 8) {
|
||||
n_symbols_taken = sizeof(tmp_text) - (place + 4);
|
||||
}
|
||||
furi_string_set_n(textCnt, tmp_text, place + 4, n_symbols_taken);
|
||||
furi_string_trim(textCnt);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Taked 8 bytes hex value starting after 'Cnt:' - %s",
|
||||
furi_string_get_cstr(textCnt));
|
||||
|
||||
// trim and convert 8 simbols string to uint32 by base 16 (hex);
|
||||
// later we use loaded_counter in subghz_scene_signal_settings_on_event to check is there 0 or not - special case
|
||||
|
||||
if(strint_to_uint32_base16(
|
||||
furi_string_get_cstr(textCnt), &loaded_counter32, &hex_char_lenght) ==
|
||||
StrintParseNoError) {
|
||||
counter_not_available = false;
|
||||
|
||||
// calculate and roundup number of hex bytes do display counter in byte_input (every 2 hex simbols = 1 byte for view)
|
||||
// later must be used in byte_input to restrict number of available byte to edit
|
||||
// cnt_byte_count = (hex_char_lenght + 1) / 2;
|
||||
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Result of conversion from String to uint_32 DEC %li, HEX %lX, HEX lenght %i symbols",
|
||||
loaded_counter32,
|
||||
loaded_counter32,
|
||||
hex_char_lenght);
|
||||
|
||||
// Check is there byte_count more than 2 hex bytes long (16 bit) or not (32bit)
|
||||
// To show hex value we must correct revert bytes for ByteInput view
|
||||
if(hex_char_lenght > 4) {
|
||||
counter32 = loaded_counter32;
|
||||
furi_string_printf(tmp_text, "%lX", counter32);
|
||||
counter32 = __bswap32(counter32);
|
||||
byte_ptr = (uint8_t*)&counter32;
|
||||
byte_count = 4;
|
||||
} else {
|
||||
counter16 = loaded_counter32;
|
||||
furi_string_printf(tmp_text, "%X", counter16);
|
||||
counter16 = __bswap16(counter16);
|
||||
byte_ptr = (uint8_t*)&counter16;
|
||||
byte_count = 2;
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Cant convert text counter value");
|
||||
};
|
||||
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Counter not available for this protocol");
|
||||
FURI_LOG_D(TAG, "Counter editor not available for this protocol");
|
||||
}
|
||||
}
|
||||
|
||||
furi_assert(byte_ptr);
|
||||
furi_assert(byte_count > 0);
|
||||
|
||||
//Create and Enable/Disable variable_item_list depent from current values
|
||||
VariableItemList* variable_item_list = subghz->variable_item_list;
|
||||
int32_t value_index;
|
||||
VariableItem* item;
|
||||
|
||||
// variable_item_list_set_selected_item(subghz->variable_item_list, 0);
|
||||
// variable_item_list_reset(subghz->variable_item_list);
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list,
|
||||
subghz_scene_signal_settings_variable_item_list_enter_callback,
|
||||
subghz);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Counter Mode",
|
||||
mode_count,
|
||||
subghz_scene_signal_settings_counter_mode_changed,
|
||||
subghz);
|
||||
value_index = value_index_int32(counter_mode, counter_mode_value, mode_count);
|
||||
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, counter_mode_text[value_index]);
|
||||
variable_item_set_locked(item, (counter_mode == 0xff), "Not available\nfor this\nprotocol !");
|
||||
|
||||
item = variable_item_list_add(variable_item_list, "Edit Counter", 1, NULL, subghz);
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text));
|
||||
@@ -248,22 +330,24 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
}
|
||||
|
||||
// at this point we must have signal Cnt:00
|
||||
// convert back after byte_view and do one send with our new mult (counter16) - at end we must have signal Cnt = counter16
|
||||
// convert back after byte_input and do one send with our new mult (counter16) - at end we must have signal Cnt = counter16
|
||||
counter16 = __bswap16(counter16);
|
||||
if(counter16 > 0) {
|
||||
furi_hal_subghz_set_rolling_counter_mult(counter16);
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_rolling_counter_mult(counter16);
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
|
||||
// restore user definded counter increase value (mult)
|
||||
furi_hal_subghz_set_rolling_counter_mult(tmp_counter);
|
||||
|
||||
break;
|
||||
case 4:
|
||||
// the same for 32 bit Counter
|
||||
tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
|
||||
|
||||
furi_hal_subghz_set_rolling_counter_mult(0xFFFFFFFF);
|
||||
furi_hal_subghz_set_rolling_counter_mult(0xFFFFFFF);
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
|
||||
@@ -274,11 +358,11 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even
|
||||
}
|
||||
|
||||
counter32 = __bswap32(counter32);
|
||||
if(counter32 > 0) {
|
||||
furi_hal_subghz_set_rolling_counter_mult(counter32);
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_rolling_counter_mult((counter32 & 0xFFFFFFF));
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
|
||||
furi_hal_subghz_set_rolling_counter_mult(tmp_counter);
|
||||
break;
|
||||
default:
|
||||
@@ -333,4 +417,5 @@ void subghz_scene_signal_settings_on_exit(void* context) {
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(subghz->byte_input, "");
|
||||
furi_string_free(byte_input_text);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ App(
|
||||
fap_icon_assets="images",
|
||||
fap_weburl="https://github.com/noproto/FlipperMfkey",
|
||||
fap_description="MIFARE Classic key recovery tool",
|
||||
fap_version="3.1",
|
||||
fap_version="4.0",
|
||||
)
|
||||
|
||||
App(
|
||||
|
||||
@@ -251,10 +251,14 @@ bool load_nested_nonces(
|
||||
MfClassicNonce res = {0};
|
||||
res.attack = static_encrypted;
|
||||
|
||||
int sector_num = 0;
|
||||
char key_type = 'A';
|
||||
int parsed = sscanf(
|
||||
line,
|
||||
"Sec %*d key %*c cuid %" PRIx32 " nt0 %" PRIx32 " ks0 %" PRIx32
|
||||
"Sec %d key %c cuid %" PRIx32 " nt0 %" PRIx32 " ks0 %" PRIx32
|
||||
" par0 %4[01] nt1 %" PRIx32 " ks1 %" PRIx32 " par1 %4[01]",
|
||||
§or_num,
|
||||
&key_type,
|
||||
&res.uid,
|
||||
&res.nt0,
|
||||
&res.ks1_1_enc,
|
||||
@@ -263,11 +267,14 @@ bool load_nested_nonces(
|
||||
&res.ks1_2_enc,
|
||||
res.par_2_str);
|
||||
|
||||
if(parsed >= 4) { // At least one nonce is present
|
||||
// Calculate key_idx from sector and key type (for static encrypted: key_idx = sector * 2 + key_offset)
|
||||
res.key_idx = (uint8_t)(sector_num * 2 + (key_type == 'B' ? 1 : 0));
|
||||
|
||||
if(parsed >= 6) { // At least one nonce is present (sector, key, uid, nt0, ks0, par0)
|
||||
res.par_1 = binaryStringToInt(res.par_1_str);
|
||||
res.uid_xor_nt0 = res.uid ^ res.nt0;
|
||||
|
||||
if(parsed == 7) { // Both nonces are present
|
||||
if(parsed == 9) { // Both nonces are present
|
||||
res.attack = static_nested;
|
||||
res.par_2 = binaryStringToInt(res.par_2_str);
|
||||
res.uid_xor_nt1 = res.uid ^ res.nt1;
|
||||
|
||||
@@ -67,8 +67,8 @@ static uint8_t MSB_LIMIT = 16;
|
||||
static inline void flush_key_buffer(ProgramState* program_state) {
|
||||
if(program_state->key_buffer && program_state->key_buffer_count > 0 &&
|
||||
program_state->cuid_dict) {
|
||||
// Pre-allocate exact size needed: 12 hex chars + 1 newline per key
|
||||
size_t total_size = program_state->key_buffer_count * 13;
|
||||
// Pre-allocate exact size needed: 2 hex chars (key_idx) + 12 hex chars (key) + 1 newline per key
|
||||
size_t total_size = program_state->key_buffer_count * 15;
|
||||
//FURI_LOG_I(TAG, "Flushing key buffer: %d keys", program_state->key_buffer_count);
|
||||
//FURI_LOG_I(TAG, "Total size: %d bytes", total_size);
|
||||
char* batch_buffer = malloc(total_size + 1); // +1 for null terminator
|
||||
@@ -77,6 +77,11 @@ static inline void flush_key_buffer(ProgramState* program_state) {
|
||||
const char hex_chars[] = "0123456789ABCDEF";
|
||||
|
||||
for(size_t i = 0; i < program_state->key_buffer_count; i++) {
|
||||
// Write key_idx as 2 hex chars
|
||||
uint8_t key_idx = program_state->key_idx_buffer[i];
|
||||
*ptr++ = hex_chars[key_idx >> 4];
|
||||
*ptr++ = hex_chars[key_idx & 0x0F];
|
||||
|
||||
// Convert key to hex string directly into buffer
|
||||
for(size_t j = 0; j < sizeof(MfClassicKey); j++) {
|
||||
uint8_t byte = program_state->key_buffer[i].data[j];
|
||||
@@ -144,6 +149,7 @@ static inline int
|
||||
|
||||
// Use key buffer - buffer is guaranteed to be available for static_encrypted
|
||||
program_state->key_buffer[program_state->key_buffer_count] = n->key;
|
||||
program_state->key_idx_buffer[program_state->key_buffer_count] = n->key_idx;
|
||||
program_state->key_buffer_count++;
|
||||
|
||||
// Flush buffer when full
|
||||
@@ -659,17 +665,20 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_
|
||||
// Allocate key buffer for static encrypted nonces
|
||||
if(n->attack == static_encrypted) {
|
||||
size_t available_ram = memmgr_heap_get_max_free_block();
|
||||
// Each key becomes 12 hex chars + 1 newline = 13 bytes in the batch string
|
||||
// Plus original 6 bytes in buffer = 19 bytes total per key
|
||||
// Each key becomes 2 hex chars (key_idx) + 12 hex chars (key) + 1 newline = 15 bytes in the batch string
|
||||
// Plus original 6 bytes (key) + 1 byte (key_idx) in buffer = 22 bytes total per key
|
||||
// Add extra safety margin for string overhead and other allocations
|
||||
const size_t safety_threshold = STATIC_ENCRYPTED_RAM_THRESHOLD;
|
||||
const size_t bytes_per_key = sizeof(MfClassicKey) + 13; // buffer + string representation
|
||||
const size_t bytes_per_key =
|
||||
sizeof(MfClassicKey) + sizeof(uint8_t) + 15; // buffer + string representation
|
||||
if(available_ram > safety_threshold) {
|
||||
program_state->key_buffer_size = (available_ram - safety_threshold) / bytes_per_key;
|
||||
program_state->key_buffer =
|
||||
malloc(program_state->key_buffer_size * sizeof(MfClassicKey));
|
||||
program_state->key_idx_buffer =
|
||||
malloc(program_state->key_buffer_size * sizeof(uint8_t));
|
||||
program_state->key_buffer_count = 0;
|
||||
if(!program_state->key_buffer) {
|
||||
if(!program_state->key_buffer || !program_state->key_idx_buffer) {
|
||||
// Free the allocated blocks before returning
|
||||
for(int i = 0; i < num_blocks; i++) {
|
||||
free(block_pointers[i]);
|
||||
@@ -691,6 +700,7 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_
|
||||
}
|
||||
} else {
|
||||
program_state->key_buffer = NULL;
|
||||
program_state->key_idx_buffer = NULL;
|
||||
program_state->key_buffer_size = 0;
|
||||
program_state->key_buffer_count = 0;
|
||||
}
|
||||
@@ -736,7 +746,9 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_
|
||||
if(n->attack == static_encrypted && program_state->key_buffer) {
|
||||
flush_key_buffer(program_state);
|
||||
free(program_state->key_buffer);
|
||||
free(program_state->key_idx_buffer);
|
||||
program_state->key_buffer = NULL;
|
||||
program_state->key_idx_buffer = NULL;
|
||||
program_state->key_buffer_size = 0;
|
||||
program_state->key_buffer_count = 0;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ typedef struct {
|
||||
FuriThread* mfkeythread;
|
||||
KeysDict* cuid_dict;
|
||||
MfClassicKey* key_buffer;
|
||||
uint8_t* key_idx_buffer;
|
||||
size_t key_buffer_size;
|
||||
size_t key_buffer_count;
|
||||
} ProgramState;
|
||||
@@ -72,6 +73,7 @@ typedef struct {
|
||||
uint32_t nt1; // tag challenge second
|
||||
uint32_t uid_xor_nt0; // uid ^ nt0
|
||||
uint32_t uid_xor_nt1; // uid ^ nt1
|
||||
uint8_t key_idx; // key index (for static encrypted nonces)
|
||||
union {
|
||||
// Mfkey32
|
||||
struct {
|
||||
|
||||
@@ -163,11 +163,14 @@ NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) {
|
||||
instance->mfc_event.type = MfClassicPollerEventTypeRequestMode;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackStandard) {
|
||||
if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackStandard ||
|
||||
instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackCUID) {
|
||||
mf_classic_copy(instance->data, instance->mfc_event_data.poller_mode.data);
|
||||
instance->mode_ctx.dict_attack_ctx.mode = instance->mfc_event_data.poller_mode.mode;
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackEnhanced) {
|
||||
mf_classic_copy(instance->data, instance->mfc_event_data.poller_mode.data);
|
||||
instance->mode_ctx.dict_attack_ctx.mode = instance->mfc_event_data.poller_mode.mode;
|
||||
instance->state = MfClassicPollerStateAnalyzeBackdoor;
|
||||
} else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeRead) {
|
||||
instance->state = MfClassicPollerStateRequestReadSector;
|
||||
@@ -590,7 +593,22 @@ NfcCommand mf_classic_poller_handler_analyze_backdoor(MfClassicPoller* instance)
|
||||
(error == MfClassicErrorProtocol || error == MfClassicErrorTimeout)) {
|
||||
FURI_LOG_D(TAG, "No backdoor identified");
|
||||
dict_attack_ctx->backdoor = MfClassicBackdoorNone;
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
|
||||
// Check if any keys were cached - if so, go directly to nested attack
|
||||
bool has_cached_keys = false;
|
||||
for(uint8_t sector = 0; sector < instance->sectors_total; sector++) {
|
||||
if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeA) ||
|
||||
mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeB)) {
|
||||
has_cached_keys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(has_cached_keys) {
|
||||
instance->state = MfClassicPollerStateNestedController;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
}
|
||||
} else if(error == MfClassicErrorNone) {
|
||||
FURI_LOG_I(TAG, "Backdoor identified: v%d", backdoor_version);
|
||||
dict_attack_ctx->backdoor = mf_classic_backdoor_keys[next_key_index].type;
|
||||
@@ -687,7 +705,15 @@ NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) {
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(instance->mfc_event_data.key_request_data.key_provided) {
|
||||
dict_attack_ctx->current_key = instance->mfc_event_data.key_request_data.key;
|
||||
instance->state = MfClassicPollerStateAuthKeyA;
|
||||
dict_attack_ctx->requested_key_type = instance->mfc_event_data.key_request_data.key_type;
|
||||
|
||||
// In CUID mode, go directly to the appropriate Auth state based on key_type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID &&
|
||||
dict_attack_ctx->requested_key_type == MfClassicKeyTypeB) {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyA;
|
||||
}
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateNextSector;
|
||||
}
|
||||
@@ -701,7 +727,12 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
||||
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
// In CUID mode, skip directly to RequestKey since we test keys by specific type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
}
|
||||
} else {
|
||||
uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->current_sector);
|
||||
uint64_t key =
|
||||
@@ -722,7 +753,12 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
||||
instance->state = MfClassicPollerStateReadSector;
|
||||
} else {
|
||||
mf_classic_poller_halt(instance);
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
// In CUID mode, skip directly to RequestKey since we test keys by specific type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,8 +771,11 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) {
|
||||
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeB)) {
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
// In CUID mode, just request next key since we iterate by key_idx
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
instance->state = MfClassicPollerStateNextSector;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
@@ -774,12 +813,20 @@ NfcCommand mf_classic_poller_handler_next_sector(MfClassicPoller* instance) {
|
||||
MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx;
|
||||
|
||||
dict_attack_ctx->current_sector++;
|
||||
|
||||
if(dict_attack_ctx->current_sector == instance->sectors_total) {
|
||||
instance->state = MfClassicPollerStateSuccess;
|
||||
} else {
|
||||
instance->mfc_event.type = MfClassicPollerEventTypeNextSector;
|
||||
instance->mfc_event_data.next_sector_data.current_sector = dict_attack_ctx->current_sector;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
// In CUID mode, NFC app manages sector based on key_idx - read it back
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
dict_attack_ctx->current_sector =
|
||||
instance->mfc_event_data.next_sector_data.current_sector;
|
||||
}
|
||||
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef enum {
|
||||
MfClassicPollerModeRead, /**< Poller reading mode. */
|
||||
MfClassicPollerModeWrite, /**< Poller writing mode. */
|
||||
MfClassicPollerModeDictAttackStandard, /**< Poller dictionary attack mode. */
|
||||
MfClassicPollerModeDictAttackCUID, /**< Poller CUID dictionary attack mode. */
|
||||
MfClassicPollerModeDictAttackEnhanced, /**< Poller enhanced dictionary attack mode. */
|
||||
} MfClassicPollerMode;
|
||||
|
||||
@@ -129,6 +130,7 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
MfClassicKey key; /**< Key to be used by poller. */
|
||||
MfClassicKeyType key_type; /**< Key type (A or B) for CUID dict attack mode. */
|
||||
bool key_provided; /**< Flag indicating if key is provided. */
|
||||
} MfClassicPollerEventDataKeyRequest;
|
||||
|
||||
|
||||
@@ -128,10 +128,12 @@ typedef struct {
|
||||
uint8_t current_sector;
|
||||
MfClassicKey current_key;
|
||||
MfClassicKeyType current_key_type;
|
||||
MfClassicKeyType requested_key_type; // Key type requested from app (for CUID mode)
|
||||
bool auth_passed;
|
||||
uint16_t current_block;
|
||||
uint8_t reuse_key_sector;
|
||||
MfClassicBackdoor backdoor;
|
||||
MfClassicPollerMode mode; // Current attack mode
|
||||
// Enhanced dictionary attack and nested nonce collection
|
||||
bool enhanced_dict;
|
||||
MfClassicNestedPhase nested_phase;
|
||||
|
||||
@@ -277,23 +277,17 @@ static bool subghz_protocol_alutech_at_4n_gen_data(
|
||||
|
||||
if(alutech_at4n_counter_mode == 0) {
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -189,23 +189,17 @@ static void subghz_protocol_encoder_came_atomo_get_upload(
|
||||
|
||||
if(came_atomo_counter_mode == 0) {
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -138,40 +138,35 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst
|
||||
uint8_t data_prg[8];
|
||||
|
||||
data_prg[0] = 0x00;
|
||||
// faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF)
|
||||
|
||||
if(allow_zero_seed || (instance->generic.seed != 0x0)) {
|
||||
if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFE)) {
|
||||
if(instance->generic.cnt < 0xFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
|
||||
0xFFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
// check OFEX mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt +
|
||||
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt +=
|
||||
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
|
||||
}
|
||||
} else {
|
||||
// to do OFEX mode
|
||||
instance->generic.cnt += 1;
|
||||
}
|
||||
|
||||
if(temp_counter_backup != 0x0) {
|
||||
if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFE)) {
|
||||
if(temp_counter_backup < 0xFFFFF) {
|
||||
if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) >
|
||||
0xFFFFF) {
|
||||
temp_counter_backup = 0;
|
||||
} else {
|
||||
temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(temp_counter_backup >= 0xFFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
// check OFEX mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((temp_counter_backup +
|
||||
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) {
|
||||
temp_counter_backup = 0;
|
||||
} else {
|
||||
temp_counter_backup +=
|
||||
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
|
||||
}
|
||||
} else {
|
||||
// todo OFEX mode
|
||||
temp_counter_backup += 1;
|
||||
}
|
||||
}
|
||||
@@ -239,21 +234,19 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst
|
||||
fixx[i] = (fix >> (shiftby -= 4)) & 0xF;
|
||||
}
|
||||
|
||||
// faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF)
|
||||
if(allow_zero_seed || (instance->generic.seed != 0x0)) {
|
||||
if(!(furi_hal_subghz_get_rolling_counter_mult() >= 0xFFFE)) {
|
||||
if(instance->generic.cnt < 0xFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
|
||||
0xFFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
// check OFEX mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) >
|
||||
0xFFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
|
||||
}
|
||||
|
||||
} else {
|
||||
// OFEX mode
|
||||
if(instance->generic.cnt < 0xFFFFF) {
|
||||
if((instance->generic.cnt + 0xFFFFF) > 0xFFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
|
||||
@@ -146,20 +146,15 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21*
|
||||
|
||||
// Counter increment
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() >= 0xF) {
|
||||
instance->generic.cnt = 0xF;
|
||||
}
|
||||
} else if(instance->generic.cnt >= 0xF) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
//not matter how big and long mult - we take only 4 bits ( AND 0xF) beacose hay21 counter have only 4 bits long (0..F)
|
||||
if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xF)) > 0xF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xF);
|
||||
}
|
||||
} else {
|
||||
// OFEX mode
|
||||
if((instance->generic.cnt + 0x1) > 0xF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xE) {
|
||||
|
||||
@@ -186,26 +186,17 @@ static bool subghz_protocol_keeloq_gen_data(
|
||||
|
||||
if(keeloq_counter_mode == 0) {
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
// If counter is 0xFFFF we will reset it to 0
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
// Increase counter with value set in global settings (mult)
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
|
||||
0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -256,11 +256,13 @@ void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) {
|
||||
uint32_t code_found_hi = instance->generic.data >> 32;
|
||||
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
|
||||
|
||||
// use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s %dbit\r\n"
|
||||
"Key:%08lX%08lX\r\n"
|
||||
"Sn:%07lX Btn:%X Cnt:%04lX\r\n",
|
||||
"Sn:%07lX Btn:%X\r\n"
|
||||
"Cntr:%04lX\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
code_found_hi,
|
||||
|
||||
@@ -156,23 +156,17 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data(
|
||||
instance->generic.cnt = decrypt & 0xFFFF;
|
||||
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -154,23 +154,17 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
|
||||
}
|
||||
if(nice_flors_counter_mode == 0) {
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -253,23 +253,17 @@ static bool
|
||||
|
||||
// Reconstruction of the data
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
@@ -599,7 +593,7 @@ void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* ou
|
||||
"V2 Phoenix %dbit\r\n"
|
||||
"Key:%05lX%08lX\r\n"
|
||||
"Sn:0x%07lX \r\n"
|
||||
"Cnt:0x%04lX\r\n"
|
||||
"Cnt:%04lX\r\n"
|
||||
"Btn:%X\r\n",
|
||||
instance->generic.data_count_bit,
|
||||
(uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF,
|
||||
|
||||
@@ -297,11 +297,13 @@ void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* ou
|
||||
subghz_protocol_scher_khan_check_remote_controller(
|
||||
&instance->generic, &instance->protocol_name);
|
||||
|
||||
// use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s %dbit\r\n"
|
||||
"Key:0x%lX%08lX\r\n"
|
||||
"Sn:%07lX Btn:%X Cnt:%04lX\r\n"
|
||||
"Sn:%07lX Btn:%X\r\n"
|
||||
"Cntr:%04lX\r\n"
|
||||
"Pt: %s\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
|
||||
@@ -218,15 +218,60 @@ static bool subghz_protocol_secplus_v1_encode(SubGhzProtocolEncoderSecPlus_v1* i
|
||||
uint32_t acc = 0;
|
||||
|
||||
//increment the counter
|
||||
rolling += 2;
|
||||
//rolling += 2; - old way
|
||||
// Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE6000000 - 0xFFFFFFFF
|
||||
// one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value
|
||||
// so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value);
|
||||
// at second step check what user set for new Cnt (and correct it if cnt less than 0xE6000000 or more than 0xFFFFFFFF)
|
||||
int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF);
|
||||
// Adjust for negative multiplier
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() < 0) {
|
||||
multicntr = furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
if(multicntr == 1) {
|
||||
multicntr = 2; // to keep old behaviour when mult = 1
|
||||
}
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) & (rolling != 0)) {
|
||||
rolling = 0;
|
||||
} else {
|
||||
// if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE6000000 or 0xFFFFFFFF or new user value
|
||||
if(rolling == 0) {
|
||||
if((furi_hal_subghz_get_rolling_counter_mult()) < (int32_t)0x6000000) {
|
||||
rolling = 0xE6000000;
|
||||
} else {
|
||||
if((furi_hal_subghz_get_rolling_counter_mult()) >= (int32_t)0xFFFFFFF) {
|
||||
rolling = 0xFFFFFFFF;
|
||||
} else {
|
||||
rolling = 0xE0000000;
|
||||
rolling += multicntr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if we have not special cases - so work as standart mode
|
||||
if((rolling + multicntr) > 0xFFFFFFFF) {
|
||||
rolling = 0xE6000000;
|
||||
} else {
|
||||
rolling += multicntr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// OFEX (overflow experimental) mode
|
||||
if((rolling + 0x1) > 0xFFFFFFFF) {
|
||||
rolling = 0xE6000000;
|
||||
} else if(rolling >= 0xE6000000 && rolling != 0xFFFFFFFE) {
|
||||
rolling = 0xFFFFFFFE;
|
||||
} else {
|
||||
rolling++;
|
||||
}
|
||||
}
|
||||
|
||||
//update data
|
||||
instance->generic.data &= 0xFFFFFFFF00000000;
|
||||
instance->generic.data |= rolling;
|
||||
|
||||
if(rolling == 0xFFFFFFFF) {
|
||||
rolling = 0xE6000000;
|
||||
}
|
||||
if(fixed > 0xCFD41B90) {
|
||||
FURI_LOG_E(TAG, "Encode wrong fixed data");
|
||||
return false;
|
||||
@@ -596,10 +641,11 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou
|
||||
} else {
|
||||
furi_string_cat_printf(output, "\r\n");
|
||||
}
|
||||
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Sn:0x%08lX\r\n"
|
||||
"Cnt:%03lX "
|
||||
"Cnt:%08lX "
|
||||
"SwID:0x%X\r\n",
|
||||
instance->generic.serial,
|
||||
instance->generic.cnt,
|
||||
@@ -618,7 +664,7 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Sn:0x%08lX\r\n"
|
||||
"Cnt:%03lX "
|
||||
"Cnt:%08lX "
|
||||
"SwID:0x%X\r\n",
|
||||
instance->generic.serial,
|
||||
instance->generic.cnt,
|
||||
|
||||
@@ -401,10 +401,52 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i
|
||||
uint8_t roll_1[9] = {0};
|
||||
uint8_t roll_2[9] = {0};
|
||||
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
// Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE500000 - 0xFFFFFFF
|
||||
// one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value
|
||||
// so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value);
|
||||
// at second step check what user set for new Cnt (and correct it if cnt less than 0xE500000 or more than 0xFFFFFFF)
|
||||
int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF);
|
||||
// Adjust for negative multiplier
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() < 0) {
|
||||
multicntr = furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) &
|
||||
(instance->generic.cnt != 0)) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
// if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE500000 or 0xFFFFFFF or new user value
|
||||
if(instance->generic.cnt == 0) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() < (int32_t)0xE500000) {
|
||||
instance->generic.cnt = 0xE500000;
|
||||
} else {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() >= (int32_t)0xFFFFFFF) {
|
||||
instance->generic.cnt = 0xFFFFFFF;
|
||||
} else {
|
||||
instance->generic.cnt += multicntr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if we have not special cases - so work as standart mode
|
||||
if((instance->generic.cnt + multicntr) > 0xFFFFFFF) {
|
||||
instance->generic.cnt = 0xE500000;
|
||||
} else {
|
||||
instance->generic.cnt += multicntr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// OFEX (overflow experimental) mode
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFFFFF) {
|
||||
instance->generic.cnt = 0xE500000;
|
||||
} else if(instance->generic.cnt >= 0xE500000 && instance->generic.cnt != 0xFFFFFFE) {
|
||||
instance->generic.cnt = 0xFFFFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
//ToDo it is not known what value the counter starts
|
||||
if(instance->generic.cnt > 0xFFFFFFF) instance->generic.cnt = 0xE500000;
|
||||
uint32_t rolling = subghz_protocol_blocks_reverse_key(instance->generic.cnt, 28);
|
||||
|
||||
for(int8_t i = 17; i > -1; i--) {
|
||||
@@ -939,13 +981,14 @@ void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* ou
|
||||
SubGhzProtocolDecoderSecPlus_v2* instance = context;
|
||||
subghz_protocol_secplus_v2_remote_controller(&instance->generic, instance->secplus_packet_1);
|
||||
|
||||
// need to research or practice check how much bits in counter
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s %db\r\n"
|
||||
"Pk1:0x%lX%08lX\r\n"
|
||||
"Pk2:0x%lX%08lX\r\n"
|
||||
"Sn:0x%08lX Btn:0x%01X\r\n"
|
||||
"Cnt:%03lX\r\n",
|
||||
"Cnt:%07lX\r\n",
|
||||
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
|
||||
@@ -131,23 +131,17 @@ static bool
|
||||
instance->generic.serial = data & 0xFFFFFF;
|
||||
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -125,23 +125,17 @@ static bool subghz_protocol_somfy_telis_gen_data(
|
||||
btn = subghz_protocol_somfy_telis_get_btn_code();
|
||||
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
@@ -130,23 +130,17 @@ void subghz_protocol_encoder_star_line_free(void* context) {
|
||||
static bool
|
||||
subghz_protocol_star_line_gen_data(SubGhzProtocolEncoderStarLine* instance, uint8_t btn) {
|
||||
// Check for OFEX (overflow experimental) mode
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != 0xFFFE) {
|
||||
if(instance->generic.cnt < 0xFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else if(
|
||||
(instance->generic.cnt >= 0xFFFF) &&
|
||||
(furi_hal_subghz_get_rolling_counter_mult() != 0)) {
|
||||
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
|
||||
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else {
|
||||
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
|
||||
}
|
||||
} else {
|
||||
if((instance->generic.cnt + 0x1) > 0xFFFF) {
|
||||
instance->generic.cnt = 0;
|
||||
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
|
||||
instance->generic.cnt = furi_hal_subghz_get_rolling_counter_mult();
|
||||
instance->generic.cnt = 0xFFFE;
|
||||
} else {
|
||||
instance->generic.cnt++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user