mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-09-11 18:29:22 -07:00
Refine Innovatron protocol handling
This commit is contained in:
+6
-11
@@ -1925,19 +1925,14 @@ int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type B' / Innovatron APGEN.
|
||||
*/
|
||||
static int iso14443b_select_prime_card(iso14b_prime_card_select_t *card) {
|
||||
uint8_t apgen[] = {
|
||||
ISO14443B_PRIME_VT_ADDR_DEFAULT,
|
||||
ISO14443B_PRIME_CMD_APGEN,
|
||||
// Seems to affect time slots / response chance:
|
||||
// 0x3f card responds every time
|
||||
// 0x3e-0x00 reduced success rate
|
||||
// 0x40-0xff card does not respond
|
||||
0x3f,
|
||||
ISO14443B_PRIME_REQUEST_EXTENDED_REPGEN,
|
||||
// OccuPar 0x3F is the default value used by most readers in real installations.
|
||||
ISO14443B_PRIME_OCCUPAR_DEFAULT,
|
||||
// APGEN Config bit 7 requests the long REPGEN form with CONFIG/ATR.
|
||||
ISO14443B_PRIME_APGEN_CONFIG_REQUEST_ATR,
|
||||
0x00,
|
||||
0x00
|
||||
};
|
||||
@@ -1976,9 +1971,9 @@ static int iso14443b_select_prime_card(iso14b_prime_card_select_t *card) {
|
||||
card->verlog = r_repgen[6];
|
||||
|
||||
uint16_t offset = 7;
|
||||
if ((card->verlog & 0x80) && repgen_len > offset) {
|
||||
if ((card->verlog & ISO14443B_PRIME_VERLOG_LONG_REPGEN) && repgen_len > offset) {
|
||||
card->config = r_repgen[offset++];
|
||||
if ((card->config & 0x40) && repgen_len > offset) {
|
||||
if ((card->config & ISO14443B_PRIME_CONFIG_ATR_PRESENT) && repgen_len > offset) {
|
||||
uint16_t atr_len = repgen_len - offset;
|
||||
if (atr_len >= 2 && r_repgen[repgen_len - 2] == 0x90 && r_repgen[repgen_len - 1] == 0x00) {
|
||||
atr_len -= 2;
|
||||
|
||||
+22
-12
@@ -62,7 +62,7 @@
|
||||
// iso14b apdu input frame length
|
||||
static uint16_t apdu_frame_length = 0;
|
||||
static uint8_t prime_vt_addr = ISO14443B_PRIME_VT_ADDR_DEFAULT;
|
||||
static uint8_t prime_com_ra_cmd = ISO14443B_PRIME_COM_RA_START;
|
||||
static uint8_t prime_frame_seq = ISO14443B_PRIME_SEQUENCE_START;
|
||||
//static uint16_t ats_fsc[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
|
||||
static bool apdu_in_framing_enable = true;
|
||||
|
||||
@@ -70,6 +70,8 @@ static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int switch_off_field_14b(void) {
|
||||
SetISODEPState(ISODEP_INACTIVE);
|
||||
prime_vt_addr = ISO14443B_PRIME_VT_ADDR_DEFAULT;
|
||||
prime_frame_seq = ISO14443B_PRIME_SEQUENCE_START;
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = ISO14B_DISCONNECT,
|
||||
.timeout = 0,
|
||||
@@ -770,14 +772,22 @@ static void print_ct_general_info(void *vcard) {
|
||||
}
|
||||
|
||||
static void print_prime_general_info(const iso14b_prime_card_select_t *card) {
|
||||
const uint8_t vt_card_addr = (card->vt_addr & ISO14443B_PRIME_VT_CARD_ADDR_MASK) >> ISO14443B_PRIME_VT_CARD_ADDR_SHIFT;
|
||||
const uint8_t vt_coupler_addr = card->vt_addr & ISO14443B_PRIME_VT_COUPLER_ADDR_MASK;
|
||||
const bool long_repgen = (card->verlog & ISO14443B_PRIME_VERLOG_LONG_REPGEN) == ISO14443B_PRIME_VERLOG_LONG_REPGEN;
|
||||
const uint8_t software_version = (card->verlog & ISO14443B_PRIME_VERLOG_VERSION_MASK) >> ISO14443B_PRIME_VERLOG_VERSION_SHIFT;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Type B' / Innovatron") " ---------------------");
|
||||
PrintAndLogEx(SUCCESS, " V&T Ad : %02X", card->vt_addr);
|
||||
PrintAndLogEx(SUCCESS, " Cmd : %02X (REPGEN)", card->repgen_cmd);
|
||||
PrintAndLogEx(SUCCESS, " V&T Ad : %02X (card %u, coupler %u)", card->vt_addr, vt_card_addr, vt_coupler_addr);
|
||||
PrintAndLogEx(SUCCESS, " DIV : " _GREEN_("%s"), sprint_hex(card->div, sizeof(card->div)));
|
||||
PrintAndLogEx(SUCCESS, " VerLog : %02X", card->verlog);
|
||||
if (card->verlog & 0x80) {
|
||||
PrintAndLogEx(SUCCESS, " Config : %02X", card->config);
|
||||
PrintAndLogEx(SUCCESS, " VerLog : %02X (%s REPGEN, software version %u)",
|
||||
card->verlog, long_repgen ? "long" : "short", software_version);
|
||||
if (long_repgen) {
|
||||
PrintAndLogEx(SUCCESS, " Config : %02X (WAIT %s, ATR %s)",
|
||||
card->config,
|
||||
(card->config & ISO14443B_PRIME_CONFIG_WAIT_SUPPORTED) ? "supported" : "not indicated",
|
||||
(card->config & ISO14443B_PRIME_CONFIG_ATR_PRESENT) ? "present" : "absent");
|
||||
}
|
||||
if (card->atr_len) {
|
||||
PrintAndLogEx(SUCCESS, " ATR : %s", sprint_hex(card->atr, card->atr_len));
|
||||
@@ -1382,7 +1392,7 @@ int select_card_14443b_prime(bool disconnect, iso14b_prime_card_select_t *card,
|
||||
}
|
||||
|
||||
prime_vt_addr = selected.vt_addr;
|
||||
prime_com_ra_cmd = ISO14443B_PRIME_COM_RA_START;
|
||||
prime_frame_seq = ISO14443B_PRIME_SEQUENCE_START;
|
||||
SetISODEPState(disconnect ? ISODEP_INACTIVE : ISODEP_NFCB_PRIME);
|
||||
if (card) {
|
||||
*card = selected;
|
||||
@@ -2607,8 +2617,8 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t next_prime_com_ra_cmd(uint8_t cmd) {
|
||||
return (cmd + 0x02) & 0x0F;
|
||||
static uint8_t next_prime_frame_seq(uint8_t seq) {
|
||||
return seq >= ISO14443B_PRIME_SEQUENCE_END ? ISO14443B_PRIME_SEQUENCE_START : seq + 1;
|
||||
}
|
||||
|
||||
int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
@@ -2634,7 +2644,7 @@ int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
}
|
||||
|
||||
frame[0] = prime_vt_addr;
|
||||
frame[1] = prime_com_ra_cmd;
|
||||
frame[1] = ISO14443B_PRIME_CMD_COM_R(prime_frame_seq);
|
||||
frame[2] = (uint8_t)datainlen + 1;
|
||||
if (datainlen > 0) {
|
||||
memcpy(frame + 3, datain, datainlen);
|
||||
@@ -2692,7 +2702,7 @@ int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
}
|
||||
|
||||
const uint8_t rx_len = rx[2];
|
||||
if (rx[0] != prime_vt_addr || (rx[1] & 0x01) || rx_len == 0 || resp.length < (uint16_t)rx_len + 4) {
|
||||
if (rx[0] != prime_vt_addr || rx[1] != ISO14443B_PRIME_CMD_REC(prime_frame_seq) || rx_len == 0 || resp.length < (uint16_t)rx_len + 4) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
@@ -2710,7 +2720,7 @@ int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
|
||||
memcpy(dataout, rx + 3, apdu_len);
|
||||
*dataoutlen = apdu_len;
|
||||
prime_com_ra_cmd = next_prime_com_ra_cmd(prime_com_ra_cmd);
|
||||
prime_frame_seq = next_prime_frame_seq(prime_frame_seq);
|
||||
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
|
||||
+66
-27
@@ -331,38 +331,77 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
/*
|
||||
* Type B' / Innovatron frame format.
|
||||
*
|
||||
* Byte 0: V&T address. Public docs and traces label this "V&T Ad".
|
||||
* 0x01 is the default address observed in APGEN, REPGEN,
|
||||
* ATTRIB, COM_RA, and DISC frames.
|
||||
* Observed cards respond to any value from 0x00 to 0xFF, and
|
||||
* echo that same address in the response.
|
||||
* Byte 0 is V&T Ad. The high nibble is the card/tag address and the low
|
||||
* nibble is the coupler/validator address. APGEN uses card address 0;
|
||||
*
|
||||
* Byte 1: payload type / command.
|
||||
* APGEN: [V&T Ad, 0B, OccuPar] or [V&T Ad, 0B, OccuPar, Config]
|
||||
* REPGEN: [V&T Ad, 07, DIV(4), VERLOG] or
|
||||
* [V&T Ad, 07, DIV(4), VERLOG, CONFIG, ATR/application bytes...]
|
||||
* ATTRIB: [V&T Ad, 0F, DIV(4)] -> RR
|
||||
* DISC: [V&T Ad, 03] -> RR
|
||||
* RR: [V&T Ad, 01]
|
||||
*
|
||||
* Primary commands:
|
||||
* 0x0B APGEN "Appel General"; acts as the wake-up command.
|
||||
* 0x07 REPGEN response to APGEN.
|
||||
* 0x0F ATTRIB attribute / activation command.
|
||||
* 0x03 DISC disconnect.
|
||||
* Data exchange commands:
|
||||
* family | (seq << 1), with bit 0 clear and seq carried in bits 1..3.
|
||||
* COM_RA C2..CE allows assigning card address and performing APDU exchange by DIV.
|
||||
* COM_R 02..0E is the normal APDU exchange command, relying on card address only.
|
||||
* REC 42..4E is the card response to COM_RA/COM_R.
|
||||
* Public PICS rows list seq 1..7.
|
||||
*
|
||||
* COM_RA frames:
|
||||
* COM_RA uses the even-valued payload type bytes. Bit 0 is clear; bits 1..3
|
||||
* are the rolling frame counter. The resulting byte advances by 0x02 for
|
||||
* each exchange and wraps in the low nibble:
|
||||
* Byte 2 in data frames is LNG. LNG includes byte 2 itself, so the APDU/R-APDU
|
||||
* byte count is LNG - 1. In COM_RA the trailing DIV is outside LNG.
|
||||
*
|
||||
* 04 -> 06 -> 08 -> 0A -> 0C -> 0E -> 00 -> 02 -> 04 ...
|
||||
*
|
||||
* Byte 2 is the COM_RA length byte. The length includes byte 2 itself, so
|
||||
* the number of bytes after byte 2 is length - 1.
|
||||
*/
|
||||
#define ISO14443B_PRIME_VT_ADDR_DEFAULT 0x01
|
||||
#define ISO14443B_PRIME_CMD_DISC 0x03
|
||||
#define ISO14443B_PRIME_CMD_REPGEN 0x07
|
||||
#define ISO14443B_PRIME_CMD_APGEN 0x0B
|
||||
#define ISO14443B_PRIME_CMD_ATTRIB 0x0F
|
||||
// APGEN parameter requesting the extended REPGEN response; also called 'APGEN!'
|
||||
#define ISO14443B_PRIME_REQUEST_EXTENDED_REPGEN 0x80
|
||||
#define ISO14443B_PRIME_COM_RA_START 0x02
|
||||
#define ISO14443B_PRIME_VT_ADDR_DEFAULT 0x01
|
||||
#define ISO14443B_PRIME_VT_CARD_ADDR_MASK 0xF0
|
||||
#define ISO14443B_PRIME_VT_CARD_ADDR_SHIFT 4
|
||||
#define ISO14443B_PRIME_VT_COUPLER_ADDR_MASK 0x0F
|
||||
#define ISO14443B_PRIME_VT_CARD_ADDR_FIRST 1
|
||||
#define ISO14443B_PRIME_VT_ADDR(card, coupler) ((((card) << ISO14443B_PRIME_VT_CARD_ADDR_SHIFT) & ISO14443B_PRIME_VT_CARD_ADDR_MASK) | ((coupler) & ISO14443B_PRIME_VT_COUPLER_ADDR_MASK))
|
||||
|
||||
#define ISO14443B_PRIME_CMD_RR 0x01
|
||||
#define ISO14443B_PRIME_CMD_DISC 0x03
|
||||
#define ISO14443B_PRIME_CMD_REPGEN 0x07
|
||||
#define ISO14443B_PRIME_CMD_APGEN 0x0B
|
||||
#define ISO14443B_PRIME_CMD_ATTRIB 0x0F
|
||||
|
||||
#define ISO14443B_PRIME_OCCUPAR_VALUE_MASK 0x3F
|
||||
// Public documents and sources identify bit 6 as short APGEN;
|
||||
// it's not proven to work yet
|
||||
#define ISO14443B_PRIME_OCCUPAR_SHORT_APGEN 0x40
|
||||
#define ISO14443B_PRIME_OCCUPAR_HIGH_BITS_MASK 0xC0
|
||||
#define ISO14443B_PRIME_OCCUPAR_BPSK_FLAG 0x80
|
||||
// OccuPar controls APGEN response chance:
|
||||
// 0x3F card answers every poll attempt
|
||||
// 0x3E-0x00 lower values reduce the response chance
|
||||
#define ISO14443B_PRIME_OCCUPAR_DEFAULT 0x3F
|
||||
|
||||
#define ISO14443B_PRIME_APGEN_CONFIG_REQUEST_ATR 0x80
|
||||
#define ISO14443B_PRIME_APGEN_CONFIG_RFU_MASK 0x7F
|
||||
|
||||
#define ISO14443B_PRIME_VERLOG_LONG_REPGEN 0x80
|
||||
#define ISO14443B_PRIME_VERLOG_FIXED_BITS_MASK 0x61
|
||||
#define ISO14443B_PRIME_VERLOG_FIXED_BITS_VALUE 0x61
|
||||
#define ISO14443B_PRIME_VERLOG_VERSION_MASK 0x1E
|
||||
#define ISO14443B_PRIME_VERLOG_VERSION_SHIFT 1
|
||||
|
||||
#define ISO14443B_PRIME_CONFIG_WAIT_SUPPORTED 0x80
|
||||
#define ISO14443B_PRIME_CONFIG_ATR_PRESENT 0x40
|
||||
#define ISO14443B_PRIME_CONFIG_RFU_MASK 0x3F
|
||||
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_FAMILY_MASK 0xC0
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_SEQ_MASK 0x0E
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_SEQ_SHIFT 1
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_FAMILY_COM_R 0x00
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_FAMILY_REC 0x40
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_FAMILY_COM_RA 0xC0
|
||||
#define ISO14443B_PRIME_SEQUENCE_START 1
|
||||
#define ISO14443B_PRIME_SEQUENCE_END 7
|
||||
#define ISO14443B_PRIME_CMD_COM_DATA_SEQ(cmd) (((cmd) & ISO14443B_PRIME_CMD_COM_DATA_SEQ_MASK) >> ISO14443B_PRIME_CMD_COM_DATA_SEQ_SHIFT)
|
||||
#define ISO14443B_PRIME_CMD_COM_R(seq) (ISO14443B_PRIME_CMD_COM_DATA_FAMILY_COM_R | (((seq) << ISO14443B_PRIME_CMD_COM_DATA_SEQ_SHIFT) & ISO14443B_PRIME_CMD_COM_DATA_SEQ_MASK))
|
||||
#define ISO14443B_PRIME_CMD_REC(seq) (ISO14443B_PRIME_CMD_COM_DATA_FAMILY_REC | (((seq) << ISO14443B_PRIME_CMD_COM_DATA_SEQ_SHIFT) & ISO14443B_PRIME_CMD_COM_DATA_SEQ_MASK))
|
||||
#define ISO14443B_PRIME_CMD_COM_RA(seq) (ISO14443B_PRIME_CMD_COM_DATA_FAMILY_COM_RA | (((seq) << ISO14443B_PRIME_CMD_COM_DATA_SEQ_SHIFT) & ISO14443B_PRIME_CMD_COM_DATA_SEQ_MASK))
|
||||
#define ISO14443B_PRIME_COM_RA_START ISO14443B_PRIME_CMD_COM_RA(ISO14443B_PRIME_SEQUENCE_START)
|
||||
|
||||
// XEROX Commands
|
||||
#define ISO14443B_XEROX_PWD 0x38
|
||||
|
||||
Reference in New Issue
Block a user