mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-16 04:24:45 -07:00
Implement progress bar for upgraded attacks in NFC app
This commit is contained in:
@@ -100,6 +100,8 @@ typedef struct {
|
|||||||
uint8_t nested_phase;
|
uint8_t nested_phase;
|
||||||
uint8_t prng_type;
|
uint8_t prng_type;
|
||||||
uint8_t backdoor;
|
uint8_t backdoor;
|
||||||
|
uint16_t nested_target_key;
|
||||||
|
uint16_t msb_count;
|
||||||
} NfcMfClassicDictAttackContext;
|
} NfcMfClassicDictAttackContext;
|
||||||
|
|
||||||
struct NfcApp {
|
struct NfcApp {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define TAG "NfcMfClassicDictAttack"
|
#define TAG "NfcMfClassicDictAttack"
|
||||||
|
|
||||||
// TODO: Update progress bar with nested attacks
|
// TODO: Fix lag when leaving the dictionary attack view during Hardnested
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DictAttackStateUserDictInProgress,
|
DictAttackStateUserDictInProgress,
|
||||||
@@ -63,6 +63,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
|||||||
instance->nfc_dict_context.nested_phase = data_update->nested_phase;
|
instance->nfc_dict_context.nested_phase = data_update->nested_phase;
|
||||||
instance->nfc_dict_context.prng_type = data_update->prng_type;
|
instance->nfc_dict_context.prng_type = data_update->prng_type;
|
||||||
instance->nfc_dict_context.backdoor = data_update->backdoor;
|
instance->nfc_dict_context.backdoor = data_update->backdoor;
|
||||||
|
instance->nfc_dict_context.nested_target_key = data_update->nested_target_key;
|
||||||
|
instance->nfc_dict_context.msb_count = data_update->msb_count;
|
||||||
view_dispatcher_send_custom_event(
|
view_dispatcher_send_custom_event(
|
||||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||||
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
|
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
|
||||||
@@ -125,6 +127,8 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* instance) {
|
|||||||
dict_attack_set_nested_phase(instance->dict_attack, mfc_dict->nested_phase);
|
dict_attack_set_nested_phase(instance->dict_attack, mfc_dict->nested_phase);
|
||||||
dict_attack_set_prng_type(instance->dict_attack, mfc_dict->prng_type);
|
dict_attack_set_prng_type(instance->dict_attack, mfc_dict->prng_type);
|
||||||
dict_attack_set_backdoor(instance->dict_attack, mfc_dict->backdoor);
|
dict_attack_set_backdoor(instance->dict_attack, mfc_dict->backdoor);
|
||||||
|
dict_attack_set_nested_target_key(instance->dict_attack, mfc_dict->nested_target_key);
|
||||||
|
dict_attack_set_msb_count(instance->dict_attack, mfc_dict->msb_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ typedef struct {
|
|||||||
MfClassicNestedPhase nested_phase;
|
MfClassicNestedPhase nested_phase;
|
||||||
MfClassicPrngType prng_type;
|
MfClassicPrngType prng_type;
|
||||||
MfClassicBackdoor backdoor;
|
MfClassicBackdoor backdoor;
|
||||||
|
uint16_t nested_target_key;
|
||||||
|
uint16_t msb_count;
|
||||||
} DictAttackViewModel;
|
} DictAttackViewModel;
|
||||||
|
|
||||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||||
@@ -71,7 +73,12 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
|||||||
|
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
||||||
if(m->is_key_attack) {
|
if(m->nested_phase == MfClassicNestedPhaseCollectNtEnc) {
|
||||||
|
uint8_t nonce_sector =
|
||||||
|
m->nested_target_key / (m->prng_type == MfClassicPrngTypeWeak ? 4 : 2);
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "Collecting from sector: %d", nonce_sector);
|
||||||
|
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
||||||
|
} else if(m->is_key_attack) {
|
||||||
snprintf(
|
snprintf(
|
||||||
draw_str,
|
draw_str,
|
||||||
sizeof(draw_str),
|
sizeof(draw_str),
|
||||||
@@ -81,21 +88,47 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
|||||||
snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector);
|
snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector);
|
||||||
}
|
}
|
||||||
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
||||||
float dict_progress = m->dict_keys_total == 0 ?
|
float dict_progress = 0;
|
||||||
0 :
|
if(m->nested_phase == MfClassicNestedPhaseAnalyzePRNG ||
|
||||||
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
m->nested_phase == MfClassicNestedPhaseDictAttack ||
|
||||||
float progress = m->sectors_total == 0 ? 0 :
|
m->nested_phase == MfClassicNestedPhaseDictAttackResume) {
|
||||||
((float)(m->current_sector) + dict_progress) /
|
// Phase: Nested dictionary attack
|
||||||
(float)(m->sectors_total);
|
uint8_t target_sector =
|
||||||
if(progress > 1.0f) {
|
m->nested_target_key / (m->prng_type == MfClassicPrngTypeWeak ? 2 : 16);
|
||||||
progress = 1.0f;
|
dict_progress = (float)(target_sector) / (float)(m->sectors_total);
|
||||||
}
|
snprintf(draw_str, sizeof(draw_str), "%d/%d", target_sector, m->sectors_total);
|
||||||
if(m->dict_keys_current == 0) {
|
} else if(
|
||||||
// Cause when people see 0 they think it's broken
|
m->nested_phase == MfClassicNestedPhaseCalibrate ||
|
||||||
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
m->nested_phase == MfClassicNestedPhaseRecalibrate ||
|
||||||
|
m->nested_phase == MfClassicNestedPhaseCollectNtEnc) {
|
||||||
|
// Phase: Nonce collection
|
||||||
|
if(m->prng_type == MfClassicPrngTypeWeak) {
|
||||||
|
uint8_t target_sector = m->nested_target_key / 4;
|
||||||
|
dict_progress = (float)(target_sector) / (float)(m->sectors_total);
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "%d/%d", target_sector, m->sectors_total);
|
||||||
|
} else {
|
||||||
|
uint16_t max_msb = UINT8_MAX + 1;
|
||||||
|
dict_progress = (float)(m->msb_count) / (float)(max_msb);
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "%d/%d", m->msb_count, max_msb);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(
|
dict_progress = m->dict_keys_total == 0 ?
|
||||||
draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
|
0 :
|
||||||
|
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
||||||
|
if(m->dict_keys_current == 0) {
|
||||||
|
// Cause when people see 0 they think it's broken
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
||||||
|
} else {
|
||||||
|
snprintf(
|
||||||
|
draw_str,
|
||||||
|
sizeof(draw_str),
|
||||||
|
"%zu/%zu",
|
||||||
|
m->dict_keys_current,
|
||||||
|
m->dict_keys_total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dict_progress > 1.0f) {
|
||||||
|
dict_progress = 1.0f;
|
||||||
}
|
}
|
||||||
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
@@ -170,6 +203,8 @@ void dict_attack_reset(DictAttack* instance) {
|
|||||||
model->nested_phase = MfClassicNestedPhaseNone;
|
model->nested_phase = MfClassicNestedPhaseNone;
|
||||||
model->prng_type = MfClassicPrngTypeUnknown;
|
model->prng_type = MfClassicPrngTypeUnknown;
|
||||||
model->backdoor = MfClassicBackdoorUnknown;
|
model->backdoor = MfClassicBackdoorUnknown;
|
||||||
|
model->nested_target_key = 0;
|
||||||
|
model->msb_count = 0;
|
||||||
furi_string_reset(model->header);
|
furi_string_reset(model->header);
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
@@ -301,3 +336,20 @@ void dict_attack_set_backdoor(DictAttack* instance, uint8_t backdoor) {
|
|||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view, DictAttackViewModel * model, { model->backdoor = backdoor; }, true);
|
instance->view, DictAttackViewModel * model, { model->backdoor = backdoor; }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t nested_target_key) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
instance->view,
|
||||||
|
DictAttackViewModel * model,
|
||||||
|
{ model->nested_target_key = nested_target_key; },
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
instance->view, DictAttackViewModel * model, { model->msb_count = msb_count; }, true);
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ void dict_attack_set_prng_type(DictAttack* instance, uint8_t prng_type);
|
|||||||
|
|
||||||
void dict_attack_set_backdoor(DictAttack* instance, uint8_t backdoor);
|
void dict_attack_set_backdoor(DictAttack* instance, uint8_t backdoor);
|
||||||
|
|
||||||
|
void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t target_key);
|
||||||
|
|
||||||
|
void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#define TAG "MfClassicPoller"
|
#define TAG "MfClassicPoller"
|
||||||
|
|
||||||
// TODO: Reflect status in NFC app (second text line, progress bar)
|
|
||||||
// TODO: Buffer writes for Hardnested, set state to Log when finished and sum property matches
|
// TODO: Buffer writes for Hardnested, set state to Log when finished and sum property matches
|
||||||
// TODO: Load dictionaries specific to a CUID to not clutter the user dictionary
|
// TODO: Load dictionaries specific to a CUID to not clutter the user dictionary
|
||||||
// TODO: Fix rare nested_target_key 64 bug
|
// TODO: Fix rare nested_target_key 64 bug
|
||||||
@@ -97,6 +96,8 @@ static NfcCommand mf_classic_poller_handle_data_update(MfClassicPoller* instance
|
|||||||
data_update->nested_phase = instance->mode_ctx.dict_attack_ctx.nested_phase;
|
data_update->nested_phase = instance->mode_ctx.dict_attack_ctx.nested_phase;
|
||||||
data_update->prng_type = instance->mode_ctx.dict_attack_ctx.prng_type;
|
data_update->prng_type = instance->mode_ctx.dict_attack_ctx.prng_type;
|
||||||
data_update->backdoor = instance->mode_ctx.dict_attack_ctx.backdoor;
|
data_update->backdoor = instance->mode_ctx.dict_attack_ctx.backdoor;
|
||||||
|
data_update->nested_target_key = instance->mode_ctx.dict_attack_ctx.nested_target_key;
|
||||||
|
data_update->msb_count = instance->mode_ctx.dict_attack_ctx.msb_count;
|
||||||
instance->mfc_event.type = MfClassicPollerEventTypeDataUpdate;
|
instance->mfc_event.type = MfClassicPollerEventTypeDataUpdate;
|
||||||
return instance->callback(instance->general_event, instance->context);
|
return instance->callback(instance->general_event, instance->context);
|
||||||
}
|
}
|
||||||
@@ -1415,6 +1416,7 @@ NfcCommand mf_classic_poller_handler_nested_collect_nt_enc(MfClassicPoller* inst
|
|||||||
// Hardnested
|
// Hardnested
|
||||||
if(!is_byte_found(dict_attack_ctx->nt_enc_msb, (nt_enc >> 24) & 0xFF)) {
|
if(!is_byte_found(dict_attack_ctx->nt_enc_msb, (nt_enc >> 24) & 0xFF)) {
|
||||||
set_byte_found(dict_attack_ctx->nt_enc_msb, (nt_enc >> 24) & 0xFF);
|
set_byte_found(dict_attack_ctx->nt_enc_msb, (nt_enc >> 24) & 0xFF);
|
||||||
|
dict_attack_ctx->msb_count++;
|
||||||
// Add unique parity to sum
|
// Add unique parity to sum
|
||||||
dict_attack_ctx->msb_par_sum += nfc_util_even_parity32(parity & 0x08);
|
dict_attack_ctx->msb_par_sum += nfc_util_even_parity32(parity & 0x08);
|
||||||
}
|
}
|
||||||
@@ -1751,15 +1753,6 @@ bool mf_classic_nested_is_target_key_found(MfClassicPoller* instance, bool is_di
|
|||||||
return mf_classic_is_key_found(instance->data, target_sector, target_key_type);
|
return mf_classic_is_key_found(instance->data, target_sector, target_key_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found_all_nt_enc_msb(const MfClassicPollerDictAttackContext* dict_attack_ctx) {
|
|
||||||
for(int i = 0; i < 32; i++) {
|
|
||||||
if(dict_attack_ctx->nt_enc_msb[i] != 0xFF) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid_sum(uint16_t sum) {
|
bool is_valid_sum(uint16_t sum) {
|
||||||
for(size_t i = 0; i < 19; i++) {
|
for(size_t i = 0; i < 19; i++) {
|
||||||
if(sum == valid_sums[i]) {
|
if(sum == valid_sums[i]) {
|
||||||
@@ -1964,7 +1957,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
}
|
}
|
||||||
// Target all remaining sectors, key A and B
|
// Target all remaining sectors, key A and B
|
||||||
if(dict_attack_ctx->nested_target_key < nonce_collect_key_max) {
|
if(dict_attack_ctx->nested_target_key < nonce_collect_key_max) {
|
||||||
if((!(is_weak)) && found_all_nt_enc_msb(dict_attack_ctx)) {
|
if((!(is_weak)) && (dict_attack_ctx->msb_count == (UINT8_MAX + 1))) {
|
||||||
if(is_valid_sum(dict_attack_ctx->msb_par_sum)) {
|
if(is_valid_sum(dict_attack_ctx->msb_par_sum)) {
|
||||||
// All Hardnested nonces collected
|
// All Hardnested nonces collected
|
||||||
dict_attack_ctx->nested_target_key++;
|
dict_attack_ctx->nested_target_key++;
|
||||||
@@ -1975,6 +1968,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
dict_attack_ctx->attempt_count++;
|
dict_attack_ctx->attempt_count++;
|
||||||
instance->state = MfClassicPollerStateNestedCollectNtEnc;
|
instance->state = MfClassicPollerStateNestedCollectNtEnc;
|
||||||
}
|
}
|
||||||
|
dict_attack_ctx->msb_count = 0;
|
||||||
dict_attack_ctx->msb_par_sum = 0;
|
dict_attack_ctx->msb_par_sum = 0;
|
||||||
memset(dict_attack_ctx->nt_enc_msb, 0, sizeof(dict_attack_ctx->nt_enc_msb));
|
memset(dict_attack_ctx->nt_enc_msb, 0, sizeof(dict_attack_ctx->nt_enc_msb));
|
||||||
return command;
|
return command;
|
||||||
@@ -2038,6 +2032,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
dict_attack_ctx->nested_target_key += 2;
|
dict_attack_ctx->nested_target_key += 2;
|
||||||
dict_attack_ctx->current_key_checked = false;
|
dict_attack_ctx->current_key_checked = false;
|
||||||
} else {
|
} else {
|
||||||
|
dict_attack_ctx->msb_count = 0;
|
||||||
dict_attack_ctx->msb_par_sum = 0;
|
dict_attack_ctx->msb_par_sum = 0;
|
||||||
memset(dict_attack_ctx->nt_enc_msb, 0, sizeof(dict_attack_ctx->nt_enc_msb));
|
memset(dict_attack_ctx->nt_enc_msb, 0, sizeof(dict_attack_ctx->nt_enc_msb));
|
||||||
dict_attack_ctx->nested_target_key++;
|
dict_attack_ctx->nested_target_key++;
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ typedef struct {
|
|||||||
uint8_t nested_phase; /**< Nested attack phase. */
|
uint8_t nested_phase; /**< Nested attack phase. */
|
||||||
uint8_t prng_type; /**< PRNG (weak or hard). */
|
uint8_t prng_type; /**< PRNG (weak or hard). */
|
||||||
uint8_t backdoor; /**< Backdoor type. */
|
uint8_t backdoor; /**< Backdoor type. */
|
||||||
|
uint16_t nested_target_key; /**< Target key for nested attack. */
|
||||||
|
uint16_t
|
||||||
|
msb_count; /**< Number of unique most significant bytes seen during Hardnested attack. */
|
||||||
} MfClassicPollerEventDataUpdate;
|
} MfClassicPollerEventDataUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ typedef struct {
|
|||||||
uint8_t nt_enc_msb
|
uint8_t nt_enc_msb
|
||||||
[32]; // Bit-packed array to track which unique most significant bytes have been seen (256 bits = 32 bytes)
|
[32]; // Bit-packed array to track which unique most significant bytes have been seen (256 bits = 32 bytes)
|
||||||
uint16_t msb_par_sum; // Sum of parity bits for each unique most significant byte
|
uint16_t msb_par_sum; // Sum of parity bits for each unique most significant byte
|
||||||
|
uint16_t msb_count; // Number of unique most significant bytes seen
|
||||||
} MfClassicPollerDictAttackContext;
|
} MfClassicPollerDictAttackContext;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user