Skip to content

Commit

Permalink
Fix issue with resume logic
Browse files Browse the repository at this point in the history
  • Loading branch information
noproto committed Oct 25, 2024
1 parent bf7b91f commit 6dbb46a
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 12 deletions.
2 changes: 2 additions & 0 deletions applications/main/nfc/views/dict_attack.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
furi_string_set(m->header, "PRNG Analysis");
break;
case MfClassicNestedPhaseDictAttack:
case MfClassicNestedPhaseDictAttackVerify:
case MfClassicNestedPhaseDictAttackResume:
furi_string_set(m->header, "Nested Dictionary");
break;
Expand Down Expand Up @@ -91,6 +92,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
float dict_progress = 0;
if(m->nested_phase == MfClassicNestedPhaseAnalyzePRNG ||
m->nested_phase == MfClassicNestedPhaseDictAttack ||
m->nested_phase == MfClassicNestedPhaseDictAttackVerify ||
m->nested_phase == MfClassicNestedPhaseDictAttackResume) {
// Phase: Nested dictionary attack
uint8_t target_sector =
Expand Down
13 changes: 9 additions & 4 deletions lib/nfc/protocols/mf_classic/mf_classic_poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -1881,9 +1881,10 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
uint16_t dict_target_key_max = (dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) ?
(instance->sectors_total * 2) :
(instance->sectors_total * 16);
if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) {
if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackVerify) {
if(!(mf_classic_nested_is_target_key_found(instance, true)) &&
(dict_attack_ctx->nested_nonce.count > 0)) {
dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackResume;
instance->state = MfClassicPollerStateNestedDictAttack;
return command;
} else {
Expand All @@ -1898,7 +1899,8 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttack;
}
}
if((dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttack) &&
if((dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttack ||
dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) &&
(dict_attack_ctx->nested_target_key < dict_target_key_max)) {
bool is_last_iter_for_hard_key =
((!is_weak) && ((dict_attack_ctx->nested_target_key % 8) == 7));
Expand All @@ -1922,11 +1924,14 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
NULL;
}
if((is_weak || is_last_iter_for_hard_key) && dict_attack_ctx->nested_nonce.count > 0) {
// Key reuse
dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackResume;
// Key verify and reuse
dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackVerify;
dict_attack_ctx->auth_passed = false;
instance->state = MfClassicPollerStateKeyReuseStartNoOffset;
return command;
} else if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) {
dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttack;
dict_attack_ctx->auth_passed = true;
}
if(!(dict_attack_ctx->auth_passed)) {
dict_attack_ctx->attempt_count++;
Expand Down
17 changes: 9 additions & 8 deletions lib/nfc/protocols/mf_classic/mf_classic_poller.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ typedef enum {
* @brief MfClassic poller nested attack phase.
*/
typedef enum {
MfClassicNestedPhaseNone,
MfClassicNestedPhaseAnalyzePRNG,
MfClassicNestedPhaseDictAttack,
MfClassicNestedPhaseDictAttackResume,
MfClassicNestedPhaseCalibrate,
MfClassicNestedPhaseRecalibrate,
MfClassicNestedPhaseCollectNtEnc,
MfClassicNestedPhaseFinished,
MfClassicNestedPhaseNone, /**< No nested attack has taken place yet. */
MfClassicNestedPhaseAnalyzePRNG, /**< Analyze nonces produced by the PRNG to determine if they fit a weak PRNG */
MfClassicNestedPhaseDictAttack, /**< Search keys which match the expected PRNG properties and parity for collected nonces */
MfClassicNestedPhaseDictAttackVerify, /**< Verify candidate keys by authenticating to the sector with the key */
MfClassicNestedPhaseDictAttackResume, /**< Resume nested dictionary attack from the last tested (invalid) key */
MfClassicNestedPhaseCalibrate, /**< Perform necessary calculations to recover the plaintext nonce during later collection phase (weak PRNG tags only) */
MfClassicNestedPhaseRecalibrate, /**< Collect the next plaintext static encrypted nonce for backdoor static encrypted nonce nested attack */
MfClassicNestedPhaseCollectNtEnc, /**< Log nonces collected during nested authentication for key recovery */
MfClassicNestedPhaseFinished, /**< Nested attack has finished */
} MfClassicNestedPhase;

/**
Expand Down

0 comments on commit 6dbb46a

Please sign in to comment.