mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-07-02 22:12:15 +00:00
Add support for Innovatron protocol to Calypso commands
This commit is contained in:
+21
-1
@@ -1440,7 +1440,13 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
|
||||
|
||||
if (Handle14443bSamplesFromTag(ci, cq)) {
|
||||
|
||||
*eof_time = GetCountSspClkDelta(dma_start_time) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
// Response timing is measured from DMA start, but trace rows use
|
||||
// absolute SSP time like reader frames.
|
||||
uint32_t eof_delta = GetCountSspClkDelta(dma_start_time);
|
||||
if (eof_delta > DELAY_TAG_TO_ARM) {
|
||||
eof_delta -= DELAY_TAG_TO_ARM;
|
||||
}
|
||||
*eof_time = dma_start_time + eof_delta; // end of EOF
|
||||
|
||||
if (Demod.len > Demod.max_len) {
|
||||
ret = PM3_EOVFLOW;
|
||||
@@ -1983,6 +1989,20 @@ static int iso14443b_select_prime_card(iso14b_prime_card_select_t *card) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t attrib[] = {
|
||||
r_repgen[0],
|
||||
ISO14443B_PRIME_CMD_ATTRIB,
|
||||
r_repgen[2],
|
||||
r_repgen[3],
|
||||
r_repgen[4],
|
||||
r_repgen[5],
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
AddCrc14B(attrib, sizeof(attrib) - 2);
|
||||
start_time = eof_time + ISO14B_TR2;
|
||||
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time, true);
|
||||
|
||||
s_iso14b_pcb_blocknum = 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
+137
-15
@@ -61,6 +61,8 @@
|
||||
|
||||
// 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 uint16_t ats_fsc[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
|
||||
static bool apdu_in_framing_enable = true;
|
||||
|
||||
@@ -1339,18 +1341,18 @@ static bool HF14B_ST_Info(bool verbose, bool do_aid_search) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_prime_card(iso14b_prime_card_select_t *card, bool verbose) {
|
||||
|
||||
if (card == NULL) {
|
||||
return false;
|
||||
}
|
||||
int select_card_14443b_prime(bool disconnect, iso14b_prime_card_select_t *card, bool verbose) {
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_PRIME | ISO14B_DISCONNECT),
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_PRIME | ISO14B_CLEARTRACE),
|
||||
.timeout = 0,
|
||||
.rawlen = 0,
|
||||
};
|
||||
|
||||
if (disconnect) {
|
||||
packet.flags |= ISO14B_DISCONNECT;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||
@@ -1358,26 +1360,34 @@ static bool get_prime_card(iso14b_prime_card_select_t *card, bool verbose) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
}
|
||||
return false;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
switch (resp.status) {
|
||||
case PM3_SUCCESS: {
|
||||
if (resp.length < sizeof(*card)) {
|
||||
if (resp.length < sizeof(iso14b_prime_card_select_t)) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(FAILED, "ISO 14443-B' card select response too short (%u bytes)", resp.length);
|
||||
}
|
||||
return false;
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
||||
memcpy(card, resp.data.asBytes, sizeof(*card));
|
||||
if (card->repgen_cmd != ISO14443B_PRIME_CMD_REPGEN || card->atr_len > sizeof(card->atr)) {
|
||||
iso14b_prime_card_select_t selected = {0};
|
||||
memcpy(&selected, resp.data.asBytes, sizeof(selected));
|
||||
if (selected.repgen_cmd != ISO14443B_PRIME_CMD_REPGEN || selected.atr_len > sizeof(selected.atr)) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(FAILED, "ISO 14443-B' invalid card select response");
|
||||
}
|
||||
return false;
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
return true;
|
||||
|
||||
prime_vt_addr = selected.vt_addr;
|
||||
prime_com_ra_cmd = ISO14443B_PRIME_COM_RA_START;
|
||||
SetISODEPState(disconnect ? ISODEP_INACTIVE : ISODEP_NFCB_PRIME);
|
||||
if (card) {
|
||||
*card = selected;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
case PM3_ELENGTH:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-B' REPGEN wrong length");
|
||||
@@ -1393,7 +1403,7 @@ static bool get_prime_card(iso14b_prime_card_select_t *card, bool verbose) {
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
// menu command to get and print all info known about any known 14b tag
|
||||
@@ -1656,7 +1666,7 @@ static bool HF14B_picopass_reader(bool verbose) {
|
||||
static bool HF14B_prime_reader(bool verbose) {
|
||||
|
||||
iso14b_prime_card_select_t card = {0};
|
||||
if (get_prime_card(&card, verbose) == false) {
|
||||
if (select_card_14443b_prime(true, &card, verbose) != PM3_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
print_prime_general_info(&card);
|
||||
@@ -2597,6 +2607,118 @@ 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;
|
||||
}
|
||||
|
||||
int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
||||
bool leave_signal_on, uint8_t *dataout, int maxdataoutlen,
|
||||
int *dataoutlen, int user_timeout) {
|
||||
|
||||
if (dataoutlen == NULL || dataout == NULL || datainlen < 0 || datainlen > 0xFE || (datain == NULL && datainlen > 0)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
*dataoutlen = 0;
|
||||
|
||||
if (activate_field) {
|
||||
int selres = select_card_14443b_prime(false, NULL, false);
|
||||
if (selres != PM3_SUCCESS) {
|
||||
return selres;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t frame[PM3_CMD_DATA_SIZE] = {0};
|
||||
const uint16_t frame_len = (uint16_t)datainlen + 3;
|
||||
if (frame_len > sizeof(frame)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
frame[0] = prime_vt_addr;
|
||||
frame[1] = prime_com_ra_cmd;
|
||||
frame[2] = (uint8_t)datainlen + 1;
|
||||
if (datainlen > 0) {
|
||||
memcpy(frame + 3, datain, datainlen);
|
||||
}
|
||||
|
||||
uint32_t flags = ISO14B_RAW | ISO14B_APPEND_CRC;
|
||||
uint32_t timeout = 0;
|
||||
if (user_timeout > 0) {
|
||||
flags |= ISO14B_SET_TIMEOUT;
|
||||
if (user_timeout > MAX_14B_TIMEOUT_MS) {
|
||||
user_timeout = MAX_14B_TIMEOUT_MS;
|
||||
PrintAndLogEx(INFO, "set timeout to 4.9 seconds. The max we can wait for response");
|
||||
}
|
||||
timeout = (uint32_t)((13560 / 128) * user_timeout);
|
||||
}
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + frame_len);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
packet->flags = flags;
|
||||
packet->timeout = timeout;
|
||||
packet->rawlen = frame_len;
|
||||
memcpy(packet->raw, frame, frame_len);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
free(packet);
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, MAX(APDU_TIMEOUT, user_timeout)) == false) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
PrintAndLogEx(ERR, "APDU: reply timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
PrintAndLogEx(ERR, "APDU: no Type B' APDU response");
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
const uint8_t *rx = resp.data.asBytes;
|
||||
if (resp.length < 5 || check_crc(CRC_14443_B, rx, resp.length) == false) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
return PM3_ECRC;
|
||||
}
|
||||
|
||||
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 (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
|
||||
const int apdu_len = rx_len - 1;
|
||||
if (maxdataoutlen && apdu_len > maxdataoutlen) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
PrintAndLogEx(ERR, "APDU: buffer too small ( " _RED_("%d") " ), needs " _YELLOW_("%d") " bytes", maxdataoutlen, apdu_len);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
memcpy(dataout, rx + 3, apdu_len);
|
||||
*dataoutlen = apdu_len;
|
||||
prime_com_ra_cmd = next_prime_com_ra_cmd(prime_com_ra_cmd);
|
||||
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// ISO14443-4. 7. Half-duplex block transmission protocol
|
||||
static int CmdHF14BAPDU(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
|
||||
@@ -27,7 +27,9 @@ int CmdHF14BNdefRead(const char *Cmd);
|
||||
|
||||
uint8_t *get_uid_from_filename(const char *filename);
|
||||
int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout);
|
||||
int exchange_14b_prime_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout);
|
||||
int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card);
|
||||
int select_card_14443b_prime(bool disconnect, iso14b_prime_card_select_t *card, bool verbose);
|
||||
|
||||
int infoHF14B(bool verbose, bool do_aid_search);
|
||||
int readHF14B(bool loop, bool verbose, bool read_plot);
|
||||
|
||||
@@ -131,6 +131,8 @@ typedef struct {
|
||||
iso14a_card_select_t card_a;
|
||||
bool has_14b;
|
||||
iso14b_card_select_t card_b;
|
||||
bool has_prime;
|
||||
iso14b_prime_card_select_t card_prime;
|
||||
} calypso_rf_info_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -395,6 +397,9 @@ static const char *calypso_rf_protocol_desc(isodep_state_t protocol) {
|
||||
if (protocol == ISODEP_NFCA) {
|
||||
return "ISO14443-A";
|
||||
}
|
||||
if (protocol == ISODEP_NFCB_PRIME) {
|
||||
return "ISO14443-B' / Innovatron";
|
||||
}
|
||||
if (protocol == ISODEP_NFCB) {
|
||||
return "ISO14443-B";
|
||||
}
|
||||
@@ -430,6 +435,18 @@ static int calypso_connect_contactless(bool verbose, calypso_rf_info_t *rf) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
iso14b_prime_card_select_t card_prime = {0};
|
||||
res = select_card_14443b_prime(false, &card_prime, verbose);
|
||||
if (res == PM3_SUCCESS) {
|
||||
if (rf != NULL) {
|
||||
rf->present = true;
|
||||
rf->protocol = ISODEP_NFCB_PRIME;
|
||||
rf->has_prime = true;
|
||||
rf->card_prime = card_prime;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2169,6 +2186,10 @@ static void calypso_print_rf_info(const calypso_rf_info_t *rf) {
|
||||
} else if (rf->has_14b) {
|
||||
calypso_print_rf_hex_line(" PUPI : ", rf->card_b.uid, rf->card_b.uidlen);
|
||||
calypso_print_rf_hex_line(" ATQB : ", rf->card_b.atqb, sizeof(rf->card_b.atqb));
|
||||
} else if (rf->has_prime) {
|
||||
PrintAndLogEx(SUCCESS, " V&T Ad : " _GREEN_("%02X"), rf->card_prime.vt_addr);
|
||||
calypso_print_rf_hex_line(" DIV : ", rf->card_prime.div, sizeof(rf->card_prime.div));
|
||||
calypso_print_rf_hex_line(" ATR : ", rf->card_prime.atr, rf->card_prime.atr_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4494,7 +4515,8 @@ static int calypso_probe_setup(const calypso_select_result_t *selected, bool ver
|
||||
uint8_t select_response[APDU_RES_LEN] = {0};
|
||||
size_t select_response_len = 0;
|
||||
uint16_t select_sw = 0;
|
||||
int res = Iso7816Select(CC_CONTACTLESS, false, true, aid, aid_len, select_response, sizeof(select_response), &select_response_len, &select_sw);
|
||||
sAPDU_t apdu = {0x00, ISO7816_SELECT_FILE, 0x04, 0x00, (uint8_t)aid_len, aid};
|
||||
int res = Iso7816ExchangeEx(CC_CONTACTLESS, false, true, apdu, true, 0, select_response, sizeof(select_response), &select_response_len, &select_sw);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -44,10 +44,11 @@ static isodep_state_t isodep_state = ISODEP_INACTIVE;
|
||||
void SetISODEPState(isodep_state_t state) {
|
||||
isodep_state = state;
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s%s"
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s%s%s"
|
||||
, isodep_state == ISODEP_INACTIVE ? "inactive" : ""
|
||||
, isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
|
||||
, isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
|
||||
, isodep_state == ISODEP_NFCB_PRIME ? _GREEN_("NFC-B'") : ""
|
||||
, isodep_state == ISODEP_NFCV ? _GREEN_("NFC-V") : ""
|
||||
);
|
||||
}
|
||||
@@ -125,6 +126,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
||||
case ISODEP_NFCB:
|
||||
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
break;
|
||||
case ISODEP_NFCB_PRIME:
|
||||
res = exchange_14b_prime_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
break;
|
||||
case ISODEP_NFCV:
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
break;
|
||||
|
||||
@@ -31,6 +31,7 @@ typedef enum {
|
||||
ISODEP_NFCA,
|
||||
ISODEP_NFCB,
|
||||
ISODEP_NFCV,
|
||||
ISODEP_NFCB_PRIME,
|
||||
} isodep_state_t;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -1286,6 +1286,9 @@ static int l_set_iso_dep_state(lua_State *L) {
|
||||
case 3:
|
||||
SetISODEPState(ISODEP_NFCV);
|
||||
break;
|
||||
case 4:
|
||||
SetISODEPState(ISODEP_NFCB_PRIME);
|
||||
break;
|
||||
default:
|
||||
return returnToLuaWithError(L, "Wrong ISODEP STATE value");
|
||||
}
|
||||
|
||||
@@ -362,6 +362,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
#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
|
||||
|
||||
// XEROX Commands
|
||||
#define ISO14443B_XEROX_PWD 0x38
|
||||
|
||||
Reference in New Issue
Block a user