From 344118c3463ecb0019812f75f2129c7d77ef9762 Mon Sep 17 00:00:00 2001 From: ted-logan Date: Wed, 9 Oct 2024 02:47:19 -0700 Subject: [PATCH 1/4] nfc/clipper: Update BART station codes (#3937) In the NFC Clipper card plugin, update the BART station codes for two newer East Bay stations (Milpitas, and Berryessa/North San Jose), and correct the station code for Castro Valley. These station ids come from visiting the stations and checking what id they presented as in the Clipper card data. --- applications/main/nfc/plugins/supported_cards/clipper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/plugins/supported_cards/clipper.c b/applications/main/nfc/plugins/supported_cards/clipper.c index 04a2afcda..35d0c7039 100644 --- a/applications/main/nfc/plugins/supported_cards/clipper.c +++ b/applications/main/nfc/plugins/supported_cards/clipper.c @@ -106,7 +106,7 @@ static const IdMapping bart_zones[] = { {.id = 0x0023, .name = "South Hayward"}, {.id = 0x0024, .name = "Union City"}, {.id = 0x0025, .name = "Fremont"}, - {.id = 0x0026, .name = "Daly City(2)?"}, + {.id = 0x0026, .name = "Castro Valley"}, {.id = 0x0027, .name = "Dublin/Pleasanton"}, {.id = 0x0028, .name = "South San Francisco"}, {.id = 0x0029, .name = "San Bruno"}, @@ -115,6 +115,8 @@ static const IdMapping bart_zones[] = { {.id = 0x002c, .name = "West Dublin/Pleasanton"}, {.id = 0x002d, .name = "OAK Airport"}, {.id = 0x002e, .name = "Warm Springs/South Fremont"}, + {.id = 0x002f, .name = "Milpitas"}, + {.id = 0x0030, .name = "Berryessa/North San Jose"}, }; static const size_t kNumBARTZones = COUNT(bart_zones); From b8438569762b2c715e33e4c2be12d8559e0f8bbc Mon Sep 17 00:00:00 2001 From: noproto Date: Wed, 9 Oct 2024 15:51:21 -0400 Subject: [PATCH 2/4] Fix memory leak, use COUNT_OF macro --- .../main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c | 1 + lib/nfc/protocols/mf_classic/mf_classic_poller.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 5ff014a1c..0286cf7a5 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -151,6 +151,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { if(!keys_dict_check_presence(furi_string_get_cstr(cuid_dict_path))) { state = DictAttackStateUserDictInProgress; + furi_string_free(cuid_dict_path); break; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index e8f660b16..7417322e9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -20,8 +20,7 @@ const MfClassicBackdoorKeyPair mf_classic_backdoor_keys[] = { {{{0xa3, 0x16, 0x67, 0xa8, 0xce, 0xc1}}, MfClassicBackdoorAuth1}, // Fudan, Infineon, NXP {{{0x51, 0x8b, 0x33, 0x54, 0xe7, 0x60}}, MfClassicBackdoorAuth2}, // Fudan }; -const size_t mf_classic_backdoor_keys_count = - sizeof(mf_classic_backdoor_keys) / sizeof(mf_classic_backdoor_keys[0]); +const size_t mf_classic_backdoor_keys_count = COUNT_OF(mf_classic_backdoor_keys); const uint16_t valid_sums[] = {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256}; From 3976f128dc86be161cb0bb62900e1259aa3a34e1 Mon Sep 17 00:00:00 2001 From: noproto Date: Wed, 9 Oct 2024 16:03:29 -0400 Subject: [PATCH 3/4] Use single call to free FuriString --- .../scenes/nfc_scene_mf_classic_dict_attack.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 0286cf7a5..ab1ecfdf0 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -141,17 +141,16 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack); if(state == DictAttackStateCUIDDictInProgress) { - do { - size_t cuid_len = 0; - const uint8_t* cuid = nfc_device_get_uid(instance->nfc_device, &cuid_len); - FuriString* cuid_dict_path = furi_string_alloc_printf( - "%s/mf_classic_dict_%08lx.nfc", - EXT_PATH("nfc/assets"), - (uint32_t)bit_lib_bytes_to_num_be(cuid + (cuid_len - 4), 4)); + size_t cuid_len = 0; + const uint8_t* cuid = nfc_device_get_uid(instance->nfc_device, &cuid_len); + FuriString* cuid_dict_path = furi_string_alloc_printf( + "%s/mf_classic_dict_%08lx.nfc", + EXT_PATH("nfc/assets"), + (uint32_t)bit_lib_bytes_to_num_be(cuid + (cuid_len - 4), 4)); + do { if(!keys_dict_check_presence(furi_string_get_cstr(cuid_dict_path))) { state = DictAttackStateUserDictInProgress; - furi_string_free(cuid_dict_path); break; } @@ -160,8 +159,6 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { KeysDictModeOpenExisting, sizeof(MfClassicKey)); - furi_string_free(cuid_dict_path); - if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) { keys_dict_free(instance->nfc_dict_context.dict); state = DictAttackStateUserDictInProgress; @@ -170,6 +167,8 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { dict_attack_set_header(instance->dict_attack, "MF Classic CUID Dictionary"); } while(false); + + furi_string_free(cuid_dict_path); } if(state == DictAttackStateUserDictInProgress) { do { From a7c0819034fdbe591d64d16b95ba1f88cff660eb Mon Sep 17 00:00:00 2001 From: noproto Date: Fri, 11 Oct 2024 10:01:30 -0400 Subject: [PATCH 4/4] Refactor enums to avoid redefinition --- applications/main/nfc/nfc_app_i.h | 6 +-- .../scenes/nfc_scene_mf_classic_dict_attack.c | 1 - applications/main/nfc/views/dict_attack.c | 6 +-- applications/main/nfc/views/dict_attack.h | 33 ++------------- .../protocols/mf_classic/mf_classic_poller.h | 41 +++++++++++++++++-- .../mf_classic/mf_classic_poller_i.h | 26 ------------ 6 files changed, 48 insertions(+), 65 deletions(-) diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 9656eae11..14e484622 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -97,9 +97,9 @@ typedef struct { bool is_key_attack; uint8_t key_attack_current_sector; bool is_card_present; - uint8_t nested_phase; - uint8_t prng_type; - uint8_t backdoor; + MfClassicNestedPhase nested_phase; + MfClassicPrngType prng_type; + MfClassicBackdoor backdoor; uint16_t nested_target_key; uint16_t msb_count; bool enhanced_dict; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index ab1ecfdf0..526a89a74 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -2,7 +2,6 @@ #include #include -#include #define TAG "NfcMfClassicDictAttack" diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 5138dd912..4efbe6d60 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -316,21 +316,21 @@ void dict_attack_reset_key_attack(DictAttack* instance) { instance->view, DictAttackViewModel * model, { model->is_key_attack = false; }, true); } -void dict_attack_set_nested_phase(DictAttack* instance, uint8_t nested_phase) { +void dict_attack_set_nested_phase(DictAttack* instance, MfClassicNestedPhase nested_phase) { furi_assert(instance); with_view_model( instance->view, DictAttackViewModel * model, { model->nested_phase = nested_phase; }, true); } -void dict_attack_set_prng_type(DictAttack* instance, uint8_t prng_type) { +void dict_attack_set_prng_type(DictAttack* instance, MfClassicPrngType prng_type) { furi_assert(instance); with_view_model( instance->view, DictAttackViewModel * model, { model->prng_type = prng_type; }, true); } -void dict_attack_set_backdoor(DictAttack* instance, uint8_t backdoor) { +void dict_attack_set_backdoor(DictAttack* instance, MfClassicBackdoor backdoor) { furi_assert(instance); with_view_model( diff --git a/applications/main/nfc/views/dict_attack.h b/applications/main/nfc/views/dict_attack.h index 8dc9b9708..b6c6fdbdc 100644 --- a/applications/main/nfc/views/dict_attack.h +++ b/applications/main/nfc/views/dict_attack.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -9,32 +10,6 @@ extern "C" { typedef struct DictAttack DictAttack; -typedef enum { - MfClassicNestedPhaseNone, - MfClassicNestedPhaseAnalyzePRNG, - MfClassicNestedPhaseDictAttack, - MfClassicNestedPhaseDictAttackResume, - MfClassicNestedPhaseCalibrate, - MfClassicNestedPhaseRecalibrate, - MfClassicNestedPhaseCollectNtEnc, - MfClassicNestedPhaseFinished, -} MfClassicNestedPhase; - -typedef enum { - MfClassicPrngTypeUnknown, // Tag not yet tested - MfClassicPrngTypeNoTag, // No tag detected during test - MfClassicPrngTypeWeak, // Weak PRNG, standard Nested - MfClassicPrngTypeHard, // Hard PRNG, Hardnested -} MfClassicPrngType; - -typedef enum { - MfClassicBackdoorUnknown, // Tag not yet tested - MfClassicBackdoorNone, // No observed backdoor - MfClassicBackdoorAuth1, // Tag responds to v1 auth backdoor - MfClassicBackdoorAuth2, // Tag responds to v2 auth backdoor - MfClassicBackdoorAuth3, // Tag responds to v3 auth backdoor (static encrypted nonce) -} MfClassicBackdoor; - typedef enum { DictAttackEventSkipPressed, } DictAttackEvent; @@ -71,11 +46,11 @@ void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector); void dict_attack_reset_key_attack(DictAttack* instance); -void dict_attack_set_nested_phase(DictAttack* instance, uint8_t nested_phase); +void dict_attack_set_nested_phase(DictAttack* instance, MfClassicNestedPhase nested_phase); -void dict_attack_set_prng_type(DictAttack* instance, uint8_t prng_type); +void dict_attack_set_prng_type(DictAttack* instance, MfClassicPrngType prng_type); -void dict_attack_set_backdoor(DictAttack* instance, uint8_t backdoor); +void dict_attack_set_backdoor(DictAttack* instance, MfClassicBackdoor backdoor); void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t target_key); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 5c2550b7e..7dfd3b6ab 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -48,6 +48,41 @@ typedef enum { MfClassicPollerModeDictAttackEnhanced, /**< Poller enhanced dictionary attack mode. */ } MfClassicPollerMode; +/** + * @brief MfClassic poller nested attack phase. + */ +typedef enum { + MfClassicNestedPhaseNone, + MfClassicNestedPhaseAnalyzePRNG, + MfClassicNestedPhaseDictAttack, + MfClassicNestedPhaseDictAttackResume, + MfClassicNestedPhaseCalibrate, + MfClassicNestedPhaseRecalibrate, + MfClassicNestedPhaseCollectNtEnc, + MfClassicNestedPhaseFinished, +} MfClassicNestedPhase; + +/** + * @brief MfClassic pseudorandom number generator (PRNG) type. + */ +typedef enum { + MfClassicPrngTypeUnknown, // Tag not yet tested + MfClassicPrngTypeNoTag, // No tag detected during test + MfClassicPrngTypeWeak, // Weak PRNG, standard Nested + MfClassicPrngTypeHard, // Hard PRNG, Hardnested +} MfClassicPrngType; + +/** + * @brief MfClassic authentication backdoor type. + */ +typedef enum { + MfClassicBackdoorUnknown, // Tag not yet tested + MfClassicBackdoorNone, // No observed backdoor + MfClassicBackdoorAuth1, // Tag responds to v1 auth backdoor + MfClassicBackdoorAuth2, // Tag responds to v2 auth backdoor (sometimes static encrypted) + MfClassicBackdoorAuth3, // Tag responds to v3 auth backdoor (static encrypted nonce) +} MfClassicBackdoor; + /** * @brief MfClassic poller request mode event data. * @@ -78,9 +113,9 @@ typedef struct { uint8_t sectors_read; /**< Number of sectors read. */ uint8_t keys_found; /**< Number of keys found. */ uint8_t current_sector; /**< Current sector number. */ - uint8_t nested_phase; /**< Nested attack phase. */ - uint8_t prng_type; /**< PRNG (weak or hard). */ - uint8_t backdoor; /**< Backdoor type. */ + MfClassicNestedPhase nested_phase; /**< Nested attack phase. */ + MfClassicPrngType prng_type; /**< PRNG (weak or hard). */ + MfClassicBackdoor 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. */ diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 7b05ce240..915c899c3 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -48,32 +48,6 @@ typedef enum { MfClassicCardStateLost, } MfClassicCardState; -typedef enum { - MfClassicNestedPhaseNone, - MfClassicNestedPhaseAnalyzePRNG, - MfClassicNestedPhaseDictAttack, - MfClassicNestedPhaseDictAttackResume, - MfClassicNestedPhaseCalibrate, - MfClassicNestedPhaseRecalibrate, - MfClassicNestedPhaseCollectNtEnc, - MfClassicNestedPhaseFinished, -} MfClassicNestedPhase; - -typedef enum { - MfClassicPrngTypeUnknown, // Tag not yet tested - MfClassicPrngTypeNoTag, // No tag detected during test - MfClassicPrngTypeWeak, // Weak PRNG, standard Nested - MfClassicPrngTypeHard, // Hard PRNG, Hardnested -} MfClassicPrngType; - -typedef enum { - MfClassicBackdoorUnknown, // Tag not yet tested - MfClassicBackdoorNone, // No observed backdoor - MfClassicBackdoorAuth1, // Tag responds to v1 auth backdoor - MfClassicBackdoorAuth2, // Tag responds to v2 auth backdoor - MfClassicBackdoorAuth3, // Tag responds to v3 auth backdoor (static encrypted nonce) -} MfClassicBackdoor; - typedef struct { MfClassicKey key; MfClassicBackdoor type;