X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/10403a6a3005f81839603dcb415ee352f939c06b..f07e76c687291ad31eff9e76b2ebb72a326d01c1:/client/cmdhf14a.c diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 69c65893..15faa2bc 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -14,20 +14,19 @@ #include #include #include "util.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "data.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhf14a.h" -#include "../include/common.h" +#include "common.h" #include "cmdmain.h" -#include "../include/mifare.h" +#include "mifare.h" static int CmdHelp(const char *Cmd); static void waitCmd(uint8_t iLen); - // structure and database for uid -> tagtype lookups typedef struct { uint8_t uid; @@ -111,22 +110,17 @@ const manufactureName manufactureMapping[] = { // get a product description based on the UID // uid[8] tag uid // returns description of the best match -static char* getTagInfo(uint8_t uid) { +char* getTagInfo(uint8_t uid) { - int i, best = -1; + int i; int len = sizeof(manufactureMapping) / sizeof(manufactureName); - for ( i = 0; i < len; ++i ) { - if ( uid == manufactureMapping[i].uid) { - if (best == -1) { - best = i; - } - } - } + for ( i = 0; i < len; ++i ) + if ( uid == manufactureMapping[i].uid) + return manufactureMapping[i].desc; - if (best>=0) return manufactureMapping[best].desc; - - return manufactureMapping[i].desc; + //No match, return default + return manufactureMapping[len-1].desc; } int CmdHF14AList(const char *Cmd) @@ -135,11 +129,6 @@ int CmdHF14AList(const char *Cmd) return 0; } -void iso14a_set_timeout(uint32_t timeout) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; - SendCommand(&c); -} - int CmdHF14AReader(const char *Cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; @@ -151,7 +140,7 @@ int CmdHF14AReader(const char *Cmd) iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision if(select_status == 0) { PrintAndLog("iso14443a card select failed"); @@ -163,17 +152,43 @@ int CmdHF14AReader(const char *Cmd) return 0; } - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + if(select_status == 3) { + PrintAndLog("Card doesn't support standard iso14443-3 anticollision"); + PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + return 0; + } + PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); - - // Double & triple sized UID, can be mapped to a manufacturer. - if ( card.uidlen > 4 ) { - PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0])); - } switch (card.sak) { - case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; + case 0x00: + // check if the tag answers to GETVERSION (0x60) + c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; + c.arg[1] = 1; + c.arg[2] = 0; + c.d.asBytes[0] = 0x60; + SendCommand(&c); + WaitForResponse(CMD_ACK,&resp); + + uint8_t version[8] = {0x00}; + memcpy(&version, resp.d.asBytes, resp.arg[0]); + uint8_t len = resp.arg[0] & 0xff; + switch ( len){ + // todo, identify "Magic UL-C tags". // they usually have a static nonce response to 0x1A command. + // UL-EV1, size, check version[6] == 0x0b (smaller) 0x0b * 4 == 48 + case 0x0A:PrintAndLog("TYPE : NXP MIFARE Ultralight EV1 %d bytes", (version[6] == 0xB) ? 48 : 128); break; + case 0x01:PrintAndLog("TYPE : NXP MIFARE Ultralight C");break; + case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break; + } + + break; case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; @@ -189,6 +204,12 @@ int CmdHF14AReader(const char *Cmd) case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break; default: ; } + + // Double & triple sized UID, can be mapped to a manufacturer. + // HACK: does this apply for Ultralight cards? + if ( card.uidlen > 4 ) { + PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0])); + } // try to request ATS even if tag claims not to support it if (select_status == 2) { @@ -203,7 +224,7 @@ int CmdHF14AReader(const char *Cmd) memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes } - + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; @@ -351,7 +372,7 @@ int CmdHF14AReader(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK,&resp); uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog(" Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); + PrintAndLog("Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); // disconnect c.cmd = CMD_READER_ISO_14443a; @@ -359,7 +380,7 @@ int CmdHF14AReader(const char *Cmd) c.arg[1] = 0; c.arg[2] = 0; SendCommand(&c); - + return select_status; } @@ -417,9 +438,9 @@ int CmdHF14ASim(const char *Cmd) PrintAndLog(" syntax: hf 14a sim "); PrintAndLog(" types: 1 = MIFARE Classic"); PrintAndLog(" 2 = MIFARE Ultralight"); - PrintAndLog(" 3 = MIFARE DESFIRE"); + PrintAndLog(" 3 = MIFARE Desfire"); PrintAndLog(" 4 = ISO/IEC 14443-4"); - PrintAndLog(" 5 = MIFARE TNP3XXX"); + PrintAndLog(" 5 = MIFARE Tnp3xxx"); PrintAndLog(""); return 1; } @@ -485,7 +506,8 @@ int CmdHF14ASim(const char *Cmd) int CmdHF14ASnoop(const char *Cmd) { int param = 0; - if (param_getchar(Cmd, 0) == 'h') { + 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]"); @@ -496,7 +518,7 @@ int CmdHF14ASnoop(const char *Cmd) { } for (int i = 0; i < 2; i++) { - char ctmp = param_getchar(Cmd, i); + ctmp = param_getchar(Cmd, i); if (ctmp == 'c' || ctmp == 'C') param |= 0x01; if (ctmp == 'r' || ctmp == 'R') param |= 0x02; } @@ -506,33 +528,38 @@ int CmdHF14ASnoop(const char *Cmd) { return 0; } + int CmdHF14ACmdRaw(const char *cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; - uint8_t reply=1; - uint8_t crc=0; - uint8_t power=0; - uint8_t active=0; - uint8_t active_select=0; + bool reply=1; + bool crc = FALSE; + bool power = FALSE; + bool active = FALSE; + bool active_select = FALSE; uint16_t numbits=0; - uint16_t timeout=0; - uint8_t bTimeout=0; + bool bTimeout = FALSE; + uint32_t timeout=0; + bool topazmode = FALSE; char buf[5]=""; int i=0; uint8_t data[USB_CMD_DATA_SIZE]; - unsigned int datalen=0, temp; + uint16_t datalen=0; + uint32_t temp; if (strlen(cmd)<2) { - PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <0A 0B 0C ... hex>"); + PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-a] [-t] [-b] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -c calculate and append CRC"); PrintAndLog(" -p leave the signal field ON after receive"); PrintAndLog(" -a active signal field ON without select"); PrintAndLog(" -s active signal field ON with select"); PrintAndLog(" -b number of bits to send. Useful for send partial byte"); - PrintAndLog(" -t timeout"); + PrintAndLog(" -t timeout in ms"); + PrintAndLog(" -T use Topaz protocol to send command"); return 0; } + // strip while (*cmd==' ' || *cmd=='\t') cmd++; @@ -541,19 +568,19 @@ int CmdHF14ACmdRaw(const char *cmd) { if (cmd[i]=='-') { switch (cmd[i+1]) { case 'r': - reply=0; + reply = FALSE; break; case 'c': - crc=1; + crc = TRUE; break; case 'p': - power=1; + power = TRUE; break; case 'a': - active=1; + active = TRUE; break; case 's': - active_select=1; + active_select = TRUE; break; case 'b': sscanf(cmd+i+2,"%d",&temp); @@ -563,12 +590,15 @@ int CmdHF14ACmdRaw(const char *cmd) { i-=2; break; case 't': - bTimeout=1; + bTimeout = TRUE; sscanf(cmd+i+2,"%d",&temp); - timeout = temp & 0xFFFF; + timeout = temp; i+=3; while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i+=2; + i-=2; + break; + case 'T': + topazmode = TRUE; break; default: PrintAndLog("Invalid option"); @@ -599,10 +629,15 @@ int CmdHF14ACmdRaw(const char *cmd) { PrintAndLog("Invalid char on input"); return 0; } + if(crc && datalen>0 && datalenMAX_TIMEOUT) { - c.arg[2] = MAX_TIMEOUT; - PrintAndLog("Set timeout to 624 ms. The max we can wait for response"); + 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; + // Max buffer is USB_CMD_DATA_SIZE c.arg[1] = (datalen & 0xFFFF) | (numbits << 16); memcpy(c.d.asBytes,data,datalen); @@ -642,13 +683,14 @@ int CmdHF14ACmdRaw(const char *cmd) { return 0; } + static void waitCmd(uint8_t iSelect) { uint8_t *recv; UsbCommand resp; char *hexout; - if (WaitForResponseTimeout(CMD_ACK,&resp,10000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { recv = resp.d.asBytes; uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0]; PrintAndLog("received %i octets",iLen); @@ -675,7 +717,7 @@ static command_t CommandTable[] = {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, + {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL}