Merge branch 'master' of github.com:RfidResearchGroup/proxmark3

This commit is contained in:
iceman1001 2025-03-19 08:57:28 +01:00
commit 0de915e189

View file

@ -44,14 +44,14 @@
#define DPRINTF_DEBUG(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel >= DBG_DEBUG )) { Dbprintf x ; } } while (0); #define DPRINTF_DEBUG(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel >= DBG_DEBUG )) { Dbprintf x ; } } while (0);
#define DPRINTF_EXTENDED(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel >= DBG_EXTENDED)) { Dbprintf x ; } } while (0); #define DPRINTF_EXTENDED(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel >= DBG_EXTENDED)) { Dbprintf x ; } } while (0);
#define DPRINTF_PROLIX(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel > DBG_EXTENDED)) { Dbprintf x ; } } while (0); #define DPRINTF_PROLIX(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel > DBG_EXTENDED)) { Dbprintf x ; } } while (0);
static em4x70_tag_t tag = { 0 };
// EM4170 requires a parity bit on commands, other variants do not. // EM4170 requires a parity bit on commands, other variants do not.
static bool command_parity = true; static bool g_command_parity = true;
static em4x70_tag_t g_tag = { 0 };
#if 1 // Calculation of ticks for timing functions #if 1 // Calculation of ticks for timing functions
// Conversion from Ticks to RF periods // Nearly every calculation is done in terms of Field Codes (FC) aka RF periods
// 1 us = 1.5 ticks // 1 us = 1.5 ticks
// 1RF Period = 8us = 12 Ticks // 1RF Period = 8us = 12 Ticks
#define TICKS_PER_FC 12 #define TICKS_PER_FC 12
@ -71,10 +71,13 @@ static bool command_parity = true;
#define EM4X70_T_TAG_TOLERANCE (8 * TICKS_PER_FC) // Tolerance in RF periods for receive/LIW #define EM4X70_T_TAG_TOLERANCE (8 * TICKS_PER_FC) // Tolerance in RF periods for receive/LIW
#define EM4X70_T_TAG_TIMEOUT (4 * EM4X70_T_TAG_FULL_PERIOD) // Timeout if we ever get a pulse longer than this #define EM4X70_T_TAG_TIMEOUT (4 * EM4X70_T_TAG_FULL_PERIOD) // Timeout if we ever get a pulse longer than this
#define EM4X70_T_WAITING_FOR_LIW 50 // Pulses to wait for listen window
#define EM4X70_T_READ_HEADER_LEN 16 // Read header length (16 bit periods)
#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command #define EM4X70_T_DELAY_FROM_LIW_TO_RM (72 * TICKS_PER_FC) // Default delay from finding LIW until start sending RM bits
#define EM4X70_T_PULSES_TO_SEARCH_FOR_LIW 50 // Pulses to wait for listen window
#define EM4X70_T_PULSES_TO_SEARCH_FOR_HEADER_TRANSITION 16 // Read header length (16 bit periods), wait that many pulses to find transition from the 12x `1` to 4x `0`
#define EM4X70_COMMAND_LIW_SEARCH_RETRIES 5 // Attempts to send/read command
#define EM4X70_MAX_SEND_BITCOUNT 96u // Authentication == CMD(4) + NONCE(56) + DIVERGENCY(7) + FRND(28) == 6 + 56 + 35 == 56 + 41 == 95 bits (NOTE: RM(2) is handled as part of LIW detection) #define EM4X70_MAX_SEND_BITCOUNT 96u // Authentication == CMD(4) + NONCE(56) + DIVERGENCY(7) + FRND(28) == 6 + 56 + 35 == 56 + 41 == 95 bits (NOTE: RM(2) is handled as part of LIW detection)
#define EM4X70_MAX_RECEIVE_BITCOUNT 64u // Maximum bits to receive in response to any command (NOTE: This is EXCLUDING the 16-bit header of 0b1111'1111'1111'0000) #define EM4X70_MAX_RECEIVE_BITCOUNT 64u // Maximum bits to receive in response to any command (NOTE: This is EXCLUDING the 16-bit header of 0b1111'1111'1111'0000)
#endif // Calculation of ticks for timing functions #endif // Calculation of ticks for timing functions
@ -215,7 +218,7 @@ static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read);
static bool find_listen_window(bool command); static bool find_listen_window(bool command);
static void init_tag(void) { static void init_tag(void) {
memset(tag.data, 0x00, sizeof(tag.data)); memset(g_tag.data, 0x00, sizeof(g_tag.data));
} }
static void em4x70_setup_read(void) { static void em4x70_setup_read(void) {
@ -572,7 +575,7 @@ static void bitstream_dump(const em4x70_command_bitstream_t *cmd_bitstream) {
/// @return /// @return
static bool send_bitstream_internal(const em4x70_bitstream_t *send) { static bool send_bitstream_internal(const em4x70_bitstream_t *send) {
// similar to original send_command_and_read, but using provided bitstream // similar to original send_command_and_read, but using provided bitstream
int retries = EM4X70_COMMAND_RETRIES; int retries = EM4X70_COMMAND_LIW_SEARCH_RETRIES; // only retries finding the LIW ... not the actual command
// TIMING SENSITIVE FUNCTION ... Minimize delays after finding the listen window // TIMING SENSITIVE FUNCTION ... Minimize delays after finding the listen window
while (retries) { while (retries) {
@ -902,7 +905,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_ID; out_cmd_bitstream->command = EM4X70_COMMAND_ID;
uint8_t cmd = with_command_parity ? 0x3u : 0x1u; //uint8_t cmd = with_command_parity ? 0x3u : 0x1u;
uint8_t cmd = 0x3u;
result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false);
out_cmd_bitstream->to_receive.bitcount = 32; out_cmd_bitstream->to_receive.bitcount = 32;
if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) {
@ -916,7 +920,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_UM1; out_cmd_bitstream->command = EM4X70_COMMAND_UM1;
uint8_t cmd = with_command_parity ? 0x5u : 0x2u; //uint8_t cmd = with_command_parity ? 0x5u : 0x2u;
uint8_t cmd = 0x5u;
result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false);
out_cmd_bitstream->to_receive.bitcount = 32; out_cmd_bitstream->to_receive.bitcount = 32;
if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) {
@ -930,7 +935,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_
bool result = true; bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_UM2; out_cmd_bitstream->command = EM4X70_COMMAND_UM2;
uint8_t cmd = with_command_parity ? 0xFu : 0x7u; //uint8_t cmd = with_command_parity ? 0xFu : 0x7u;
uint8_t cmd = 0xFu;
result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false);
out_cmd_bitstream->to_receive.bitcount = 64; out_cmd_bitstream->to_receive.bitcount = 64;
if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) {
@ -948,11 +954,6 @@ static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream
em4x70_bitstream_t *s = &out_cmd_bitstream->to_send; em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior
// *********************************************************************************
result = result && add_bit_to_bitstream(s, 0);
// uint8_t cmd = with_command_parity ? 0x6u : 0x3u; // uint8_t cmd = with_command_parity ? 0x6u : 0x3u;
uint8_t cmd = 0x6u; // HACK - always sent with cmd parity uint8_t cmd = 0x6u; // HACK - always sent with cmd parity
result = result && add_nibble_to_bitstream(s, cmd, false); result = result && add_nibble_to_bitstream(s, cmd, false);
@ -1003,11 +1004,6 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_
out_cmd_bitstream->command = EM4X70_COMMAND_PIN; out_cmd_bitstream->command = EM4X70_COMMAND_PIN;
// *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior
// *********************************************************************************
result = result && add_bit_to_bitstream(s, 0);
//uint8_t cmd = with_command_parity ? 0x9u : 0x4u; //uint8_t cmd = with_command_parity ? 0x9u : 0x4u;
uint8_t cmd = 0x9u; // HACK - always sent with cmd parity, with extra zero bit in RM? uint8_t cmd = 0x9u; // HACK - always sent with cmd parity, with extra zero bit in RM?
result = result && add_nibble_to_bitstream(s, cmd, false); result = result && add_nibble_to_bitstream(s, cmd, false);
@ -1041,11 +1037,6 @@ static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstrea
em4x70_bitstream_t *s = &out_cmd_bitstream->to_send; em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior
// *********************************************************************************
result = result && add_bit_to_bitstream(s, 0);
//uint8_t cmd = with_command_parity ? 0xAu : 0x5u; //uint8_t cmd = with_command_parity ? 0xAu : 0x5u;
uint8_t cmd = 0xAu; // HACK - always sent with cmd parity, with extra zero bit in RM? uint8_t cmd = 0xAu; // HACK - always sent with cmd parity, with extra zero bit in RM?
result = result && add_nibble_to_bitstream(s, cmd, false); result = result && add_nibble_to_bitstream(s, cmd, false);
@ -1106,7 +1097,7 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
em4x70_command_bitstream_t auth_cmd; em4x70_command_bitstream_t auth_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->auth(&auth_cmd, command_parity, rnd, frnd); generator->auth(&auth_cmd, g_command_parity, rnd, frnd);
bool result = send_bitstream_and_read(&auth_cmd); bool result = send_bitstream_and_read(&auth_cmd);
if (result) { if (result) {
@ -1194,7 +1185,7 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *
static int send_pin(const uint32_t pin) { static int send_pin(const uint32_t pin) {
em4x70_command_bitstream_t send_pin_cmd; em4x70_command_bitstream_t send_pin_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->pin(&send_pin_cmd, command_parity, &tag.data[4], pin); generator->pin(&send_pin_cmd, g_command_parity, &g_tag.data[4], pin);
bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd); bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd);
return result ? PM3_SUCCESS : PM3_ESOFT; return result ? PM3_SUCCESS : PM3_ESOFT;
@ -1205,7 +1196,7 @@ static int write(const uint16_t word, const uint8_t address) {
em4x70_command_bitstream_t write_cmd; em4x70_command_bitstream_t write_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->write(&write_cmd, command_parity, word, address); generator->write(&write_cmd, g_command_parity, word, address);
bool result = send_bitstream_wait_ack_wait_ack(&write_cmd); bool result = send_bitstream_wait_ack_wait_ack(&write_cmd);
if (!result) { if (!result) {
@ -1218,7 +1209,7 @@ static int write(const uint16_t word, const uint8_t address) {
static bool find_listen_window(bool command) { static bool find_listen_window(bool command) {
int cnt = 0; int cnt = 0;
while (cnt < EM4X70_T_WAITING_FOR_LIW) { while (cnt < EM4X70_T_PULSES_TO_SEARCH_FOR_LIW) {
/* /*
80 ( 64 + 16 ) 80 ( 64 + 16 )
80 ( 64 + 16 ) 80 ( 64 + 16 )
@ -1240,7 +1231,7 @@ static bool find_listen_window(bool command) {
* Allow user adjustment in range: 24-48 field cycles? * Allow user adjustment in range: 24-48 field cycles?
* On PM3Easy I've seen success at 24..40 field * On PM3Easy I've seen success at 24..40 field
*/ */
WaitTicks(40 * TICKS_PER_FC); WaitTicks(EM4X70_T_DELAY_FROM_LIW_TO_RM);
// Send RM Command // Send RM Command
em4x70_send_bit(0); em4x70_send_bit(0);
em4x70_send_bit(0); em4x70_send_bit(0);
@ -1292,11 +1283,11 @@ static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits)
static bool em4x70_read_id(void) { static bool em4x70_read_id(void) {
em4x70_command_bitstream_t read_id_cmd; em4x70_command_bitstream_t read_id_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->id(&read_id_cmd, command_parity); generator->id(&read_id_cmd, g_command_parity);
bool result = send_bitstream_and_read(&read_id_cmd); bool result = send_bitstream_and_read(&read_id_cmd);
if (result) { if (result) {
encoded_bit_array_to_bytes(read_id_cmd.to_receive.one_bit_per_byte, read_id_cmd.to_receive.bitcount, &tag.data[4]); encoded_bit_array_to_bytes(read_id_cmd.to_receive.one_bit_per_byte, read_id_cmd.to_receive.bitcount, &g_tag.data[4]);
} }
return result; return result;
} }
@ -1309,11 +1300,11 @@ static bool em4x70_read_id(void) {
static bool em4x70_read_um1(void) { static bool em4x70_read_um1(void) {
em4x70_command_bitstream_t read_um1_cmd; em4x70_command_bitstream_t read_um1_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um1(&read_um1_cmd, command_parity); generator->um1(&read_um1_cmd, g_command_parity);
bool result = send_bitstream_and_read(&read_um1_cmd); bool result = send_bitstream_and_read(&read_um1_cmd);
if (result) { if (result) {
encoded_bit_array_to_bytes(read_um1_cmd.to_receive.one_bit_per_byte, read_um1_cmd.to_receive.bitcount, &tag.data[0]); encoded_bit_array_to_bytes(read_um1_cmd.to_receive.one_bit_per_byte, read_um1_cmd.to_receive.bitcount, &g_tag.data[0]);
} }
bitstream_dump(&read_um1_cmd); bitstream_dump(&read_um1_cmd);
@ -1328,11 +1319,11 @@ static bool em4x70_read_um1(void) {
static bool em4x70_read_um2(void) { static bool em4x70_read_um2(void) {
em4x70_command_bitstream_t read_um2_cmd; em4x70_command_bitstream_t read_um2_cmd;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um2(&read_um2_cmd, command_parity); generator->um2(&read_um2_cmd, g_command_parity);
bool result = send_bitstream_and_read(&read_um2_cmd); bool result = send_bitstream_and_read(&read_um2_cmd);
if (result) { if (result) {
encoded_bit_array_to_bytes(read_um2_cmd.to_receive.one_bit_per_byte, read_um2_cmd.to_receive.bitcount, &tag.data[24]); encoded_bit_array_to_bytes(read_um2_cmd.to_receive.one_bit_per_byte, read_um2_cmd.to_receive.bitcount, &g_tag.data[24]);
} }
@ -1361,7 +1352,7 @@ static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read) {
WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD); WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD);
// wait until we get the transition from 1's to 0's which is 1.5 full windows // wait until we get the transition from 1's to 0's which is 1.5 full windows
for (int i = 0; i < EM4X70_T_READ_HEADER_LEN; i++) { for (int i = 0; i < EM4X70_T_PULSES_TO_SEARCH_FOR_HEADER_TRANSITION; i++) {
pl = get_pulse_length(edge); pl = get_pulse_length(edge);
if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) {
foundheader = true; foundheader = true;
@ -1444,7 +1435,7 @@ void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) {
bool success_with_UM2 = false; bool success_with_UM2 = false;
// Support tags with and without command parity bits // Support tags with and without command parity bits
command_parity = etd->parity; g_command_parity = etd->parity;
init_tag(); init_tag();
em4x70_setup_read(); em4x70_setup_read();
@ -1466,16 +1457,16 @@ void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) {
0; 0;
// not returning the data to the client about actual length read? // not returning the data to the client about actual length read?
reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, data_size); reply_ng(CMD_LF_EM4X70_INFO, status, g_tag.data, data_size);
} }
void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) { void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
int status = PM3_ESOFT; int status = PM3_ESOFT;
command_parity = etd->parity; g_command_parity = etd->parity;
// Disable to prevent sending corrupted data to the tag. // Disable to prevent sending corrupted data to the tag.
if (command_parity) { if (g_command_parity) {
DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 write` is non-functional and may corrupt data on the tag.")); DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 write` is non-functional and may corrupt data on the tag."));
// reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
// return; // return;
@ -1501,14 +1492,14 @@ void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
StopTicks(); StopTicks();
lf_finalize(ledcontrol); lf_finalize(ledcontrol);
reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data)); reply_ng(CMD_LF_EM4X70_WRITE, status, g_tag.data, sizeof(g_tag.data));
} }
void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) { void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
int status = PM3_ESOFT; int status = PM3_ESOFT;
command_parity = etd->parity; g_command_parity = etd->parity;
init_tag(); init_tag();
em4x70_setup_read(); em4x70_setup_read();
@ -1534,7 +1525,7 @@ void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
StopTicks(); StopTicks();
lf_finalize(ledcontrol); lf_finalize(ledcontrol);
reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data)); reply_ng(CMD_LF_EM4X70_UNLOCK, status, g_tag.data, sizeof(g_tag.data));
} }
void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) { void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
@ -1543,10 +1534,10 @@ void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
uint8_t response[3] = {0}; uint8_t response[3] = {0};
command_parity = etd->parity; g_command_parity = etd->parity;
// Disable to prevent sending corrupted data to the tag. // Disable to prevent sending corrupted data to the tag.
if (command_parity) { if (g_command_parity) {
DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 auth` is non-functional.")); DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 auth` is non-functional."));
// reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
// return; // return;
@ -1571,10 +1562,10 @@ void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) {
int status = PM3_ESOFT; int status = PM3_ESOFT;
uint8_t response[2] = {0}; uint8_t response[2] = {0};
command_parity = etd->parity; g_command_parity = etd->parity;
// Disable to prevent sending corrupted data to the tag. // Disable to prevent sending corrupted data to the tag.
if (command_parity) { if (g_command_parity) {
DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 brute` is non-functional and may corrupt data on the tag.")); DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 brute` is non-functional and may corrupt data on the tag."));
// reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
// return; // return;
@ -1599,10 +1590,10 @@ void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
int status = PM3_ESOFT; int status = PM3_ESOFT;
command_parity = etd->parity; g_command_parity = etd->parity;
// Disable to prevent sending corrupted data to the tag. // Disable to prevent sending corrupted data to the tag.
if (command_parity) { if (g_command_parity) {
DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setpin` is non-functional and may corrupt data on the tag.")); DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setpin` is non-functional and may corrupt data on the tag."));
// reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
// return; // return;
@ -1641,17 +1632,17 @@ void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
StopTicks(); StopTicks();
lf_finalize(ledcontrol); lf_finalize(ledcontrol);
reply_ng(CMD_LF_EM4X70_SETPIN, status, tag.data, sizeof(tag.data)); reply_ng(CMD_LF_EM4X70_SETPIN, status, g_tag.data, sizeof(g_tag.data));
} }
void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) { void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) {
int status = PM3_ESOFT; int status = PM3_ESOFT;
command_parity = etd->parity; g_command_parity = etd->parity;
// Disable to prevent sending corrupted data to the tag. // Disable to prevent sending corrupted data to the tag.
if (command_parity) { if (g_command_parity) {
DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setkey` is non-functional and may corrupt data on the tag.")); DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setkey` is non-functional and may corrupt data on the tag."));
// reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0);
// return; // return;
@ -1688,5 +1679,5 @@ void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) {
StopTicks(); StopTicks();
lf_finalize(ledcontrol); lf_finalize(ledcontrol);
reply_ng(CMD_LF_EM4X70_SETKEY, status, tag.data, sizeof(tag.data)); reply_ng(CMD_LF_EM4X70_SETKEY, status, g_tag.data, sizeof(g_tag.data));
} }