diff --git a/nfc_magic/.catalog/changelog.md b/nfc_magic/.catalog/changelog.md index 640b67cb..9e774276 100644 --- a/nfc_magic/.catalog/changelog.md +++ b/nfc_magic/.catalog/changelog.md @@ -1,3 +1,11 @@ +## 1.9 + - Get revision, get config moved into main Gen4 menu + - New function: Set Gen4 card shadow mode + - New function: Set Gen4 card direct write to block 0 mode + - Fixed: back button did not allow to exit from some scenes while the card is next to the Flipper HF RFID antenna + - Gen4 protocol refactor + - Gen4 UI refactor + ## 1.8 - Ultralight Various fixes and improvements diff --git a/nfc_magic/.catalog/screenshots/1.png b/nfc_magic/.catalog/screenshots/1.png index 238489ed..16a14ab2 100644 Binary files a/nfc_magic/.catalog/screenshots/1.png and b/nfc_magic/.catalog/screenshots/1.png differ diff --git a/nfc_magic/magic/nfc_magic_scanner.c b/nfc_magic/magic/nfc_magic_scanner.c index 77be4e11..9c00f8ed 100644 --- a/nfc_magic/magic/nfc_magic_scanner.c +++ b/nfc_magic/magic/nfc_magic_scanner.c @@ -1,5 +1,7 @@ #include "nfc_magic_scanner.h" +#include "core/check.h" +#include "protocols/gen4/gen4.h" #include "protocols/gen1a/gen1a_poller.h" #include "protocols/gen2/gen2_poller.h" #include "protocols/gen4/gen4_poller.h" @@ -18,7 +20,8 @@ struct NfcMagicScanner { NfcMagicScannerSessionState session_state; NfcMagicProtocol current_protocol; - uint32_t gen4_password; + Gen4Password gen4_password; + Gen4* gen4_data; bool magic_protocol_detected; NfcMagicScannerCallback callback; @@ -43,6 +46,7 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc) { NfcMagicScanner* instance = malloc(sizeof(NfcMagicScanner)); instance->nfc = nfc; + instance->gen4_data = gen4_alloc(); return instance; } @@ -50,10 +54,11 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc) { void nfc_magic_scanner_free(NfcMagicScanner* instance) { furi_assert(instance); + gen4_free(instance->gen4_data); free(instance); } -void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password) { +void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, Gen4Password password) { furi_assert(instance); instance->gen4_password = password; @@ -73,9 +78,13 @@ static int32_t nfc_magic_scanner_worker(void* context) { break; } } else if(instance->current_protocol == NfcMagicProtocolGen4) { - Gen4PollerError error = gen4_poller_detect(instance->nfc, instance->gen4_password); + gen4_reset(instance->gen4_data); + Gen4 gen4_data; + Gen4PollerError error = + gen4_poller_detect(instance->nfc, instance->gen4_password, &gen4_data); instance->magic_protocol_detected = (error == Gen4PollerErrorNone); if(instance->magic_protocol_detected) { + gen4_copy(instance->gen4_data, &gen4_data); break; } } else if(instance->current_protocol == NfcMagicProtocolGen2) { @@ -162,3 +171,9 @@ void nfc_magic_scanner_stop(NfcMagicScanner* instance) { instance->callback = NULL; instance->context = NULL; } + +const Gen4* nfc_magic_scanner_get_gen4_data(NfcMagicScanner* instance) { + furi_assert(instance); + + return instance->gen4_data; +} diff --git a/nfc_magic/magic/nfc_magic_scanner.h b/nfc_magic/magic/nfc_magic_scanner.h index 3a2720e6..20355c85 100644 --- a/nfc_magic/magic/nfc_magic_scanner.h +++ b/nfc_magic/magic/nfc_magic_scanner.h @@ -1,5 +1,6 @@ #pragma once +#include "protocols/gen4/gen4.h" #include #include "protocols/nfc_magic_protocols.h" @@ -30,7 +31,7 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc); void nfc_magic_scanner_free(NfcMagicScanner* instance); -void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password); +void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, Gen4Password password); void nfc_magic_scanner_start( NfcMagicScanner* instance, @@ -39,6 +40,8 @@ void nfc_magic_scanner_start( void nfc_magic_scanner_stop(NfcMagicScanner* instance); +const Gen4* nfc_magic_scanner_get_gen4_data(NfcMagicScanner* instance); + #ifdef __cplusplus } #endif diff --git a/nfc_magic/magic/protocols/gen4/gen4.c b/nfc_magic/magic/protocols/gen4/gen4.c new file mode 100644 index 00000000..6fbdfb47 --- /dev/null +++ b/nfc_magic/magic/protocols/gen4/gen4.c @@ -0,0 +1,120 @@ +#include "gen4.h" +#include "core/check.h" + +Gen4* gen4_alloc() { + Gen4* instance = malloc(sizeof(Gen4)); + + return instance; +} + +void gen4_free(Gen4* instance) { + furi_check(instance); + + free(instance); +} + +void gen4_reset(Gen4* instance) { + furi_check(instance); + + memset(&instance->config, 0, sizeof(Gen4Config)); + memset(&instance->revision, 0, sizeof(Gen4Revision)); +} + +void gen4_copy(Gen4* dest, const Gen4* source) { + furi_check(dest); + furi_check(source); + + memcpy(dest, source, sizeof(Gen4)); +} + +bool gen4_password_is_set(const Gen4Password* instance) { + furi_check(instance); + + return (instance->bytes[0] || instance->bytes[1] || instance->bytes[2] || instance->bytes[3]); +} + +void gen4_password_reset(Gen4Password* instance) { + furi_check(instance); + + memset(instance->bytes, 0, GEN4_PASSWORD_LEN); +} + +void gen4_password_copy(Gen4Password* dest, const Gen4Password* source) { + furi_check(dest); + furi_check(source); + + memcpy(dest->bytes, source->bytes, GEN4_PASSWORD_LEN); +} + +const char* gen4_get_shadow_mode_name(Gen4ShadowMode mode) { + switch(mode) { + case Gen4ShadowModePreWrite: + return "Pre-Write"; + case Gen4ShadowModeRestore: + return "Restore"; + case Gen4ShadowModeDisabled: + return "Disabled"; + case Gen4ShadowModeHighSpeedDisabled: + return "Disabled (High-speed)"; + case Gen4ShadowModeSplit: + return "Split"; + default: + return "Unknown"; + } +} + +const char* gen4_get_direct_write_mode_name(Gen4DirectWriteBlock0Mode mode) { + switch(mode) { + case Gen4DirectWriteBlock0ModeEnabled: + return "Enabled"; + case Gen4DirectWriteBlock0ModeDisabled: + return "Disabled"; + case Gen4DirectWriteBlock0ModeDefault: + return "Default"; + default: + return "Unknown"; + } +} + +const char* gen4_get_uid_len_num(Gen4UIDLength code) { + switch(code) { + case Gen4UIDLengthSingle: + return "4"; + case Gen4UIDLengthDouble: + return "7"; + case Gen4UIDLengthTriple: + return "10"; + default: + return "Unknown"; + } +} + +const char* gen4_get_configuration_name(const Gen4Config* config) { + switch(config->data_parsed.protocol) { + case Gen4ProtocolMfClassic: { + switch(config->data_parsed.total_blocks) { + case 255: + return "MIFARE Classic 4K"; + case 63: + return "MIFARE Classic 1K"; + case 19: + return "MIFARE Classic Mini (0.3K)"; + default: + return "Unknown"; + } + } break; + case Gen4ProtocolMfUltralight: { + switch(config->data_parsed.total_blocks) { + case 63: + return "MIFARE Ultralight"; + case 127: + return "NTAG 2XX"; + default: + return "Unknown"; + } + } break; + default: + return "Unknown"; + break; + }; +} diff --git a/nfc_magic/magic/protocols/gen4/gen4.h b/nfc_magic/magic/protocols/gen4/gen4.h new file mode 100644 index 00000000..054a95a3 --- /dev/null +++ b/nfc_magic/magic/protocols/gen4/gen4.h @@ -0,0 +1,105 @@ +#pragma once + +#include "core/common_defines.h" +#include + +#define GEN4_CONFIG_SIZE (32) +#define GEN4_REVISION_SIZE (5) + +#define GEN4_PASSWORD_LEN (4) +#define GEN4_ATS_MAX_LEN (16) +#define GEN4_ATQA_LEN (2) +#define GEN4_CRC_LEN (2) + +typedef enum { + Gen4ProtocolMfClassic = 0x00, + Gen4ProtocolMfUltralight = 0x01, +} Gen4Protocol; + +typedef struct { + uint8_t bytes[GEN4_PASSWORD_LEN]; +} Gen4Password; + +typedef enum { + Gen4UIDLengthSingle = 0x00, + Gen4UIDLengthDouble = 0x01, + Gen4UIDLengthTriple = 0x02 +} Gen4UIDLength; + +typedef enum { + Gen4UltralightModeUL_EV1 = 0x00, + Gen4UltralightModeNTAG = 0x01, + Gen4UltralightModeUL_C = 0x02, + Gen4UltralightModeUL = 0x03 +} Gen4UltralightMode; + +typedef enum { + // for writing original (shadow) data + Gen4ShadowModePreWrite = 0x00, + // written data can be read once before restored to original + Gen4ShadowModeRestore = 0x01, + // shadow mode disabled + Gen4ShadowModeDisabled = 0x02, + // apparently for UL? + Gen4ShadowModeHighSpeedDisabled = 0x03, + // work with new UMC. With old UMC is untested + Gen4ShadowModeSplit = 0x04, +} Gen4ShadowMode; + +typedef enum { + // gen2 card behavour + Gen4DirectWriteBlock0ModeEnabled = 0x00, + // common card behavour + Gen4DirectWriteBlock0ModeDisabled = 0x01, + // default mode. same behavour as Gen4DirectWriteBlock0ModeActivate + Gen4DirectWriteBlock0ModeDefault = 0x02, +} Gen4DirectWriteBlock0Mode; + +typedef union { + uint8_t data_raw[GEN4_CONFIG_SIZE]; + struct { + Gen4Protocol protocol; + Gen4UIDLength uid_len_code; + Gen4Password password; + Gen4ShadowMode gtu_mode; + uint8_t ats_len; + uint8_t ats[GEN4_ATS_MAX_LEN]; // mb another class? + uint8_t atqa[GEN4_ATQA_LEN]; + uint8_t sak; + Gen4UltralightMode mfu_mode; + uint8_t total_blocks; + Gen4DirectWriteBlock0Mode direct_write_mode; + uint8_t crc[GEN4_CRC_LEN]; + } FURI_PACKED data_parsed; +} Gen4Config; + +typedef struct { + uint8_t data[GEN4_REVISION_SIZE]; +} Gen4Revision; + +typedef struct { + Gen4Config config; + Gen4Revision revision; +} Gen4; + +Gen4* gen4_alloc(); + +void gen4_free(Gen4* instance); + +void gen4_reset(Gen4* instance); + +void gen4_copy(Gen4* dest, const Gen4* source); + +bool gen4_password_is_set(const Gen4Password* instance); + +void gen4_password_reset(Gen4Password* instance); + +void gen4_password_copy(Gen4Password* dest, const Gen4Password* source); + +const char* gen4_get_shadow_mode_name(Gen4ShadowMode mode); + +const char* gen4_get_direct_write_mode_name(Gen4DirectWriteBlock0Mode mode); + +const char* gen4_get_uid_len_num(Gen4UIDLength code); + +const char* gen4_get_configuration_name(const Gen4Config* config); \ No newline at end of file diff --git a/nfc_magic/magic/protocols/gen4/gen4_poller.c b/nfc_magic/magic/protocols/gen4/gen4_poller.c index 1cb53b4a..aab15b3c 100644 --- a/nfc_magic/magic/protocols/gen4/gen4_poller.c +++ b/nfc_magic/magic/protocols/gen4/gen4_poller.c @@ -1,30 +1,34 @@ -#include "core/log.h" +#include "bit_buffer.h" +#include "core/check.h" #include "gen4_poller_i.h" +#include "magic/protocols/gen4/gen4.h" +#include "magic/protocols/gen4/gen4_poller.h" #include #include -#include -#include #include - -#include +#include +#include #define GEN4_POLLER_THREAD_FLAG_DETECTED (1U << 0) +#define GEN4_POLLER_DEFAULT_CONFIG_SIZE (28) typedef NfcCommand (*Gen4PollerStateHandler)(Gen4Poller* instance); typedef struct { NfcPoller* poller; - uint32_t password; + Gen4Password password; + Gen4 gen4_data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; FuriThreadId thread_id; Gen4PollerError error; } Gen4PollerDetectContext; -static const uint8_t gen4_poller_default_config[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, - 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00}; +static const Gen4Config gen4_poller_default_config = { + .data_raw = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x78, + 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00}}; + static const uint8_t gen4_poller_default_block_0[GEN4_POLLER_BLOCK_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -56,6 +60,8 @@ Gen4Poller* gen4_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE); + instance->gen4_data = gen4_alloc(); + return instance; } @@ -67,10 +73,12 @@ void gen4_poller_free(Gen4Poller* instance) { bit_buffer_free(instance->tx_buffer); bit_buffer_free(instance->rx_buffer); + gen4_free(instance->gen4_data); + free(instance); } -void gen4_poller_set_password(Gen4Poller* instance, uint32_t password) { +void gen4_poller_set_password(Gen4Poller* instance, Gen4Password password) { furi_assert(instance); instance->password = password; @@ -90,10 +98,12 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) { if(iso3_event->type == Iso14443_3aPollerEventTypeReady) { do { + // check config bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_PREFIX); - uint8_t pwd_arr[4] = {}; - bit_lib_num_to_bytes_be(gen4_poller_detect_ctx->password, COUNT_OF(pwd_arr), pwd_arr); - bit_buffer_append_bytes(gen4_poller_detect_ctx->tx_buffer, pwd_arr, COUNT_OF(pwd_arr)); + bit_buffer_append_bytes( + gen4_poller_detect_ctx->tx_buffer, + gen4_poller_detect_ctx->password.bytes, + GEN4_PASSWORD_LEN); bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_GET_CFG); Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( @@ -107,11 +117,48 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) { break; } size_t rx_bytes = bit_buffer_get_size_bytes(gen4_poller_detect_ctx->rx_buffer); - if((rx_bytes != 30) && (rx_bytes != 32)) { + if(rx_bytes != GEN4_CONFIG_SIZE) { + gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol; + break; + } + + memcpy( + gen4_poller_detect_ctx->gen4_data.config.data_raw, + bit_buffer_get_data(gen4_poller_detect_ctx->rx_buffer), + GEN4_CONFIG_SIZE); + + // check revision + bit_buffer_reset(gen4_poller_detect_ctx->tx_buffer); + bit_buffer_reset(gen4_poller_detect_ctx->rx_buffer); + + bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_PREFIX); + bit_buffer_append_bytes( + gen4_poller_detect_ctx->tx_buffer, + gen4_poller_detect_ctx->password.bytes, + GEN4_PASSWORD_LEN); + bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_GET_REVISION); + + error = iso14443_3a_poller_send_standard_frame( + iso3_poller, + gen4_poller_detect_ctx->tx_buffer, + gen4_poller_detect_ctx->rx_buffer, + GEN4_POLLER_MAX_FWT); + + if(error != Iso14443_3aErrorNone) { + gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol; + break; + } + rx_bytes = bit_buffer_get_size_bytes(gen4_poller_detect_ctx->rx_buffer); + if(rx_bytes != GEN4_REVISION_SIZE) { gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol; break; } + memcpy( + gen4_poller_detect_ctx->gen4_data.revision.data, + bit_buffer_get_data(gen4_poller_detect_ctx->rx_buffer), + GEN4_REVISION_SIZE); + gen4_poller_detect_ctx->error = Gen4PollerErrorNone; } while(false); } else if(iso3_event->type == Iso14443_3aPollerEventTypeError) { @@ -122,7 +169,7 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) { return command; } -Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password) { +Gen4PollerError gen4_poller_detect(Nfc* nfc, Gen4Password password, Gen4* gen4_data) { furi_assert(nfc); Gen4PollerDetectContext gen4_poller_detect_ctx = {}; @@ -146,6 +193,10 @@ Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password) { bit_buffer_free(gen4_poller_detect_ctx.tx_buffer); bit_buffer_free(gen4_poller_detect_ctx.rx_buffer); + if(gen4_poller_detect_ctx.error == Gen4PollerErrorNone) { + gen4_copy(gen4_data, &gen4_poller_detect_ctx.gen4_data); + } + return gen4_poller_detect_ctx.error; } @@ -153,7 +204,7 @@ NfcCommand gen4_poller_idle_handler(Gen4Poller* instance) { NfcCommand command = NfcCommandContinue; instance->current_block = 0; - memset(instance->config, 0, sizeof(instance->config)); + instance->gen4_event.type = Gen4PollerEventTypeCardDetected; command = instance->callback(instance->gen4_event, instance->context); instance->state = Gen4PollerStateRequestMode; @@ -172,12 +223,14 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) { instance->state = Gen4PollerStateRequestWriteData; } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) { instance->state = Gen4PollerStateChangePassword; - } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDefaultCFG) { + } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetInfo) { + instance->state = Gen4PollerStateGetInfo; + } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDefaultCfg) { instance->state = Gen4PollerStateSetDefaultConfig; - } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetCFG) { - instance->state = Gen4PollerStateGetCurrentConfig; - } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetRevision) { - instance->state = Gen4PollerStateGetRevision; + } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetShadowMode) { + instance->state = Gen4PollerStateSetShadowMode; + } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDirectWriteBlock0Mode) { + instance->state = Gen4PollerStateSetDirectWriteBlock0; } else { instance->state = Gen4PollerStateFail; } @@ -194,15 +247,15 @@ NfcCommand gen4_poller_wipe_handler(Gen4Poller* instance) { error = gen4_poller_set_config( instance, instance->password, - gen4_poller_default_config, - sizeof(gen4_poller_default_config), + &gen4_poller_default_config, + GEN4_POLLER_DEFAULT_CONFIG_SIZE, false); if(error != Gen4PollerErrorNone) { FURI_LOG_D(TAG, "Failed to set default config: %d", error); instance->state = Gen4PollerStateFail; break; } - instance->password = 0; + gen4_password_reset(&instance->password); error = gen4_poller_write_block( instance, instance->password, instance->current_block, gen4_poller_default_block_0); if(error != Gen4PollerErrorNone) { @@ -257,29 +310,29 @@ static NfcCommand gen4_poller_write_mf_classic(Gen4Poller* instance) { const MfClassicData* mfc_data = instance->data; const Iso14443_3aData* iso3_data = mfc_data->iso14443_3a_data; if(instance->current_block == 0) { - instance->config[0] = 0x00; + instance->config.data_parsed.protocol = Gen4ProtocolMfClassic; instance->total_blocks = mf_classic_get_total_block_num(mfc_data->type); if(iso3_data->uid_len == 4) { - instance->config[1] = Gen4PollerUIDLengthSingle; + instance->config.data_parsed.uid_len_code = Gen4UIDLengthSingle; } else if(iso3_data->uid_len == 7) { - instance->config[1] = Gen4PollerUIDLengthDouble; + instance->config.data_parsed.uid_len_code = Gen4UIDLengthDouble; } else { FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len); instance->state = Gen4PollerStateFail; break; } - instance->config[6] = Gen4PollerShadowModeIgnore; - instance->config[24] = iso3_data->atqa[0]; - instance->config[25] = iso3_data->atqa[1]; - instance->config[26] = iso3_data->sak; - instance->config[27] = 0x00; - instance->config[28] = instance->total_blocks - 1; - instance->config[29] = 0x01; + instance->config.data_parsed.gtu_mode = Gen4ShadowModeDisabled; + instance->config.data_parsed.atqa[0] = iso3_data->atqa[0]; + instance->config.data_parsed.atqa[1] = iso3_data->atqa[1]; + instance->config.data_parsed.sak = iso3_data->sak; + instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_EV1; + instance->config.data_parsed.total_blocks = instance->total_blocks - 1; + instance->config.data_parsed.direct_write_mode = Gen4DirectWriteBlock0ModeDisabled; Gen4PollerError error = gen4_poller_set_config( - instance, instance->password, instance->config, sizeof(instance->config), false); + instance, instance->password, &instance->config, GEN4_CONFIG_SIZE, false); if(error != Gen4PollerErrorNone) { FURI_LOG_D(TAG, "Failed to write config: %d", error); instance->state = Gen4PollerStateFail; @@ -316,7 +369,7 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) { const Iso14443_3aData* iso3_data = mfu_data->iso14443_3a_data; if(instance->current_block == 0) { instance->total_blocks = 64; - instance->config[0] = 0x01; + instance->config.data_parsed.protocol = Gen4ProtocolMfUltralight; switch(mfu_data->type) { case MfUltralightTypeNTAG203: case MfUltralightTypeNTAG213: @@ -327,47 +380,47 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) { case MfUltralightTypeNTAGI2CPlus1K: case MfUltralightTypeNTAGI2CPlus2K: FURI_LOG_D(TAG, "NTAG type"); - instance->config[27] = Gen4PollerUltralightModeNTAG; + instance->config.data_parsed.mfu_mode = Gen4UltralightModeNTAG; instance->total_blocks = 64 * 2; break; case MfUltralightTypeUnknown: FURI_LOG_D(TAG, "Ultralight type"); - instance->config[27] = Gen4PollerUltralightModeUL; + instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL; break; case MfUltralightTypeMfulC: FURI_LOG_D(TAG, "MfulC type"); - instance->config[27] = Gen4PollerUltralightModeUL_C; + instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_C; break; case MfUltralightTypeUL11: case MfUltralightTypeUL21: default: FURI_LOG_D(TAG, "EV1 type"); - instance->config[27] = Gen4PollerUltralightModeUL_EV1; + instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_EV1; break; } if(iso3_data->uid_len == 4) { - instance->config[1] = Gen4PollerUIDLengthSingle; + instance->config.data_parsed.uid_len_code = Gen4UIDLengthSingle; } else if(iso3_data->uid_len == 7) { - instance->config[1] = Gen4PollerUIDLengthDouble; + instance->config.data_parsed.uid_len_code = Gen4UIDLengthDouble; } else { FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len); instance->state = Gen4PollerStateFail; break; } - instance->config[6] = Gen4PollerShadowModeHighSpeedIgnore; - instance->config[24] = iso3_data->atqa[0]; - instance->config[25] = iso3_data->atqa[1]; - instance->config[26] = iso3_data->sak; - instance->config[28] = instance->total_blocks - 1; - instance->config[29] = 0x01; + instance->config.data_parsed.gtu_mode = Gen4ShadowModeHighSpeedDisabled; + instance->config.data_parsed.atqa[0] = iso3_data->atqa[0]; + instance->config.data_parsed.atqa[1] = iso3_data->atqa[1]; + instance->config.data_parsed.sak = iso3_data->sak; + instance->config.data_parsed.total_blocks = instance->total_blocks - 1; + instance->config.data_parsed.direct_write_mode = Gen4DirectWriteBlock0ModeDisabled; Gen4PollerError error = gen4_poller_set_config( - instance, instance->password, instance->config, sizeof(instance->config), false); + instance, instance->password, &instance->config, GEN4_CONFIG_SIZE, false); if(error != Gen4PollerErrorNone) { FURI_LOG_D(TAG, "Failed to write config: %d", error); instance->state = Gen4PollerStateFail; @@ -502,11 +555,14 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) { NfcCommand gen4_poller_write_handler(Gen4Poller* instance) { NfcCommand command = NfcCommandContinue; - memcpy(instance->config, gen4_poller_default_config, sizeof(gen4_poller_default_config)); - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(instance->password, sizeof(password_arr), password_arr); - memcpy(&instance->config[2], password_arr, sizeof(password_arr)); - memset(&instance->config[7], 0, 17); + memcpy( + instance->config.data_raw, + gen4_poller_default_config.data_raw, + GEN4_POLLER_DEFAULT_CONFIG_SIZE); + + memcpy( + instance->config.data_parsed.password.bytes, instance->password.bytes, GEN4_PASSWORD_LEN); + memset(&instance->config.data_raw[7], 0, 17); if(instance->protocol == NfcProtocolMfClassic) { command = gen4_poller_write_mf_classic(instance); } else if(instance->protocol == NfcProtocolMfUltralight) { @@ -526,7 +582,7 @@ NfcCommand gen4_poller_change_password_handler(Gen4Poller* instance) { command = instance->callback(instance->gen4_event, instance->context); if(command != NfcCommandContinue) break; - uint32_t new_password = instance->gen4_event_data.request_password.password; + Gen4Password new_password = instance->gen4_event_data.request_password.password; Gen4PollerError error = gen4_poller_change_password(instance, instance->password, new_password); if(error != Gen4PollerErrorNone) { @@ -549,8 +605,8 @@ NfcCommand gen4_poller_set_default_cfg_handler(Gen4Poller* instance) { Gen4PollerError error = gen4_poller_set_config( instance, instance->password, - gen4_poller_default_config, - sizeof(gen4_poller_default_config), + &gen4_poller_default_config, + GEN4_POLLER_DEFAULT_CONFIG_SIZE, false); if(error != Gen4PollerErrorNone) { FURI_LOG_E(TAG, "Failed to set default config: %d", error); @@ -568,16 +624,16 @@ NfcCommand gen4_poller_get_current_cfg_handler(Gen4Poller* instance) { NfcCommand command = NfcCommandContinue; do { - uint8_t the_config[32] = {}; + Gen4Config config = {}; - Gen4PollerError error = gen4_poller_get_config(instance, instance->password, the_config); + Gen4PollerError error = gen4_poller_get_config(instance, instance->password, &config); if(error != Gen4PollerErrorNone) { FURI_LOG_E(TAG, "Failed to get current config: %d", error); instance->state = Gen4PollerStateFail; break; } // Copy config data to event data buffer - memcpy(instance->gen4_event_data.display_config, the_config, sizeof(the_config)); + memcpy(instance->gen4_data->config.data_raw, config.data_raw, sizeof(config)); instance->state = Gen4PollerStateSuccess; } while(false); @@ -589,16 +645,83 @@ NfcCommand gen4_poller_get_revision_handler(Gen4Poller* instance) { NfcCommand command = NfcCommandContinue; do { - uint8_t the_revision[5] = {0}; - Gen4PollerError error = - gen4_poller_get_revision(instance, instance->password, the_revision); + Gen4Revision revision = {}; + Gen4PollerError error = gen4_poller_get_revision(instance, instance->password, &revision); if(error != Gen4PollerErrorNone) { FURI_LOG_E(TAG, "Failed to get revision: %d", error); instance->state = Gen4PollerStateFail; break; } // Copy revision data to event data buffer - memcpy(instance->gen4_event_data.revision_data, the_revision, sizeof(the_revision)); + memcpy(instance->gen4_data->revision.data, revision.data, sizeof(revision)); + + instance->state = Gen4PollerStateSuccess; + } while(false); + + return command; +} + +NfcCommand gen4_poller_get_info_handler(Gen4Poller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + Gen4 gen4_data; + + Gen4PollerError error = + gen4_poller_get_revision(instance, instance->password, &gen4_data.revision); + if(error != Gen4PollerErrorNone) { + FURI_LOG_E(TAG, "Failed to get revision: %d", error); + instance->state = Gen4PollerStateFail; + break; + } + + error = gen4_poller_get_config(instance, instance->password, &gen4_data.config); + if(error != Gen4PollerErrorNone) { + FURI_LOG_E(TAG, "Failed to get current config: %d", error); + instance->state = Gen4PollerStateFail; + break; + } + + // Copy config&&revision data to event data buffer + gen4_copy(instance->gen4_data, &gen4_data); + + instance->state = Gen4PollerStateSuccess; + } while(false); + + return command; +} + +NfcCommand gen4_poller_set_shadow_mode_handler(Gen4Poller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + Gen4PollerError error = + gen4_poller_set_shadow_mode(instance, instance->password, instance->shadow_mode); + + if(error != Gen4PollerErrorNone) { + FURI_LOG_E(TAG, "Failed to set shadow mode: %d", error); + instance->state = Gen4PollerStateFail; + break; + } + + instance->state = Gen4PollerStateSuccess; + } while(false); + + return command; +} + +NfcCommand gen4_poller_set_direct_write_block_0_mode_handler(Gen4Poller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + Gen4PollerError error = gen4_poller_set_direct_write_block_0_mode( + instance, instance->password, instance->direct_write_block_0_mode); + + if(error != Gen4PollerErrorNone) { + FURI_LOG_E(TAG, "Failed to set direct write to block 0 mode: %d", error); + instance->state = Gen4PollerStateFail; + break; + } instance->state = Gen4PollerStateSuccess; } while(false); @@ -637,9 +760,10 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu [Gen4PollerStateWrite] = gen4_poller_write_handler, [Gen4PollerStateWipe] = gen4_poller_wipe_handler, [Gen4PollerStateChangePassword] = gen4_poller_change_password_handler, + [Gen4PollerStateGetInfo] = gen4_poller_get_info_handler, [Gen4PollerStateSetDefaultConfig] = gen4_poller_set_default_cfg_handler, - [Gen4PollerStateGetCurrentConfig] = gen4_poller_get_current_cfg_handler, - [Gen4PollerStateGetRevision] = gen4_poller_get_revision_handler, + [Gen4PollerStateSetShadowMode] = gen4_poller_set_shadow_mode_handler, + [Gen4PollerStateSetDirectWriteBlock0] = gen4_poller_set_direct_write_block_0_mode_handler, [Gen4PollerStateSuccess] = gen4_poller_success_handler, [Gen4PollerStateFail] = gen4_poller_fail_handler, @@ -678,3 +802,23 @@ void gen4_poller_stop(Gen4Poller* instance) { nfc_poller_stop(instance->poller); } + +const Gen4* gen4_poller_get_gen4_data(const Gen4Poller* instance) { + furi_assert(instance); + + return instance->gen4_data; +} + +void gen4_poller_struct_set_direct_write_block_0_mode( + Gen4Poller* instance, + Gen4DirectWriteBlock0Mode mode) { + furi_assert(instance); + + instance->direct_write_block_0_mode = mode; +} + +void gen4_poller_struct_set_shadow_mode(Gen4Poller* instance, Gen4ShadowMode mode) { + furi_assert(instance); + + instance->shadow_mode = mode; +} diff --git a/nfc_magic/magic/protocols/gen4/gen4_poller.h b/nfc_magic/magic/protocols/gen4/gen4_poller.h index a1966164..cbad6986 100644 --- a/nfc_magic/magic/protocols/gen4/gen4_poller.h +++ b/nfc_magic/magic/protocols/gen4/gen4_poller.h @@ -1,5 +1,6 @@ #pragma once +#include "gen4.h" #include #include #include @@ -9,8 +10,10 @@ extern "C" { #endif +// TODO: cleanup, check gen4_poller_i.c defines #define GEN4_CMD_PREFIX (0xCF) #define GEN4_CMD_GET_CFG (0xC6) +#define GEN4_CMD_GET_REVISION (0xCC) #define GEN4_CMD_WRITE (0xCD) #define GEN4_CMD_READ (0xCE) #define GEN4_CMD_SET_CFG (0xF0) @@ -38,9 +41,11 @@ typedef enum { Gen4PollerModeWrite, Gen4PollerModeSetPassword, - Gen4PollerModeSetDefaultCFG, - Gen4PollerModeGetCFG, - Gen4PollerModeGetRevision, + Gen4PollerModeGetInfo, + + Gen4PollerModeSetDefaultCfg, + Gen4PollerModeSetShadowMode, + Gen4PollerModeSetDirectWriteBlock0Mode } Gen4PollerMode; typedef struct { @@ -53,16 +58,13 @@ typedef struct { } Gen4PollerEventDataRequestDataToWrite; typedef struct { - uint32_t password; + Gen4Password password; } Gen4PollerEventDataRequestNewPassword; typedef union { Gen4PollerEventDataRequestMode request_mode; Gen4PollerEventDataRequestDataToWrite request_data; Gen4PollerEventDataRequestNewPassword request_password; - - uint8_t display_config[32]; - uint8_t revision_data[5]; } Gen4PollerEventData; typedef struct { @@ -74,18 +76,26 @@ typedef NfcCommand (*Gen4PollerCallback)(Gen4PollerEvent event, void* context); typedef struct Gen4Poller Gen4Poller; -Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password); +Gen4PollerError gen4_poller_detect(Nfc* nfc, Gen4Password password, Gen4* gen4_data); Gen4Poller* gen4_poller_alloc(Nfc* nfc); void gen4_poller_free(Gen4Poller* instance); -void gen4_poller_set_password(Gen4Poller* instance, uint32_t password); +void gen4_poller_set_password(Gen4Poller* instance, Gen4Password password); void gen4_poller_start(Gen4Poller* instance, Gen4PollerCallback callback, void* context); void gen4_poller_stop(Gen4Poller* instance); +const Gen4* gen4_poller_get_gen4_data(const Gen4Poller* instance); + +void gen4_poller_struct_set_direct_write_block_0_mode( + Gen4Poller* instance, + Gen4DirectWriteBlock0Mode mode); + +void gen4_poller_struct_set_shadow_mode(Gen4Poller* instance, Gen4ShadowMode mode); + #ifdef __cplusplus } #endif diff --git a/nfc_magic/magic/protocols/gen4/gen4_poller_i.c b/nfc_magic/magic/protocols/gen4/gen4_poller_i.c index 3a2629cc..88979cc0 100644 --- a/nfc_magic/magic/protocols/gen4/gen4_poller_i.c +++ b/nfc_magic/magic/protocols/gen4/gen4_poller_i.c @@ -1,21 +1,22 @@ #include "gen4_poller_i.h" #include "bit_buffer.h" -#include "core/log.h" +#include "magic/protocols/gen4/gen4_poller.h" #include #define GEN4_CMD_PREFIX (0xCF) +#define GEN4_CMD_SET_SHD_MODE (0x32) #define GEN4_CMD_GET_CFG (0xC6) #define GEN4_CMD_GET_REVISION (0xCC) #define GEN4_CMD_WRITE (0xCD) #define GEN4_CMD_READ (0xCE) +#define GEN4_CMD_SET_DW_BLOCK_0 (0xCF) #define GEN4_CMD_SET_CFG (0xF0) #define GEN4_CMD_FUSE_CFG (0xF1) #define GEN4_CMD_SET_PWD (0xFE) -#define CONFIG_SIZE (32) -#define REVISION_SIZE (5) +#define GEN4_RESPONSE_SUCCESS (0x02) static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) { Gen4PollerError ret = Gen4PollerErrorNone; @@ -30,15 +31,81 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) { } Gen4PollerError - gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result) { + gen4_poller_set_shadow_mode(Gen4Poller* instance, Gen4Password password, Gen4ShadowMode mode) { Gen4PollerError ret = Gen4PollerErrorNone; bit_buffer_reset(instance->tx_buffer); do { - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); + bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_SHD_MODE); + bit_buffer_append_byte(instance->tx_buffer, mode); + + Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( + instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT); + + if(error != Iso14443_3aErrorNone) { + ret = gen4_poller_process_error(error); + break; + } + + size_t response = bit_buffer_get_size_bytes(instance->rx_buffer); + + FURI_LOG_D(TAG, "Card response: 0x%02X, Shadow mode set: 0x%02X", response, mode); + + if(response != GEN4_RESPONSE_SUCCESS) { + ret = Gen4PollerErrorProtocol; + break; + } + + } while(false); + + return ret; +} + +Gen4PollerError gen4_poller_set_direct_write_block_0_mode( + Gen4Poller* instance, + Gen4Password password, + Gen4DirectWriteBlock0Mode mode) { + Gen4PollerError ret = Gen4PollerErrorNone; + bit_buffer_reset(instance->tx_buffer); + + do { + bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); + bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_DW_BLOCK_0); + bit_buffer_append_byte(instance->tx_buffer, mode); + + Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( + instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT); + + if(error != Iso14443_3aErrorNone) { + ret = gen4_poller_process_error(error); + break; + } + size_t response = bit_buffer_get_size_bytes(instance->rx_buffer); + + FURI_LOG_D( + TAG, "Card response: 0x%02X, Direct write to block 0 mode set: 0x%02X", response, mode); + + if(response != GEN4_RESPONSE_SUCCESS) { + ret = Gen4PollerErrorProtocol; + break; + } + + } while(false); + + return ret; +} + +Gen4PollerError + gen4_poller_get_config(Gen4Poller* instance, Gen4Password password, Gen4Config* config_result) { + Gen4PollerError ret = Gen4PollerErrorNone; + bit_buffer_reset(instance->tx_buffer); + + do { + bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_GET_CFG); Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( @@ -51,26 +118,26 @@ Gen4PollerError size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer); - if(rx_bytes != CONFIG_SIZE) { + if(rx_bytes != GEN4_CONFIG_SIZE) { ret = Gen4PollerErrorProtocol; break; } - bit_buffer_write_bytes(instance->rx_buffer, config_result, CONFIG_SIZE); + bit_buffer_write_bytes(instance->rx_buffer, config_result->data_raw, GEN4_CONFIG_SIZE); } while(false); return ret; } -Gen4PollerError - gen4_poller_get_revision(Gen4Poller* instance, uint32_t password, uint8_t* revision_result) { +Gen4PollerError gen4_poller_get_revision( + Gen4Poller* instance, + Gen4Password password, + Gen4Revision* revision_result) { Gen4PollerError ret = Gen4PollerErrorNone; bit_buffer_reset(instance->tx_buffer); do { - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_GET_REVISION); Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( @@ -82,11 +149,11 @@ Gen4PollerError } size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer); - if(rx_bytes != 5) { + if(rx_bytes != GEN4_REVISION_SIZE) { ret = Gen4PollerErrorProtocol; break; } - bit_buffer_write_bytes(instance->rx_buffer, revision_result, REVISION_SIZE); + bit_buffer_write_bytes(instance->rx_buffer, revision_result->data, GEN4_REVISION_SIZE); } while(false); return ret; @@ -94,21 +161,19 @@ Gen4PollerError Gen4PollerError gen4_poller_set_config( Gen4Poller* instance, - uint32_t password, - const uint8_t* config, + Gen4Password password, + const Gen4Config* config, size_t config_size, bool fuse) { Gen4PollerError ret = Gen4PollerErrorNone; bit_buffer_reset(instance->tx_buffer); do { - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); uint8_t fuse_config = fuse ? GEN4_CMD_FUSE_CFG : GEN4_CMD_SET_CFG; bit_buffer_append_byte(instance->tx_buffer, fuse_config); - bit_buffer_append_bytes(instance->tx_buffer, config, config_size); + bit_buffer_append_bytes(instance->tx_buffer, config->data_raw, config_size); Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT); @@ -118,8 +183,11 @@ Gen4PollerError gen4_poller_set_config( break; } - size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer); - if(rx_bytes != 2) { + size_t response = bit_buffer_get_size_bytes(instance->rx_buffer); + + FURI_LOG_D(TAG, "Card response to set default config command: 0x%02X", response); + + if(response != GEN4_RESPONSE_SUCCESS) { ret = Gen4PollerErrorProtocol; break; } @@ -130,17 +198,15 @@ Gen4PollerError gen4_poller_set_config( Gen4PollerError gen4_poller_write_block( Gen4Poller* instance, - uint32_t password, + Gen4Password password, uint8_t block_num, const uint8_t* data) { Gen4PollerError ret = Gen4PollerErrorNone; bit_buffer_reset(instance->tx_buffer); do { - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_WRITE); bit_buffer_append_byte(instance->tx_buffer, block_num); bit_buffer_append_bytes(instance->tx_buffer, data, GEN4_POLLER_BLOCK_SIZE); @@ -163,20 +229,19 @@ Gen4PollerError gen4_poller_write_block( return ret; } -Gen4PollerError - gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new) { +Gen4PollerError gen4_poller_change_password( + Gen4Poller* instance, + Gen4Password pwd_current, + Gen4Password pwd_new) { Gen4PollerError ret = Gen4PollerErrorNone; bit_buffer_reset(instance->tx_buffer); do { - uint8_t password_arr[4] = {}; - bit_lib_num_to_bytes_be(pwd_current, COUNT_OF(password_arr), password_arr); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, pwd_current.bytes, GEN4_PASSWORD_LEN); bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_PWD); - bit_lib_num_to_bytes_be(pwd_new, COUNT_OF(password_arr), password_arr); - bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr)); + bit_buffer_append_bytes(instance->tx_buffer, pwd_new.bytes, GEN4_PASSWORD_LEN); Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT); @@ -186,8 +251,23 @@ Gen4PollerError break; } - size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer); - if(rx_bytes != 2) { + size_t response = bit_buffer_get_size_bytes(instance->rx_buffer); + + FURI_LOG_D( + TAG, + "Trying to change password from 0x%02X %02X %02X %02X to " + "0x%02X %02X %02X %02X. Card response: 0x%02X", + pwd_current.bytes[0], + pwd_current.bytes[1], + pwd_current.bytes[2], + pwd_current.bytes[3], + pwd_new.bytes[0], + pwd_new.bytes[1], + pwd_new.bytes[2], + pwd_new.bytes[3], + response); + + if(response != GEN4_RESPONSE_SUCCESS) { ret = Gen4PollerErrorProtocol; break; } diff --git a/nfc_magic/magic/protocols/gen4/gen4_poller_i.h b/nfc_magic/magic/protocols/gen4/gen4_poller_i.h index ccfa1132..d7e993ba 100644 --- a/nfc_magic/magic/protocols/gen4/gen4_poller_i.h +++ b/nfc_magic/magic/protocols/gen4/gen4_poller_i.h @@ -17,32 +17,6 @@ extern "C" { #define GEN4_POLLER_BLOCK_SIZE (16) #define GEN4_POLLER_BLOCKS_TOTAL (256) -#define GEN4_POLLER_CONFIG_SIZE_MAX (30) - -typedef enum { - Gen4PollerUIDLengthSingle = 0x00, - Gen4PollerUIDLengthDouble = 0x01, - Gen4PollerUIDLengthTriple = 0x02 -} Gen4PollerUIDLength; - -typedef enum { - Gen4PollerUltralightModeUL_EV1 = 0x00, - Gen4PollerUltralightModeNTAG = 0x01, - Gen4PollerUltralightModeUL_C = 0x02, - Gen4PollerUltralightModeUL = 0x03 -} Gen4PollerUltralightMode; - -typedef enum { - // for writing original (shadow) data - Gen4PollerShadowModePreWrite = 0x00, - // written data can be read once before restored to original - Gen4PollerShadowModeRestore = 0x01, - // written data is discarded - Gen4PollerShadowModeIgnore = 0x02, - // apparently for UL? - Gen4PollerShadowModeHighSpeedIgnore = 0x03 -} Gen4PollerShadowMode; - typedef enum { Gen4PollerStateIdle, Gen4PollerStateRequestMode, @@ -51,9 +25,10 @@ typedef enum { Gen4PollerStateWipe, Gen4PollerStateChangePassword, + Gen4PollerStateGetInfo, Gen4PollerStateSetDefaultConfig, - Gen4PollerStateGetCurrentConfig, - Gen4PollerStateGetRevision, + Gen4PollerStateSetShadowMode, + Gen4PollerStateSetDirectWriteBlock0, Gen4PollerStateSuccess, Gen4PollerStateFail, @@ -65,7 +40,15 @@ struct Gen4Poller { NfcPoller* poller; Iso14443_3aPoller* iso3_poller; Gen4PollerState state; - uint32_t password; + + Gen4* gen4_data; + + Gen4Password password; + + Gen4Password new_password; + Gen4Config config; + Gen4ShadowMode shadow_mode; + Gen4DirectWriteBlock0Mode direct_write_block_0_mode; BitBuffer* tx_buffer; BitBuffer* rx_buffer; @@ -75,9 +58,6 @@ struct Gen4Poller { NfcProtocol protocol; const NfcDeviceData* data; - uint32_t new_password; - - uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX]; Gen4PollerEvent gen4_event; Gen4PollerEventData gen4_event_data; @@ -88,25 +68,37 @@ struct Gen4Poller { Gen4PollerError gen4_poller_set_config( Gen4Poller* instance, - uint32_t password, - const uint8_t* config, + Gen4Password password, + const Gen4Config* config, size_t config_size, bool fuse); Gen4PollerError gen4_poller_write_block( Gen4Poller* instance, - uint32_t password, + Gen4Password password, uint8_t block_num, const uint8_t* data); -Gen4PollerError - gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new); +Gen4PollerError gen4_poller_change_password( + Gen4Poller* instance, + Gen4Password pwd_current, + Gen4Password pwd_new); + +Gen4PollerError gen4_poller_get_revision( + Gen4Poller* instance, + Gen4Password password, + Gen4Revision* revision_result); Gen4PollerError - gen4_poller_get_revision(Gen4Poller* instance, uint32_t password, uint8_t* revision_result); + gen4_poller_get_config(Gen4Poller* instance, Gen4Password password, Gen4Config* config_result); Gen4PollerError - gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result); + gen4_poller_set_shadow_mode(Gen4Poller* instance, Gen4Password password, Gen4ShadowMode mode); + +Gen4PollerError gen4_poller_set_direct_write_block_0_mode( + Gen4Poller* instance, + Gen4Password password, + Gen4DirectWriteBlock0Mode mode); #ifdef __cplusplus } diff --git a/nfc_magic/nfc_magic_app.c b/nfc_magic/nfc_magic_app.c index bf35f5fe..34fca2b3 100644 --- a/nfc_magic/nfc_magic_app.c +++ b/nfc_magic/nfc_magic_app.c @@ -1,4 +1,5 @@ #include "nfc_magic_app_i.h" +#include "magic/protocols/gen4/gen4.h" bool nfc_magic_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -106,6 +107,8 @@ NfcMagicApp* nfc_magic_app_alloc() { view_dispatcher_add_view( instance->view_dispatcher, NfcMagicAppViewWidget, widget_get_view(instance->widget)); + instance->gen4_data = gen4_alloc(); + // Dict attack instance->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( @@ -191,6 +194,8 @@ void nfc_magic_app_free(NfcMagicApp* instance) { furi_record_close(RECORD_STORAGE); instance->storage = NULL; + gen4_free(instance->gen4_data); + nfc_magic_scanner_free(instance->scanner); nfc_free(instance->nfc); diff --git a/nfc_magic/nfc_magic_app_i.h b/nfc_magic/nfc_magic_app_i.h index d67bc428..39fe2dfc 100644 --- a/nfc_magic/nfc_magic_app_i.h +++ b/nfc_magic/nfc_magic_app_i.h @@ -109,17 +109,16 @@ struct NfcMagicApp { Gen4Poller* gen4_poller; + Gen4* gen4_data; + + Gen4Password gen4_password; + Gen4Password gen4_password_new; + NfcMagicAppMfClassicDictAttackContext nfc_dict_context; DictAttack* dict_attack; NfcMagicAppWriteProblemsContext write_problems_context; WriteProblems* write_problems; - uint32_t gen4_password; - uint32_t gen4_password_new; - - uint8_t gen4_config_display[32]; - uint8_t gen4_revision_display[5]; - FuriString* text_box_store; uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE]; diff --git a/nfc_magic/scenes/nfc_magic_scene_config.h b/nfc_magic/scenes/nfc_magic_scene_config.h index 71a1315a..5f890586 100644 --- a/nfc_magic/scenes/nfc_magic_scene_config.h +++ b/nfc_magic/scenes/nfc_magic_scene_config.h @@ -5,11 +5,13 @@ ADD_SCENE(nfc_magic, magic_info, MagicInfo) ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu) ADD_SCENE(nfc_magic, gen4_menu, Gen4Menu) ADD_SCENE(nfc_magic, gen4_actions_menu, Gen4ActionsMenu) -ADD_SCENE(nfc_magic, gen4_get_cfg, Gen4GetCFG) -ADD_SCENE(nfc_magic, gen4_set_cfg, Gen4SetCFG) -ADD_SCENE(nfc_magic, gen4_revision, Gen4Revision) -ADD_SCENE(nfc_magic, gen4_show_rev, Gen4ShowRev) -ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCFG) +ADD_SCENE(nfc_magic, gen4_set_default_cfg, Gen4SetDefaultCfg) +ADD_SCENE(nfc_magic, gen4_get_info, Gen4GetInfo) +ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCfg) +ADD_SCENE(nfc_magic, gen4_show_info, Gen4ShowInfo) +ADD_SCENE(nfc_magic, gen4_select_shd_mode, Gen4SelectShdMode) +ADD_SCENE(nfc_magic, gen4_set_shd_mode, Gen4SetShdMode) +ADD_SCENE(nfc_magic, gen4_set_direct_write_block_0_mode, Gen4SetDirectWriteBlock0Mode) ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail) ADD_SCENE(nfc_magic, wipe, Wipe) ADD_SCENE(nfc_magic, wipe_fail, WipeFail) diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c b/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c index 40d910cc..c0755a9e 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c @@ -1,11 +1,8 @@ #include "../nfc_magic_app_i.h" -#include "furi_hal_rtc.h" enum SubmenuIndex { SubmenuIndexAuthenticate, - SubmenuIndexSetStandardConfig, - SubmenuIndexGetConfig, - SubmenuIndexGetRevision + SubmenuIndexSetDefaultConfig, }; void nfc_magic_scene_gen4_actions_menu_submenu_callback(void* context, uint32_t index) { @@ -26,24 +23,10 @@ void nfc_magic_scene_gen4_actions_menu_on_enter(void* context) { instance); submenu_add_item( submenu, - "Get Revision", - SubmenuIndexGetRevision, + "Set Default Config", + SubmenuIndexSetDefaultConfig, nfc_magic_scene_gen4_actions_menu_submenu_callback, instance); - submenu_add_item( - submenu, - "Set Standard Config", - SubmenuIndexSetStandardConfig, - nfc_magic_scene_gen4_actions_menu_submenu_callback, - instance); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - submenu_add_item( - submenu, - "Get Config", - SubmenuIndexGetConfig, - nfc_magic_scene_gen4_actions_menu_submenu_callback, - instance); - } submenu_set_selected_item( submenu, @@ -59,16 +42,11 @@ bool nfc_magic_scene_gen4_actions_menu_on_event(void* context, SceneManagerEvent if(event.event == SubmenuIndexAuthenticate) { scene_manager_next_scene(instance->scene_manager, NfcMagicSceneKeyInput); consumed = true; - } else if(event.event == SubmenuIndexSetStandardConfig) { - scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetCFG); - consumed = true; - } else if(event.event == SubmenuIndexGetConfig) { - scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4GetCFG); - consumed = true; - } else if(event.event == SubmenuIndexGetRevision) { - scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Revision); + } else if(event.event == SubmenuIndexSetDefaultConfig) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetDefaultCfg); consumed = true; } + scene_manager_set_scene_state( instance->scene_manager, NfcMagicSceneGen4ActionsMenu, event.event); } else if(event.type == SceneManagerEventTypeBack) { diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_revision.c b/nfc_magic/scenes/nfc_magic_scene_gen4_get_info.c similarity index 66% rename from nfc_magic/scenes/nfc_magic_scene_gen4_revision.c rename to nfc_magic/scenes/nfc_magic_scene_gen4_get_info.c index c3d863e0..8cda9a0e 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_revision.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_get_info.c @@ -1,11 +1,11 @@ #include "../nfc_magic_app_i.h" enum { - NfcMagicSceneGen4RevisionStateCardSearch, - NfcMagicSceneGen4RevisionStateCardFound, + NfcMagicSceneGen4GetInfoStateCardSearch, + NfcMagicSceneGen4GetInfoStateCardFound, }; -NfcCommand nfc_mafic_scene_gen4_revision_poller_callback(Gen4PollerEvent event, void* context) { +NfcCommand nfc_mafic_scene_gen4_get_info_poller_callback(Gen4PollerEvent event, void* context) { NfcMagicApp* instance = context; furi_assert(event.data); @@ -15,13 +15,10 @@ NfcCommand nfc_mafic_scene_gen4_revision_poller_callback(Gen4PollerEvent event, view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventCardDetected); } else if(event.type == Gen4PollerEventTypeRequestMode) { - event.data->request_mode.mode = Gen4PollerModeGetRevision; + event.data->request_mode.mode = Gen4PollerModeGetInfo; } else if(event.type == Gen4PollerEventTypeSuccess) { - // Copy revision from event to main instance to display it on success scene - memcpy( - instance->gen4_revision_display, - event.data->revision_data, - sizeof(event.data->revision_data)); + // Copy data from event to main instance + gen4_copy(instance->gen4_data, gen4_poller_get_gen4_data(instance->gen4_poller)); view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess); @@ -35,13 +32,13 @@ NfcCommand nfc_mafic_scene_gen4_revision_poller_callback(Gen4PollerEvent event, return command; } -static void nfc_magic_scene_gen4_revision_setup_view(NfcMagicApp* instance) { +static void nfc_magic_scene_gen4_get_info_setup_view(NfcMagicApp* instance) { Popup* popup = instance->popup; popup_reset(popup); uint32_t state = - scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Revision); + scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4GetInfo); - if(state == NfcMagicSceneGen4RevisionStateCardSearch) { + if(state == NfcMagicSceneGen4GetInfoStateCardSearch) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); popup_set_text( instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter); @@ -53,24 +50,24 @@ static void nfc_magic_scene_gen4_revision_setup_view(NfcMagicApp* instance) { view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup); } -void nfc_magic_scene_gen4_revision_on_enter(void* context) { +void nfc_magic_scene_gen4_get_info_on_enter(void* context) { NfcMagicApp* instance = context; scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4Revision, - NfcMagicSceneGen4RevisionStateCardSearch); - nfc_magic_scene_gen4_revision_setup_view(instance); + NfcMagicSceneGen4GetInfo, + NfcMagicSceneGen4GetInfoStateCardSearch); + nfc_magic_scene_gen4_get_info_setup_view(instance); nfc_magic_app_blink_start(instance); instance->gen4_poller = gen4_poller_alloc(instance->nfc); gen4_poller_set_password(instance->gen4_poller, instance->gen4_password); gen4_poller_start( - instance->gen4_poller, nfc_mafic_scene_gen4_revision_poller_callback, instance); + instance->gen4_poller, nfc_mafic_scene_gen4_get_info_poller_callback, instance); } -bool nfc_magic_scene_gen4_revision_on_event(void* context, SceneManagerEvent event) { +bool nfc_magic_scene_gen4_get_info_on_event(void* context, SceneManagerEvent event) { NfcMagicApp* instance = context; bool consumed = false; @@ -78,19 +75,22 @@ bool nfc_magic_scene_gen4_revision_on_event(void* context, SceneManagerEvent eve if(event.event == NfcMagicCustomEventCardDetected) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4Revision, - NfcMagicSceneGen4RevisionStateCardFound); - nfc_magic_scene_gen4_revision_setup_view(instance); + NfcMagicSceneGen4GetInfo, + NfcMagicSceneGen4GetInfoStateCardFound); + nfc_magic_scene_gen4_get_info_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventCardLost) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4Revision, - NfcMagicSceneGen4RevisionStateCardSearch); - nfc_magic_scene_gen4_revision_setup_view(instance); + NfcMagicSceneGen4GetInfo, + NfcMagicSceneGen4GetInfoStateCardSearch); + nfc_magic_scene_gen4_get_info_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventWorkerSuccess) { - scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowRev); + // for notification message + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4ShowInfo, true); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowInfo); consumed = true; } else if(event.event == NfcMagicCustomEventWorkerFail) { scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail); @@ -101,15 +101,15 @@ bool nfc_magic_scene_gen4_revision_on_event(void* context, SceneManagerEvent eve return consumed; } -void nfc_magic_scene_gen4_revision_on_exit(void* context) { +void nfc_magic_scene_gen4_get_info_on_exit(void* context) { NfcMagicApp* instance = context; gen4_poller_stop(instance->gen4_poller); gen4_poller_free(instance->gen4_poller); scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4Revision, - NfcMagicSceneGen4RevisionStateCardSearch); + NfcMagicSceneGen4GetInfo, + NfcMagicSceneGen4GetInfoStateCardSearch); // Clear view popup_reset(instance->popup); diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c b/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c index 69fb78af..899921cc 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c @@ -3,6 +3,9 @@ enum SubmenuIndex { SubmenuIndexWrite, SubmenuIndexChangePassword, + SubmenuIndexSetShadowMode, + SubmenuIndexSetDirectWriteBlock0Mode, + SubmenuIndexInfo, SubmenuIndexWipe, }; @@ -24,8 +27,41 @@ void nfc_magic_scene_gen4_menu_on_enter(void* context) { SubmenuIndexChangePassword, nfc_magic_scene_gen4_menu_submenu_callback, instance); + submenu_add_item( + submenu, + "Set Shadow Mode", + SubmenuIndexSetShadowMode, + nfc_magic_scene_gen4_menu_submenu_callback, + instance); + if(instance->gen4_data->config.data_parsed.direct_write_mode == + Gen4DirectWriteBlock0ModeEnabled) { + submenu_add_item( + submenu, + "Disable Direct Write Mode", + SubmenuIndexSetDirectWriteBlock0Mode, + nfc_magic_scene_gen4_menu_submenu_callback, + instance); + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + Gen4DirectWriteBlock0ModeDisabled); + } else { + submenu_add_item( + submenu, + "Enable Direct Write Mode", + SubmenuIndexSetDirectWriteBlock0Mode, + nfc_magic_scene_gen4_menu_submenu_callback, + instance); + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + Gen4DirectWriteBlock0ModeEnabled); + } + submenu_add_item( submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen4_menu_submenu_callback, instance); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_magic_scene_gen4_menu_submenu_callback, instance); submenu_set_selected_item( submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu)); @@ -46,10 +82,21 @@ bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexWipe) { scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe); consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4GetInfo); + consumed = true; + } else if(event.event == SubmenuIndexSetShadowMode) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SelectShdMode); + consumed = true; + } else if(event.event == SubmenuIndexSetDirectWriteBlock0Mode) { + scene_manager_next_scene( + instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode); + consumed = true; } + scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event); } else if(event.type == SceneManagerEventTypeBack) { - if(instance->gen4_password != 0) { + if(gen4_password_is_set(&instance->gen4_password)) { consumed = scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcMagicSceneGen4ActionsMenu); } else { diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_select_shd_mode.c b/nfc_magic/scenes/nfc_magic_scene_gen4_select_shd_mode.c new file mode 100644 index 00000000..47372c10 --- /dev/null +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_select_shd_mode.c @@ -0,0 +1,105 @@ +#include "../nfc_magic_app_i.h" + +enum SubmenuIndex { + SubmenuIndexPreWriteMode, + SubmenuIndexRestoreMode, + SubmenuIndexDisable, + SubmenuIndexDisableHighSpeed, + SubmenuIndexSplitMode, +}; + +void nfc_magic_scene_gen4_select_shd_mode_submenu_callback(void* context, uint32_t index) { + NfcMagicApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, index); +} + +void nfc_magic_scene_gen4_select_shd_mode_on_enter(void* context) { + NfcMagicApp* instance = context; + + Submenu* submenu = instance->submenu; + submenu_add_item( + submenu, + "Pre-Write", + SubmenuIndexPreWriteMode, + nfc_magic_scene_gen4_select_shd_mode_submenu_callback, + instance); + submenu_add_item( + submenu, + "Restore", + SubmenuIndexRestoreMode, + nfc_magic_scene_gen4_select_shd_mode_submenu_callback, + instance); + submenu_add_item( + submenu, + "Disable", + SubmenuIndexDisable, + nfc_magic_scene_gen4_select_shd_mode_submenu_callback, + instance); + submenu_add_item( + submenu, + "Disable (High-Speed)", + SubmenuIndexDisableHighSpeed, + nfc_magic_scene_gen4_select_shd_mode_submenu_callback, + instance); + submenu_add_item( + submenu, + "Split", + SubmenuIndexSplitMode, + nfc_magic_scene_gen4_select_shd_mode_submenu_callback, + instance); + + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SelectShdMode)); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu); +} + +bool nfc_magic_scene_gen4_select_shd_mode_on_event(void* context, SceneManagerEvent event) { + NfcMagicApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexPreWriteMode) { + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModePreWrite); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + consumed = true; + } else if(event.event == SubmenuIndexRestoreMode) { + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeRestore); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + consumed = true; + } else if(event.event == SubmenuIndexDisable) { + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeDisabled); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + consumed = true; + } else if(event.event == SubmenuIndexDisableHighSpeed) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetShdMode, + Gen4ShadowModeHighSpeedDisabled); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + consumed = true; + } else if(event.event == SubmenuIndexSplitMode) { + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeSplit); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + consumed = true; + } + scene_manager_set_scene_state( + instance->scene_manager, NfcMagicSceneGen4SelectShdMode, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneGen4ActionsMenu); + } + + return consumed; +} + +void nfc_magic_scene_gen4_select_shd_mode_on_exit(void* context) { + NfcMagicApp* instance = context; + + submenu_reset(instance->submenu); +} diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c b/nfc_magic/scenes/nfc_magic_scene_gen4_set_default_cfg.c similarity index 67% rename from nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c rename to nfc_magic/scenes/nfc_magic_scene_gen4_set_default_cfg.c index d9910dec..bb0441a1 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_set_default_cfg.c @@ -1,11 +1,12 @@ #include "../nfc_magic_app_i.h" enum { - NfcMagicSceneGen4SetDefCFGStateCardSearch, - NfcMagicSceneGen4SetDefCFGStateCardFound, + NfcMagicSceneGen4SetDefCfgStateCardSearch, + NfcMagicSceneGen4SetDefCfgStateCardFound, }; -NfcCommand nfc_mafic_scene_gen4_set_cfg_poller_callback(Gen4PollerEvent event, void* context) { +NfcCommand + nfc_mafic_scene_gen4_set_default_cfg_poller_callback(Gen4PollerEvent event, void* context) { NfcMagicApp* instance = context; furi_assert(event.data); @@ -15,7 +16,7 @@ NfcCommand nfc_mafic_scene_gen4_set_cfg_poller_callback(Gen4PollerEvent event, v view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventCardDetected); } else if(event.type == Gen4PollerEventTypeRequestMode) { - event.data->request_mode.mode = Gen4PollerModeSetDefaultCFG; + event.data->request_mode.mode = Gen4PollerModeSetDefaultCfg; } else if(event.type == Gen4PollerEventTypeSuccess) { view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess); @@ -29,42 +30,42 @@ NfcCommand nfc_mafic_scene_gen4_set_cfg_poller_callback(Gen4PollerEvent event, v return command; } -static void nfc_magic_scene_gen4_set_cfg_setup_view(NfcMagicApp* instance) { +static void nfc_magic_scene_gen4_set_default_cfg_setup_view(NfcMagicApp* instance) { Popup* popup = instance->popup; popup_reset(popup); uint32_t state = - scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetCFG); + scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetDefaultCfg); - if(state == NfcMagicSceneGen4SetDefCFGStateCardSearch) { + if(state == NfcMagicSceneGen4SetDefCfgStateCardSearch) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); popup_set_text( instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); - popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter); } view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup); } -void nfc_magic_scene_gen4_set_cfg_on_enter(void* context) { +void nfc_magic_scene_gen4_set_default_cfg_on_enter(void* context) { NfcMagicApp* instance = context; scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4SetCFG, - NfcMagicSceneGen4SetDefCFGStateCardSearch); - nfc_magic_scene_gen4_set_cfg_setup_view(instance); + NfcMagicSceneGen4SetDefaultCfg, + NfcMagicSceneGen4SetDefCfgStateCardSearch); + nfc_magic_scene_gen4_set_default_cfg_setup_view(instance); nfc_magic_app_blink_start(instance); instance->gen4_poller = gen4_poller_alloc(instance->nfc); gen4_poller_set_password(instance->gen4_poller, instance->gen4_password); gen4_poller_start( - instance->gen4_poller, nfc_mafic_scene_gen4_set_cfg_poller_callback, instance); + instance->gen4_poller, nfc_mafic_scene_gen4_set_default_cfg_poller_callback, instance); } -bool nfc_magic_scene_gen4_set_cfg_on_event(void* context, SceneManagerEvent event) { +bool nfc_magic_scene_gen4_set_default_cfg_on_event(void* context, SceneManagerEvent event) { NfcMagicApp* instance = context; bool consumed = false; @@ -72,16 +73,16 @@ bool nfc_magic_scene_gen4_set_cfg_on_event(void* context, SceneManagerEvent even if(event.event == NfcMagicCustomEventCardDetected) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4SetCFG, - NfcMagicSceneGen4SetDefCFGStateCardFound); - nfc_magic_scene_gen4_set_cfg_setup_view(instance); + NfcMagicSceneGen4SetDefaultCfg, + NfcMagicSceneGen4SetDefCfgStateCardFound); + nfc_magic_scene_gen4_set_default_cfg_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventCardLost) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4SetCFG, - NfcMagicSceneGen4SetDefCFGStateCardSearch); - nfc_magic_scene_gen4_set_cfg_setup_view(instance); + NfcMagicSceneGen4SetDefaultCfg, + NfcMagicSceneGen4SetDefCfgStateCardSearch); + nfc_magic_scene_gen4_set_default_cfg_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventWorkerSuccess) { scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess); @@ -95,15 +96,15 @@ bool nfc_magic_scene_gen4_set_cfg_on_event(void* context, SceneManagerEvent even return consumed; } -void nfc_magic_scene_gen4_set_cfg_on_exit(void* context) { +void nfc_magic_scene_gen4_set_default_cfg_on_exit(void* context) { NfcMagicApp* instance = context; gen4_poller_stop(instance->gen4_poller); gen4_poller_free(instance->gen4_poller); scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4SetCFG, - NfcMagicSceneGen4SetDefCFGStateCardSearch); + NfcMagicSceneGen4SetDefaultCfg, + NfcMagicSceneGen4SetDefCfgStateCardSearch); // Clear view popup_reset(instance->popup); diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_set_direct_write_block_0_mode.c b/nfc_magic/scenes/nfc_magic_scene_gen4_set_direct_write_block_0_mode.c new file mode 100644 index 00000000..b4fd9d56 --- /dev/null +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_set_direct_write_block_0_mode.c @@ -0,0 +1,123 @@ +#include "../nfc_magic_app_i.h" + +enum { + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch, + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardFound, +}; + +NfcCommand nfc_magic_scene_gen4_set_direct_write_block_0_mode_poller_callback( + Gen4PollerEvent event, + void* context) { + NfcMagicApp* instance = context; + furi_assert(event.data); + + NfcCommand command = NfcCommandContinue; + if(event.type == Gen4PollerEventTypeCardDetected) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcMagicCustomEventCardDetected); + } else if(event.type == Gen4PollerEventTypeRequestMode) { + event.data->request_mode.mode = Gen4PollerModeSetDirectWriteBlock0Mode; + } else if(event.type == Gen4PollerEventTypeSuccess) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess); + command = NfcCommandStop; + } else if(event.type == Gen4PollerEventTypeFail) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcMagicCustomEventWorkerFail); + command = NfcCommandStop; + } + + return command; +} + +static void nfc_magic_scene_gen4_set_direct_write_block_0_mode_setup_view(NfcMagicApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode); + + if(state == NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch) { + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + popup_set_text( + instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter); + } else { + popup_set_icon(popup, 12, 23, &I_Loading_24); + popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup); +} + +void nfc_magic_scene_gen4_set_direct_write_block_0_mode_on_enter(void* context) { + NfcMagicApp* instance = context; + + uint8_t direct_write_block_0_mode = scene_manager_get_scene_state( + instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch); + nfc_magic_scene_gen4_set_direct_write_block_0_mode_setup_view(instance); + + nfc_magic_app_blink_start(instance); + + instance->gen4_poller = gen4_poller_alloc(instance->nfc); + gen4_poller_set_password(instance->gen4_poller, instance->gen4_password); + + gen4_poller_struct_set_direct_write_block_0_mode( + instance->gen4_poller, direct_write_block_0_mode); + + gen4_poller_start( + instance->gen4_poller, + nfc_magic_scene_gen4_set_direct_write_block_0_mode_poller_callback, + instance); +} + +bool nfc_magic_scene_gen4_set_direct_write_block_0_mode_on_event( + void* context, + SceneManagerEvent event) { + NfcMagicApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardFound); + nfc_magic_scene_gen4_set_direct_write_block_0_mode_setup_view(instance); + consumed = true; + } else if(event.event == NfcMagicCustomEventCardLost) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch); + nfc_magic_scene_gen4_set_direct_write_block_0_mode_setup_view(instance); + consumed = true; + } else if(event.event == NfcMagicCustomEventWorkerSuccess) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess); + consumed = true; + } else if(event.event == NfcMagicCustomEventWorkerFail) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail); + consumed = true; + } + } + + return consumed; +} + +void nfc_magic_scene_gen4_set_direct_write_block_0_mode_on_exit(void* context) { + NfcMagicApp* instance = context; + + gen4_poller_stop(instance->gen4_poller); + gen4_poller_free(instance->gen4_poller); + scene_manager_set_scene_state( + instance->scene_manager, + NfcMagicSceneGen4SetDirectWriteBlock0Mode, + NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch); + // Clear view + popup_reset(instance->popup); + + nfc_magic_app_blink_stop(instance); +} diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c b/nfc_magic/scenes/nfc_magic_scene_gen4_set_shd_mode.c similarity index 61% rename from nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c rename to nfc_magic/scenes/nfc_magic_scene_gen4_set_shd_mode.c index 9d698035..c41245a2 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_set_shd_mode.c @@ -1,28 +1,22 @@ #include "../nfc_magic_app_i.h" enum { - NfcMagicSceneGen4GetCFGStateCardSearch, - NfcMagicSceneGen4GetCFGStateCardFound, + NfcMagicSceneGen4SetShadowModeStateCardSearch, + NfcMagicSceneGen4SetShadowModeStateCardFound, }; -NfcCommand nfc_mafic_scene_gen4_get_cfg_poller_callback(Gen4PollerEvent event, void* context) { +NfcCommand + nfc_magic_scene_gen4_set_shd_mode_poller_callback(Gen4PollerEvent event, void* context) { NfcMagicApp* instance = context; furi_assert(event.data); NfcCommand command = NfcCommandContinue; - if(event.type == Gen4PollerEventTypeCardDetected) { view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventCardDetected); } else if(event.type == Gen4PollerEventTypeRequestMode) { - event.data->request_mode.mode = Gen4PollerModeGetCFG; + event.data->request_mode.mode = Gen4PollerModeSetShadowMode; } else if(event.type == Gen4PollerEventTypeSuccess) { - // Copy config from event to main instance to display it on success scene - memcpy( - instance->gen4_config_display, - event.data->display_config, - sizeof(event.data->display_config)); - view_dispatcher_send_custom_event( instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess); command = NfcCommandStop; @@ -35,40 +29,47 @@ NfcCommand nfc_mafic_scene_gen4_get_cfg_poller_callback(Gen4PollerEvent event, v return command; } -static void nfc_magic_scene_gen4_get_cfg_setup_view(NfcMagicApp* instance) { +static void nfc_magic_scene_gen4_set_shd_mode_setup_view(NfcMagicApp* instance) { Popup* popup = instance->popup; popup_reset(popup); uint32_t state = - scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4GetCFG); + scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetShdMode); - if(state == NfcMagicSceneGen4GetCFGStateCardSearch) { + if(state == NfcMagicSceneGen4SetShadowModeStateCardSearch) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); popup_set_text( instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); - popup_set_header(popup, "Reading\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter); } view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup); } -void nfc_magic_scene_gen4_get_cfg_on_enter(void* context) { +void nfc_magic_scene_gen4_set_shd_mode_on_enter(void* context) { NfcMagicApp* instance = context; + uint8_t shadow_mode = + scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetShdMode); + scene_manager_set_scene_state( - instance->scene_manager, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch); - nfc_magic_scene_gen4_get_cfg_setup_view(instance); + instance->scene_manager, + NfcMagicSceneGen4SetShdMode, + NfcMagicSceneGen4SetShadowModeStateCardSearch); + nfc_magic_scene_gen4_set_shd_mode_setup_view(instance); nfc_magic_app_blink_start(instance); instance->gen4_poller = gen4_poller_alloc(instance->nfc); gen4_poller_set_password(instance->gen4_poller, instance->gen4_password); + gen4_poller_struct_set_shadow_mode(instance->gen4_poller, shadow_mode); + gen4_poller_start( - instance->gen4_poller, nfc_mafic_scene_gen4_get_cfg_poller_callback, instance); + instance->gen4_poller, nfc_magic_scene_gen4_set_shd_mode_poller_callback, instance); } -bool nfc_magic_scene_gen4_get_cfg_on_event(void* context, SceneManagerEvent event) { +bool nfc_magic_scene_gen4_set_shd_mode_on_event(void* context, SceneManagerEvent event) { NfcMagicApp* instance = context; bool consumed = false; @@ -76,19 +77,19 @@ bool nfc_magic_scene_gen4_get_cfg_on_event(void* context, SceneManagerEvent even if(event.event == NfcMagicCustomEventCardDetected) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4GetCFG, - NfcMagicSceneGen4GetCFGStateCardFound); - nfc_magic_scene_gen4_get_cfg_setup_view(instance); + NfcMagicSceneGen4SetShdMode, + NfcMagicSceneGen4SetShadowModeStateCardFound); + nfc_magic_scene_gen4_set_shd_mode_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventCardLost) { scene_manager_set_scene_state( instance->scene_manager, - NfcMagicSceneGen4GetCFG, - NfcMagicSceneGen4GetCFGStateCardSearch); - nfc_magic_scene_gen4_get_cfg_setup_view(instance); + NfcMagicSceneGen4SetShdMode, + NfcMagicSceneGen4SetShadowModeStateCardSearch); + nfc_magic_scene_gen4_set_shd_mode_setup_view(instance); consumed = true; } else if(event.event == NfcMagicCustomEventWorkerSuccess) { - scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowCFG); + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess); consumed = true; } else if(event.event == NfcMagicCustomEventWorkerFail) { scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail); @@ -99,13 +100,15 @@ bool nfc_magic_scene_gen4_get_cfg_on_event(void* context, SceneManagerEvent even return consumed; } -void nfc_magic_scene_gen4_get_cfg_on_exit(void* context) { +void nfc_magic_scene_gen4_set_shd_mode_on_exit(void* context) { NfcMagicApp* instance = context; gen4_poller_stop(instance->gen4_poller); gen4_poller_free(instance->gen4_poller); scene_manager_set_scene_state( - instance->scene_manager, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch); + instance->scene_manager, + NfcMagicSceneGen4SetShdMode, + NfcMagicSceneGen4SetShadowModeStateCardSearch); // Clear view popup_reset(instance->popup); diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c b/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c index 0aed4588..7ab6fc32 100644 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c @@ -1,7 +1,5 @@ #include "../nfc_magic_app_i.h" -#define CONFIG_SIZE (32) - void nfc_magic_scene_gen4_show_cfg_widget_callback( GuiButtonType result, InputType type, @@ -17,25 +15,20 @@ void nfc_magic_scene_gen4_show_cfg_on_enter(void* context) { NfcMagicApp* instance = context; Widget* widget = instance->widget; - notification_message(instance->notifications, &sequence_success); + FuriString* output = furi_string_alloc(); + + Gen4Config* config = &instance->gen4_data->config; - FuriString* temp_config = furi_string_alloc(); - for(size_t i = 0; i < CONFIG_SIZE; i++) { - if((i != 0) && (i % 8 == 0)) { - furi_string_cat_printf(temp_config, "\n"); - } - furi_string_cat_printf(temp_config, "%02X ", instance->gen4_config_display[i]); + for(size_t i = 0; i < GEN4_CONFIG_SIZE; i += 2) { + if(i && !(i % 8)) furi_string_cat_printf(output, "\n"); + furi_string_cat_printf(output, "%02X%02X ", config->data_raw[i], config->data_raw[i + 1]); } - furi_string_cat_printf(temp_config, "\n"); widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Config"); - widget_add_text_scroll_element(widget, 3, 17, 124, 50, furi_string_get_cstr(temp_config)); - - widget_add_button_element( - widget, GuiButtonTypeLeft, "Exit", nfc_magic_scene_gen4_show_cfg_widget_callback, instance); + widget_add_text_scroll_element(widget, 3, 17, 124, 50, furi_string_get_cstr(output)); - furi_string_free(temp_config); + furi_string_free(output); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget); } @@ -43,11 +36,9 @@ bool nfc_magic_scene_gen4_show_cfg_on_event(void* context, SceneManagerEvent eve NfcMagicApp* instance = context; bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, NfcMagicSceneGen4ActionsMenu); - } + if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneGen4ShowInfo); } return consumed; } diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_show_info.c b/nfc_magic/scenes/nfc_magic_scene_gen4_show_info.c new file mode 100644 index 00000000..81533a6c --- /dev/null +++ b/nfc_magic/scenes/nfc_magic_scene_gen4_show_info.c @@ -0,0 +1,121 @@ +#include "../nfc_magic_app_i.h" + +void nfc_magic_scene_gen4_show_info_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcMagicApp* instance = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_magic_scene_gen4_show_info_on_enter(void* context) { + NfcMagicApp* instance = context; + Widget* widget = instance->widget; + + if(scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4ShowInfo)) + notification_message(instance->notifications, &sequence_success); + scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4ShowInfo, false); + + Gen4* gen4 = instance->gen4_data; + + Gen4DirectWriteBlock0Mode dw_mode = gen4->config.data_parsed.direct_write_mode; + Gen4ShadowMode s_mode = gen4->config.data_parsed.gtu_mode; + uint8_t ats_len = gen4->config.data_parsed.ats_len; + + FuriString* output = furi_string_alloc(); + + furi_string_printf(output, "\e#Gen4\n"); + + // Revision + furi_string_cat_printf( + output, "Revision: %02X %02X\n", gen4->revision.data[3], gen4->revision.data[4]); + + // Password + furi_string_cat_printf( + output, + "Password: %02X %02X %02X %02X\n", + gen4->config.data_parsed.password.bytes[0], + gen4->config.data_parsed.password.bytes[1], + gen4->config.data_parsed.password.bytes[2], + gen4->config.data_parsed.password.bytes[3]); + + // Shadow mode + furi_string_cat_printf(output, "Shadow Mode: %s\n", gen4_get_shadow_mode_name(s_mode)); + + // Direct write to block 0 mode + furi_string_cat_printf( + output, "Direct Write Mode: %s\n", gen4_get_direct_write_mode_name(dw_mode)); + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + furi_string_cat_printf(output, ":::::::::::::[Configured As]::::::::::::::\n"); + ///////////////////////////////////////////////////////////////////////////////////////////////////// + + // Configuration type: + furi_string_cat_printf(output, "%s\n", gen4_get_configuration_name(&gen4->config)); + + // UID len + furi_string_cat_printf( + output, "UID Length: %s\n", gen4_get_uid_len_num(gen4->config.data_parsed.uid_len_code)); + + // ATS + furi_string_cat_printf(output, "ATS:"); + if(ats_len) + for(uint8_t i = 0; i < ats_len; i++) + furi_string_cat_printf(output, " %02X", gen4->config.data_parsed.ats[i]); + else + furi_string_cat_printf(output, " No"); + furi_string_cat_printf(output, "\n"); + + // ATQA + furi_string_cat_printf( + output, + "ATQA: %02X %02X\n", + gen4->config.data_parsed.atqa[0], + gen4->config.data_parsed.atqa[1]); + + // SAK + furi_string_cat_printf(output, "SAK: %02X\n", gen4->config.data_parsed.sak); + + // Blocks + furi_string_cat_printf( + output, + "Total blocks: %u", + gen4->config.data_parsed.total_blocks + 1); // config stores the number of the last block + + widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(output)); + + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + nfc_magic_scene_gen4_show_info_widget_callback, + instance); + + furi_string_free(output); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget); +} + +bool nfc_magic_scene_gen4_show_info_on_event(void* context, SceneManagerEvent event) { + NfcMagicApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowCfg); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneGen4Menu); + } + return consumed; +} + +void nfc_magic_scene_gen4_show_info_on_exit(void* context) { + NfcMagicApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c b/nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c deleted file mode 100644 index 74b525ff..00000000 --- a/nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "../nfc_magic_app_i.h" - -#define REVISION_SIZE (5) - -void nfc_magic_scene_gen4_show_rev_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcMagicApp* instance = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(instance->view_dispatcher, result); - } -} - -void nfc_magic_scene_gen4_show_rev_on_enter(void* context) { - NfcMagicApp* instance = context; - Widget* widget = instance->widget; - - notification_message(instance->notifications, &sequence_success); - - FuriString* temp_revision = furi_string_alloc(); - for(size_t i = REVISION_SIZE - 2; i < REVISION_SIZE; i++) { - furi_string_cat_printf(temp_revision, "%02X ", instance->gen4_revision_display[i]); - } - - widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); - widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Revision"); - widget_add_string_multiline_element( - widget, 3, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_revision)); - widget_add_button_element( - widget, GuiButtonTypeLeft, "Exit", nfc_magic_scene_gen4_show_rev_widget_callback, instance); - - furi_string_free(temp_revision); - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget); -} - -bool nfc_magic_scene_gen4_show_rev_on_event(void* context, SceneManagerEvent event) { - NfcMagicApp* instance = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, NfcMagicSceneGen4ActionsMenu); - } - } - return consumed; -} - -void nfc_magic_scene_gen4_show_rev_on_exit(void* context) { - NfcMagicApp* instance = context; - - widget_reset(instance->widget); -} diff --git a/nfc_magic/scenes/nfc_magic_scene_key_input.c b/nfc_magic/scenes/nfc_magic_scene_key_input.c index 7fa79a4e..dfc56227 100644 --- a/nfc_magic/scenes/nfc_magic_scene_key_input.c +++ b/nfc_magic/scenes/nfc_magic_scene_key_input.c @@ -1,7 +1,5 @@ #include "../nfc_magic_app_i.h" -#include - void nfc_magic_scene_key_input_byte_input_callback(void* context) { NfcMagicApp* instance = context; @@ -31,13 +29,16 @@ bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcMagicAppCustomEventByteInputDone) { + // TODO: NEED TEST if(scene_manager_has_previous_scene(instance->scene_manager, NfcMagicSceneGen4Menu)) { - instance->gen4_password_new = bit_lib_bytes_to_num_be( - instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE); + memcpy( + instance->gen4_password_new.bytes, + instance->byte_input_store, + GEN4_PASSWORD_LEN); scene_manager_next_scene(instance->scene_manager, NfcMagicSceneChangeKey); } else { - instance->gen4_password = bit_lib_bytes_to_num_be( - instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE); + memcpy( + instance->gen4_password.bytes, instance->byte_input_store, GEN4_PASSWORD_LEN); scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck); } consumed = true; diff --git a/nfc_magic/scenes/nfc_magic_scene_magic_info.c b/nfc_magic/scenes/nfc_magic_scene_magic_info.c index d26e8dff..ca4320e7 100644 --- a/nfc_magic/scenes/nfc_magic_scene_magic_info.c +++ b/nfc_magic/scenes/nfc_magic_scene_magic_info.c @@ -1,4 +1,5 @@ #include "../nfc_magic_app_i.h" +#include "magic/nfc_magic_scanner.h" void nfc_magic_scene_magic_info_widget_callback( GuiButtonType result, @@ -31,6 +32,28 @@ void nfc_magic_scene_magic_info_on_enter(void* context) { message, "Magic Type: %s", nfc_magic_protocols_get_name(instance->protocol)); widget_add_text_box_element( widget, 0, 10, 128, 54, AlignLeft, AlignTop, furi_string_get_cstr(message), false); + + if(instance->protocol == NfcMagicProtocolGen4) { + gen4_copy(instance->gen4_data, nfc_magic_scanner_get_gen4_data(instance->scanner)); + + furi_string_printf( + message, + "Revision: %02X %02X\n", + instance->gen4_data->revision.data[3], + instance->gen4_data->revision.data[4]); + + widget_add_string_element( + widget, 0, 20, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(message)); + + furi_string_printf( + message, + "Configured As %s", + gen4_get_configuration_name(&instance->gen4_data->config)); + + widget_add_string_multiline_element( + widget, 0, 30, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(message)); + } + widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, instance); widget_add_button_element( @@ -63,6 +86,9 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event) consumed = true; } } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneStart); } return consumed; } diff --git a/nfc_magic/scenes/nfc_magic_scene_not_magic.c b/nfc_magic/scenes/nfc_magic_scene_not_magic.c index 8baf7240..2cc22710 100644 --- a/nfc_magic/scenes/nfc_magic_scene_not_magic.c +++ b/nfc_magic/scenes/nfc_magic_scene_not_magic.c @@ -38,6 +38,9 @@ bool nfc_magic_scene_not_magic_on_event(void* context, SceneManagerEvent event) if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(instance->scene_manager); } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneStart); } return consumed; } diff --git a/nfc_magic/scenes/nfc_magic_scene_start.c b/nfc_magic/scenes/nfc_magic_scene_start.c index 92212989..e37a62be 100644 --- a/nfc_magic/scenes/nfc_magic_scene_start.c +++ b/nfc_magic/scenes/nfc_magic_scene_start.c @@ -27,7 +27,7 @@ void nfc_magic_scene_start_on_enter(void* context) { nfc_magic_scene_start_submenu_callback, instance); - instance->gen4_password = 0; + gen4_password_reset(&instance->gen4_password); submenu_set_selected_item( submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneStart)); diff --git a/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/nfc_magic/scenes/nfc_magic_scene_wrong_card.c index 74c14ace..d0f08d65 100644 --- a/nfc_magic/scenes/nfc_magic_scene_wrong_card.c +++ b/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -42,6 +42,9 @@ bool nfc_magic_scene_wrong_card_on_event(void* context, SceneManagerEvent event) if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(instance->scene_manager); } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcMagicSceneStart); } return consumed; }