mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-05 20:41:34 -07:00
Add support for polling loop annotations
This commit is contained in:
parent
cd5fb7add7
commit
56336d9d82
4 changed files with 144 additions and 59 deletions
|
@ -36,9 +36,9 @@
|
|||
#include "protocols.h"
|
||||
#include "generator.h"
|
||||
#include "desfire_crypto.h" // UL-C authentication helpers
|
||||
#include "mifare.h" // for iso14a_polling_frame_t structure
|
||||
|
||||
#define MAX_ISO14A_TIMEOUT 524288
|
||||
|
||||
// this timeout is in MS
|
||||
static uint32_t iso14a_timeout;
|
||||
|
||||
|
@ -141,7 +141,7 @@ Default HF 14a config is set to:
|
|||
forcecl3 = 0 (auto)
|
||||
forcerats = 0 (auto)
|
||||
*/
|
||||
static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ;
|
||||
static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0, {{0}, 0, 0, 0} };
|
||||
|
||||
|
||||
// Polling frames and configurations
|
||||
|
@ -166,31 +166,37 @@ struct Crypto1State crypto1_state = {0, 0};
|
|||
|
||||
void printHf14aConfig(void) {
|
||||
DbpString(_CYAN_("HF 14a config"));
|
||||
Dbprintf(" [a] Anticol override.... %s%s%s",
|
||||
Dbprintf(" [a] Anticol override.............. %s%s%s",
|
||||
(hf14aconfig.forceanticol == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forceanticol == 1) ? _RED_("force") " ( always do anticol )" : "",
|
||||
(hf14aconfig.forceanticol == 2) ? _RED_("skip") " ( always skip anticol )" : ""
|
||||
);
|
||||
Dbprintf(" [b] BCC override........ %s%s%s",
|
||||
Dbprintf(" [b] BCC override.................. %s%s%s",
|
||||
(hf14aconfig.forcebcc == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcebcc == 1) ? _RED_("fix") " ( fix bad BCC )" : "",
|
||||
(hf14aconfig.forcebcc == 2) ? _RED_("ignore") " ( ignore bad BCC, always use card BCC )" : ""
|
||||
);
|
||||
Dbprintf(" [2] CL2 override........ %s%s%s",
|
||||
Dbprintf(" [2] CL2 override.................. %s%s%s",
|
||||
(hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcecl2 == 1) ? _RED_("force") " ( always do CL2 )" : "",
|
||||
(hf14aconfig.forcecl2 == 2) ? _RED_("skip") " ( always skip CL2 )" : ""
|
||||
);
|
||||
Dbprintf(" [3] CL3 override........ %s%s%s",
|
||||
Dbprintf(" [3] CL3 override.................. %s%s%s",
|
||||
(hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcecl3 == 1) ? _RED_("force") " ( always do CL3 )" : "",
|
||||
(hf14aconfig.forcecl3 == 2) ? _RED_("skip") " ( always skip CL3 )" : ""
|
||||
);
|
||||
Dbprintf(" [r] RATS override....... %s%s%s",
|
||||
Dbprintf(" [r] RATS override................. %s%s%s",
|
||||
(hf14aconfig.forcerats == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "",
|
||||
(hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : ""
|
||||
);
|
||||
Dbprintf(" [p] Polling loop annotation....... %s %*D",
|
||||
(hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"),
|
||||
hf14aconfig.polling_loop_annotation.frame_length,
|
||||
hf14aconfig.polling_loop_annotation.frame,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,6 +219,13 @@ void setHf14aConfig(const hf14a_config *hc) {
|
|||
hf14aconfig.forcecl3 = hc->forcecl3;
|
||||
if ((hc->forcerats >= 0) && (hc->forcerats <= 2))
|
||||
hf14aconfig.forcerats = hc->forcerats;
|
||||
|
||||
if (hc->polling_loop_annotation.frame_length > 0) {
|
||||
memcpy(&hf14aconfig.polling_loop_annotation, &hc->polling_loop_annotation, sizeof(iso14a_polling_frame_t));
|
||||
} else if (hc->polling_loop_annotation.frame_length < 0) {
|
||||
// Reset if set to empty
|
||||
hf14aconfig.polling_loop_annotation.frame_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
hf14a_config *getHf14aConfig(void) {
|
||||
|
@ -448,7 +461,6 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) {
|
|||
Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit
|
||||
Uart.bitCount = 0;
|
||||
Uart.shiftReg = 0;
|
||||
|
||||
// Every 8 data bytes, store 8 parity bits into a parity byte
|
||||
if ((Uart.len & 0x0007) == 0) { // every 8 data bytes
|
||||
Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits
|
||||
|
@ -592,7 +604,7 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t
|
|||
|
||||
if (Demod.bitCount > 0) { // there are some remaining data bits
|
||||
Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits
|
||||
Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output
|
||||
Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); // and add them to the output
|
||||
Demod.parityBits <<= 1; // add a (void) parity bit
|
||||
Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits
|
||||
Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them
|
||||
|
@ -1421,7 +1433,6 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
|||
// "precompiled" responses.
|
||||
// These exist for speed reasons. There are no time in the anti collision phase to calculate responses.
|
||||
// There are 12 predefined responses with a total of 84 bytes data to transmit.
|
||||
//
|
||||
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
|
||||
// 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits
|
||||
// 85 * 8 + 85 + 12 + 12 + 12 == 801
|
||||
|
@ -2702,16 +2713,37 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_p
|
|||
|
||||
uint32_t save_iso14a_timeout = iso14a_get_timeout();
|
||||
iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer.
|
||||
|
||||
// Create temporary polling parameters structure that might include both standard and custom frames
|
||||
iso14a_polling_parameters_t temp_params;
|
||||
memcpy(&temp_params, polling_parameters, sizeof(iso14a_polling_parameters_t));
|
||||
|
||||
// If we have a custom polling frame annotation, add it to the temporary structure
|
||||
if (hf14aconfig.polling_loop_annotation.frame_length > 0) {
|
||||
// Only add if we have space in the frames array
|
||||
if (temp_params.frame_count < ARRAYLEN(temp_params.frames)) {
|
||||
// Add the custom frame at the end of the frames array
|
||||
memcpy(&temp_params.frames[temp_params.frame_count],
|
||||
&hf14aconfig.polling_loop_annotation,
|
||||
sizeof(iso14a_polling_frame_t));
|
||||
temp_params.frame_count++;
|
||||
}
|
||||
|
||||
// Increase timeout if polling loop annotation is provided, as target may respond slower
|
||||
if (temp_params.extra_timeout == 0) {
|
||||
temp_params.extra_timeout = 250;
|
||||
}
|
||||
}
|
||||
|
||||
bool first_try = true;
|
||||
uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * polling_parameters->frame_count + polling_parameters->extra_timeout;
|
||||
uint32_t start_time = 0;
|
||||
int len;
|
||||
|
||||
uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * temp_params.frame_count + temp_params.extra_timeout;
|
||||
uint32_t start_time = 0;
|
||||
uint8_t current_frame = 0;
|
||||
|
||||
|
||||
// Use the temporary polling parameters
|
||||
do {
|
||||
iso14a_polling_frame_t *frame_parameters = &polling_parameters->frames[current_frame];
|
||||
iso14a_polling_frame_t *frame_parameters = &temp_params.frames[current_frame];
|
||||
|
||||
if (frame_parameters->last_byte_bits == 8) {
|
||||
ReaderTransmit(frame_parameters->frame, frame_parameters->frame_length, NULL);
|
||||
|
@ -2729,12 +2761,11 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_p
|
|||
// We set the start_time here otherwise in some cases we miss the window and only ever try once
|
||||
if (first_try) {
|
||||
start_time = GetTickCount();
|
||||
first_try = false;
|
||||
}
|
||||
|
||||
first_try = false;
|
||||
|
||||
// Go over frame configurations, loop back when we reach the end
|
||||
current_frame = current_frame < (polling_parameters->frame_count - 1) ? current_frame + 1 : 0;
|
||||
current_frame = current_frame < (temp_params.frame_count - 1) ? current_frame + 1 : 0;
|
||||
} while (len == 0 && GetTickCountDelta(start_time) <= retry_timeout);
|
||||
|
||||
iso14a_set_timeout(save_iso14a_timeout);
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include "mifare/desfirecore.h" // desfire context
|
||||
#include "mifare/mifaredefault.h"
|
||||
#include "preferences.h" // get/set device debug level
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
|
||||
static bool g_apdu_in_framing_enable = true;
|
||||
bool Get_apdu_in_framing(void) {
|
||||
|
@ -333,6 +335,15 @@ static int hf_14a_config_example(void) {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip -rats skip"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid --uid 04112233445566"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std"));
|
||||
|
||||
PrintAndLogEx(NORMAL, "\nExamples of polling loop annotations used to enable anticollision on mobile targets:");
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" ECP Express Transit EMV")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a02c801000300027900000000"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" ECP VAS Only")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a01000002"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" ECP Access Wildcard")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a02c3020002ffff"));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int CmdHf14AConfig(const char *Cmd) {
|
||||
|
@ -341,25 +352,26 @@ static int CmdHf14AConfig(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14a config",
|
||||
"Configure 14a settings (use with caution)\n"
|
||||
" `-v` also prints examples for reviving Gen2 cards",
|
||||
"hf 14a config -> Print current configuration\n"
|
||||
"hf 14a config --std -> Reset default configuration (follow standard)\n"
|
||||
"hf 14a config --atqa std -> Follow standard\n"
|
||||
"hf 14a config --atqa force -> Force execution of anticollision\n"
|
||||
"hf 14a config --atqa skip -> Skip anticollision\n"
|
||||
"hf 14a config --bcc std -> Follow standard\n"
|
||||
"hf 14a config --bcc fix -> Fix bad BCC in anticollision\n"
|
||||
"hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n"
|
||||
"hf 14a config --cl2 std -> Follow standard\n"
|
||||
"hf 14a config --cl2 force -> Execute CL2\n"
|
||||
"hf 14a config --cl2 skip -> Skip CL2\n"
|
||||
"hf 14a config --cl3 std -> Follow standard\n"
|
||||
"hf 14a config --cl3 force -> Execute CL3\n"
|
||||
"hf 14a config --cl3 skip -> Skip CL3\n"
|
||||
"hf 14a config --rats std -> Follow standard\n"
|
||||
"hf 14a config --rats force -> Execute RATS\n"
|
||||
"hf 14a config --rats skip -> Skip RATS");
|
||||
|
||||
" `-v` also prints examples for reviving Gen2 cards & configuring polling loop annotations",
|
||||
"hf 14a config -> Print current configuration\n"
|
||||
"hf 14a config --std -> Reset default configuration (follow standard)\n"
|
||||
"hf 14a config --atqa std -> Follow standard\n"
|
||||
"hf 14a config --atqa force -> Force execution of anticollision\n"
|
||||
"hf 14a config --atqa skip -> Skip anticollision\n"
|
||||
"hf 14a config --bcc std -> Follow standard\n"
|
||||
"hf 14a config --bcc fix -> Fix bad BCC in anticollision\n"
|
||||
"hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n"
|
||||
"hf 14a config --cl2 std -> Follow standard\n"
|
||||
"hf 14a config --cl2 force -> Execute CL2\n"
|
||||
"hf 14a config --cl2 skip -> Skip CL2\n"
|
||||
"hf 14a config --cl3 std -> Follow standard\n"
|
||||
"hf 14a config --cl3 force -> Execute CL3\n"
|
||||
"hf 14a config --cl3 skip -> Skip CL3\n"
|
||||
"hf 14a config --rats std -> Follow standard\n"
|
||||
"hf 14a config --rats force -> Execute RATS\n"
|
||||
"hf 14a config --rats skip -> Skip RATS\n"
|
||||
"hf 14a config --pla <hex> -> Set polling loop annotation (max 22 bytes)\n"
|
||||
"hf 14a config --pla skip -> Disable polling loop annotation\n");
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "atqa", "<std|force|skip>", "Configure ATQA<>anticollision behavior"),
|
||||
|
@ -367,14 +379,17 @@ static int CmdHf14AConfig(const char *Cmd) {
|
|||
arg_str0(NULL, "cl2", "<std|force|skip>", "Configure SAK<>CL2 behavior"),
|
||||
arg_str0(NULL, "cl3", "<std|force|skip>", "Configure SAK<>CL3 behavior"),
|
||||
arg_str0(NULL, "rats", "<std|force|skip>", "Configure RATS behavior"),
|
||||
arg_str0(NULL, "pla", "<hex|skip>", "Configure polling loop annotation"),
|
||||
arg_lit0(NULL, "std", "Reset default configuration: follow all standard"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool defaults = arg_get_lit(ctx, 6);
|
||||
bool defaults = arg_get_lit(ctx, 7);
|
||||
bool verbose = arg_get_lit(ctx, 8);
|
||||
|
||||
int vlen = 0;
|
||||
char value[10];
|
||||
char value[64];
|
||||
int atqa = defaults ? 0 : -1;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)value, sizeof(value), &vlen);
|
||||
if (vlen > 0) {
|
||||
|
@ -436,11 +451,43 @@ static int CmdHf14AConfig(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
bool verbose = arg_get_lit(ctx, 7);
|
||||
// Handle polling loop annotation parameter
|
||||
iso14a_polling_frame_t pla = {
|
||||
// -1 signals that PLA has to be disabled, 0 signals that no change has to be made
|
||||
.frame_length = defaults ? -1 : 0,
|
||||
.last_byte_bits = 8,
|
||||
.extra_delay = 5
|
||||
};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)value, sizeof(value), &vlen);
|
||||
if (vlen > 0 && (strncmp((char *)value, "skip", 4) || strncmp((char *)value, "std", 3)) == 0) {
|
||||
pla.frame_length = -1;
|
||||
} else if (vlen > 0) {
|
||||
// Convert hex string to bytes
|
||||
int length = 0;
|
||||
if (param_gethex_to_eol((char *)value, 0, pla.frame, sizeof(pla.frame), &length) != 0) {
|
||||
PrintAndLogEx(ERR, "Error parsing polling loop annotation bytes");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
pla.frame_length = length;
|
||||
|
||||
// Validate length before adding CRC
|
||||
if (pla.frame_length < 1 || pla.frame_length > 22) {
|
||||
PrintAndLogEx(ERR, "Polling loop annotation length invalid: min %d; max %d", 1, 22);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t first, second;
|
||||
compute_crc(CRC_14443_A, pla.frame, pla.frame_length, &first, &second);
|
||||
pla.frame[pla.frame_length++] = first;
|
||||
pla.frame[pla.frame_length++] = second;
|
||||
PrintAndLogEx(INFO, "Added CRC16A to polling loop annotation: %s", sprint_hex(pla.frame, pla.frame_length));
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// validations
|
||||
// Handle empty command
|
||||
if (strlen(Cmd) == 0) {
|
||||
return hf14a_setconfig(NULL, verbose);
|
||||
}
|
||||
|
@ -449,12 +496,14 @@ static int CmdHf14AConfig(const char *Cmd) {
|
|||
hf_14a_config_example();
|
||||
}
|
||||
|
||||
// Initialize config with all parameters
|
||||
hf14a_config config = {
|
||||
.forceanticol = atqa,
|
||||
.forcebcc = bcc,
|
||||
.forcecl2 = cl2,
|
||||
.forcecl3 = cl3,
|
||||
.forcerats = rats
|
||||
.forcerats = rats,
|
||||
.polling_loop_annotation = pla
|
||||
};
|
||||
|
||||
return hf14a_setconfig(&config, verbose);
|
||||
|
|
|
@ -108,23 +108,6 @@ typedef enum ISO14A_COMMAND {
|
|||
ISO14A_CRYPTO1MODE = (1 << 14)
|
||||
} iso14a_command_t;
|
||||
|
||||
// Defines a frame that will be used in a polling sequence
|
||||
// ECP Frames are up to (7 + 16) bytes long, 24 bytes should cover future and other cases
|
||||
typedef struct {
|
||||
uint8_t frame[24];
|
||||
uint8_t frame_length;
|
||||
uint8_t last_byte_bits;
|
||||
uint16_t extra_delay;
|
||||
} PACKED iso14a_polling_frame_t;
|
||||
|
||||
// Defines polling sequence configuration
|
||||
// 6 would be enough for 4 magsafe, 1 wupa, 1 ecp,
|
||||
typedef struct {
|
||||
iso14a_polling_frame_t frames[6];
|
||||
uint8_t frame_count;
|
||||
uint16_t extra_timeout;
|
||||
} PACKED iso14a_polling_parameters_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *response;
|
||||
uint8_t *modulation;
|
||||
|
|
|
@ -131,6 +131,27 @@ typedef struct {
|
|||
bool verbose;
|
||||
} PACKED sample_config;
|
||||
|
||||
|
||||
// Defines a frame that will be used in a polling sequence
|
||||
// Polling loop annotations are up to (7 + 16) bytes long, 24 bytes should cover future and other cases
|
||||
typedef struct {
|
||||
uint8_t frame[24];
|
||||
// negative values can be used to carry special info
|
||||
int8_t frame_length;
|
||||
uint8_t last_byte_bits;
|
||||
uint16_t extra_delay;
|
||||
} PACKED iso14a_polling_frame_t;
|
||||
|
||||
|
||||
// Defines polling sequence configuration
|
||||
// 6 would be enough for 4 magsafe, 1 wupa, 1 pla,
|
||||
typedef struct {
|
||||
iso14a_polling_frame_t frames[6];
|
||||
int8_t frame_count;
|
||||
uint16_t extra_timeout;
|
||||
} PACKED iso14a_polling_parameters_t;
|
||||
|
||||
|
||||
// A struct used to send hf14a-configs over USB
|
||||
typedef struct {
|
||||
int8_t forceanticol; // 0:auto 1:force executing anticol 2:force skipping anticol
|
||||
|
@ -138,6 +159,7 @@ typedef struct {
|
|||
int8_t forcecl2; // 0:auto 1:force executing CL2 2:force skipping CL2
|
||||
int8_t forcecl3; // 0:auto 1:force executing CL3 2:force skipping CL3
|
||||
int8_t forcerats; // 0:auto 1:force executing RATS 2:force skipping RATS
|
||||
iso14a_polling_frame_t polling_loop_annotation; // Polling loop annotation
|
||||
} PACKED hf14a_config;
|
||||
|
||||
// Tracelog Header struct
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue