NFC: Add support for Gen4 "ultimate card" in Magic app (#2238)
* NFC: gen4 gtu detect in magic app * NFC: more support for GTU card * NFC: Fix Gen1 in Magic * Allow double UIDs for MFClassic on GTU cards * NFC: Small magic app tweaks * nfc magic: notify card event on wiping * nfc magic: fix power consumption * nfc magic: disable i2c writing and fix wipe loop * NfcMagic: correct formatting in printf * NfcMagic: correct formatting in printf, proper version * nfc_magic: rework card found notification and gen4 wiping Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
77bb997b0b
commit
490447bbd4
175
applications/external/nfc_magic/lib/magic/classic_gen1.c
vendored
Normal file
175
applications/external/nfc_magic/lib/magic/classic_gen1.c
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
#include "classic_gen1.h"
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
#define TAG "Magic"
|
||||
|
||||
#define MAGIC_CMD_WUPA (0x40)
|
||||
#define MAGIC_CMD_WIPE (0x41)
|
||||
#define MAGIC_CMD_ACCESS (0x43)
|
||||
|
||||
#define MAGIC_MIFARE_READ_CMD (0x30)
|
||||
#define MAGIC_MIFARE_WRITE_CMD (0xA0)
|
||||
|
||||
#define MAGIC_ACK (0x0A)
|
||||
|
||||
#define MAGIC_BUFFER_SIZE (32)
|
||||
|
||||
bool magic_gen1_wupa() {
|
||||
bool magic_activated = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_WUPA;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
7,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON |
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnIncompleteByte) break;
|
||||
if(rx_len != 4) break;
|
||||
if(rx_data[0] != MAGIC_ACK) break;
|
||||
magic_activated = true;
|
||||
} while(false);
|
||||
|
||||
return magic_activated;
|
||||
}
|
||||
|
||||
bool magic_gen1_data_access_cmd() {
|
||||
bool write_cmd_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
tx_data[0] = MAGIC_CMD_ACCESS;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
8,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON |
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnIncompleteByte) break;
|
||||
if(rx_len != 4) break;
|
||||
if(rx_data[0] != MAGIC_ACK) break;
|
||||
|
||||
write_cmd_success = true;
|
||||
} while(false);
|
||||
|
||||
return write_cmd_success;
|
||||
}
|
||||
|
||||
bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) {
|
||||
furi_assert(data);
|
||||
|
||||
bool read_success = false;
|
||||
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
tx_data[0] = MAGIC_MIFARE_READ_CMD;
|
||||
tx_data[1] = block_num;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
2 * 8,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
if(rx_len != 16 * 8) break;
|
||||
memcpy(data->value, rx_data, sizeof(data->value));
|
||||
read_success = true;
|
||||
} while(false);
|
||||
|
||||
return read_success;
|
||||
}
|
||||
|
||||
bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) {
|
||||
furi_assert(data);
|
||||
|
||||
bool write_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
tx_data[0] = MAGIC_MIFARE_WRITE_CMD;
|
||||
tx_data[1] = block_num;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
2 * 8,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnIncompleteByte) break;
|
||||
if(rx_len != 4) break;
|
||||
if(rx_data[0] != MAGIC_ACK) break;
|
||||
|
||||
memcpy(tx_data, data->value, sizeof(data->value));
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
16 * 8,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnIncompleteByte) break;
|
||||
if(rx_len != 4) break;
|
||||
if(rx_data[0] != MAGIC_ACK) break;
|
||||
|
||||
write_success = true;
|
||||
} while(false);
|
||||
|
||||
return write_success;
|
||||
}
|
||||
|
||||
bool magic_gen1_wipe() {
|
||||
bool wipe_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
tx_data[0] = MAGIC_CMD_WIPE;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
8,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON |
|
||||
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
|
||||
furi_hal_nfc_ll_ms2fc(2000));
|
||||
|
||||
if(ret != FuriHalNfcReturnIncompleteByte) break;
|
||||
if(rx_len != 4) break;
|
||||
if(rx_data[0] != MAGIC_ACK) break;
|
||||
|
||||
wipe_success = true;
|
||||
} while(false);
|
||||
|
||||
return wipe_success;
|
||||
}
|
||||
13
applications/external/nfc_magic/lib/magic/classic_gen1.h
vendored
Normal file
13
applications/external/nfc_magic/lib/magic/classic_gen1.h
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/mifare_classic.h>
|
||||
|
||||
bool magic_gen1_wupa();
|
||||
|
||||
bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data);
|
||||
|
||||
bool magic_gen1_data_access_cmd();
|
||||
|
||||
bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data);
|
||||
|
||||
bool magic_gen1_wipe();
|
||||
33
applications/external/nfc_magic/lib/magic/common.c
vendored
Normal file
33
applications/external/nfc_magic/lib/magic/common.c
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
#define REQA (0x26)
|
||||
#define CL1_PREFIX (0x93)
|
||||
#define SELECT (0x70)
|
||||
|
||||
#define MAGIC_BUFFER_SIZE (32)
|
||||
|
||||
bool magic_activate() {
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
// Setup nfc poller
|
||||
furi_hal_nfc_exit_sleep();
|
||||
furi_hal_nfc_ll_txrx_on();
|
||||
furi_hal_nfc_ll_poll();
|
||||
ret = furi_hal_nfc_ll_set_mode(
|
||||
FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106);
|
||||
if(ret != FuriHalNfcReturnOk) return false;
|
||||
|
||||
furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER);
|
||||
furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER);
|
||||
furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc);
|
||||
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void magic_deactivate() {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_sleep();
|
||||
}
|
||||
19
applications/external/nfc_magic/lib/magic/common.h
vendored
Normal file
19
applications/external/nfc_magic/lib/magic/common.h
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
MagicTypeClassicGen1,
|
||||
MagicTypeClassicDirectWrite,
|
||||
MagicTypeClassicAPDU,
|
||||
MagicTypeUltralightGen1,
|
||||
MagicTypeUltralightDirectWrite,
|
||||
MagicTypeUltralightC_Gen1,
|
||||
MagicTypeUltralightC_DirectWrite,
|
||||
MagicTypeGen4,
|
||||
} MagicType;
|
||||
|
||||
bool magic_activate();
|
||||
|
||||
void magic_deactivate();
|
||||
199
applications/external/nfc_magic/lib/magic/gen4.c
vendored
Normal file
199
applications/external/nfc_magic/lib/magic/gen4.c
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
#include "gen4.h"
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TAG "Magic"
|
||||
|
||||
#define MAGIC_CMD_PREFIX (0xCF)
|
||||
|
||||
#define MAGIC_CMD_GET_CFG (0xC6)
|
||||
#define MAGIC_CMD_WRITE (0xCD)
|
||||
#define MAGIC_CMD_READ (0xCE)
|
||||
#define MAGIC_CMD_SET_CFG (0xF0)
|
||||
#define MAGIC_CMD_FUSE_CFG (0xF1)
|
||||
#define MAGIC_CMD_SET_PWD (0xFE)
|
||||
|
||||
#define MAGIC_BUFFER_SIZE (40)
|
||||
|
||||
const uint8_t MAGIC_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
|
||||
};
|
||||
|
||||
const uint8_t MAGIC_DEFAULT_BLOCK0[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const uint8_t MAGIC_EMPTY_BLOCK[16] = { 0 };
|
||||
|
||||
const uint8_t MAGIC_DEFAULT_SECTOR_TRAILER[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
static bool magic_gen4_is_block_num_trailer(uint8_t n) {
|
||||
n++;
|
||||
if (n < 32 * 4) {
|
||||
return (n % 4 == 0);
|
||||
}
|
||||
|
||||
return (n % 16 == 0);
|
||||
}
|
||||
|
||||
bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config) {
|
||||
bool is_valid_config_len = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_PREFIX;
|
||||
tx_data[1] = (uint8_t)(pwd >> 24);
|
||||
tx_data[2] = (uint8_t)(pwd >> 16);
|
||||
tx_data[3] = (uint8_t)(pwd >> 8);
|
||||
tx_data[4] = (uint8_t)pwd;
|
||||
tx_data[5] = MAGIC_CMD_GET_CFG;
|
||||
ret = furi_hal_nfc_ll_txrx(
|
||||
tx_data,
|
||||
6,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_TXRX_DEFAULT,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
if(rx_len != 30 && rx_len != 32) break;
|
||||
memcpy(config, rx_data, rx_len);
|
||||
is_valid_config_len = true;
|
||||
} while(false);
|
||||
|
||||
return is_valid_config_len;
|
||||
}
|
||||
|
||||
bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse) {
|
||||
bool write_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_PREFIX;
|
||||
tx_data[1] = (uint8_t)(pwd >> 24);
|
||||
tx_data[2] = (uint8_t)(pwd >> 16);
|
||||
tx_data[3] = (uint8_t)(pwd >> 8);
|
||||
tx_data[4] = (uint8_t)pwd;
|
||||
tx_data[5] = fuse ? MAGIC_CMD_FUSE_CFG : MAGIC_CMD_SET_CFG;
|
||||
memcpy(tx_data + 6, config, config_length);
|
||||
ret = furi_hal_nfc_ll_txrx(
|
||||
tx_data,
|
||||
6 + config_length,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_TXRX_DEFAULT,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
if(rx_len != 2) break;
|
||||
write_success = true;
|
||||
} while(false);
|
||||
|
||||
return write_success;
|
||||
}
|
||||
|
||||
bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd) {
|
||||
bool change_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_PREFIX;
|
||||
tx_data[1] = (uint8_t)(old_pwd >> 24);
|
||||
tx_data[2] = (uint8_t)(old_pwd >> 16);
|
||||
tx_data[3] = (uint8_t)(old_pwd >> 8);
|
||||
tx_data[4] = (uint8_t)old_pwd;
|
||||
tx_data[5] = MAGIC_CMD_SET_PWD;
|
||||
tx_data[6] = (uint8_t)(new_pwd >> 24);
|
||||
tx_data[7] = (uint8_t)(new_pwd >> 16);
|
||||
tx_data[8] = (uint8_t)(new_pwd >> 8);
|
||||
tx_data[9] = (uint8_t)new_pwd;
|
||||
ret = furi_hal_nfc_ll_txrx(
|
||||
tx_data,
|
||||
10,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_TXRX_DEFAULT,
|
||||
furi_hal_nfc_ll_ms2fc(20));
|
||||
FURI_LOG_I(TAG, "ret %d, len %d", ret, rx_len);
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
if(rx_len != 2) break;
|
||||
change_success = true;
|
||||
} while(false);
|
||||
|
||||
return change_success;
|
||||
}
|
||||
|
||||
bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data) {
|
||||
bool write_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint16_t rx_len = 0;
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_PREFIX;
|
||||
tx_data[1] = (uint8_t)(pwd >> 24);
|
||||
tx_data[2] = (uint8_t)(pwd >> 16);
|
||||
tx_data[3] = (uint8_t)(pwd >> 8);
|
||||
tx_data[4] = (uint8_t)pwd;
|
||||
tx_data[5] = MAGIC_CMD_WRITE;
|
||||
tx_data[6] = block_num;
|
||||
memcpy(tx_data + 7, data, 16);
|
||||
ret = furi_hal_nfc_ll_txrx(
|
||||
tx_data,
|
||||
23,
|
||||
rx_data,
|
||||
sizeof(rx_data),
|
||||
&rx_len,
|
||||
FURI_HAL_NFC_TXRX_DEFAULT,
|
||||
furi_hal_nfc_ll_ms2fc(200));
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
if(rx_len != 2) break;
|
||||
write_success = true;
|
||||
} while(false);
|
||||
|
||||
return write_success;
|
||||
}
|
||||
|
||||
bool magic_gen4_wipe(uint32_t pwd) {
|
||||
if(!magic_gen4_set_cfg(pwd, MAGIC_DEFAULT_CONFIG, sizeof(MAGIC_DEFAULT_CONFIG), false)) {
|
||||
FURI_LOG_E(TAG, "Set config failed");
|
||||
return false;
|
||||
}
|
||||
if(!magic_gen4_write_blk(pwd, 0, MAGIC_DEFAULT_BLOCK0)) {
|
||||
FURI_LOG_E(TAG, "Block 0 write failed");
|
||||
return false;
|
||||
}
|
||||
for(size_t i = 1; i < 64; i++) {
|
||||
const uint8_t* block = magic_gen4_is_block_num_trailer(i) ? MAGIC_DEFAULT_SECTOR_TRAILER : MAGIC_EMPTY_BLOCK;
|
||||
if(!magic_gen4_write_blk(pwd, i, block)) {
|
||||
FURI_LOG_E(TAG, "Block %d write failed", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for(size_t i = 65; i < 256; i++) {
|
||||
if(!magic_gen4_write_blk(pwd, i, MAGIC_EMPTY_BLOCK)) {
|
||||
FURI_LOG_E(TAG, "Block %d write failed", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
48
applications/external/nfc_magic/lib/magic/gen4.h
vendored
Normal file
48
applications/external/nfc_magic/lib/magic/gen4.h
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/mifare_classic.h>
|
||||
|
||||
#define MAGIC_GEN4_DEFAULT_PWD 0x00000000
|
||||
#define MAGIC_GEN4_CONFIG_LEN 32
|
||||
|
||||
#define NFCID1_SINGLE_SIZE 4
|
||||
#define NFCID1_DOUBLE_SIZE 7
|
||||
#define NFCID1_TRIPLE_SIZE 10
|
||||
|
||||
typedef enum {
|
||||
MagicGen4UIDLengthSingle = 0x00,
|
||||
MagicGen4UIDLengthDouble = 0x01,
|
||||
MagicGen4UIDLengthTriple = 0x02
|
||||
} MagicGen4UIDLength;
|
||||
|
||||
typedef enum {
|
||||
MagicGen4UltralightModeUL_EV1 = 0x00,
|
||||
MagicGen4UltralightModeNTAG = 0x01,
|
||||
MagicGen4UltralightModeUL_C = 0x02,
|
||||
MagicGen4UltralightModeUL = 0x03
|
||||
} MagicGen4UltralightMode;
|
||||
|
||||
typedef enum {
|
||||
// for writing original (shadow) data
|
||||
MagicGen4ShadowModePreWrite = 0x00,
|
||||
// written data can be read once before restored to original
|
||||
MagicGen4ShadowModeRestore = 0x01,
|
||||
// written data is discarded
|
||||
MagicGen4ShadowModeIgnore = 0x02,
|
||||
// apparently for UL?
|
||||
MagicGen4ShadowModeHighSpeedIgnore = 0x03
|
||||
} MagicGen4ShadowMode;
|
||||
|
||||
bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config);
|
||||
|
||||
bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse);
|
||||
|
||||
bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd);
|
||||
|
||||
bool magic_gen4_read_blk(uint32_t pwd, uint8_t block_num, uint8_t* data);
|
||||
|
||||
bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data);
|
||||
|
||||
bool magic_gen4_wipe(uint32_t pwd);
|
||||
|
||||
void magic_gen4_deactivate();
|
||||
@ -1,4 +1,4 @@
|
||||
#include "magic.h"
|
||||
#include "classic_gen1.h"
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
#define MAGIC_BUFFER_SIZE (32)
|
||||
|
||||
bool magic_wupa() {
|
||||
bool magic_gen1_wupa() {
|
||||
bool magic_activated = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
@ -23,19 +23,6 @@ bool magic_wupa() {
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
// Setup nfc poller
|
||||
furi_hal_nfc_exit_sleep();
|
||||
furi_hal_nfc_ll_txrx_on();
|
||||
furi_hal_nfc_ll_poll();
|
||||
ret = furi_hal_nfc_ll_set_mode(
|
||||
FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106);
|
||||
if(ret != FuriHalNfcReturnOk) break;
|
||||
|
||||
furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER);
|
||||
furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER);
|
||||
furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc);
|
||||
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA);
|
||||
|
||||
// Start communication
|
||||
tx_data[0] = MAGIC_CMD_WUPA;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
@ -53,15 +40,10 @@ bool magic_wupa() {
|
||||
magic_activated = true;
|
||||
} while(false);
|
||||
|
||||
if(!magic_activated) {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
return magic_activated;
|
||||
}
|
||||
|
||||
bool magic_data_access_cmd() {
|
||||
bool magic_gen1_data_access_cmd() {
|
||||
bool write_cmd_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
@ -86,15 +68,10 @@ bool magic_data_access_cmd() {
|
||||
write_cmd_success = true;
|
||||
} while(false);
|
||||
|
||||
if(!write_cmd_success) {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
return write_cmd_success;
|
||||
}
|
||||
|
||||
bool magic_read_block(uint8_t block_num, MfClassicBlock* data) {
|
||||
bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) {
|
||||
furi_assert(data);
|
||||
|
||||
bool read_success = false;
|
||||
@ -122,15 +99,10 @@ bool magic_read_block(uint8_t block_num, MfClassicBlock* data) {
|
||||
read_success = true;
|
||||
} while(false);
|
||||
|
||||
if(!read_success) {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
return read_success;
|
||||
}
|
||||
|
||||
bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) {
|
||||
bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) {
|
||||
furi_assert(data);
|
||||
|
||||
bool write_success = false;
|
||||
@ -170,15 +142,10 @@ bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) {
|
||||
write_success = true;
|
||||
} while(false);
|
||||
|
||||
if(!write_success) {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
return write_success;
|
||||
}
|
||||
|
||||
bool magic_wipe() {
|
||||
bool magic_gen1_wipe() {
|
||||
bool wipe_success = false;
|
||||
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
|
||||
@ -206,8 +173,3 @@ bool magic_wipe() {
|
||||
|
||||
return wipe_success;
|
||||
}
|
||||
|
||||
void magic_deactivate() {
|
||||
furi_hal_nfc_ll_txrx_off();
|
||||
furi_hal_nfc_sleep();
|
||||
}
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/mifare_classic.h>
|
||||
|
||||
bool magic_wupa();
|
||||
|
||||
bool magic_read_block(uint8_t block_num, MfClassicBlock* data);
|
||||
|
||||
bool magic_data_access_cmd();
|
||||
|
||||
bool magic_write_blk(uint8_t block_num, MfClassicBlock* data);
|
||||
|
||||
bool magic_wipe();
|
||||
|
||||
void magic_deactivate();
|
||||
23
applications/external/nfc_magic/lib/magic/types.c
vendored
Normal file
23
applications/external/nfc_magic/lib/magic/types.c
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#include "types.h"
|
||||
|
||||
const char* nfc_magic_type(MagicType type) {
|
||||
if(type == MagicTypeClassicGen1) {
|
||||
return "Classic Gen 1A/B";
|
||||
} else if(type == MagicTypeClassicDirectWrite) {
|
||||
return "Classic DirectWrite";
|
||||
} else if(type == MagicTypeClassicAPDU) {
|
||||
return "Classic APDU";
|
||||
} else if(type == MagicTypeUltralightGen1) {
|
||||
return "Ultralight Gen 1";
|
||||
} else if(type == MagicTypeUltralightDirectWrite) {
|
||||
return "Ultralight DirectWrite";
|
||||
} else if(type == MagicTypeUltralightC_Gen1) {
|
||||
return "Ultralight-C Gen 1";
|
||||
} else if(type == MagicTypeUltralightC_DirectWrite) {
|
||||
return "Ultralight-C DirectWrite";
|
||||
} else if(type == MagicTypeGen4) {
|
||||
return "Gen 4 GTU";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
5
applications/external/nfc_magic/lib/magic/types.h
vendored
Normal file
5
applications/external/nfc_magic/lib/magic/types.h
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
const char* nfc_magic_type(MagicType type);
|
||||
22
applications/external/nfc_magic/nfc_magic.c
vendored
22
applications/external/nfc_magic/nfc_magic.c
vendored
@ -48,8 +48,9 @@ NfcMagic* nfc_magic_alloc() {
|
||||
nfc_magic->view_dispatcher, nfc_magic_tick_event_callback, 100);
|
||||
|
||||
// Nfc device
|
||||
nfc_magic->nfc_dev = nfc_device_alloc();
|
||||
furi_string_set(nfc_magic->nfc_dev->folder, NFC_APP_FOLDER);
|
||||
nfc_magic->dev = malloc(sizeof(NfcMagicDevice));
|
||||
nfc_magic->source_dev = nfc_device_alloc();
|
||||
furi_string_set(nfc_magic->source_dev->folder, NFC_APP_FOLDER);
|
||||
|
||||
// Open GUI record
|
||||
nfc_magic->gui = furi_record_open(RECORD_GUI);
|
||||
@ -81,6 +82,13 @@ NfcMagic* nfc_magic_alloc() {
|
||||
NfcMagicViewTextInput,
|
||||
text_input_get_view(nfc_magic->text_input));
|
||||
|
||||
// Byte Input
|
||||
nfc_magic->byte_input = byte_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
nfc_magic->view_dispatcher,
|
||||
NfcMagicViewByteInput,
|
||||
byte_input_get_view(nfc_magic->byte_input));
|
||||
|
||||
// Custom Widget
|
||||
nfc_magic->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@ -93,7 +101,8 @@ void nfc_magic_free(NfcMagic* nfc_magic) {
|
||||
furi_assert(nfc_magic);
|
||||
|
||||
// Nfc device
|
||||
nfc_device_free(nfc_magic->nfc_dev);
|
||||
free(nfc_magic->dev);
|
||||
nfc_device_free(nfc_magic->source_dev);
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
|
||||
@ -107,10 +116,14 @@ void nfc_magic_free(NfcMagic* nfc_magic) {
|
||||
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewLoading);
|
||||
loading_free(nfc_magic->loading);
|
||||
|
||||
// TextInput
|
||||
// Text Input
|
||||
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewTextInput);
|
||||
text_input_free(nfc_magic->text_input);
|
||||
|
||||
// Byte Input
|
||||
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
|
||||
byte_input_free(nfc_magic->byte_input);
|
||||
|
||||
// Custom Widget
|
||||
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
|
||||
widget_free(nfc_magic->widget);
|
||||
@ -164,6 +177,7 @@ int32_t nfc_magic_app(void* p) {
|
||||
|
||||
view_dispatcher_run(nfc_magic->view_dispatcher);
|
||||
|
||||
magic_deactivate();
|
||||
nfc_magic_free(nfc_magic);
|
||||
|
||||
return 0;
|
||||
|
||||
2
applications/external/nfc_magic/nfc_magic.h
vendored
2
applications/external/nfc_magic/nfc_magic.h
vendored
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct NfcMagicDevice NfcMagicDevice;
|
||||
|
||||
typedef struct NfcMagic NfcMagic;
|
||||
|
||||
20
applications/external/nfc_magic/nfc_magic_i.h
vendored
20
applications/external/nfc_magic/nfc_magic_i.h
vendored
@ -3,7 +3,10 @@
|
||||
#include "nfc_magic.h"
|
||||
#include "nfc_magic_worker.h"
|
||||
|
||||
#include "lib/magic/magic.h"
|
||||
#include "lib/magic/common.h"
|
||||
#include "lib/magic/types.h"
|
||||
#include "lib/magic/classic_gen1.h"
|
||||
#include "lib/magic/gen4.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
@ -15,6 +18,7 @@
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include <input/input.h>
|
||||
@ -39,14 +43,22 @@ enum NfcMagicCustomEvent {
|
||||
NfcMagicCustomEventTextInputDone,
|
||||
};
|
||||
|
||||
struct NfcMagicDevice {
|
||||
MagicType type;
|
||||
uint32_t cuid;
|
||||
uint32_t password;
|
||||
};
|
||||
|
||||
struct NfcMagic {
|
||||
NfcMagicWorker* worker;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
NotificationApp* notifications;
|
||||
SceneManager* scene_manager;
|
||||
// NfcMagicDevice* dev;
|
||||
NfcDevice* nfc_dev;
|
||||
struct NfcMagicDevice* dev;
|
||||
NfcDevice* source_dev;
|
||||
|
||||
uint32_t new_password;
|
||||
|
||||
FuriString* text_box_store;
|
||||
|
||||
@ -55,6 +67,7 @@ struct NfcMagic {
|
||||
Popup* popup;
|
||||
Loading* loading;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
Widget* widget;
|
||||
};
|
||||
|
||||
@ -63,6 +76,7 @@ typedef enum {
|
||||
NfcMagicViewPopup,
|
||||
NfcMagicViewLoading,
|
||||
NfcMagicViewTextInput,
|
||||
NfcMagicViewByteInput,
|
||||
NfcMagicViewWidget,
|
||||
} NfcMagicView;
|
||||
|
||||
|
||||
372
applications/external/nfc_magic/nfc_magic_worker.c
vendored
372
applications/external/nfc_magic/nfc_magic_worker.c
vendored
@ -1,6 +1,9 @@
|
||||
#include "nfc_magic_worker_i.h"
|
||||
|
||||
#include "lib/magic/magic.h"
|
||||
#include "nfc_magic_i.h"
|
||||
#include "lib/magic/common.h"
|
||||
#include "lib/magic/classic_gen1.h"
|
||||
#include "lib/magic/gen4.h"
|
||||
|
||||
#define TAG "NfcMagicWorker"
|
||||
|
||||
@ -43,15 +46,20 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker) {
|
||||
void nfc_magic_worker_start(
|
||||
NfcMagicWorker* nfc_magic_worker,
|
||||
NfcMagicWorkerState state,
|
||||
NfcMagicDevice* magic_dev,
|
||||
NfcDeviceData* dev_data,
|
||||
uint32_t new_password,
|
||||
NfcMagicWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_assert(nfc_magic_worker);
|
||||
furi_assert(magic_dev);
|
||||
furi_assert(dev_data);
|
||||
|
||||
nfc_magic_worker->callback = callback;
|
||||
nfc_magic_worker->context = context;
|
||||
nfc_magic_worker->magic_dev = magic_dev;
|
||||
nfc_magic_worker->dev_data = dev_data;
|
||||
nfc_magic_worker->new_password = new_password;
|
||||
nfc_magic_worker_change_state(nfc_magic_worker, state);
|
||||
furi_thread_start(nfc_magic_worker->thread);
|
||||
}
|
||||
@ -63,6 +71,8 @@ int32_t nfc_magic_worker_task(void* context) {
|
||||
nfc_magic_worker_check(nfc_magic_worker);
|
||||
} else if(nfc_magic_worker->state == NfcMagicWorkerStateWrite) {
|
||||
nfc_magic_worker_write(nfc_magic_worker);
|
||||
} else if(nfc_magic_worker->state == NfcMagicWorkerStateRekey) {
|
||||
nfc_magic_worker_rekey(nfc_magic_worker);
|
||||
} else if(nfc_magic_worker->state == NfcMagicWorkerStateWipe) {
|
||||
nfc_magic_worker_wipe(nfc_magic_worker);
|
||||
}
|
||||
@ -74,59 +84,245 @@ int32_t nfc_magic_worker_task(void* context) {
|
||||
|
||||
void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) {
|
||||
bool card_found_notified = false;
|
||||
bool done = false;
|
||||
FuriHalNfcDevData nfc_data = {};
|
||||
MfClassicData* src_data = &nfc_magic_worker->dev_data->mf_classic_data;
|
||||
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
|
||||
NfcDeviceData* dev_data = nfc_magic_worker->dev_data;
|
||||
NfcProtocol dev_protocol = dev_data->protocol;
|
||||
|
||||
while(nfc_magic_worker->state == NfcMagicWorkerStateWrite) {
|
||||
if(furi_hal_nfc_detect(&nfc_data, 200)) {
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
if(!magic_wupa()) {
|
||||
FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
break;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
}
|
||||
if(magic_wupa()) {
|
||||
if(!magic_data_access_cmd()) {
|
||||
FURI_LOG_E(TAG, "No card response to data access command (not a magic card)");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
break;
|
||||
}
|
||||
for(size_t i = 0; i < 64; i++) {
|
||||
FURI_LOG_D(TAG, "Writing block %d", i);
|
||||
if(!magic_write_blk(i, &src_data->block[i])) {
|
||||
FURI_LOG_E(TAG, "Failed to write %d block", i);
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
do {
|
||||
if(furi_hal_nfc_detect(&nfc_data, 200)) {
|
||||
if(nfc_data.cuid != magic_dev->cuid) break;
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
|
||||
magic_activate();
|
||||
if(magic_dev->type == MagicTypeClassicGen1) {
|
||||
if(dev_protocol != NfcDeviceProtocolMifareClassic) break;
|
||||
MfClassicData* mfc_data = &dev_data->mf_classic_data;
|
||||
|
||||
if(mfc_data->type != MfClassicType1k) break;
|
||||
if(!magic_gen1_wupa()) {
|
||||
FURI_LOG_E(TAG, "Not Magic card");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
if(!magic_gen1_data_access_cmd()) {
|
||||
FURI_LOG_E(TAG, "Not Magic card");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
for(size_t i = 0; i < 64; i++) {
|
||||
FURI_LOG_D(TAG, "Writing block %d", i);
|
||||
if(!magic_gen1_write_blk(i, &mfc_data->block[i])) {
|
||||
FURI_LOG_E(TAG, "Failed to write %d block", i);
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
} else if(magic_dev->type == MagicTypeGen4) {
|
||||
uint8_t gen4_config[28];
|
||||
uint32_t password = magic_dev->password;
|
||||
|
||||
uint32_t cuid;
|
||||
if(dev_protocol == NfcDeviceProtocolMifareClassic) {
|
||||
gen4_config[0] = 0x00;
|
||||
gen4_config[27] = 0x00;
|
||||
} else if(dev_protocol == NfcDeviceProtocolMifareUl) {
|
||||
MfUltralightData* mf_ul_data = &dev_data->mf_ul_data;
|
||||
gen4_config[0] = 0x01;
|
||||
switch(mf_ul_data->type) {
|
||||
case MfUltralightTypeUL11:
|
||||
case MfUltralightTypeUL21:
|
||||
// UL-C?
|
||||
// UL?
|
||||
default:
|
||||
gen4_config[27] = MagicGen4UltralightModeUL_EV1;
|
||||
break;
|
||||
case MfUltralightTypeNTAG203:
|
||||
case MfUltralightTypeNTAG213:
|
||||
case MfUltralightTypeNTAG215:
|
||||
case MfUltralightTypeNTAG216:
|
||||
case MfUltralightTypeNTAGI2C1K:
|
||||
case MfUltralightTypeNTAGI2C2K:
|
||||
case MfUltralightTypeNTAGI2CPlus1K:
|
||||
case MfUltralightTypeNTAGI2CPlus2K:
|
||||
gen4_config[27] = MagicGen4UltralightModeNTAG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dev_data->nfc_data.uid_len == 4) {
|
||||
gen4_config[1] = MagicGen4UIDLengthSingle;
|
||||
} else if(dev_data->nfc_data.uid_len == 7) {
|
||||
gen4_config[1] = MagicGen4UIDLengthDouble;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unexpected UID length %d", dev_data->nfc_data.uid_len);
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
gen4_config[2] = (uint8_t)(password >> 24);
|
||||
gen4_config[3] = (uint8_t)(password >> 16);
|
||||
gen4_config[4] = (uint8_t)(password >> 8);
|
||||
gen4_config[5] = (uint8_t)password;
|
||||
|
||||
if(dev_protocol == NfcDeviceProtocolMifareUl) {
|
||||
gen4_config[6] = MagicGen4ShadowModeHighSpeedIgnore;
|
||||
} else {
|
||||
gen4_config[6] = MagicGen4ShadowModeIgnore;
|
||||
}
|
||||
gen4_config[7] = 0x00;
|
||||
memset(gen4_config + 8, 0, 16);
|
||||
gen4_config[24] = dev_data->nfc_data.atqa[0];
|
||||
gen4_config[25] = dev_data->nfc_data.atqa[1];
|
||||
gen4_config[26] = dev_data->nfc_data.sak;
|
||||
|
||||
furi_hal_nfc_activate_nfca(200, &cuid);
|
||||
if(!magic_gen4_set_cfg(password, gen4_config, sizeof(gen4_config), false)) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
if(dev_protocol == NfcDeviceProtocolMifareClassic) {
|
||||
MfClassicData* mfc_data = &dev_data->mf_classic_data;
|
||||
size_t block_count = 64;
|
||||
if(mfc_data->type == MfClassicType4k) block_count = 256;
|
||||
for(size_t i = 0; i < block_count; i++) {
|
||||
FURI_LOG_D(TAG, "Writing block %d", i);
|
||||
if(!magic_gen4_write_blk(password, i, mfc_data->block[i].value)) {
|
||||
FURI_LOG_E(TAG, "Failed to write %d block", i);
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(dev_protocol == NfcDeviceProtocolMifareUl) {
|
||||
MfUltralightData* mf_ul_data = &dev_data->mf_ul_data;
|
||||
for(size_t i = 0; (i * 4) < mf_ul_data->data_read; i++) {
|
||||
size_t data_offset = i * 4;
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Writing page %zu (%zu/%u)",
|
||||
i,
|
||||
data_offset,
|
||||
mf_ul_data->data_read);
|
||||
uint8_t* block = mf_ul_data->data + data_offset;
|
||||
if(!magic_gen4_write_blk(password, i, block)) {
|
||||
FURI_LOG_E(TAG, "Failed to write %zu page", i);
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t buffer[16] = {0};
|
||||
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
memcpy(buffer, &mf_ul_data->signature[i * 4], 4); //-V1086
|
||||
if(!magic_gen4_write_blk(password, 0xF2 + i, buffer)) {
|
||||
FURI_LOG_E(TAG, "Failed to write signature block %d", i);
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[0] = mf_ul_data->version.header;
|
||||
buffer[1] = mf_ul_data->version.vendor_id;
|
||||
buffer[2] = mf_ul_data->version.prod_type;
|
||||
buffer[3] = mf_ul_data->version.prod_subtype;
|
||||
if(!magic_gen4_write_blk(password, 0xFA, buffer)) {
|
||||
FURI_LOG_E(TAG, "Failed to write version block 0");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[0] = mf_ul_data->version.prod_ver_major;
|
||||
buffer[1] = mf_ul_data->version.prod_ver_minor;
|
||||
buffer[2] = mf_ul_data->version.storage_size;
|
||||
buffer[3] = mf_ul_data->version.protocol_type;
|
||||
if(!magic_gen4_write_blk(password, 0xFB, buffer)) {
|
||||
FURI_LOG_E(TAG, "Failed to write version block 1");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventFail, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
break;
|
||||
} else {
|
||||
if(card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(done) break;
|
||||
|
||||
if(card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
|
||||
furi_delay_ms(300);
|
||||
}
|
||||
magic_deactivate();
|
||||
}
|
||||
|
||||
void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) {
|
||||
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
|
||||
bool card_found_notified = false;
|
||||
uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN];
|
||||
|
||||
while(nfc_magic_worker->state == NfcMagicWorkerStateCheck) {
|
||||
if(magic_wupa()) {
|
||||
magic_activate();
|
||||
if(magic_gen1_wupa()) {
|
||||
magic_dev->type = MagicTypeClassicGen1;
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
}
|
||||
|
||||
furi_hal_nfc_activate_nfca(200, &magic_dev->cuid);
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
break;
|
||||
}
|
||||
|
||||
magic_deactivate();
|
||||
furi_delay_ms(300);
|
||||
magic_activate();
|
||||
|
||||
furi_hal_nfc_activate_nfca(200, &magic_dev->cuid);
|
||||
if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) {
|
||||
magic_dev->type = MagicTypeGen4;
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
@ -135,12 +331,56 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) {
|
||||
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
|
||||
if(card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
|
||||
magic_deactivate();
|
||||
furi_delay_ms(300);
|
||||
}
|
||||
|
||||
magic_deactivate();
|
||||
}
|
||||
|
||||
void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker) {
|
||||
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
|
||||
bool card_found_notified = false;
|
||||
|
||||
if(magic_dev->type != MagicTypeGen4) {
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
return;
|
||||
}
|
||||
|
||||
while(nfc_magic_worker->state == NfcMagicWorkerStateRekey) {
|
||||
magic_activate();
|
||||
uint32_t cuid;
|
||||
furi_hal_nfc_activate_nfca(200, &cuid);
|
||||
if(cuid != magic_dev->cuid) {
|
||||
if(card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
|
||||
if(magic_gen4_set_pwd(magic_dev->password, nfc_magic_worker->new_password)) {
|
||||
magic_dev->password = nfc_magic_worker->new_password;
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
break;
|
||||
}
|
||||
|
||||
if(card_found_notified) { //-V547
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
furi_delay_ms(300);
|
||||
}
|
||||
@ -148,6 +388,10 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) {
|
||||
}
|
||||
|
||||
void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) {
|
||||
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
|
||||
bool card_found_notified = false;
|
||||
bool card_wiped = false;
|
||||
|
||||
MfClassicBlock block;
|
||||
memset(&block, 0, sizeof(MfClassicBlock));
|
||||
block.value[0] = 0x01;
|
||||
@ -159,14 +403,48 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) {
|
||||
block.value[6] = 0x04;
|
||||
|
||||
while(nfc_magic_worker->state == NfcMagicWorkerStateWipe) {
|
||||
magic_deactivate();
|
||||
furi_delay_ms(300);
|
||||
if(!magic_wupa()) continue;
|
||||
if(!magic_wipe()) continue;
|
||||
if(!magic_data_access_cmd()) continue;
|
||||
if(!magic_write_blk(0, &block)) continue;
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
break;
|
||||
do {
|
||||
magic_deactivate();
|
||||
furi_delay_ms(300);
|
||||
if(!magic_activate()) break;
|
||||
if(magic_dev->type == MagicTypeClassicGen1) {
|
||||
if(!magic_gen1_wupa()) break;
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
}
|
||||
|
||||
if(!magic_gen1_wipe()) break;
|
||||
if(!magic_gen1_data_access_cmd()) break;
|
||||
if(!magic_gen1_write_blk(0, &block)) break;
|
||||
|
||||
card_wiped = true;
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
} else if(magic_dev->type == MagicTypeGen4) {
|
||||
uint32_t cuid;
|
||||
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
|
||||
if(cuid != magic_dev->cuid) break;
|
||||
if(!card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = true;
|
||||
}
|
||||
|
||||
if(!magic_gen4_wipe(magic_dev->password)) break;
|
||||
|
||||
card_wiped = true;
|
||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(card_wiped) break;
|
||||
|
||||
if(card_found_notified) {
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
|
||||
card_found_notified = false;
|
||||
}
|
||||
}
|
||||
magic_deactivate();
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/nfc_device.h>
|
||||
#include "nfc_magic.h"
|
||||
|
||||
typedef struct NfcMagicWorker NfcMagicWorker;
|
||||
|
||||
@ -9,6 +10,7 @@ typedef enum {
|
||||
|
||||
NfcMagicWorkerStateCheck,
|
||||
NfcMagicWorkerStateWrite,
|
||||
NfcMagicWorkerStateRekey,
|
||||
NfcMagicWorkerStateWipe,
|
||||
|
||||
NfcMagicWorkerStateStop,
|
||||
@ -33,6 +35,8 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker);
|
||||
void nfc_magic_worker_start(
|
||||
NfcMagicWorker* nfc_magic_worker,
|
||||
NfcMagicWorkerState state,
|
||||
NfcMagicDevice* magic_dev,
|
||||
NfcDeviceData* dev_data,
|
||||
uint32_t new_password,
|
||||
NfcMagicWorkerCallback callback,
|
||||
void* context);
|
||||
|
||||
@ -3,11 +3,14 @@
|
||||
#include <furi.h>
|
||||
|
||||
#include "nfc_magic_worker.h"
|
||||
#include "lib/magic/common.h"
|
||||
|
||||
struct NfcMagicWorker {
|
||||
FuriThread* thread;
|
||||
|
||||
NfcMagicDevice* magic_dev;
|
||||
NfcDeviceData* dev_data;
|
||||
uint32_t new_password;
|
||||
|
||||
NfcMagicWorkerCallback callback;
|
||||
void* context;
|
||||
@ -21,4 +24,6 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker);
|
||||
|
||||
void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker);
|
||||
|
||||
void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker);
|
||||
|
||||
void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker);
|
||||
|
||||
50
applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c
vendored
Normal file
50
applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexWipe,
|
||||
};
|
||||
|
||||
void nfc_magic_scene_actions_submenu_callback(void* context, uint32_t index) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_magic_scene_actions_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
Submenu* submenu = nfc_magic->submenu;
|
||||
submenu_add_item(
|
||||
submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_actions_submenu_callback, nfc_magic);
|
||||
submenu_add_item(
|
||||
submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_actions_submenu_callback, nfc_magic);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions));
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_actions_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexWrite) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexWipe) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions, event.event);
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_actions_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
submenu_reset(nfc_magic->submenu);
|
||||
}
|
||||
@ -42,7 +42,9 @@ void nfc_magic_scene_check_on_enter(void* context) {
|
||||
nfc_magic_worker_start(
|
||||
nfc_magic->worker,
|
||||
NfcMagicWorkerStateCheck,
|
||||
&nfc_magic->nfc_dev->dev_data,
|
||||
nfc_magic->dev,
|
||||
&nfc_magic->source_dev->dev_data,
|
||||
nfc_magic->new_password,
|
||||
nfc_magic_check_worker_callback,
|
||||
nfc_magic);
|
||||
nfc_magic_blink_start(nfc_magic);
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
ADD_SCENE(nfc_magic, start, Start)
|
||||
ADD_SCENE(nfc_magic, key_input, KeyInput)
|
||||
ADD_SCENE(nfc_magic, actions, Actions)
|
||||
ADD_SCENE(nfc_magic, gen4_actions, Gen4Actions)
|
||||
ADD_SCENE(nfc_magic, new_key_input, NewKeyInput)
|
||||
ADD_SCENE(nfc_magic, file_select, FileSelect)
|
||||
ADD_SCENE(nfc_magic, write_confirm, WriteConfirm)
|
||||
ADD_SCENE(nfc_magic, wrong_card, WrongCard)
|
||||
@ -8,5 +12,7 @@ ADD_SCENE(nfc_magic, success, Success)
|
||||
ADD_SCENE(nfc_magic, check, Check)
|
||||
ADD_SCENE(nfc_magic, not_magic, NotMagic)
|
||||
ADD_SCENE(nfc_magic, magic_info, MagicInfo)
|
||||
ADD_SCENE(nfc_magic, rekey, Rekey)
|
||||
ADD_SCENE(nfc_magic, rekey_fail, RekeyFail)
|
||||
ADD_SCENE(nfc_magic, wipe, Wipe)
|
||||
ADD_SCENE(nfc_magic, wipe_fail, WipeFail)
|
||||
|
||||
@ -1,22 +1,60 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
|
||||
static bool nfc_magic_scene_file_select_is_file_suitable(NfcDevice* nfc_dev) {
|
||||
return (nfc_dev->format == NfcDeviceSaveFormatMifareClassic) &&
|
||||
(nfc_dev->dev_data.mf_classic_data.type == MfClassicType1k) &&
|
||||
(nfc_dev->dev_data.nfc_data.uid_len == 4);
|
||||
static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) {
|
||||
NfcDevice* nfc_dev = nfc_magic->source_dev;
|
||||
if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
switch(nfc_magic->dev->type) {
|
||||
case MagicTypeClassicGen1:
|
||||
case MagicTypeClassicDirectWrite:
|
||||
case MagicTypeClassicAPDU:
|
||||
if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) ||
|
||||
(nfc_dev->dev_data.nfc_data.uid_len != 4)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case MagicTypeGen4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if(
|
||||
(nfc_dev->format == NfcDeviceSaveFormatMifareUl) &&
|
||||
(nfc_dev->dev_data.nfc_data.uid_len == 7)) {
|
||||
switch(nfc_magic->dev->type) {
|
||||
case MagicTypeUltralightGen1:
|
||||
case MagicTypeUltralightDirectWrite:
|
||||
case MagicTypeUltralightC_Gen1:
|
||||
case MagicTypeUltralightC_DirectWrite:
|
||||
case MagicTypeGen4:
|
||||
switch(nfc_dev->dev_data.mf_ul_data.type) {
|
||||
case MfUltralightTypeNTAGI2C1K:
|
||||
case MfUltralightTypeNTAGI2C2K:
|
||||
case MfUltralightTypeNTAGI2CPlus1K:
|
||||
case MfUltralightTypeNTAGI2CPlus2K:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_file_select_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
// Process file_select return
|
||||
nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic);
|
||||
nfc_device_set_loading_callback(
|
||||
nfc_magic->source_dev, nfc_magic_show_loading_popup, nfc_magic);
|
||||
|
||||
if(!furi_string_size(nfc_magic->nfc_dev->load_path)) {
|
||||
furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER);
|
||||
if(!furi_string_size(nfc_magic->source_dev->load_path)) {
|
||||
furi_string_set_str(nfc_magic->source_dev->load_path, NFC_APP_FOLDER);
|
||||
}
|
||||
|
||||
if(nfc_file_select(nfc_magic->nfc_dev)) {
|
||||
if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) {
|
||||
if(nfc_file_select(nfc_magic->source_dev)) {
|
||||
if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic)) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrongCard);
|
||||
@ -34,5 +72,5 @@ bool nfc_magic_scene_file_select_on_event(void* context, SceneManagerEvent event
|
||||
|
||||
void nfc_magic_scene_file_select_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
nfc_device_set_loading_callback(nfc_magic->nfc_dev, NULL, nfc_magic);
|
||||
nfc_device_set_loading_callback(nfc_magic->source_dev, NULL, nfc_magic);
|
||||
}
|
||||
|
||||
70
applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c
vendored
Normal file
70
applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexChangePassword,
|
||||
SubmenuIndexWipe,
|
||||
};
|
||||
|
||||
void nfc_magic_scene_gen4_actions_submenu_callback(void* context, uint32_t index) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_magic_scene_gen4_actions_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
Submenu* submenu = nfc_magic->submenu;
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Write",
|
||||
SubmenuIndexWrite,
|
||||
nfc_magic_scene_gen4_actions_submenu_callback,
|
||||
nfc_magic);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Change password",
|
||||
SubmenuIndexChangePassword,
|
||||
nfc_magic_scene_gen4_actions_submenu_callback,
|
||||
nfc_magic);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Wipe",
|
||||
SubmenuIndexWipe,
|
||||
nfc_magic_scene_gen4_actions_submenu_callback,
|
||||
nfc_magic);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu,
|
||||
scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneGen4Actions));
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_gen4_actions_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexWrite) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexChangePassword) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNewKeyInput);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexWipe) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneGen4Actions, event.event);
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_gen4_actions_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
submenu_reset(nfc_magic->submenu);
|
||||
}
|
||||
45
applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c
vendored
Normal file
45
applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
|
||||
void nfc_magic_scene_key_input_byte_input_callback(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_magic_scene_key_input_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = nfc_magic->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter the password in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_magic_scene_key_input_byte_input_callback,
|
||||
NULL,
|
||||
nfc_magic,
|
||||
(uint8_t*)&nfc_magic->dev->password,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcMagicCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_key_input_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(nfc_magic->byte_input, "");
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
#include "../lib/magic/types.h"
|
||||
|
||||
void nfc_magic_scene_magic_info_widget_callback(
|
||||
GuiButtonType result,
|
||||
@ -13,14 +14,18 @@ void nfc_magic_scene_magic_info_widget_callback(
|
||||
void nfc_magic_scene_magic_info_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
Widget* widget = nfc_magic->widget;
|
||||
const char* card_type = nfc_magic_type(nfc_magic->dev->type);
|
||||
|
||||
notification_message(nfc_magic->notifications, &sequence_success);
|
||||
|
||||
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
|
||||
widget_add_string_element(
|
||||
widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Magic card detected");
|
||||
widget_add_string_element(widget, 3, 17, AlignLeft, AlignTop, FontSecondary, card_type);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, nfc_magic);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeRight, "More", nfc_magic_scene_magic_info_widget_callback, nfc_magic);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
|
||||
@ -33,6 +38,15 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event)
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
MagicType type = nfc_magic->dev->type;
|
||||
if(type == MagicTypeGen4) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneGen4Actions);
|
||||
consumed = true;
|
||||
} else {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneActions);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
|
||||
45
applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c
vendored
Normal file
45
applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
|
||||
void nfc_magic_scene_new_key_input_byte_input_callback(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_magic_scene_new_key_input_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = nfc_magic->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter the password in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_magic_scene_new_key_input_byte_input_callback,
|
||||
NULL,
|
||||
nfc_magic,
|
||||
(uint8_t*)&nfc_magic->new_password,
|
||||
4);
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_new_key_input_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcMagicCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekey);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_new_key_input_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(nfc_magic->byte_input, "");
|
||||
}
|
||||
95
applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c
vendored
Normal file
95
applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
|
||||
enum {
|
||||
NfcMagicSceneRekeyStateCardSearch,
|
||||
NfcMagicSceneRekeyStateCardFound,
|
||||
};
|
||||
|
||||
bool nfc_magic_rekey_worker_callback(NfcMagicWorkerEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
NfcMagic* nfc_magic = context;
|
||||
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nfc_magic_scene_rekey_setup_view(NfcMagic* nfc_magic) {
|
||||
Popup* popup = nfc_magic->popup;
|
||||
popup_reset(popup);
|
||||
uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneRekey);
|
||||
|
||||
if(state == NfcMagicSceneRekeyStateCardSearch) {
|
||||
popup_set_text(
|
||||
nfc_magic->popup,
|
||||
"Apply the\nsame card\nto the back",
|
||||
128,
|
||||
32,
|
||||
AlignRight,
|
||||
AlignCenter);
|
||||
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
} else {
|
||||
popup_set_icon(popup, 12, 23, &I_Loading_24);
|
||||
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
|
||||
}
|
||||
|
||||
void nfc_magic_scene_rekey_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
|
||||
nfc_magic_scene_rekey_setup_view(nfc_magic);
|
||||
|
||||
// Setup and start worker
|
||||
nfc_magic_worker_start(
|
||||
nfc_magic->worker,
|
||||
NfcMagicWorkerStateRekey,
|
||||
nfc_magic->dev,
|
||||
&nfc_magic->source_dev->dev_data,
|
||||
nfc_magic->new_password,
|
||||
nfc_magic_rekey_worker_callback,
|
||||
nfc_magic);
|
||||
nfc_magic_blink_start(nfc_magic);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_rekey_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcMagicWorkerEventSuccess) {
|
||||
nfc_magic->dev->password = nfc_magic->new_password;
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcMagicWorkerEventFail) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekeyFail);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcMagicWorkerEventCardDetected) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardFound);
|
||||
nfc_magic_scene_rekey_setup_view(nfc_magic);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcMagicWorkerEventNoCardDetected) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
|
||||
nfc_magic_scene_rekey_setup_view(nfc_magic);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_rekey_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
nfc_magic_worker_stop(nfc_magic->worker);
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
|
||||
// Clear view
|
||||
popup_reset(nfc_magic->popup);
|
||||
|
||||
nfc_magic_blink_stop(nfc_magic);
|
||||
}
|
||||
50
applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c
vendored
Normal file
50
applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
|
||||
void nfc_magic_scene_rekey_fail_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_magic_scene_rekey_fail_on_enter(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
Widget* widget = nfc_magic->widget;
|
||||
|
||||
notification_message(nfc_magic->notifications, &sequence_error);
|
||||
|
||||
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
|
||||
widget_add_string_element(
|
||||
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Can't change password!");
|
||||
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_rekey_fail_widget_callback, nfc_magic);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_magic_scene_rekey_fail_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_magic_scene_rekey_fail_on_exit(void* context) {
|
||||
NfcMagic* nfc_magic = context;
|
||||
|
||||
widget_reset(nfc_magic->widget);
|
||||
}
|
||||
@ -1,8 +1,7 @@
|
||||
#include "../nfc_magic_i.h"
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexCheck,
|
||||
SubmenuIndexWriteGen1A,
|
||||
SubmenuIndexWipe,
|
||||
SubmenuIndexAuthenticateGen4,
|
||||
};
|
||||
|
||||
void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
@ -22,12 +21,10 @@ void nfc_magic_scene_start_on_enter(void* context) {
|
||||
nfc_magic);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Write Gen1A",
|
||||
SubmenuIndexWriteGen1A,
|
||||
"Authenticate Gen4",
|
||||
SubmenuIndexAuthenticateGen4,
|
||||
nfc_magic_scene_start_submenu_callback,
|
||||
nfc_magic);
|
||||
submenu_add_item(
|
||||
submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_start_submenu_callback, nfc_magic);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart));
|
||||
@ -40,23 +37,13 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexCheck) {
|
||||
nfc_magic->dev->password = MAGIC_GEN4_DEFAULT_PWD;
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexWriteGen1A) {
|
||||
// Explicitly save state in each branch so that the
|
||||
// correct option is reselected if the user cancels
|
||||
// loading a file.
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWriteGen1A);
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexWipe) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWipe);
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAuthenticateGen4) {
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneKeyInput);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,12 @@ static void nfc_magic_scene_wipe_setup_view(NfcMagic* nfc_magic) {
|
||||
if(state == NfcMagicSceneWipeStateCardSearch) {
|
||||
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
popup_set_text(
|
||||
nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter);
|
||||
nfc_magic->popup,
|
||||
"Apply the\nsame card\nto the back",
|
||||
128,
|
||||
32,
|
||||
AlignRight,
|
||||
AlignCenter);
|
||||
} else {
|
||||
popup_set_icon(popup, 12, 23, &I_Loading_24);
|
||||
popup_set_header(popup, "Wiping\nDon't move...", 52, 32, AlignLeft, AlignCenter);
|
||||
@ -42,7 +47,9 @@ void nfc_magic_scene_wipe_on_enter(void* context) {
|
||||
nfc_magic_worker_start(
|
||||
nfc_magic->worker,
|
||||
NfcMagicWorkerStateWipe,
|
||||
&nfc_magic->nfc_dev->dev_data,
|
||||
nfc_magic->dev,
|
||||
&nfc_magic->source_dev->dev_data,
|
||||
nfc_magic->new_password,
|
||||
nfc_magic_wipe_worker_callback,
|
||||
nfc_magic);
|
||||
nfc_magic_blink_start(nfc_magic);
|
||||
|
||||
@ -21,7 +21,12 @@ static void nfc_magic_scene_write_setup_view(NfcMagic* nfc_magic) {
|
||||
|
||||
if(state == NfcMagicSceneWriteStateCardSearch) {
|
||||
popup_set_text(
|
||||
nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter);
|
||||
nfc_magic->popup,
|
||||
"Apply the\nsame card\nto the back",
|
||||
128,
|
||||
32,
|
||||
AlignRight,
|
||||
AlignCenter);
|
||||
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
} else {
|
||||
popup_set_icon(popup, 12, 23, &I_Loading_24);
|
||||
@ -42,7 +47,9 @@ void nfc_magic_scene_write_on_enter(void* context) {
|
||||
nfc_magic_worker_start(
|
||||
nfc_magic->worker,
|
||||
NfcMagicWorkerStateWrite,
|
||||
&nfc_magic->nfc_dev->dev_data,
|
||||
nfc_magic->dev,
|
||||
&nfc_magic->source_dev->dev_data,
|
||||
nfc_magic->new_password,
|
||||
nfc_magic_write_worker_callback,
|
||||
nfc_magic);
|
||||
nfc_magic_blink_start(nfc_magic);
|
||||
|
||||
@ -26,7 +26,7 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) {
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
"Writing is supported\nonly for 4 bytes UID\nMifare Classic 1k");
|
||||
"Writing this file is\nnot supported for\nthis magic card.");
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user