//----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh // Modified 2018 iceman // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- // High frequency ISO14443B commands //----------------------------------------------------------------------------- #include "cmdhf14b.h" #include #include "fileutils.h" #include "cmdparser.h" // command_t #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "crc16.h" #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14B protocol #define TIMEOUT 2000 static int CmdHelp(const char *Cmd); static int usage_hf_14b_info(void) { PrintAndLogEx(NORMAL, "Usage: hf 14b info [h] [s]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " s silently"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b info"); return 0; } static int usage_hf_14b_reader(void) { PrintAndLogEx(NORMAL, "Usage: hf 14b reader [h] [s]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " s silently"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b reader"); return 0; } static int usage_hf_14b_raw(void) { PrintAndLogEx(NORMAL, "Usage: hf 14b raw [-h] [-r] [-c] [-p] [-s / -ss] [-t] <0A 0B 0C ... hex>"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -r do not read response"); PrintAndLogEx(NORMAL, " -c calculate and append CRC"); PrintAndLogEx(NORMAL, " -p leave the field on after receive"); PrintAndLogEx(NORMAL, " -s active signal field ON with select"); PrintAndLogEx(NORMAL, " -ss active signal field ON with select for SRx ST Microelectronics tags"); PrintAndLogEx(NORMAL, " -t timeout in ms"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b raw -s -c -p 0200a40400"); return 0; } static int usage_hf_14b_sniff(void) { PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list 14b'"); PrintAndLogEx(NORMAL, "Usage: hf 14b sniff [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b sniff"); return 0; } static int usage_hf_14b_sim(void) { PrintAndLogEx(NORMAL, "Emulating ISO/IEC 14443 type B tag with 4 UID / PUPI"); PrintAndLogEx(NORMAL, "Usage: hf 14b sim [h] u "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " u 4byte UID/PUPI"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b sim"); PrintAndLogEx(NORMAL, " hf 14b sim u 11223344"); return 0; } static int usage_hf_14b_read_srx(void) { PrintAndLogEx(NORMAL, "Usage: hf 14b sriread [h] <1|2>"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b sriread 1"); PrintAndLogEx(NORMAL, " hf 14b sriread 2"); return 0; } static int usage_hf_14b_write_srx(void) { PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); PrintAndLogEx(NORMAL, " BLOCK number depends on tag, special block == FF"); PrintAndLogEx(NORMAL, " hex bytes of data to be written"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 7F 11223344"); PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 FF 11223344"); PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 15 11223344"); PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 FF 11223344"); return 0; } static int usage_hf_14b_dump(void) { PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n" "\n" "Usage: hf 14b dump [h] [card memory] \n" "Options:\n" "\th this help\n" "\t[card memory] 1 = SRIX4K (default), 2 = SRI512" "\tf filename, if no UID will be used as filename\n" "\n" "Example:\n" "\thf 14b dump f\n" "\thf 14b dump 2 f mydump"); return 0; } /* static void switch_on_field_14b(void) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT, 0, 0, NULL, 0); } */ static int switch_off_field_14b(void) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_DISCONNECT, 0, 0, NULL, 0); return 0; } static bool waitCmd14b(bool verbose) { PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { if ((resp.oldarg[0] & 0xFF) > 0) return false; uint16_t len = (resp.oldarg[1] & 0xFFFF); uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; memcpy(data, resp.data.asBytes, len); if (verbose) { if (len >= 3) { bool crc = check_crc(CRC_14443_B, data, len); PrintAndLogEx(SUCCESS, "[LEN %u] %s[%02X %02X] %s", len, sprint_hex(data, len - 2), data[len - 2], data[len - 1], (crc) ? _GREEN_("OK") : _RED_("FAIL") ); } else { PrintAndLogEx(SUCCESS, "[LEN %u] %s", len, sprint_hex(data, len)); } } return true; } else { PrintAndLogEx(WARNING, "command execution timeout"); return false; } } static int CmdHF14BList(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdTraceList("14b"); return 0; } static int CmdHF14BSim(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_14b_sim(); uint32_t pupi = 0; if (cmdp == 'u') { pupi = param_get32ex(Cmd, 1, 0, 16); } clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_SIMULATE, pupi, 0, 0, NULL, 0); return PM3_SUCCESS; } static int CmdHF14BSniff(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_14b_sniff(); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); return PM3_SUCCESS; } static int CmdHF14BCmdRaw(const char *Cmd) { bool reply = true, power = false, select = false, hasTimeout = false; char buf[5] = ""; int i = 0; uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; uint16_t datalen = 0; uint32_t flags = ISO14B_CONNECT; uint32_t temp = 0, user_timeout = 0, time_wait = 0; if (strlen(Cmd) < 3) return usage_hf_14b_raw(); // strip while (*Cmd == ' ' || *Cmd == '\t') ++Cmd; while (Cmd[i] != '\0') { if (Cmd[i] == ' ' || Cmd[i] == '\t') { ++i; continue; } if (Cmd[i] == '-') { switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_14b_raw(); case 'r': reply = false; break; case 'c': flags |= ISO14B_APPEND_CRC; break; case 'p': power = true; break; case 's': select = true; if (tolower(Cmd[i + 2]) == 's') { flags |= ISO14B_SELECT_SR; ++i; } else { flags |= ISO14B_SELECT_STD; } break; case 't': hasTimeout = true; sscanf(Cmd + i + 2, "%d", &user_timeout); i += 3; while (Cmd[i] != ' ' && Cmd[i] != '\0') { i++; } i -= 2; break; default: return usage_hf_14b_raw(); } i += 2; continue; } if ((Cmd[i] >= '0' && Cmd[i] <= '9') || (Cmd[i] >= 'a' && Cmd[i] <= 'f') || (Cmd[i] >= 'A' && Cmd[i] <= 'F')) { buf[strlen(buf) + 1] = 0; buf[strlen(buf)] = Cmd[i]; i++; if (strlen(buf) >= 2) { sscanf(buf, "%x", &temp); data[datalen++] = (uint8_t)(temp & 0xff); *buf = 0; memset(buf, 0x00, sizeof(buf)); } continue; } PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, i)); return PM3_EINVARG; } if (hasTimeout) { #define MAX_14B_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s flags |= ISO14B_SET_TIMEOUT; if (user_timeout > MAX_14B_TIMEOUT) { user_timeout = MAX_14B_TIMEOUT; PrintAndLogEx(INFO, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); } time_wait = 13560000 / 1000 / (8 * 16) * user_timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) } if (power == 0) 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; clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO14443B_COMMAND, flags, datalen, time_wait, data, datalen); if (!reply) return PM3_SUCCESS; bool success = true; // get back iso14b_card_select_t, don't print it. if (select) success = waitCmd14b(false); // get back response from the raw bytes you sent. if (success && datalen > 0) waitCmd14b(true); return PM3_SUCCESS; } static bool get_14b_UID(iso14b_card_select_t *card) { if (!card) return false; int8_t retry = 3; PacketResponseNG resp; // test for 14b SR while (retry--) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { uint8_t status = resp.oldarg[0]; if (status == 0) { memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); return true; } } } // retry // test 14b standard retry = 3; while (retry--) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { uint8_t status = resp.oldarg[0]; if (status == 0) { memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); return true; } } } // retry if (retry <= 0) PrintAndLogEx(WARNING, "timeout while waiting for reply."); return false; } // print full atqb info // bytes // 0,1,2,3 = application data // 4 = bit rate capacity // 5 = max frame size / -4 info // 6 = FWI / Coding options static void print_atqb_resp(uint8_t *data, uint8_t cid) { //PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(data+1,4)); PrintAndLogEx(NORMAL, " App Data: %s", sprint_hex(data, 4)); PrintAndLogEx(NORMAL, " Protocol: %s", sprint_hex(data + 4, 3)); uint8_t BitRate = data[4]; if (!BitRate) PrintAndLogEx(NORMAL, " Bit Rate: 106 kbit/s only PICC <-> PCD"); if (BitRate & 0x10) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC -> PCD supported"); if (BitRate & 0x20) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC -> PCD supported"); if (BitRate & 0x40) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC -> PCD supported"); if (BitRate & 0x01) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC <- PCD supported"); if (BitRate & 0x02) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC <- PCD supported"); if (BitRate & 0x04) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC <- PCD supported"); if (BitRate & 0x80) PrintAndLogEx(NORMAL, " Same bit rate <-> required"); uint16_t maxFrame = data[5] >> 4; if (maxFrame < 5) maxFrame = 8 * maxFrame + 16; else if (maxFrame == 5) maxFrame = 64; else if (maxFrame == 6) maxFrame = 96; else if (maxFrame == 7) maxFrame = 128; else if (maxFrame == 8) maxFrame = 256; else maxFrame = 257; PrintAndLogEx(NORMAL, "Max Frame Size: %u%s bytes", maxFrame, (maxFrame == 257) ? "+ RFU" : ""); uint8_t protocolT = data[5] & 0xF; PrintAndLogEx(NORMAL, " Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4", (protocolT) ? "" : "not "); uint8_t fwt = data[6] >> 4; if (fwt < 16) { uint32_t etus = (32 << fwt); uint32_t fwt_time = (302 << fwt); PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - %u ETUs | %u us", fwt, etus, fwt_time); } else { PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - RFU", fwt); } PrintAndLogEx(NORMAL, " App Data Code: Application is %s", (data[6] & 4) ? "Standard" : "Proprietary"); PrintAndLogEx(NORMAL, " Frame Options: NAD is %ssupported", (data[6] & 2) ? "" : "not "); PrintAndLogEx(NORMAL, " Frame Options: CID is %ssupported", (data[6] & 1) ? "" : "not "); PrintAndLogEx(NORMAL, "Tag :"); PrintAndLogEx(NORMAL, " Max Buf Length: %u (MBLI) %s", cid >> 4, (cid & 0xF0) ? "" : "chained frames not supported"); PrintAndLogEx(NORMAL, " CID : %u", cid & 0x0f); return; } // get SRx chip model (from UID) // from ST Microelectronics static char *get_ST_Chip_Model(uint8_t data) { static char model[20]; char *retStr = model; memset(model, 0, sizeof(model)); switch (data) { case 0x0: sprintf(retStr, "SRIX4K (Special)"); break; case 0x2: sprintf(retStr, "SR176"); break; case 0x3: sprintf(retStr, "SRIX4K"); break; case 0x4: sprintf(retStr, "SRIX512"); break; case 0x6: sprintf(retStr, "SRI512"); break; case 0x7: sprintf(retStr, "SRI4K"); break; case 0xC: sprintf(retStr, "SRT512"); break; default : sprintf(retStr, "Unknown"); break; } return retStr; } // REMAKE: /* static int print_ST_Lock_info(uint8_t model) { PrintAndLogEx(NORMAL, "Chip Write Protection Bits:"); // now interpret the data switch (model){ case 0x0: //fall through (SRIX4K special) case 0x3: //fall through (SRIx4K) case 0x7: // (SRI4K) //only need data[3] blk1 = 9; PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+3, 1)); PrintAndLogEx(NORMAL, " 07/08:%slocked", (data[3] & 1) ? " not " : " " ); for (uint8_t i = 1; i<8; i++){ PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[3] & (1 << i)) ? " not " : " " ); blk1++; } break; case 0x4: //fall through (SRIX512) case 0x6: //fall through (SRI512) case 0xC: // (SRT512) //need data[2] and data[3] blk1 = 0; PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 2)); for (uint8_t b=2; b<4; b++){ for (uint8_t i=0; i<8; i++){ PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " ); blk1++; } } break; case 0x2: // (SR176) //need data[2] blk1 = 0; PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 1)); for (uint8_t i = 0; i<8; i++){ PrintAndLogEx(NORMAL, " %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " ); blk1+=2; } break; default: return rawClose(); } return 1; } */ // print UID info from SRx chips (ST Microelectronics) static void print_st_general_info(uint8_t *data, uint8_t len) { //uid = first 8 bytes in data PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(SwapEndian64(data, 8, 8), len)); PrintAndLogEx(NORMAL, " MFG: %02X, %s", data[6], getTagInfo(data[6])); PrintAndLogEx(NORMAL, "Chip: %02X, %s", data[5] >> 2, get_ST_Chip_Model(data[5] >> 2)); } //05 00 00 = find one tag in field //1d xx xx xx xx 00 08 01 00 = attrib xx=UID (resp 10 [f9 e0]) //a3 = ? (resp 03 [e2 c2]) //02 = ? (resp 02 [6a d3]) // 022b (resp 02 67 00 [29 5b]) // 0200a40400 (resp 02 67 00 [29 5b]) // 0200a4040c07a0000002480300 (resp 02 67 00 [29 5b]) // 0200a4040c07a0000002480200 (resp 02 67 00 [29 5b]) // 0200a4040006a0000000010100 (resp 02 6a 82 [4b 4c]) // 0200a4040c09d27600002545500200 (resp 02 67 00 [29 5b]) // 0200a404000cd2760001354b414e4d30310000 (resp 02 6a 82 [4b 4c]) // 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c]) // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c]) //03 = ? (resp 03 [e3 c2]) //c2 = ? (resp c2 [66 15]) //b2 = ? (resp a3 [e9 67]) //a2 = ? (resp 02 [6a d3]) // 14b get and print Full Info (as much as we know) static bool HF14B_Std_Info(bool verbose) { bool isSuccess = false; // 14b get and print UID only (general info) clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); switch_off_field_14b(); return false; } iso14b_card_select_t card; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); uint64_t status = resp.oldarg[0]; switch (status) { case 0: PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; case 2: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); break; case 3: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); break; default: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); break; } return isSuccess; } // SRx get and print full info (needs more info...) static bool HF14B_ST_Info(bool verbose) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } iso14b_card_select_t card; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); uint64_t status = resp.oldarg[0]; if (status > 0) return false; print_st_general_info(card.uid, card.uidlen); //add locking bit information here. uint8_t data[16] = {0x00}; // uint8_t datalen = 2; // uint8_t resplen; // uint8_t blk1; // data[0] = 0x08; // // if (model == 0x2) { //SR176 has special command: // data[1] = 0xf; // resplen = 4; // } else { // data[1] = 0xff; // resplen = 6; // } // //std read cmd // if (HF14BCmdRaw(true, true, data, &datalen, false)==0) // return rawClose(); // if (datalen != resplen || !crc) return rawClose(); //print_ST_Lock_info(data[5]>>2); return true; } // menu command to get and print all info known about any known 14b tag static int CmdHF14Binfo(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_14b_info(); bool verbose = !(cmdp == 's'); return infoHF14B(verbose); } static bool HF14B_ST_Reader(bool verbose) { bool isSuccess = false; // SRx get and print general info about SRx chip from UID clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } iso14b_card_select_t card; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); uint64_t status = resp.oldarg[0]; switch (status) { case 0: print_st_general_info(card.uid, card.uidlen); isSuccess = true; break; case 1: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 random chip id fail"); break; case 2: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); break; case 3: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); break; default: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select SRx failed"); break; } return isSuccess; } static bool HF14B_Std_Reader(bool verbose) { bool isSuccess = false; // 14b get and print UID only (general info) clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } iso14b_card_select_t card; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); uint64_t status = resp.oldarg[0]; switch (status) { case 0: PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; case 2: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); break; case 3: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); break; default: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); break; } return isSuccess; } // test for other 14b type tags (mimic another reader - don't have tags to identify) static bool HF14B_Other_Reader() { // uint8_t data[] = {0x00, 0x0b, 0x3f, 0x80}; // uint8_t datalen = 4; // // 14b get and print UID only (general info) // uint32_t flags = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_RAW | ISO14B_APPEND_CRC; // clearCommandBuffer(); // SendCommandOLD(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen); // PacketResponseNG resp; // WaitForResponse(CMD_ACK,&resp); // if (datalen > 2 ) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); // PrintAndLogEx(NORMAL, "unknown tag type answered to a 0x000b3f80 command ans:"); // //PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); // rawclose(); // return true; // } // data[0] = ISO14443B_AUTHENTICATE; // clearCommandBuffer(); // SendCommandOLD(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); // PacketResponseNG resp; // WaitForResponse(CMD_ACK, &resp); // if (datalen > 0) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0A command ans:"); // // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); // rawClose(); // return true; // } // data[0] = ISO14443B_RESET; // clearCommandBuffer(); // SendCommandOLD(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); // PacketResponseNG resp; // WaitForResponse(CMD_ACK, &resp); // if (datalen > 0) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0C command ans:"); // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); // rawClose(); // return true; // } // rawClose(); return false; } // menu command to get and print general info about all known 14b chips static int CmdHF14BReader(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_14b_reader(); bool verbose = !(cmdp == 's'); return readHF14B(verbose); } /* New command to read the contents of a SRI512|SRIX4K tag * SRI* tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory/ */ static int CmdHF14BReadSri(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_read_srx(); uint8_t tagtype = param_get8(Cmd, 0); uint8_t blocks = (tagtype == 1) ? 0x7F : 0x0F; clearCommandBuffer(); SendCommandMIX(CMD_HF_SRI_READ, blocks, 0, 0, NULL, 0); return 0; } // New command to write a SRI512/SRIX4K tag. static int CmdHF14BWriteSri(const char *Cmd) { /* * For SRIX4K blocks 00 - 7F * hf 14b raw -c -p 09 $srix4kwblock $srix4kwdata * * For SR512 blocks 00 - 0F * hf 14b raw -c -p 09 $sr512wblock $sr512wdata * * Special block FF = otp_lock_reg block. * Data len 4 bytes- */ char cmdp = tolower(param_getchar(Cmd, 0)); uint8_t blockno = -1; uint8_t data[4] = {0x00}; bool isSrix4k = true; char str[30]; memset(str, 0x00, sizeof(str)); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_write_srx(); if (cmdp == '2') isSrix4k = false; //blockno = param_get8(Cmd, 1); if (param_gethex(Cmd, 1, &blockno, 2)) { PrintAndLogEx(WARNING, "block number must include 2 HEX symbols"); return 0; } if (isSrix4k) { if (blockno > 0x7f && blockno != 0xff) { PrintAndLogEx(FAILED, "block number out of range"); return PM3_ESOFT; } } else { if (blockno > 0x0f && blockno != 0xff) { PrintAndLogEx(FAILED, "block number out of range"); return PM3_ESOFT; } } if (param_gethex(Cmd, 2, data, 8)) { PrintAndLogEx(WARNING, "data must include 8 HEX symbols"); return PM3_ESOFT; } if (blockno == 0xff) { PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) ); } else { PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) ); } sprintf(str, "-ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); return CmdHF14BCmdRaw(str); } // need to write to file static int CmdHF14BDump(const char *Cmd) { uint8_t fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; bool errors = false; uint8_t cmdp = 0, cardtype = 1; uint16_t cardsize = 0; uint8_t blocks = 0; iso14b_card_select_t card; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_hf_14b_dump(); case 'f': fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); cmdp += 2; break; default: if (cmdp == 0) { cardtype = param_get8ex(Cmd, cmdp, 1, 10); cmdp++; } else { PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } } } //Validations if (errors) return usage_hf_14b_dump(); switch (cardtype) { case 2: cardsize = (512 / 8) + 4; blocks = 0x0F; break; case 1: default: cardsize = (4096 / 8) + 4; blocks = 0x7F; break; } if (!get_14b_UID(&card)) { PrintAndLogEx(WARNING, "No tag found."); return PM3_SUCCESS; } if (fileNameLen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); fptr += sprintf(fptr, "hf-14b-"); FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); } // detect blocksize from card :) PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprint_hex(card.uid, card.uidlen)); uint8_t data[cardsize]; memset(data, 0, sizeof(data)); int blocknum = 0; uint8_t *recv = NULL; PacketResponseNG resp; clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); //select if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { if (resp.oldarg[0]) { PrintAndLogEx(INFO, "failed to select %" PRId64 " | %" PRId64, resp.oldarg[0], resp.oldarg[1]); goto out; } } uint8_t req[2] = {ISO14443B_READ_BLK}; for (int retry = 0; retry < 5; retry++) { req[1] = blocknum; clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t status = resp.oldarg[0] & 0xFF; if (status > 0) { continue; } uint16_t len = (resp.oldarg[1] & 0xFFFF); recv = resp.data.asBytes; if (!check_crc(CRC_14443_B, recv, len)) { PrintAndLogEx(FAILED, "crc fail, retrying one more time"); continue; } memcpy(data + (blocknum * 4), resp.data.asBytes, 4); if (blocknum == 0xFF) { //last read. break; } retry = 0; blocknum++; if (blocknum > blocks) { // read config block blocknum = 0xFF; } printf("."); fflush(stdout); } } if (blocknum != 0xFF) { PrintAndLogEx(NORMAL, "\n Dump failed"); goto out; } PrintAndLogEx(NORMAL, "\n"); PrintAndLogEx(NORMAL, "block# | data | ascii"); PrintAndLogEx(NORMAL, "---------+--------------+----------"); for (int i = 0; i <= blocks; i++) { PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %s", i, i, sprint_hex(data + (i * 4), 4), sprint_ascii(data + (i * 4), 4) ); } PrintAndLogEx(NORMAL, "\n"); size_t datalen = (blocks + 1) * 4; saveFileEML(filename, data, datalen, 4); saveFile(filename, ".bin", data, datalen); out: return switch_off_field_14b(); } /* static uint32_t srix4kEncode(uint32_t value) { // vv = value // pp = position // vv vv vv pp // 4 bytes : 00 1A 20 01 // only the lower crumbs. uint8_t block = (value & 0xFF); uint8_t i = 0; uint8_t valuebytes[] = {0, 0, 0}; num_to_bytes(value, 3, valuebytes); // 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); // chksum part uint32_t chksum = 0xFF - block; // chksum is reduced by each nibbles of value. for (i = 0; i < 3; ++i) { chksum -= NIBBLE_HIGH(valuebytes[i]); chksum -= NIBBLE_LOW(valuebytes[i]); } // base4 conversion and left shift twice i = 3; uint8_t base4[] = {0, 0, 0, 0}; while (chksum != 0) { base4[i--] = (chksum % 4 << 2); chksum /= 4; } // merge scambled and chksum parts uint32_t encvalue = (NIBBLE_LOW(base4[0]) << 28) | (NIBBLE_HIGH(temp[0]) << 24) | (NIBBLE_LOW(base4[1]) << 20) | (NIBBLE_LOW(temp[0]) << 16) | (NIBBLE_LOW(base4[2]) << 12) | (NIBBLE_HIGH(temp[1]) << 8) | (NIBBLE_LOW(base4[3]) << 4) | NIBBLE_LOW(temp[1]); PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue); return encvalue; } static uint32_t srix4kDecode(uint32_t value) { switch (value) { case 0xC04F42C5: return 0x003139; case 0xC1484807: return 0x002943; case 0xC0C60848: return 0x001A20; } 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) { #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 doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1; uint32_t result = (uid32 * doubleBlock * counter) & MASK; PrintAndLogEx(SUCCESS, "Magic bytes | %08X", result); return result; } static int srix4kValid(const char *Cmd) { (void)Cmd; // Cmd is not used so far uint64_t uid = 0xD00202501A4532F9; uint32_t block6 = 0xFFFFFFFF; uint32_t block18 = 0xC04F42C5; 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); PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc, ""); uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19); PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21); return 0; } */ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO14443-B tag, save to file"}, {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, {"list", CmdHF14BList, AlwaysAvailable, "List ISO 14443B history"}, {"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, {"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a 14443B reader to identify a tag"}, {"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO 14443B tag"}, {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO 14443B"}, {"sriread", CmdHF14BReadSri, IfPm3Iso14443b, "Read contents of a SRI512 | SRIX4K tag"}, {"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 | SRIX4K tag"}, //{"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"}, {NULL, NULL, NULL, NULL} }; static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); return PM3_SUCCESS; } int CmdHF14B(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } // get and print all info known about any known 14b tag int infoHF14B(bool verbose) { // try std 14b (atqb) if (HF14B_Std_Info(verbose)) return 1; // try ST 14b if (HF14B_ST_Info(verbose)) return 1; // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); return 0; } // get and print general info about all known 14b chips int readHF14B(bool verbose) { // try std 14b (atqb) if (HF14B_Std_Reader(verbose)) return 1; // try ST Microelectronics 14b if (HF14B_ST_Reader(verbose)) return 1; // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. if (HF14B_Other_Reader()) return 1; if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); return 0; }