+int CmdHF14ASnoop(const char *Cmd) {
+ int param = 0;
+
+ uint8_t ctmp = param_getchar(Cmd, 0) ;
+ if (ctmp == 'h' || ctmp == 'H') {
+ PrintAndLog("It get data from the field and saves it into command buffer.");
+ PrintAndLog("Buffer accessible from command hf list 14a.");
+ PrintAndLog("Usage: hf 14a snoop [c][r]");
+ PrintAndLog("c - triggered by first data from card");
+ PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)");
+ PrintAndLog("sample: hf 14a snoop c r");
+ return 0;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ ctmp = param_getchar(Cmd, i);
+ if (ctmp == 'c' || ctmp == 'C') param |= 0x01;
+ if (ctmp == 'r' || ctmp == 'R') param |= 0x02;
+ }
+
+ UsbCommand c = {CMD_SNOOP_ISO_14443a, {param, 0, 0}};
+ SendCommand(&c);
+ return 0;
+}
+
+void DropField() {
+ UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
+ SendCommand(&c);
+}
+
+int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
+ static bool responseNum = false;
+ uint16_t cmdc = 0;
+ *dataoutlen = 0;
+
+ if (activateField) {
+ responseNum = false;
+ UsbCommand resp;
+
+ // Anticollision + SELECT card
+ UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_CLEAR_TRACE, 0, 0}};
+ SendCommand(&ca);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
+ return 1;
+ }
+
+ // check result
+ if (resp.arg[0] == 0) {
+ PrintAndLog("14aRAW ERROR: No card in field.");
+ return 1;
+ }
+
+ if (resp.arg[0] != 1 && resp.arg[0] != 2) {
+ PrintAndLog("14aRAW ERROR: card not in iso14443-4. res=%d.", resp.arg[0]);
+ return 1;
+ }
+
+ if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
+ // get ATS
+ UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}};
+ uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
+ memcpy(cr.d.asBytes, rats, 2);
+ SendCommand(&cr);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
+ return 1;
+ }
+
+ if (resp.arg[0] <= 0) { // ats_len
+ PrintAndLog("14aRAW ERROR: Can't get ATS.");
+ return 1;
+ }
+ }
+ }
+
+ if (leaveSignalON)
+ cmdc |= ISO14A_NO_DISCONNECT;
+
+ UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}};
+ uint8_t header[] = {0x0a | responseNum, 0x00};
+ responseNum ^= 1;
+ memcpy(c.d.asBytes, header, 2);
+ memcpy(&c.d.asBytes[2], datain, datainlen);
+ SendCommand(&c);
+
+ uint8_t *recv;
+ UsbCommand resp;
+
+ if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ recv = resp.d.asBytes;
+ int iLen = resp.arg[0];
+
+ if(!iLen) {
+ PrintAndLog("14aRAW ERROR: No card response.");
+ return 1;
+ }
+
+ *dataoutlen = iLen - 2;
+ if (*dataoutlen < 0)
+ *dataoutlen = 0;
+
+ if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
+ PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
+ return 2;
+ }
+
+ if (recv[0] != header[0]) {
+ PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]);
+ return 2;
+ }
+
+ memcpy(dataout, &recv[2], *dataoutlen);
+
+ // CRC Check
+ if (iLen == -1) {
+ PrintAndLog("14aRAW ERROR: ISO 14443A CRC error.");
+ return 3;
+ }
+
+
+ } else {
+ PrintAndLog("14aRAW ERROR: Reply timeout.");
+ return 4;
+ }
+
+ return 0;
+}
+
+int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) {
+ uint16_t cmdc = 0;
+
+ *chaining = false;
+
+ if (activateField) {
+ cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
+ }
+
+ // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
+ // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
+ // here length USB_CMD_DATA_SIZE=512
+ // timeout must be authomatically set by "get ATS"
+ UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}};
+ memcpy(c.d.asBytes, datain, datainlen);
+ SendCommand(&c);
+
+ uint8_t *recv;
+ UsbCommand resp;
+
+ if (activateField) {
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ PrintAndLog("APDU ERROR: Proxmark connection timeout.");
+ return 1;
+ }
+ if (resp.arg[0] != 1) {
+ PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]);
+ DropField();
+ return 1;
+ }
+ }
+
+ if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ recv = resp.d.asBytes;
+ int iLen = resp.arg[0];
+ uint8_t res = resp.arg[1];
+
+ int dlen = iLen - 2;
+ if (dlen < 0)
+ dlen = 0;
+ *dataoutlen += dlen;
+
+ if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
+ PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
+ return 2;
+ }
+
+ if(!iLen) {
+ PrintAndLog("APDU ERROR: No APDU response.");
+ return 1;
+ }
+
+ // check apdu length
+ if (iLen < 4 && iLen >= 0) {
+ PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
+ return 2;
+ }
+
+ // check block TODO
+ if (iLen == -2) {
+ PrintAndLog("APDU ERROR: Block type mismatch.");
+ return 2;
+ }
+
+ memcpy(dataout, recv, dlen);
+
+ // chaining
+ if ((res & 0x10) != 0) {
+ *chaining = true;
+ }
+
+ // CRC Check
+ if (iLen == -1) {
+ PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
+ return 3;
+ }
+ } else {
+ PrintAndLog("APDU ERROR: Reply timeout.");
+ return 4;
+ }
+
+ return 0;
+}
+
+
+int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
+ *dataoutlen = 0;
+ bool chaining = false;
+
+ int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining);
+
+ while (chaining) {
+ // I-block with chaining
+ res = CmdExchangeAPDU(NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining);
+
+ if (res) {
+ if (!leaveSignalON)
+ DropField();
+
+ return 100;
+ }
+ }
+
+ if (!leaveSignalON)
+ DropField();
+
+ return 0;
+}
+
+// ISO14443-4. 7. Half-duplex block transmission protocol
+int CmdHF14AAPDU(const char *cmd) {
+ uint8_t data[USB_CMD_DATA_SIZE];
+ int datalen = 0;
+ bool activateField = false;
+ bool leaveSignalON = false;
+ bool decodeTLV = false;
+
+ CLIParserInit("hf 14a apdu",
+ "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)",
+ "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n");
+
+ void* argtable[] = {
+ arg_param_begin,
+ arg_lit0("sS", "select", "activate field and select card"),
+ arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
+ arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
+ arg_strx1(NULL, NULL, "<APDU (hex)>", NULL),
+ arg_param_end
+ };
+ CLIExecWithReturn(cmd, argtable, false);
+
+ activateField = arg_get_lit(1);
+ leaveSignalON = arg_get_lit(2);
+ decodeTLV = arg_get_lit(3);
+ // len = data + PCB(1b) + CRC(2b)
+ CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2);
+
+
+ CLIParserFree();
+// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]);
+ PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
+
+ int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
+
+ if (res)
+ return res;
+
+ PrintAndLog("<<<< %s", sprint_hex(data, datalen));
+
+ PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
+
+ // TLV decoder
+ if (decodeTLV && datalen > 4) {
+ TLVPrintFromBuffer(data, datalen - 2);
+ }
+
+ return 0;
+}
+
+int CmdHF14ACmdRaw(const char *cmd) {
+ UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
+ bool reply=1;
+ bool crc = false;
+ bool power = false;
+ bool active = false;
+ bool active_select = false;
+ bool no_rats = false;
+ uint16_t numbits = 0;
+ bool bTimeout = false;
+ uint32_t timeout = 0;
+ bool topazmode = false;
+ uint8_t data[USB_CMD_DATA_SIZE];
+ int datalen = 0;
+
+ // extract parameters
+ CLIParserInit("hf 14a raw", "Send raw hex data to tag",
+ "Sample:\n"\
+ "\thf 14a raw -pa -b7 -t1000 52 -- execute WUPA\n"\
+ "\thf 14a raw -p 9320 -- anticollision\n"\
+ "\thf 14a raw -psc 60 00 -- select and mifare AUTH\n");
+ void* argtable[] = {
+ arg_param_begin,
+ arg_lit0("rR", "nreply", "do not read response"),
+ arg_lit0("cC", "crc", "calculate and append CRC"),
+ arg_lit0("pP", "power", "leave the signal field ON after receive"),
+ arg_lit0("aA", "active", "active signal field ON without select"),
+ arg_lit0("sS", "actives", "active signal field ON with select"),
+ arg_int0("bB", "bits", NULL, "number of bits to send. Useful for send partial byte"),
+ arg_int0("t", "timeout", NULL, "timeout in ms"),
+ arg_lit0("T", "topaz", "use Topaz protocol to send command"),
+ arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"),
+ arg_strx1(NULL, NULL, "<data (hex)>", NULL),
+ arg_param_end
+ };
+ // defaults
+ arg_get_int(6) = 0;
+ arg_get_int(7) = 0;
+
+ if (CLIParserParseString(cmd, argtable, arg_getsize(argtable), false)){
+ CLIParserFree();
+ return 0;
+ }
+
+ reply = !arg_get_lit(1);
+ crc = arg_get_lit(2);
+ power = arg_get_lit(3);
+ active = arg_get_lit(4);
+ active_select = arg_get_lit(5);
+ numbits = arg_get_int(6) & 0xFFFF;
+ timeout = arg_get_int(7);
+ bTimeout = (timeout > 0);
+ topazmode = arg_get_lit(8);
+ no_rats = arg_get_lit(9);
+ // len = data + CRC(2b)
+ if (CLIParamHexToBuf(arg_get_str(10), data, sizeof(data) -2, &datalen)) {
+ CLIParserFree();
+ return 1;
+ }
+
+ CLIParserFree();
+
+ // logic
+ if(crc && datalen>0 && datalen<sizeof(data)-2)
+ {
+ uint8_t first, second;
+ if (topazmode) {
+ ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second);
+ } else {
+ ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
+ }
+ data[datalen++] = first;
+ data[datalen++] = second;
+ }
+
+ if(active || active_select)
+ {
+ c.arg[0] |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
+ if(active)
+ c.arg[0] |= ISO14A_NO_SELECT;
+ }
+
+ if(bTimeout){
+ #define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
+ c.arg[0] |= ISO14A_SET_TIMEOUT;
+ if(timeout > MAX_TIMEOUT) {
+ timeout = MAX_TIMEOUT;
+ PrintAndLog("Set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
+ }
+ c.arg[2] = 13560000 / 1000 / (8*16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
+ }
+
+ if(power) {
+ c.arg[0] |= ISO14A_NO_DISCONNECT;
+ }
+
+ if(datalen > 0) {
+ c.arg[0] |= ISO14A_RAW;
+ }
+
+ if(topazmode) {
+ c.arg[0] |= ISO14A_TOPAZMODE;
+ }
+
+ if(no_rats) {
+ c.arg[0] |= ISO14A_NO_RATS;
+ }
+
+ // Max buffer is USB_CMD_DATA_SIZE (512)
+ c.arg[1] = (datalen & 0xFFFF) | ((uint32_t)numbits << 16);
+ memcpy(c.d.asBytes,data,datalen);
+
+ SendCommand(&c);
+
+ if (reply) {
+ int res = 0;
+ if (active_select)
+ res = waitCmd(1);
+ if (!res && datalen > 0)
+ waitCmd(0);
+ } // if reply
+ return 0;
+}
+
+
+static int waitCmd(uint8_t iSelect) {
+ uint8_t *recv;
+ UsbCommand resp;
+ char *hexout;
+
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+ recv = resp.d.asBytes;
+ uint8_t iLen = resp.arg[0];
+ if (iSelect){
+ iLen = resp.arg[1];
+ if (iLen){
+ PrintAndLog("Card selected. UID[%i]:", iLen);
+ } else {
+ PrintAndLog("Can't select card.");
+ }
+ } else {
+ PrintAndLog("received %i bytes:", iLen);
+ }
+ if(!iLen)
+ return 1;
+ hexout = (char *)malloc(iLen * 3 + 1);
+ if (hexout != NULL) {
+ for (int i = 0; i < iLen; i++) { // data in hex
+ sprintf(&hexout[i * 3], "%02X ", recv[i]);
+ }
+ PrintAndLog("%s", hexout);
+ free(hexout);
+ } else {
+ PrintAndLog("malloc failed your client has low memory?");
+ return 2;
+ }
+ } else {
+ PrintAndLog("timeout while waiting for reply.");
+ return 3;
+ }
+ return 0;