mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
reworked the 14B comms. Uses NG packets now. Most raw / apdu / write / rd got some love
This commit is contained in:
parent
9c7890e50c
commit
70b4bee761
7 changed files with 458 additions and 464 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf 14b *` - worked apdu and comms. Improved output. Uses NG packets (@iceman1001)
|
||||
- Fixed `data manrawdecode` - now copy to demodbuf even if em4100 decode fails (@iceman1001)
|
||||
- Changed `nfc decode` - now supports Android Managed Provision NDEF message decoding (@iceman1001)
|
||||
- Changed `hf_cardhopper` - Allow button presses to break, handle non-zero CID from reader by relaying RATS and improving PPS and WTX handling, more reliably cook ATS, ignore client packets on serial line (@nvx)
|
||||
|
|
|
@ -1455,7 +1455,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_HF_ISO14443B_COMMAND: {
|
||||
iso14b_raw_cmd_t *payload = (iso14b_raw_cmd_t *)packet->data.asBytes;
|
||||
SendRawCommand14443B_Ex(payload);
|
||||
SendRawCommand14443B(payload);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_CRYPTORF_SIM : {
|
||||
|
|
|
@ -111,9 +111,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef MAX_14B_TIMEOUT
|
||||
// FWT(max) = 4949 ms or 4.95 seconds.
|
||||
// SSP_CLK = 4949000 * 3.39 = 16777120
|
||||
|
@ -195,9 +192,9 @@ static void iso14b_set_maxframesize(uint16_t size);
|
|||
static void iso14b_set_fwt(uint8_t fwt);
|
||||
|
||||
// the block number for the ISO14443-4 PCB (used with APDUs)
|
||||
static uint8_t iso14b_pcb_blocknum = 0;
|
||||
static uint8_t iso14b_fwt = 9;
|
||||
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
||||
static uint8_t s_iso14b_pcb_blocknum = 0;
|
||||
static uint8_t s_iso14b_fwt = 9;
|
||||
static uint32_t s_iso14b_timeout = MAX_14B_TIMEOUT;
|
||||
|
||||
/*
|
||||
* ISO 14443-B communications
|
||||
|
@ -350,7 +347,6 @@ static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
|||
// them yet, just leaves them ready to send in ToSend[].
|
||||
//-----------------------------------------------------------------------------
|
||||
static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
|
||||
int i;
|
||||
|
||||
tosend_reset();
|
||||
|
||||
|
@ -362,6 +358,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
|
|||
// 80/fs < TR1 < 200/fs
|
||||
// 10 ETU < TR1 < 24 ETU
|
||||
|
||||
int i;
|
||||
// Send TR1.
|
||||
// 10-11 ETU * 4times samples ONES
|
||||
for (i = 0; i < 10; i++) {
|
||||
|
@ -458,15 +455,18 @@ static void iso14b_set_timeout(uint32_t timeout_etu) {
|
|||
ssp = MAX_14B_TIMEOUT;
|
||||
}
|
||||
|
||||
iso14b_timeout = ssp;
|
||||
s_iso14b_timeout = ssp;
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout);
|
||||
Dbprintf("ISO14443B Timeout set to %ld fwt", s_iso14b_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of FWT, also updates the timeout
|
||||
static void iso14b_set_fwt(uint8_t fwt) {
|
||||
iso14b_fwt = fwt;
|
||||
s_iso14b_fwt = fwt;
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("ISO14443B FWT Timeout set to %ld fwt", s_iso14b_fwt);
|
||||
}
|
||||
iso14b_set_timeout(32 << fwt);
|
||||
}
|
||||
|
||||
|
@ -1323,6 +1323,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
|
|||
|
||||
// The DMA buffer, used to stream samples from the FPGA
|
||||
dmabuf16_t *dma = get_dma16();
|
||||
if (dma == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) {
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting");
|
||||
|
@ -1407,9 +1410,10 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t
|
|||
if (Demod.len > 0) {
|
||||
uint32_t sof_time = *eof_time - HF14_ETU_TO_SSP(
|
||||
(Demod.len * (8 + 2)) // time for byte transfers
|
||||
// + (10) // time for TR1
|
||||
+ (10 + 2) // time for SOF transfer
|
||||
+ (10)); // time for EOF transfer
|
||||
+ (10) // time for EOF transfer
|
||||
)
|
||||
;
|
||||
LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false);
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1587,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
|||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int *reponselen) {
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *reponselen) {
|
||||
|
||||
uint8_t real_cmd[msg_len + 4];
|
||||
|
||||
|
@ -1596,12 +1600,12 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
}
|
||||
|
||||
// put block number into the PCB
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
real_cmd[0] |= s_iso14b_pcb_blocknum;
|
||||
memcpy(real_cmd + 1, msg, msg_len);
|
||||
} else {
|
||||
// R-block. ACK
|
||||
real_cmd[0] = 0xA2; // r-block + ACK
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
real_cmd[0] |= s_iso14b_pcb_blocknum;
|
||||
}
|
||||
|
||||
AddCrc14B(real_cmd, msg_len + 1);
|
||||
|
@ -1618,26 +1622,25 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
// SSP_CLK = 4833 µS * 3.39 = 16384
|
||||
|
||||
uint16_t len = 0;
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
int status = Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len);
|
||||
if (status != PM3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
uint8_t *data_bytes = (uint8_t *) rxdata;
|
||||
|
||||
if (len) {
|
||||
// S-Block WTX
|
||||
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
|
||||
|
||||
uint32_t save_iso14b_timeout_spp = iso14b_timeout;
|
||||
uint32_t save_iso14b_timeout_spp = s_iso14b_timeout;
|
||||
|
||||
// 2 high bits mandatory set to 0b
|
||||
// byte1 - WTXM [1..59].
|
||||
uint8_t wtxm = data_bytes[1] & 0x3F;
|
||||
|
||||
// command FWT = FWT * WTXM
|
||||
uint32_t fwt_temp = iso14b_fwt * wtxm;
|
||||
uint32_t fwt_temp = (s_iso14b_fwt * wtxm);
|
||||
|
||||
// temporarily increase timeout
|
||||
iso14b_set_timeout((32 << fwt_temp));
|
||||
|
@ -1654,16 +1657,14 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
// retrieve the result again (with increased timeout)
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
data_bytes = rxdata;
|
||||
|
||||
// restore timeout
|
||||
iso14b_timeout = save_iso14b_timeout_spp;
|
||||
s_iso14b_timeout = save_iso14b_timeout_spp;
|
||||
}
|
||||
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
|
@ -1671,23 +1672,25 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
|
||||
if ((len >= 3) && // PCB + CRC = 3 bytes
|
||||
(((data_bytes[0] & 0xC0) == 0) || (data_bytes[0] & 0xD0) == 0x80) && // I-Block OR R-Block with ACK bit set to 0
|
||||
((data_bytes[0] & 0x01) == iso14b_pcb_blocknum)) { // equal block numbers
|
||||
((data_bytes[0] & 0x01) == s_iso14b_pcb_blocknum)) { // equal block numbers
|
||||
|
||||
iso14b_pcb_blocknum ^= 1;
|
||||
s_iso14b_pcb_blocknum ^= 1;
|
||||
|
||||
}
|
||||
|
||||
// if we received I-block with chaining we need to send ACK and receive another block of data
|
||||
if (res) {
|
||||
*res = data_bytes[0];
|
||||
if (response_byte) {
|
||||
*response_byte = data_bytes[0];
|
||||
}
|
||||
|
||||
// crc check
|
||||
if (len >= 3 && (check_crc(CRC_14443_B, data_bytes, len) == false)) {
|
||||
return PM3_ECRC;
|
||||
}
|
||||
}
|
||||
|
||||
// cut frame byte
|
||||
if (len) {
|
||||
len -= 1;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -1722,12 +1725,10 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1745,10 +1746,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(cmdMSBUID, sizeof(cmdMSBUID), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -1765,10 +1765,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(cmdLSBUID, sizeof(cmdLSBUID), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 4) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -1782,9 +1781,6 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) {
|
|||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
/**
|
||||
* SRx Initialise.
|
||||
|
@ -1802,11 +1798,9 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_init, sizeof(r_init), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(r_init, sizeof(r_init), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Randomly generated Chip ID
|
||||
if (card) {
|
||||
|
@ -1823,12 +1817,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_select, sizeof(r_select), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_select, sizeof(r_select), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 3) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1850,12 +1842,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), s_iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 10) {
|
||||
return PM3_ELENGTH;
|
||||
}
|
||||
|
@ -1869,9 +1859,6 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
memcpy(card->uid, r_papid, 8);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
// Xerox tag connect function: wup, anticoll, attrib, password
|
||||
|
@ -1907,12 +1894,11 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
for (slot = 0; slot < 4; slot++) {
|
||||
start_time = eof_time + HF14_ETU_TO_SSP(30); //(24); // next slot after 24 ETU
|
||||
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
if (retlen > 0) {
|
||||
Dbprintf("unexpected data %d", retlen);
|
||||
Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD");
|
||||
}
|
||||
goto out;
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
// tx unframed slot-marker
|
||||
|
@ -1930,8 +1916,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
|
||||
if (4 == slot) {
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("no answer to anticollision");
|
||||
}
|
||||
|
@ -1939,8 +1923,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
}
|
||||
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
|
@ -1984,10 +1968,9 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(txbuf + 1, 15, &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen < 3) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -2018,8 +2001,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(txbuf, 17, &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
if (retlen < 4) {
|
||||
|
@ -2035,10 +2018,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
/* Perform the ISO 14443 B Card Selection procedure
|
||||
|
@ -2066,12 +2045,10 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
FpgaDisableTracing();
|
||||
|
||||
// ATQB too short?
|
||||
if (retlen < 14) {
|
||||
return PM3_ELENGTH;
|
||||
|
@ -2098,10 +2075,9 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time, true);
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
goto out;
|
||||
if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Answer to ATTRIB too short?
|
||||
if (retlen < 3) {
|
||||
|
@ -2135,12 +2111,8 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
}
|
||||
// reset PCB block number
|
||||
iso14b_pcb_blocknum = 0;
|
||||
s_iso14b_pcb_blocknum = 0;
|
||||
return PM3_SUCCESS;
|
||||
|
||||
out:
|
||||
FpgaDisableTracing();
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
|
||||
// Set up ISO 14443 Type B communication (similar to iso14443a_setup)
|
||||
|
@ -2194,7 +2166,6 @@ void iso14443b_setup(void) {
|
|||
//-----------------------------------------------------------------------------
|
||||
static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
||||
|
||||
// iceman: todo add static CRC
|
||||
uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00};
|
||||
AddCrc14B(cmd, 2);
|
||||
|
||||
|
@ -2206,20 +2177,16 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
|||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
uint16_t retlen = 0;
|
||||
if (Get14443bAnswerFromTag(r_block, sizeof(r_block), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
FpgaDisableTracing();
|
||||
if (Get14443bAnswerFromTag(r_block, sizeof(r_block), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) {
|
||||
return PM3_ECARDEXCHANGE;
|
||||
}
|
||||
FpgaDisableTracing();
|
||||
|
||||
// Check if we got an answer from the tag
|
||||
if (retlen != 6) {
|
||||
Dbprintf("expected 6 bytes from tag, got %u", retlen);
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
// The check the CRC of the answer
|
||||
if (check_crc(CRC_14443_B, r_block, retlen) == false) {
|
||||
DbpString("CRC fail");
|
||||
return PM3_ECRC;
|
||||
}
|
||||
|
||||
|
@ -2227,14 +2194,6 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) {
|
|||
memcpy(block, r_block, ISO14B_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Address=%02x, Contents=%08x, CRC=%04x",
|
||||
blocknr,
|
||||
(r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0],
|
||||
(r_block[4] << 8) + r_block[5]
|
||||
);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2457,7 +2416,7 @@ static void iso14b_set_trigger(bool enable) {
|
|||
g_trigger = enable;
|
||||
}
|
||||
|
||||
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
|
||||
void SendRawCommand14443B(iso14b_raw_cmd_t *p) {
|
||||
|
||||
// turn on trigger (LED_A)
|
||||
if ((p->flags & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) {
|
||||
|
@ -2517,46 +2476,42 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) {
|
|||
|
||||
if ((p->flags & ISO14B_APDU) == ISO14B_APDU) {
|
||||
|
||||
int responselen = 0;
|
||||
uint16_t responselen = 0;
|
||||
uint8_t response_byte = 0;
|
||||
status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &response_byte, &responselen);
|
||||
bool chaining = ((p->flags & ISO14B_SEND_CHAINING) == ISO14B_SEND_CHAINING);
|
||||
status = iso14443b_apdu(p->raw, p->rawlen, chaining, buf, sizeof(buf), &response_byte, &responselen);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
responselen = MIN(responselen, PM3_CMD_DATA_SIZE);
|
||||
|
||||
iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)BigBuf_calloc(sizeof(iso14b_raw_apdu_response_t) + responselen);
|
||||
uint8_t packet[responselen + 1 + 2];
|
||||
iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)packet;
|
||||
payload->response_byte = response_byte;
|
||||
payload->datalen = responselen;
|
||||
memcpy(payload->data, buf, payload->datalen);
|
||||
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)payload, sizeof(iso14b_raw_apdu_response_t) + responselen);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, packet, sizeof(packet));
|
||||
}
|
||||
}
|
||||
|
||||
if ((p->flags & ISO14B_RAW) == ISO14B_RAW) {
|
||||
|
||||
uint8_t *raw = BigBuf_calloc(p->rawlen + 2);
|
||||
memcpy(raw, p->raw, p->rawlen);
|
||||
if (
|
||||
((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) {
|
||||
AddCrc14B(raw, p->rawlen);
|
||||
if (((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) {
|
||||
AddCrc14B(p->raw, p->rawlen);
|
||||
p->rawlen += 2;
|
||||
}
|
||||
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(raw, p->rawlen, &start_time, &eof_time, true);
|
||||
CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true);
|
||||
|
||||
FpgaDisableTracing();
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
|
||||
eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER;
|
||||
|
||||
uint16_t retlen = 0;
|
||||
status = Get14443bAnswerFromTag(buf, sizeof(buf), iso14b_timeout, &eof_time, &retlen);
|
||||
status = Get14443bAnswerFromTag(buf, sizeof(buf), s_iso14b_timeout, &eof_time, &retlen);
|
||||
if (status == PM3_SUCCESS) {
|
||||
sendlen = MIN(retlen, PM3_CMD_DATA_SIZE);
|
||||
reply_ng(CMD_HF_ISO14443B_COMMAND, status, Demod.output, sendlen);
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int *responselen);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, uint16_t * responselen);
|
||||
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
|
||||
|
@ -43,8 +43,7 @@ void SimulateIso14443bTag(const uint8_t *pupi);
|
|||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
void read_14b_st_block(uint8_t blocknr);
|
||||
void SniffIso14443b(void);
|
||||
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
|
||||
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p);
|
||||
void SendRawCommand14443B(iso14b_raw_cmd_t *p);
|
||||
|
||||
// States for 14B SIM command
|
||||
#define SIM_NOFIELD 0
|
||||
|
|
|
@ -295,226 +295,6 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static int CmdHF14BList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
|
||||
}
|
||||
|
||||
static int CmdHF14BSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sim",
|
||||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "hex", "4byte UID/PUPI"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi)));
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BSniff(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sniff",
|
||||
"Sniff the communication reader and tag",
|
||||
"hf 14b sniff"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0);
|
||||
|
||||
WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BCmdRaw(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b raw",
|
||||
"Sends raw bytes to card",
|
||||
"hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("s", "std", "activate field, use ISO14B select"),
|
||||
arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
|
||||
arg_lit0(NULL, "xrx", "activate field, use Fuji/Xerox select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("r", NULL, "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_str0("d", "data", "<hex>", "data, bytes to send"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool keep_field_on = arg_get_lit(ctx, 1);
|
||||
bool select_std = arg_get_lit(ctx, 2);
|
||||
bool select_sr = arg_get_lit(ctx, 3);
|
||||
bool select_cts = arg_get_lit(ctx, 4);
|
||||
bool select_xrx = arg_get_lit(ctx, 5);
|
||||
bool add_crc = arg_get_lit(ctx, 6);
|
||||
bool read_reply = (arg_get_lit(ctx, 7) == false);
|
||||
int user_timeout = arg_get_int_def(ctx, 8, -1);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen);
|
||||
if (res && verbose) {
|
||||
PrintAndLogEx(INFO, "called with no raw bytes");
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// FLAGS for device side
|
||||
uint32_t flags = ISO14B_CONNECT;
|
||||
if (add_crc) {
|
||||
flags |= ISO14B_APPEND_CRC;
|
||||
}
|
||||
|
||||
if (select_std) {
|
||||
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ISO14443-B select");
|
||||
}
|
||||
} else if (select_sr) {
|
||||
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ST/SRx select");
|
||||
}
|
||||
} else if (select_cts) {
|
||||
flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ASK/C-ticket select");
|
||||
}
|
||||
} else if (select_xrx) {
|
||||
flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t time_wait = 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 in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
time_wait = (uint32_t)((13560 / 128) * user_timeout);
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout);
|
||||
}
|
||||
|
||||
if (keep_field_on == false) {
|
||||
flags |= ISO14B_DISCONNECT;
|
||||
}
|
||||
|
||||
if (datalen > 0) {
|
||||
flags |= ISO14B_RAW;
|
||||
}
|
||||
|
||||
// Max buffer is PM3_CMD_DATA_SIZE
|
||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
packet->flags = flags;
|
||||
packet->timeout = time_wait;
|
||||
packet->rawlen = datalen;
|
||||
memcpy(packet->raw, data, datalen);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
free(packet);
|
||||
|
||||
if (read_reply == false) {
|
||||
clearCommandBuffer();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Select, device will send back iso14b_card_select_t, don't print it.
|
||||
if (select_std) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for standard select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_sr) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ST/SRx select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_cts) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_xrx) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
// get back response from the raw bytes you sent.
|
||||
if (success && datalen > 0) {
|
||||
wait_cmd_14b(true, false, user_timeout);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
|
||||
|
||||
// sanity checks
|
||||
|
@ -579,6 +359,30 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* extract uid from filename
|
||||
* filename must match '^hf-14b-[0-9A-F]{16}'
|
||||
*/
|
||||
uint8_t *get_uid_from_filename(const char *filename) {
|
||||
static uint8_t uid[8] ;
|
||||
memset(uid, 0, 8) ;
|
||||
char uidinhex[17] ;
|
||||
if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) {
|
||||
PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-<uid>...", filename);
|
||||
return uid ;
|
||||
}
|
||||
// extract uid part from filename
|
||||
strncpy(uidinhex, filename + 7, 16) ;
|
||||
uidinhex[16] = '\0' ;
|
||||
int len = hex_to_bytes(uidinhex, uid, 8);
|
||||
if (len == 8)
|
||||
return SwapEndian64(uid, 8, 8);
|
||||
else {
|
||||
PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len);
|
||||
memset(uid, 0, 8);
|
||||
}
|
||||
return uid ;
|
||||
}
|
||||
|
||||
// print full atqb info
|
||||
// bytes
|
||||
// 0,1,2,3 = application data
|
||||
|
@ -979,6 +783,225 @@ static void print_sr_blocks(uint8_t *data, size_t len, const uint8_t *uid) {
|
|||
// 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c])
|
||||
// 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c])
|
||||
|
||||
static int CmdHF14BList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf 14b", "14b -c");
|
||||
}
|
||||
|
||||
static int CmdHF14BSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sim",
|
||||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "hex", "4byte UID/PUPI"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi)));
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BSniff(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sniff",
|
||||
"Sniff the communication reader and tag",
|
||||
"hf 14b sniff"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0);
|
||||
|
||||
WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14BCmdRaw(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b raw",
|
||||
"Sends raw bytes to card",
|
||||
"hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("s", "std", "activate field, use ISO14B select"),
|
||||
arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
|
||||
arg_lit0(NULL, "xrx", "activate field, use Fuji/Xerox select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("r", NULL, "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_str0("d", "data", "<hex>", "data, bytes to send"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool keep_field_on = arg_get_lit(ctx, 1);
|
||||
bool select_std = arg_get_lit(ctx, 2);
|
||||
bool select_sr = arg_get_lit(ctx, 3);
|
||||
bool select_cts = arg_get_lit(ctx, 4);
|
||||
bool select_xrx = arg_get_lit(ctx, 5);
|
||||
bool add_crc = arg_get_lit(ctx, 6);
|
||||
bool read_reply = (arg_get_lit(ctx, 7) == false);
|
||||
int user_timeout = arg_get_int_def(ctx, 8, -1);
|
||||
bool verbose = arg_get_lit(ctx, 9);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen);
|
||||
if (res && verbose) {
|
||||
PrintAndLogEx(INFO, "called with no raw bytes");
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// FLAGS for device side
|
||||
uint32_t flags = ISO14B_CONNECT;
|
||||
if (add_crc) {
|
||||
flags |= ISO14B_APPEND_CRC;
|
||||
}
|
||||
|
||||
if (select_std) {
|
||||
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ISO14443-B select");
|
||||
}
|
||||
} else if (select_sr) {
|
||||
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ST/SRx select");
|
||||
}
|
||||
} else if (select_cts) {
|
||||
flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using ASK/C-ticket select");
|
||||
}
|
||||
} else if (select_xrx) {
|
||||
flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "using Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t time_wait = 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 in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
time_wait = (uint32_t)((13560 / 128) * user_timeout);
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout);
|
||||
}
|
||||
|
||||
if (keep_field_on == false) {
|
||||
flags |= ISO14B_DISCONNECT;
|
||||
}
|
||||
|
||||
if (datalen > 0) {
|
||||
flags |= ISO14B_RAW;
|
||||
}
|
||||
|
||||
// Max buffer is PM3_CMD_DATA_SIZE
|
||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||
|
||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
packet->flags = flags;
|
||||
packet->timeout = time_wait;
|
||||
packet->rawlen = datalen;
|
||||
memcpy(packet->raw, data, datalen);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||
free(packet);
|
||||
|
||||
if (read_reply == false) {
|
||||
clearCommandBuffer();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Select, device will send back iso14b_card_select_t, don't print it.
|
||||
if (select_std) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for standard select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_sr) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ST/SRx select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_cts) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select");
|
||||
}
|
||||
}
|
||||
|
||||
if (select_xrx) {
|
||||
success = wait_cmd_14b(verbose, true, user_timeout);
|
||||
if (verbose && success) {
|
||||
PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select");
|
||||
}
|
||||
}
|
||||
|
||||
// get back response from the raw bytes you sent.
|
||||
if (success && datalen > 0) {
|
||||
wait_cmd_14b(true, false, user_timeout);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// 14b get and print Full Info (as much as we know)
|
||||
static bool HF14B_Std_Info(bool verbose, bool do_aid_search) {
|
||||
// 14b get and print UID only (general info)
|
||||
|
@ -1419,13 +1442,14 @@ static int CmdHF14BWriteSri(const char *Cmd) {
|
|||
*/
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sriwrite",
|
||||
CLIParserInit(&ctx, "hf 14b wrbl",
|
||||
"Write data to a SRI512 or SRIX4K block\n"
|
||||
"If writing to a block out-of-range, use --force to override checks",
|
||||
"hf 14b sriwrite --4k -b 100 -d 11223344\n"
|
||||
"hf 14b sriwrite --4k --sb -d 11223344 --> special block write\n"
|
||||
"hf 14b sriwrite --512 -b 15 -d 11223344\n"
|
||||
"hf 14b sriwrite --512 --sb -d 11223344 --> special block write\n"
|
||||
"If writing to a block out-of-range, use `--force` to override checks\n"
|
||||
"Special block at end denots OTP and lock bits among others",
|
||||
"hf 14b wrbl --4k -b 100 -d 11223344\n"
|
||||
"hf 14b wrbl --4k --sb -d 11223344 --> special block write\n"
|
||||
"hf 14b wrbl --512 -b 15 -d 11223344\n"
|
||||
"hf 14b wrbl --512 --sb -d 11223344 --> special block write\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1713,16 +1737,38 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
uint8_t block = (value & 0xFF);
|
||||
uint8_t i = 0;
|
||||
uint8_t valuebytes[] = {0, 0, 0};
|
||||
Uint3byteToMemBe(valuebytes, value >> 8);
|
||||
|
||||
num_to_bytes(value, 3, valuebytes);
|
||||
uint32_t value_x = (value >> 8);
|
||||
PrintAndLogEx(INFO, "value...... %08x %06x", value, value_x);
|
||||
PrintAndLogEx(INFO, "3b value... %s", sprint_hex_inrow(valuebytes, sizeof(valuebytes)));
|
||||
PrintAndLogEx(INFO, "block no... %02x", block);
|
||||
|
||||
// Scrambled part
|
||||
// Crumb swapping of value.
|
||||
uint8_t temp[] = {0, 0};
|
||||
temp[0] = (CRUMB(value, 22) << 4 | CRUMB(value, 14) << 2 | CRUMB(value, 6)) << 4;
|
||||
temp[0] |= CRUMB(value, 20) << 4 | CRUMB(value, 12) << 2 | CRUMB(value, 4);
|
||||
temp[1] = (CRUMB(value, 18) << 4 | CRUMB(value, 10) << 2 | CRUMB(value, 2)) << 4;
|
||||
temp[1] |= CRUMB(value, 16) << 4 | CRUMB(value, 8) << 2 | CRUMB(value, 0);
|
||||
uint32_t foo = 0;
|
||||
foo |= CRUMB(value_x, 22) << 28;
|
||||
foo |= CRUMB(value_x, 14) << 26;
|
||||
foo |= CRUMB(value_x, 6) << 24;
|
||||
|
||||
foo |= CRUMB(value_x, 20) << 20;
|
||||
foo |= CRUMB(value_x, 12) << 18;
|
||||
foo |= CRUMB(value_x, 4) << 16;
|
||||
|
||||
foo |= CRUMB(value_x, 18) << 12;
|
||||
foo |= CRUMB(value_x, 10) << 10;
|
||||
foo |= CRUMB(value_x, 2) << 8;
|
||||
|
||||
foo |= CRUMB(value_x, 16) << 4;
|
||||
foo |= CRUMB(value_x, 8) << 2;
|
||||
foo |= CRUMB(value_x, 0) << 0;
|
||||
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 22), CRUMB(value_x, 14), CRUMB(value_x, 6));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 20), CRUMB(value_x, 12), CRUMB(value_x, 4));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 18), CRUMB(value_x, 10), CRUMB(value_x, 2));
|
||||
PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 16), CRUMB(value_x, 8), CRUMB(value_x, 0));
|
||||
|
||||
PrintAndLogEx(INFO, "hex........ %08x", foo);
|
||||
|
||||
// chksum part
|
||||
uint32_t chksum = 0xFF - block;
|
||||
|
@ -1740,9 +1786,11 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
base4[i--] = (chksum % 4 << 2);
|
||||
chksum /= 4;
|
||||
}
|
||||
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(base4, sizeof(base4)));
|
||||
|
||||
// merge scambled and chksum parts
|
||||
uint32_t encvalue =
|
||||
uint32_t encvalue = 0;
|
||||
|
||||
(NIBBLE_LOW(base4[0]) << 28) |
|
||||
(NIBBLE_HIGH(temp[0]) << 24) |
|
||||
|
||||
|
@ -1758,7 +1806,14 @@ static uint32_t srix4kEncode(uint32_t value) {
|
|||
PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue);
|
||||
return encvalue;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint32_t srix4k_decode_counter(uint32_t num) {
|
||||
uint32_t value = ~num;
|
||||
++value;
|
||||
return value;
|
||||
}
|
||||
/*
|
||||
static uint32_t srix4kDecode(uint32_t value) {
|
||||
switch (value) {
|
||||
case 0xC04F42C5:
|
||||
|
@ -1770,19 +1825,16 @@ static uint32_t srix4kDecode(uint32_t value) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint32_t srix4kDecodeCounter(uint32_t num) {
|
||||
uint32_t value = ~num;
|
||||
++value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) {
|
||||
static uint32_t srix4k_get_magicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) {
|
||||
#define MASK 0xFFFFFFFF;
|
||||
uint32_t uid32 = uid & MASK;
|
||||
uint32_t counter = srix4kDecodeCounter(block6);
|
||||
uint32_t decodedBlock18 = srix4kDecode(block18);
|
||||
uint32_t decodedBlock19 = srix4kDecode(block19);
|
||||
uint32_t counter = srix4k_decode_counter(block6);
|
||||
uint32_t decodedBlock18 = 0;
|
||||
uint32_t decodedBlock19 = 0;
|
||||
// uint32_t decodedBlock18 = srix4kDecode(block18);
|
||||
// uint32_t decodedBlock19 = srix4kDecode(block19);
|
||||
uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1;
|
||||
|
||||
uint32_t result = (uid32 * doubleBlock * counter) & MASK;
|
||||
|
@ -1790,8 +1842,19 @@ static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t bloc
|
|||
return result;
|
||||
}
|
||||
|
||||
static int srix4kValid(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
static int CmdSRIX4kValid(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b valid",
|
||||
"SRIX checksum test",
|
||||
"hf 14b valid\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint64_t uid = 0xD00202501A4532F9;
|
||||
uint32_t block6 = 0xFFFFFFFF;
|
||||
|
@ -1799,23 +1862,22 @@ static int srix4kValid(const char *Cmd) {
|
|||
uint32_t block19 = 0xC1484807;
|
||||
uint32_t block21 = 0xD1BCABA4;
|
||||
|
||||
uint32_t test_b18 = 0x00313918;
|
||||
uint32_t test_b18_enc = srix4kEncode(test_b18);
|
||||
//uint32_t test_b18_dec = srix4kDecode(test_b18_enc);
|
||||
uint32_t test_b18 = 0x001A2001; // 0x00313918;
|
||||
uint32_t test_b18_enc = 0;
|
||||
// uint32_t test_b18_enc = srix4kEncode(test_b18);
|
||||
// uint32_t test_b18_dec = srix4kDecode(test_b18_enc);
|
||||
PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc, "");
|
||||
|
||||
uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19);
|
||||
uint32_t magic = srix4k_get_magicbytes(uid, block6, block18, block19);
|
||||
PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
|
||||
if (card) {
|
||||
memset(card, 0, sizeof(iso14b_card_select_t));
|
||||
}
|
||||
|
||||
SetAPDULogging(true);
|
||||
switch_off_field_14b();
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
|
@ -1891,7 +1953,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen,
|
|||
PrintAndLogEx(FAILED, "APDU: failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
packet->flags = (ISO14B_CONNECT | ISO14B_APDU);
|
||||
packet->flags = (ISO14B_APDU);
|
||||
packet->timeout = 0;
|
||||
packet->rawlen = 0;
|
||||
|
||||
|
@ -1982,6 +2044,7 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
|||
if (apdu_in_framing_enable &&
|
||||
((apdu_frame_length && (datainlen > apdu_frame_length - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) {
|
||||
|
||||
PrintAndLogEx(INFO, "ONE");
|
||||
int clen = 0;
|
||||
bool v_activate_field = activate_field;
|
||||
|
||||
|
@ -2020,7 +2083,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
|||
} while (clen < datainlen);
|
||||
|
||||
} else {
|
||||
|
||||
res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leave_signal_on == false) {
|
||||
|
@ -2050,18 +2112,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field,
|
|||
|
||||
// ISO14443-4. 7. Half-duplex block transmission protocol
|
||||
static int CmdHF14BAPDU(const char *Cmd) {
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
int datalen = 0;
|
||||
uint8_t header[PM3_CMD_DATA_SIZE];
|
||||
int headerlen = 0;
|
||||
bool activate_field = false;
|
||||
bool leave_signal_on = false;
|
||||
bool decode_TLV = false;
|
||||
bool decode_APDU = false;
|
||||
bool make_APDU = false;
|
||||
bool extended_APDU = false;
|
||||
int le = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b apdu",
|
||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n"
|
||||
|
@ -2087,21 +2137,27 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
activate_field = arg_get_lit(ctx, 1);
|
||||
leave_signal_on = arg_get_lit(ctx, 2);
|
||||
decode_TLV = arg_get_lit(ctx, 3);
|
||||
decode_APDU = arg_get_lit(ctx, 4);
|
||||
bool activate_field = arg_get_lit(ctx, 1);
|
||||
bool leave_signal_on = arg_get_lit(ctx, 2);
|
||||
bool decode_TLV = arg_get_lit(ctx, 3);
|
||||
bool decode_APDU = arg_get_lit(ctx, 4);
|
||||
|
||||
uint8_t header[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int headerlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 5, header, &headerlen);
|
||||
make_APDU = headerlen > 0;
|
||||
|
||||
bool make_APDU = (headerlen > 0);
|
||||
if (make_APDU && headerlen != 4) {
|
||||
PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen);
|
||||
PrintAndLogEx(ERR, "header length must be 4 bytes, got " _RED_("%d"), headerlen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
extended_APDU = arg_get_lit(ctx, 6);
|
||||
le = arg_get_int_def(ctx, 7, 0);
|
||||
bool extended_APDU = arg_get_lit(ctx, 6);
|
||||
int le = arg_get_int_def(ctx, 7, 0);
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
int datalen = 0;
|
||||
|
||||
if (make_APDU) {
|
||||
uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0};
|
||||
|
@ -2145,10 +2201,10 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
int user_timeout = arg_get_int_def(ctx, 9, -1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s",
|
||||
PrintAndLogEx(INFO, ">>>> %s%s%s >>>> " _YELLOW_("%s"),
|
||||
activate_field ? "sel" : "",
|
||||
leave_signal_on ? " keep" : "",
|
||||
decode_TLV ? " TLV" : "",
|
||||
leave_signal_on ? "| keep" : "",
|
||||
decode_TLV ? "| TLV" : "",
|
||||
sprint_hex(data, datalen)
|
||||
);
|
||||
|
||||
|
@ -2165,8 +2221,12 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
|
||||
PrintAndLogEx(INFO, "<<<< %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s"
|
||||
, data[datalen - 2]
|
||||
, data[datalen - 1]
|
||||
, GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])
|
||||
);
|
||||
|
||||
// TLV decoder
|
||||
if (decode_TLV && datalen > 4) {
|
||||
|
@ -2293,30 +2353,6 @@ out:
|
|||
return res;
|
||||
}
|
||||
|
||||
/* extract uid from filename
|
||||
* filename must match '^hf-14b-[0-9A-F]{16}'
|
||||
*/
|
||||
uint8_t *get_uid_from_filename(const char *filename) {
|
||||
static uint8_t uid[8] ;
|
||||
memset(uid, 0, 8) ;
|
||||
char uidinhex[17] ;
|
||||
if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) {
|
||||
PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-<uid>...", filename);
|
||||
return uid ;
|
||||
}
|
||||
// extract uid part from filename
|
||||
strncpy(uidinhex, filename + 7, 16) ;
|
||||
uidinhex[16] = '\0' ;
|
||||
int len = hex_to_bytes(uidinhex, uid, 8);
|
||||
if (len == 8)
|
||||
return SwapEndian64(uid, 8, 8);
|
||||
else {
|
||||
PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len);
|
||||
memset(uid, 0, 8);
|
||||
}
|
||||
return uid ;
|
||||
}
|
||||
|
||||
static int CmdHF14BView(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -2342,8 +2378,8 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
|
||||
// read dump file
|
||||
uint8_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0xFF));
|
||||
size_t bytes_read = (ST25TB_SR_BLOCK_SIZE * 0x100);
|
||||
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0x100));
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
@ -2351,7 +2387,6 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
uint16_t block_cnt = bytes_read / ST25TB_SR_BLOCK_SIZE;
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
|
||||
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
|
||||
}
|
||||
|
||||
|
@ -2366,21 +2401,23 @@ static int CmdHF14BView(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"},
|
||||
{"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"},
|
||||
{"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"},
|
||||
{"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"},
|
||||
{"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"},
|
||||
{"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"},
|
||||
{"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"},
|
||||
{"---------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("general") " -----------------------"},
|
||||
{"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"},
|
||||
{"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"},
|
||||
{"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"},
|
||||
{"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"},
|
||||
{"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"},
|
||||
{"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"},
|
||||
{"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
// {"restore", CmdHF14BRestore, IfPm3Iso14443b, "Restore from file to all memory pages of an ISO-14443-B tag"},
|
||||
{"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO ISO-14443-B tag"},
|
||||
{"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO-14443-B"},
|
||||
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"},
|
||||
{"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 or SRIX4K tag"},
|
||||
{"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
// {"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"},
|
||||
{"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO ISO-14443-B tag"},
|
||||
{"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO-14443-B"},
|
||||
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"},
|
||||
{"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 or SRIX4K tag"},
|
||||
{"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
{"valid", CmdSRIX4kValid, AlwaysAvailable, "SRIX4k checksum test"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -986,7 +986,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
// Select EF_COM
|
||||
if (emrtd_select_file_by_ef(dg_table[EF_COM].fileid) == false) {
|
||||
*BAC = true;
|
||||
PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication.");
|
||||
PrintAndLogEx(INFO, "Authentication is enforced");
|
||||
PrintAndLogEx(INFO, "Switching to external authentication...");
|
||||
} else {
|
||||
*BAC = false;
|
||||
// Select EF_DG1
|
||||
|
@ -996,7 +997,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 };
|
||||
if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false) == false) {
|
||||
*BAC = true;
|
||||
PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication.");
|
||||
PrintAndLogEx(INFO, "Authentication is enforced");
|
||||
PrintAndLogEx(INFO, "Switching to external authentication...");
|
||||
} else {
|
||||
*BAC = false;
|
||||
}
|
||||
|
@ -1007,7 +1009,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA
|
|||
// If BAC isn't available, exit out and warn user.
|
||||
if (BAC_available == false) {
|
||||
PrintAndLogEx(ERR, "This eMRTD enforces authentication, but you didn't supply MRZ data. Cannot proceed.");
|
||||
PrintAndLogEx(HINT, "Check out hf emrtd info/dump --help, supply data with -n -d and -e.");
|
||||
PrintAndLogEx(HINT, "Check out `hf emrtd info/dump --h`, supply data with `-n` `-d` and `-e`");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,9 +177,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
if (isw != ISO7816_OK) {
|
||||
if (APDULogging) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);
|
||||
PrintAndLogEx(ERR, "APDU chaining len " _RED_("%02x"), *sw & 0xFF);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF));
|
||||
PrintAndLogEx(ERR, "APDU (%02x%02x) ERROR... " _RED_("%4X") " - %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF));
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
@ -189,30 +189,30 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
|
||||
int Iso7816Exchange(Iso7816CommandChannel channel, bool leave_field_on, sAPDU_t apdu, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
||||
return Iso7816ExchangeEx(channel
|
||||
, false
|
||||
, leave_field_on
|
||||
, apdu
|
||||
, false
|
||||
, 0
|
||||
, result
|
||||
, max_result_len
|
||||
, result_len
|
||||
, sw
|
||||
);
|
||||
, false
|
||||
, leave_field_on
|
||||
, apdu
|
||||
, false
|
||||
, 0
|
||||
, result
|
||||
, max_result_len
|
||||
, result_len
|
||||
, sw
|
||||
);
|
||||
}
|
||||
|
||||
int Iso7816Select(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on, uint8_t *aid, size_t aid_len,
|
||||
uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
||||
|
||||
return Iso7816ExchangeEx(channel
|
||||
, activate_field
|
||||
, leave_field_on
|
||||
, (sAPDU_t) {0x00, 0xa4, 0x04, 0x00, aid_len, aid}
|
||||
, (channel == CC_CONTACTLESS)
|
||||
, 0
|
||||
, result
|
||||
, max_result_len
|
||||
, result_len
|
||||
, sw
|
||||
);
|
||||
, activate_field
|
||||
, leave_field_on
|
||||
, (sAPDU_t) {0x00, 0xa4, 0x04, 0x00, aid_len, aid}
|
||||
, (channel == CC_CONTACTLESS)
|
||||
, 0
|
||||
, result
|
||||
, max_result_len
|
||||
, result_len
|
||||
, sw
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue