From ee1eadee0f50922d9d88692bbc5ea12a16e0d1fc Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 13 Mar 2015 07:36:52 +0100 Subject: [PATCH 1/9] add: start to support Topaz tags - hf 14a reader now exits gracefully in case of proprietary anticollision sequence - changed miller decoder to handle Topaz 8 data bits/no parity frames from reader - started to implement hf list topaz --- armsrc/iso14443a.c | 5 +++ armsrc/iso14443a.h | 2 +- client/cmdhf.c | 97 ++++++++++++++++++++++++++++++---------------- client/cmdhf14a.c | 14 ++++++- common/protocols.h | 17 ++++++-- 5 files changed, 96 insertions(+), 39 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index ac839cfd..f52e3eb8 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1719,6 +1719,11 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u memset(uid_ptr,0,10); } + // check for proprietary anticollision: + if ((resp[0] & 0x1F) == 0) { + return 3; + } + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 1e978e88..d99236b2 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -56,7 +56,7 @@ typedef struct { // DROP_FIRST_HALF, } state; uint16_t shiftReg; - uint16_t bitCount; + int16_t bitCount; uint16_t len; uint16_t byteCntMax; uint16_t posCnt; diff --git a/client/cmdhf.c b/client/cmdhf.c index 22063bbb..03d89c0b 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -141,6 +141,23 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) } } + +void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + + switch(cmd[0]) { + case TOPAZ_REQA :snprintf(exp, size, "REQA");break; + case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; + case TOPAZ_RID :snprintf(exp, size, "RID");break; + case TOPAZ_RALL :snprintf(exp, size, "RALL");break; + case TOPAZ_READ :snprintf(exp, size, "READ");break; + case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; + case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; + default: snprintf(exp,size,"?"); break; + } +} + + /** 06 00 = INITIATE 0E xx = SELECT ID (xx = Chip-ID) @@ -255,11 +272,18 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } } + +uint16_t merge_topaz_reader_frames(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *topaz_reader_command, uint16_t *data_len) +{ + return tracepos; +} + + uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles) { bool isResponse; uint16_t duration, data_len, parity_len; - + uint8_t topaz_reader_command[9]; uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; char explanation[30] = {0}; @@ -290,29 +314,35 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui uint8_t *parityBytes = trace + tracepos; tracepos += parity_len; + if (protocol == TOPAZ && !isResponse) { + // topaz reader commands come in 1 or 9 separate frames with 8 Bits each. + // merge them: + tracepos = merge_topaz_reader_frames(tracepos, traceLen, trace, topaz_reader_command, &data_len); + } + //Check the CRC status uint8_t crcStatus = 2; if (data_len > 2) { uint8_t b1, b2; - if(protocol == ICLASS) - { - crcStatus = iclass_CRC_check(isResponse, frame, data_len); - - }else if (protocol == ISO_14443B) - { - crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); - } - else if (protocol == ISO_14443A){//Iso 14443a - - ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); - - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - if(!(isResponse & (data_len < 6))) - { + switch (protocol) { + case ICLASS: + crcStatus = iclass_CRC_check(isResponse, frame, data_len); + break; + case ISO_14443B: + case TOPAZ: + crcStatus = iso14443B_CRC_check(isResponse, topaz_reader_command, data_len); + break; + case ISO_14443A: + ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + if(!(isResponse & (data_len < 6))) { crcStatus = 0; + } } - } + break; + default: + break; } } //0 CRC-command, CRC not ok @@ -361,12 +391,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if(!isResponse) { - if(protocol == ICLASS) - annotateIclass(explanation,sizeof(explanation),frame,data_len); - else if (protocol == ISO_14443A) - annotateIso14443a(explanation,sizeof(explanation),frame,data_len); - else if(protocol == ISO_14443B) - annotateIso14443b(explanation,sizeof(explanation),frame,data_len); + switch(protocol) { + case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break; + case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break; + default: break; + } } int num_lines = MIN((data_len - 1)/16 + 1, 16); @@ -382,7 +413,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } else { PrintAndLog(" | | | %-64s| %s| %s", line[j], - (j == num_lines-1)?crc:" ", + (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); } } @@ -425,20 +456,17 @@ int CmdHFList(const char *Cmd) } if(!errors) { - if(strcmp(type, "iclass") == 0) - { + if(strcmp(type, "iclass") == 0) { protocol = ICLASS; - }else if(strcmp(type, "14a") == 0) - { + } else if(strcmp(type, "14a") == 0) { protocol = ISO_14443A; - } - else if(strcmp(type, "14b") == 0) - { + } else if(strcmp(type, "14b") == 0) { protocol = ISO_14443B; - }else if(strcmp(type,"raw")== 0) - { + } else if(strcmp(type,"topaz")== 0) { + protocol = TOPAZ; + } else if(strcmp(type,"raw")== 0) { protocol = -1;//No crc, no annotations - }else{ + } else { errors = true; } } @@ -452,6 +480,7 @@ int CmdHFList(const char *Cmd) PrintAndLog(" 14a - interpret data as iso14443a communications"); PrintAndLog(" 14b - interpret data as iso14443b communications"); PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" topaz - interpret data as topaz communications"); PrintAndLog(""); PrintAndLog("example: hf list 14a f"); PrintAndLog("example: hf list iclass"); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index d36ebb8b..8978f43d 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -140,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"); @@ -152,6 +152,18 @@ int CmdHF14AReader(const char *Cmd) return 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("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); diff --git a/common/protocols.h b/common/protocols.h index 01b738c2..e687ca7a 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -168,9 +168,20 @@ NXP/Philips CUSTOM COMMANDS #define ISO15693_READ_MULTI_SECSTATUS 0x2C -#define ISO_14443A 0 -#define ICLASS 1 -#define ISO_14443B 2 +// Topaz command set: +#define TOPAZ_REQA 0x26 // Request +#define TOPAZ_WUPA 0x52 // WakeUp +#define TOPAZ_RID 0x78 // Read ID +#define TOPAZ_RALL 0x00 // Read All (all bytes) +#define TOPAZ_READ 0x01 // Read (a single byte) +#define TOPAZ_WRITE_E 0x53 // Write-with-erase (a single byte) +#define TOPAZ_WRITE_NE 0x1a // Write-no-erase (a single byte) + + +#define ISO_14443A 0 +#define ICLASS 1 +#define ISO_14443B 2 +#define TOPAZ 3 //-- Picopass fuses #define FUSE_FPERS 0x80 From a8904ebd46d747753c9f639f1577694c149ca5c2 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 15 Mar 2015 16:40:34 +0100 Subject: [PATCH 2/9] Change "hf list topaz" to "hf list nfc" fix: reduce length of expected unmodulated signal in Miller decoder in order to allow decoding of NFC reader communications add: hf list nfc: aggregate reader commands into one line add: hf list nfc: CRC check for NFC communications --- armsrc/iso14443a.c | 2 +- client/cmdhf.c | 72 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f52e3eb8..a78dae6e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -269,7 +269,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) if (Uart.state == STATE_UNSYNCD) { // not yet synced - if (Uart.highCnt < 2) { // wait for a stable unmodulated signal + if (Uart.highCnt < 1) { // wait for a stable unmodulated signal if (Uart.twoBits == 0xffff) { Uart.highCnt++; } else { diff --git a/client/cmdhf.c b/client/cmdhf.c index 03d89c0b..f4d76210 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -273,16 +273,55 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } -uint16_t merge_topaz_reader_frames(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *topaz_reader_command, uint16_t *data_len) +bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) { - return tracepos; + return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen); +} + + +bool next_record_is_response(uint16_t tracepos, uint8_t *trace) +{ + uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t))); + + return(next_records_datalen & 0x8000); +} + + +void merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) +{ + +#define MAX_TOPAZ_READER_CMD_LEN 9 + + uint32_t last_timestamp = timestamp + *duration; + + memcpy(topaz_reader_command, frame, MIN(*data_len, MAX_TOPAZ_READER_CMD_LEN)); + + while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) { + uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos)); + *tracepos += sizeof(uint32_t); + last_timestamp = next_timestamp + *((uint16_t *)(trace + *tracepos)); + *tracepos += sizeof(uint16_t); + uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF; + *tracepos += sizeof(uint16_t); + uint8_t *next_frame = (trace + *tracepos); + *tracepos += next_data_len; + if (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN) { + memcpy(topaz_reader_command + *data_len, next_frame, next_data_len); + *data_len += next_data_len; + } + uint16_t next_parity_len = (next_data_len-1)/8 + 1; + *tracepos += next_parity_len; + } + + *duration = last_timestamp - timestamp; } uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles) { bool isResponse; - uint16_t duration, data_len, parity_len; + uint16_t data_len, parity_len; + uint32_t duration; uint8_t topaz_reader_command[9]; uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; char explanation[30] = {0}; @@ -317,7 +356,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (protocol == TOPAZ && !isResponse) { // topaz reader commands come in 1 or 9 separate frames with 8 Bits each. // merge them: - tracepos = merge_topaz_reader_frames(tracepos, traceLen, trace, topaz_reader_command, &data_len); + merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len); + frame = topaz_reader_command; } //Check the CRC status @@ -331,7 +371,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui break; case ISO_14443B: case TOPAZ: - crcStatus = iso14443B_CRC_check(isResponse, topaz_reader_command, data_len); + crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); break; case ISO_14443A: ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); @@ -370,7 +410,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } - if(crcStatus == 1) + if(crcStatus == 1 || crcStatus == 2) {//CRC-command char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4)-1; (*pos1) = '['; @@ -418,19 +458,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } - if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; + if (is_last_record(tracepos, trace, traceLen)) return traceLen; - bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; - - if (showWaitCycles && !isResponse && next_isResponse) { + if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); } return tracepos; @@ -462,7 +498,7 @@ int CmdHFList(const char *Cmd) protocol = ISO_14443A; } else if(strcmp(type, "14b") == 0) { protocol = ISO_14443B; - } else if(strcmp(type,"topaz")== 0) { + } else if(strcmp(type,"nfc")== 0) { protocol = TOPAZ; } else if(strcmp(type,"raw")== 0) { protocol = -1;//No crc, no annotations From ef00343cb1f6ab306020c4108cd414e8df6b132f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 17 Mar 2015 07:41:08 +0100 Subject: [PATCH 3/9] revert change "hf list topaz" to "hf list nfc" refactored Startbit detection in MillerDecoding() relaxed startbit detection in MillerDecoding() fixed CRC checking and CRC bytes marking in hf list fixed topaz multi frame command listing in hf list topaz --- armsrc/iso14443a.c | 55 ++++++++++++---------------- armsrc/iso14443a.h | 3 +- client/cmdhf.c | 89 +++++++++++++++++++++++++++++++--------------- 3 files changed, 84 insertions(+), 63 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index a78dae6e..06a134f6 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -248,8 +248,7 @@ void UartReset() Uart.parityLen = 0; // number of decoded parity bytes Uart.shiftReg = 0; // shiftreg to hold decoded data bits Uart.parityBits = 0; // holds 8 parity bits - Uart.twoBits = 0x0000; // buffer for 2 Bits - Uart.highCnt = 0; + Uart.fourBits = 0x00000000; // buffer for 4 Bits Uart.startTime = 0; Uart.endTime = 0; } @@ -265,40 +264,34 @@ void UartInit(uint8_t *data, uint8_t *parity) static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { - Uart.twoBits = (Uart.twoBits << 8) | bit; + Uart.fourBits = (Uart.fourBits << 8) | bit; if (Uart.state == STATE_UNSYNCD) { // not yet synced - if (Uart.highCnt < 1) { // wait for a stable unmodulated signal - if (Uart.twoBits == 0xffff) { - Uart.highCnt++; - } else { - Uart.highCnt = 0; - } - } else { - Uart.syncBit = 0xFFFF; // not set - // we look for a ...1111111100x11111xxxxxx pattern (the start bit) - if ((Uart.twoBits & 0xDF00) == 0x1F00) Uart.syncBit = 8; // mask is 11x11111 xxxxxxxx, - // check for 00x11111 xxxxxxxx - else if ((Uart.twoBits & 0xEF80) == 0x8F80) Uart.syncBit = 7; // both masks shifted right one bit, left padded with '1' - else if ((Uart.twoBits & 0xF7C0) == 0xC7C0) Uart.syncBit = 6; // ... - else if ((Uart.twoBits & 0xFBE0) == 0xE3E0) Uart.syncBit = 5; - else if ((Uart.twoBits & 0xFDF0) == 0xF1F0) Uart.syncBit = 4; - else if ((Uart.twoBits & 0xFEF8) == 0xF8F8) Uart.syncBit = 3; - else if ((Uart.twoBits & 0xFF7C) == 0xFC7C) Uart.syncBit = 2; - else if ((Uart.twoBits & 0xFFBE) == 0xFE3E) Uart.syncBit = 1; - if (Uart.syncBit != 0xFFFF) { // found a sync bit - Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); - Uart.startTime -= Uart.syncBit; - Uart.endTime = Uart.startTime; - Uart.state = STATE_START_OF_COMMUNICATION; - } + Uart.syncBit = 9999; // not set + // we look for a ...xxxx1111111100x11111xxxxxx pattern + // (unmodulated, followed by the start bit = 8 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) +#define ISO14443A_STARTBIT_MASK 0x007FEF80 // mask is 00000000 01111111 11101111 10000000 +#define ISO14443A_STARTBIT_PATTERN 0x007F8F80 // pattern is 00000000 01111111 10001111 10000000 + if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 0 == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 1 == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 2 == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 3 == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 4 == ISO14443A_STARTBIT_PATTERN >> 4) Uart.syncBit = 3; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 5 == ISO14443A_STARTBIT_PATTERN >> 5) Uart.syncBit = 2; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 6 == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; + else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 7 == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; + if (Uart.syncBit != 9999) { // found a sync bit + Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); + Uart.startTime -= Uart.syncBit; + Uart.endTime = Uart.startTime; + Uart.state = STATE_START_OF_COMMUNICATION; } } else { - if (IsMillerModulationNibble1(Uart.twoBits >> Uart.syncBit)) { - if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) { // Modulation in both halves - error + if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error UartReset(); } else { // Modulation in first half = Sequence Z = logic "0" if (Uart.state == STATE_MILLER_X) { // error - must not follow after X @@ -322,7 +315,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } } } else { - if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" Uart.bitCount++; Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg Uart.state = STATE_MILLER_X; @@ -358,12 +351,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) return TRUE; // we are finished with decoding the raw data sequence } else { UartReset(); // Nothing received - start over - Uart.highCnt = 1; } } if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC UartReset(); - Uart.highCnt = 1; } else { // a logic "0" Uart.bitCount++; Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index d99236b2..ec99ab99 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -63,8 +63,7 @@ typedef struct { uint16_t syncBit; uint8_t parityBits; uint8_t parityLen; - uint16_t highCnt; - uint16_t twoBits; + uint32_t fourBits; uint32_t startTime, endTime; uint8_t *output; uint8_t *parity; diff --git a/client/cmdhf.c b/client/cmdhf.c index f4d76210..960dcf7f 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -189,7 +189,34 @@ void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) } /** - * @brief iso14443B_CRC_Ok Checks CRC in command or response + * @brief iso14443A_CRC_check Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ + +uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + + if(isResponse & (len < 6)) return 2; + + ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2); + if (b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } else { + return 1; + } +} + + +/** + * @brief iso14443B_CRC_check Checks CRC in command or response * @param isResponse * @param data * @param len @@ -206,9 +233,10 @@ uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2); if(b1 != data[len-2] || b2 != data[len-1]) { - return 0; + return 0; + } else { + return 1; } - return 1; } /** @@ -287,33 +315,42 @@ bool next_record_is_response(uint16_t tracepos, uint8_t *trace) } -void merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) +bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) { #define MAX_TOPAZ_READER_CMD_LEN 9 uint32_t last_timestamp = timestamp + *duration; - memcpy(topaz_reader_command, frame, MIN(*data_len, MAX_TOPAZ_READER_CMD_LEN)); + if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false; + + memcpy(topaz_reader_command, frame, *data_len); while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) { uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos)); *tracepos += sizeof(uint32_t); - last_timestamp = next_timestamp + *((uint16_t *)(trace + *tracepos)); + uint16_t next_duration = *((uint16_t *)(trace + *tracepos)); *tracepos += sizeof(uint16_t); uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF; *tracepos += sizeof(uint16_t); uint8_t *next_frame = (trace + *tracepos); *tracepos += next_data_len; - if (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN) { + if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) { memcpy(topaz_reader_command + *data_len, next_frame, next_data_len); *data_len += next_data_len; - } + last_timestamp = next_timestamp + next_duration; + } else { + // rewind and exit + *tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t); + break; + } uint16_t next_parity_len = (next_data_len-1)/8 + 1; *tracepos += next_parity_len; } *duration = last_timestamp - timestamp; + + return true; } @@ -354,32 +391,27 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui tracepos += parity_len; if (protocol == TOPAZ && !isResponse) { - // topaz reader commands come in 1 or 9 separate frames with 8 Bits each. + // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each. // merge them: - merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len); - frame = topaz_reader_command; + if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) { + frame = topaz_reader_command; + } } //Check the CRC status uint8_t crcStatus = 2; if (data_len > 2) { - uint8_t b1, b2; switch (protocol) { case ICLASS: crcStatus = iclass_CRC_check(isResponse, frame, data_len); break; case ISO_14443B: - case TOPAZ: + case TOPAZ: crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); break; case ISO_14443A: - ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - if(!(isResponse & (data_len < 6))) { - crcStatus = 0; - } - } + crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); break; default: break; @@ -403,19 +435,18 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } uint8_t parityBits = parityBytes[j>>3]; if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); - + snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]); } else { - snprintf(line[j/16]+(( j % 16) * 4),110, "%02x ", frame[j]); + snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); } } - if(crcStatus == 1 || crcStatus == 2) + if(crcStatus == 0 || crcStatus == 1) {//CRC-command - char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4)-1; + char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); (*pos1) = '['; - char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4)-2; - (*pos2) = ']'; + char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); + sprintf(pos2, "%c", ']'); } if(data_len == 0) { @@ -443,7 +474,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui int num_lines = MIN((data_len - 1)/16 + 1, 16); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s", + PrintAndLog(" %9d | %9d | %s |%-64s | %s| %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), (isResponse ? "Tag" : "Rdr"), @@ -451,7 +482,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); } else { - PrintAndLog(" | | | %-64s| %s| %s", + PrintAndLog(" | | |%-64s | %s| %s", line[j], (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); @@ -498,7 +529,7 @@ int CmdHFList(const char *Cmd) protocol = ISO_14443A; } else if(strcmp(type, "14b") == 0) { protocol = ISO_14443B; - } else if(strcmp(type,"nfc")== 0) { + } else if(strcmp(type,"topaz")== 0) { protocol = TOPAZ; } else if(strcmp(type,"raw")== 0) { protocol = -1;//No crc, no annotations From 05ddb52c43f932db852e18fe6836bee71e91f74e Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 18 Mar 2015 17:12:09 +0100 Subject: [PATCH 4/9] fix: introduced a stupid error when refactoring the start bit detector in MillerDecoding() chg: use -O2 instead of -Os when compiling ARM sources chg: don't clear the Miller decoders input buffer on reset chg: be more specific for the Miller decoders start bit pattern add: new option c in hf list: mark CRC bytes (default is off) --- armsrc/Makefile | 2 +- armsrc/iso14443a.c | 49 ++++++++++++++++------------ client/Makefile | 71 +++++++++++++++++++++-------------------- client/cmdhf.c | 72 +++++++++++++++++++++++++----------------- client/cmdhftopaz.c | 71 +++++++++++++++++++++++++++++++++++++++++ client/cmdhftopaz.h | 16 ++++++++++ common/Makefile.common | 2 +- 7 files changed, 197 insertions(+), 86 deletions(-) create mode 100644 client/cmdhftopaz.c create mode 100644 client/cmdhftopaz.h diff --git a/armsrc/Makefile b/armsrc/Makefile index 75ccdece..03541d61 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,7 +10,7 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE -fno-strict-aliasing +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE -fno-strict-aliasing -O2 #-DWITH_LCD #SRC_LCD = fonts.c LCD.c diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 06a134f6..0bd681d9 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -232,13 +232,19 @@ void AppendCrc14443a(uint8_t* data, int len) static tUart Uart; // Lookup-Table to decide if 4 raw bits are a modulation. -// We accept two or three consecutive "0" in any position with the rest "1" +// We accept the following: +// 0001 - a 3 tick wide pause +// 0011 - a 2 tick wide pause, or a three tick wide pause shifted left +// 0111 - a 2 tick wide pause shifted left +// 1001 - a 2 tick wide pause shifted right const bool Mod_Miller_LUT[] = { - TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, - TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE +// TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, +// TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE + FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, + FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }; -#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x00F0) >> 4]) -#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x000F)]) +#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x000000F0) >> 4]) +#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x0000000F)]) void UartReset() { @@ -248,7 +254,6 @@ void UartReset() Uart.parityLen = 0; // number of decoded parity bytes Uart.shiftReg = 0; // shiftreg to hold decoded data bits Uart.parityBits = 0; // holds 8 parity bits - Uart.fourBits = 0x00000000; // buffer for 4 Bits Uart.startTime = 0; Uart.endTime = 0; } @@ -257,6 +262,7 @@ void UartInit(uint8_t *data, uint8_t *parity) { Uart.output = data; Uart.parity = parity; + Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits UartReset(); } @@ -269,18 +275,21 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) if (Uart.state == STATE_UNSYNCD) { // not yet synced Uart.syncBit = 9999; // not set - // we look for a ...xxxx1111111100x11111xxxxxx pattern - // (unmodulated, followed by the start bit = 8 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) -#define ISO14443A_STARTBIT_MASK 0x007FEF80 // mask is 00000000 01111111 11101111 10000000 -#define ISO14443A_STARTBIT_PATTERN 0x007F8F80 // pattern is 00000000 01111111 10001111 10000000 - if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 0 == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 1 == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 2 == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 3 == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 4 == ISO14443A_STARTBIT_PATTERN >> 4) Uart.syncBit = 3; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 5 == ISO14443A_STARTBIT_PATTERN >> 5) Uart.syncBit = 2; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 6 == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; - else if ((Uart.fourBits & ISO14443A_STARTBIT_MASK) >> 7 == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; + // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from + // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111) + // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern + // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) +#define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 +#define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 + if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 3)) == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 4)) == ISO14443A_STARTBIT_PATTERN >> 4) Uart.syncBit = 3; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 5)) == ISO14443A_STARTBIT_PATTERN >> 5) Uart.syncBit = 2; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 6)) == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; + else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 7)) == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; + if (Uart.syncBit != 9999) { // found a sync bit Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Uart.startTime -= Uart.syncBit; @@ -646,7 +655,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { TRUE)) break; } /* And ready to receive another command. */ - UartReset(); + UartInit(receivedCmd, receivedCmdPar); /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ DemodReset(); @@ -2798,7 +2807,7 @@ void RAMFUNC SniffMifare(uint8_t param) { if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, TRUE)) break; /* And ready to receive another command. */ - UartReset(); + UartInit(receivedCmd, receivedCmdPar); /* And also reset the demod code */ DemodReset(); diff --git a/client/Makefile b/client/Makefile index 6ec34469..2e1c2092 100644 --- a/client/Makefile +++ b/client/Makefile @@ -65,41 +65,42 @@ CMDSRCS = nonce2key/crapto1.c\ loclass/ikeys.c \ loclass/elite_crack.c\ loclass/fileutils.c\ - mifarehost.c\ - crc16.c \ - iso14443crc.c \ - iso15693tools.c \ - data.c \ - graph.c \ - ui.c \ - cmddata.c \ - lfdemod.c \ - cmdhf.c \ - cmdhf14a.c \ - cmdhf14b.c \ - cmdhf15.c \ - cmdhfepa.c \ - cmdhflegic.c \ - cmdhficlass.c \ - cmdhfmf.c \ - cmdhfmfu.c \ - cmdhw.c \ - cmdlf.c \ - cmdlfio.c \ - cmdlfhid.c \ - cmdlfem4x.c \ - cmdlfhitag.c \ - cmdlfti.c \ - cmdparser.c \ - cmdmain.c \ - cmdlft55xx.c \ - cmdlfpcf7931.c\ - pm3_binlib.c\ - scripting.c\ - cmdscript.c\ - pm3_bitlib.c\ - aes.c\ - protocols.c\ + mifarehost.c\ + crc16.c \ + iso14443crc.c \ + iso15693tools.c \ + data.c \ + graph.c \ + ui.c \ + cmddata.c \ + lfdemod.c \ + cmdhf.c \ + cmdhf14a.c \ + cmdhf14b.c \ + cmdhf15.c \ + cmdhfepa.c \ + cmdhflegic.c \ + cmdhficlass.c \ + cmdhfmf.c \ + cmdhfmfu.c \ + cmdhftopaz.c \ + cmdhw.c \ + cmdlf.c \ + cmdlfio.c \ + cmdlfhid.c \ + cmdlfem4x.c \ + cmdlfhitag.c \ + cmdlfti.c \ + cmdparser.c \ + cmdmain.c \ + cmdlft55xx.c \ + cmdlfpcf7931.c\ + pm3_binlib.c\ + scripting.c\ + cmdscript.c\ + pm3_bitlib.c\ + aes.c\ + protocols.c\ COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o) diff --git a/client/cmdhf.c b/client/cmdhf.c index 960dcf7f..0d678ab6 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -23,6 +23,7 @@ #include "cmdhficlass.h" #include "cmdhfmf.h" #include "cmdhfmfu.h" +#include "cmdhftopaz.h" #include "protocols.h" static int CmdHelp(const char *Cmd); @@ -354,7 +355,7 @@ bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t } -uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles) +uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes) { bool isResponse; uint16_t data_len, parity_len; @@ -441,13 +442,17 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } - if(crcStatus == 0 || crcStatus == 1) - {//CRC-command - char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); - (*pos1) = '['; - char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); - sprintf(pos2, "%c", ']'); + + if (markCRCBytes) { + if(crcStatus == 0 || crcStatus == 1) + {//CRC-command + char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); + (*pos1) = '['; + char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); + sprintf(pos2, "%c", ']'); + } } + if(data_len == 0) { if(data_len == 0){ @@ -507,22 +512,26 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui int CmdHFList(const char *Cmd) { bool showWaitCycles = false; + bool markCRCBytes = false; char type[40] = {0}; int tlen = param_getstr(Cmd,0,type); - char param = param_getchar(Cmd, 1); + char param1 = param_getchar(Cmd, 1); + char param2 = param_getchar(Cmd, 2); bool errors = false; uint8_t protocol = 0; //Validate params - if(tlen == 0) - { + + if(tlen == 0) { errors = true; } - if(param == 'h' || (param !=0 && param != 'f')) - { + + if(param1 == 'h' + || (param1 != 0 && param1 != 'f' && param1 != 'c') + || (param2 != 0 && param2 != 'f' && param2 != 'c')) { errors = true; } - if(!errors) - { + + if(!errors) { if(strcmp(type, "iclass") == 0) { protocol = ICLASS; } else if(strcmp(type, "14a") == 0) { @@ -540,8 +549,9 @@ int CmdHFList(const char *Cmd) if (errors) { PrintAndLog("List protocol data in trace buffer."); - PrintAndLog("Usage: hf list [f]"); + PrintAndLog("Usage: hf list [f][c]"); PrintAndLog(" f - show frame delay times as well"); + PrintAndLog(" c - mark CRC bytes"); PrintAndLog("Supported values:"); PrintAndLog(" raw - just show raw data without annotations"); PrintAndLog(" 14a - interpret data as iso14443a communications"); @@ -555,10 +565,13 @@ int CmdHFList(const char *Cmd) } - if (param == 'f') { + if (param1 == 'f' || param2 == 'f') { showWaitCycles = true; } + if (param1 == 'c' || param2 == 'c') { + markCRCBytes = true; + } uint8_t *trace; uint16_t tracepos = 0; @@ -592,7 +605,7 @@ int CmdHFList(const char *Cmd) while(tracepos < traceLen) { - tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles); + tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); } free(trace); @@ -602,18 +615,19 @@ int CmdHFList(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, - {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, - {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, - {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, - {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, - {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {"list", CmdHFList, 1, "List protocol data in trace buffer"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, + {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, + {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, + {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, + {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, + {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, + {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, + {"list", CmdHFList, 1, "List protocol data in trace buffer"}, + {NULL, NULL, 0, NULL} }; int CmdHF(const char *Cmd) diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c new file mode 100644 index 00000000..d747ed05 --- /dev/null +++ b/client/cmdhftopaz.c @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2015 Piwi +// +// 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 Topaz (NFC Type 1) commands +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "cmdmain.h" +#include "cmdparser.h" +#include "cmdhftopaz.h" +#include "cmdhf14a.h" +#include "ui.h" + +int CmdHFTopazReader(const char *Cmd) +{ + PrintAndLog("not yet implemented"); + return 0; +} + + +int CmdHFTopazSim(const char *Cmd) +{ + PrintAndLog("not yet implemented"); + return 0; +} + + +int CmdHFTopazCmdRaw(const char *Cmd) +{ + PrintAndLog("not yet implemented"); + return 0; +} + + +static int CmdHelp(const char *Cmd); + + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"reader", CmdHFTopazReader, 0, "Act like a Topaz reader"}, + {"sim", CmdHFTopazSim, 0, " -- Simulate Topaz tag"}, + {"snoop", CmdHF14ASnoop, 0, "Eavesdrop a Topaz reader-tag communication"}, + {"raw", CmdHFTopazCmdRaw, 0, "Send raw hex data to tag"}, + {NULL, NULL, 0, NULL} +}; + + +int CmdHFTopaz(const char *Cmd) { + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + + // parse + CmdsParse(CommandTable, Cmd); + return 0; +} + +static int CmdHelp(const char *Cmd) +{ + CmdsHelp(CommandTable); + return 0; +} + + diff --git a/client/cmdhftopaz.h b/client/cmdhftopaz.h new file mode 100644 index 00000000..8d5428dd --- /dev/null +++ b/client/cmdhftopaz.h @@ -0,0 +1,16 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2015 Piwi +// +// 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 Topaz (NFC Type 1) commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFTOPAZ_H__ +#define CMDHFTOPAZ_H__ + +int CmdHFTopaz(const char *Cmd); + +#endif diff --git a/common/Makefile.common b/common/Makefile.common index 2b2bb2fb..7e264d28 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -66,7 +66,7 @@ VPATH = . ../common/ ../fpga/ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES) -CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os +CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 -Os $(APP_CFLAGS) LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n LIBS = -lgcc From 48ece4a750b41536ba2c56dfd9a088b192976c82 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 20 Mar 2015 21:06:51 +0100 Subject: [PATCH 5/9] add: Topaz mode for "hf 14a raw" (new option -T) chg: allow tracing without parity chg: make "hf list topaz" aware of additional commands for Dynamic Memory Model --- armsrc/BigBuf.c | 17 +++++++----- armsrc/iso14443a.c | 60 ++++++++++++++++++++++++++++++++--------- client/cmdhf.c | 11 +++++--- client/cmdhf14a.c | 58 ++++++++++++++++++++++++++-------------- client/cmdhftopaz.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ common/protocols.h | 5 ++++ include/mifare.h | 17 ++++++------ 7 files changed, 182 insertions(+), 51 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 703ade65..51fafdeb 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -171,18 +171,19 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ traceLen += iLen; // parity bytes - if (parity != NULL && iLen != 0) { - memcpy(trace + traceLen, parity, num_paritybytes); + if (iLen != 0) { + if (parity != NULL) { + memcpy(trace + traceLen, parity, num_paritybytes); + } else { + memset(trace + traceLen, 0x00, num_paritybytes); + } } traceLen += num_paritybytes; - if(traceLen +4 < max_traceLen) - { //If it hadn't been cleared, for whatever reason.. - memset(trace+traceLen,0x44, 4); - } - return TRUE; } + + int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag) { /** @@ -224,6 +225,8 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP return TRUE; } + + // Emulator memory uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){ uint8_t* mem = BigBuf_get_EM_addr(); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 0bd681d9..81cb9728 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -213,6 +213,12 @@ void AppendCrc14443a(uint8_t* data, int len) ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1); } +void AppendCrc14443b(uint8_t* data, int len) +{ + ComputeCrc14443(CRC_14443_B,data,len,data+len,data+len+1); +} + + //============================================================================= // ISO 14443 Type A - Miller decoder //============================================================================= @@ -238,8 +244,6 @@ static tUart Uart; // 0111 - a 2 tick wide pause shifted left // 1001 - a 2 tick wide pause shifted right const bool Mod_Miller_LUT[] = { -// TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, -// TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }; @@ -279,8 +283,8 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111) // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) -#define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 -#define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 + #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 + #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; @@ -655,7 +659,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { TRUE)) break; } /* And ready to receive another command. */ - UartInit(receivedCmd, receivedCmdPar); + UartReset(); /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ DemodReset(); @@ -680,6 +684,9 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // And ready to receive another response. DemodReset(); + // And reset the Miller decoder including itS (now outdated) input buffer + UartInit(receivedCmd, receivedCmdPar); + LED_C_OFF(); } TagIsActive = (Demod.state != DEMOD_UNSYNCD); @@ -1337,7 +1344,7 @@ void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8 } // Only transmit parity bit if we transmitted a complete byte - if (j == 8) { + if (j == 8 && parity != NULL) { // Get the parity bit if (parity[i>>3] & (0x80 >> (i&0x0007))) { // Sequence X @@ -1631,6 +1638,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive } } + void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { CodeIso14443aBitsAsReaderPar(frame, bits, par); @@ -1646,11 +1654,13 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t } } + void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing) { ReaderTransmitBitsPar(frame, len*8, par, timing); } + void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect @@ -1659,6 +1669,7 @@ void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) ReaderTransmitBitsPar(frame, len, par, timing); } + void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect @@ -1932,15 +1943,38 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_RAW) { if(param & ISO14A_APPEND_CRC) { - AppendCrc14443a(cmd,len); + if(param & ISO14A_TOPAZMODE) { + AppendCrc14443b(cmd,len); + } else { + AppendCrc14443a(cmd,len); + } len += 2; if (lenbits) lenbits += 16; } - if(lenbits>0) { - GetParity(cmd, lenbits/8, par); - ReaderTransmitBitsPar(cmd, lenbits, par, NULL); - } else { - ReaderTransmit(cmd,len, NULL); + if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) + if(param & ISO14A_TOPAZMODE) { + int bits_to_send = lenbits; + uint16_t i = 0; + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity + bits_to_send -= 7; + while (bits_to_send > 0) { + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity + bits_to_send -= 8; + } + } else { + GetParity(cmd, lenbits/8, par); + ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity + } + } else { // want to send complete bytes only + if(param & ISO14A_TOPAZMODE) { + uint16_t i = 0; + ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy + while (i < len) { + ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy + } + } else { + ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity + } } arg0 = ReaderReceive(buf, par); cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); @@ -2824,6 +2858,8 @@ void RAMFUNC SniffMifare(uint8_t param) { // And ready to receive another response. DemodReset(); + // And reset the Miller decoder including its (now outdated) input buffer + UartInit(receivedCmd, receivedCmdPar); } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } diff --git a/client/cmdhf.c b/client/cmdhf.c index 0d678ab6..66c8e53c 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -145,7 +145,6 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { - switch(cmd[0]) { case TOPAZ_REQA :snprintf(exp, size, "REQA");break; case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; @@ -154,6 +153,10 @@ void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case TOPAZ_READ :snprintf(exp, size, "READ");break; case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; + case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break; + case TOPAZ_READ8 :snprintf(exp, size, "READ8");break; + case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break; + case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break; default: snprintf(exp,size,"?"); break; } } @@ -319,7 +322,7 @@ bool next_record_is_response(uint16_t tracepos, uint8_t *trace) bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) { -#define MAX_TOPAZ_READER_CMD_LEN 9 +#define MAX_TOPAZ_READER_CMD_LEN 16 uint32_t last_timestamp = timestamp + *duration; @@ -479,7 +482,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui int num_lines = MIN((data_len - 1)/16 + 1, 16); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLog(" %9d | %9d | %s |%-64s | %s| %s", + PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), (isResponse ? "Tag" : "Rdr"), @@ -487,7 +490,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); } else { - PrintAndLog(" | | |%-64s | %s| %s", + PrintAndLog(" | | |%-64s | %s| %s", line[j], (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 8978f43d..214ff1ec 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -509,20 +509,22 @@ 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; - uint16_t numbits=0; - uint32_t timeout=0; - uint8_t bTimeout=0; + bool reply=1; + bool crc = FALSE; + bool power = FALSE; + bool active = FALSE; + bool active_select = FALSE; + uint16_t numbits = 0; + bool bTimeout = FALSE; + uint32_t timeout = 0; + bool topazmode = FALSE; char buf[5]=""; - int i=0; + int i = 0; uint8_t data[USB_CMD_DATA_SIZE]; - uint16_t datalen=0; + uint16_t datalen = 0; uint32_t temp; if (strlen(cmd)<2) { @@ -534,9 +536,11 @@ int CmdHF14ACmdRaw(const char *cmd) { PrintAndLog(" -s active signal field ON with select"); PrintAndLog(" -b number of bits to send. Useful for send partial byte"); PrintAndLog(" -t timeout in ms"); + PrintAndLog(" -T use Topaz protocol to send command"); return 0; } + // strip while (*cmd==' ' || *cmd=='\t') cmd++; @@ -545,19 +549,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); @@ -567,13 +571,16 @@ int CmdHF14ACmdRaw(const char *cmd) { i-=2; break; case 't': - bTimeout=1; + bTimeout = TRUE; sscanf(cmd+i+2,"%d",&temp); timeout = temp; i+=3; while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } i-=2; break; + case 'T': + topazmode = TRUE; + break; default: PrintAndLog("Invalid option"); return 0; @@ -603,10 +610,15 @@ int CmdHF14ACmdRaw(const char *cmd) { PrintAndLog("Invalid char on input"); return 0; } + if(crc && datalen>0 && datalen MAX_TIMEOUT) { timeout = MAX_TIMEOUT; @@ -627,11 +639,16 @@ int CmdHF14ACmdRaw(const char *cmd) { } 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) + + 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); @@ -647,6 +664,7 @@ int CmdHF14ACmdRaw(const char *cmd) { return 0; } + static void waitCmd(uint8_t iSelect) { uint8_t *recv; @@ -656,7 +674,7 @@ static void waitCmd(uint8_t iSelect) 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); + PrintAndLog("received %i octets", iLen); if(!iLen) return; hexout = (char *)malloc(iLen * 3 + 1); diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index d747ed05..aed5f023 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -17,6 +17,71 @@ #include "cmdhftopaz.h" #include "cmdhf14a.h" #include "ui.h" +#include "mifare.h" +#include "proxmark3.h" +#include "iso14443crc.h" +#include "protocols.h" + + + +static void topaz_switch_on_field(void) +{ + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK, &resp); +} + + +static void topaz_switch_off_field(void) +{ + UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK, &resp); +} + + +static void topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) +{ + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, len, 0}}; + memcpy(c.d.asBytes, cmd, len); + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK, &resp); + + memcpy(response, resp.d.asBytes, resp.arg[0]); +} + + +static void topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response) +{ + if (len > 1) { + uint8_t first, second; + ComputeCrc14443(CRC_14443_B, cmd, len, &first, &second); + cmd[len] = first; + cmd[len+1] = second; + } + + topaz_send_cmd_raw(cmd, len+2, response); +} + + +static void topaz_select(uint8_t *atqa, uint8_t *uid) +{ + // ToDo: implement anticollision + uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t wupa_cmd[] = {TOPAZ_WUPA}; + + topaz_switch_on_field(); + topaz_send_cmd(wupa_cmd, sizeof(wupa_cmd), atqa); + topaz_send_cmd(rid_cmd, sizeof(rid_cmd) - 2, uid); + topaz_switch_off_field(); +} + int CmdHFTopazReader(const char *Cmd) { diff --git a/common/protocols.h b/common/protocols.h index e687ca7a..b0f16570 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -176,6 +176,11 @@ NXP/Philips CUSTOM COMMANDS #define TOPAZ_READ 0x01 // Read (a single byte) #define TOPAZ_WRITE_E 0x53 // Write-with-erase (a single byte) #define TOPAZ_WRITE_NE 0x1a // Write-no-erase (a single byte) +// additional commands for Dynamic Memory Model +#define TOPAZ_RSEG 0x10 // Read segment +#define TOPAZ_READ8 0x02 // Read (eight bytes) +#define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes) +#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes) #define ISO_14443A 0 diff --git a/include/mifare.h b/include/mifare.h index e2b7a7c5..ad86886d 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -26,14 +26,15 @@ typedef struct { } __attribute__((__packed__)) iso14a_card_select_t; typedef enum ISO14A_COMMAND { - ISO14A_CONNECT = 1, - ISO14A_NO_DISCONNECT = 2, - ISO14A_APDU = 4, - ISO14A_RAW = 8, - ISO14A_REQUEST_TRIGGER = 0x10, - ISO14A_APPEND_CRC = 0x20, - ISO14A_SET_TIMEOUT = 0x40, - ISO14A_NO_SELECT = 0x80 + ISO14A_CONNECT = (1 << 0), + ISO14A_NO_DISCONNECT = (1 << 1), + ISO14A_APDU = (1 << 2), + ISO14A_RAW = (1 << 3), + ISO14A_REQUEST_TRIGGER = (1 << 4), + ISO14A_APPEND_CRC = (1 << 5), + ISO14A_SET_TIMEOUT = (1 << 6), + ISO14A_NO_SELECT = (1 << 7), + ISO14A_TOPAZMODE = (1 << 8) } iso14a_command_t; #endif // _MIFARE_H_ From de15fc5fe3090a95cf100c48af340e93a738576a Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 24 Mar 2015 07:17:00 +0100 Subject: [PATCH 6/9] add: hf topaz reader (basic functionality) --- client/cmdhf.c | 4 +- client/cmdhftopaz.c | 306 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 288 insertions(+), 22 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 66c8e53c..ad8e5369 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -603,8 +603,8 @@ int CmdHFList(const char *Cmd) PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); PrintAndLog("iClass - Timings are not as accurate"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); - PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------|-----|--------------------|"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); while(tracepos < traceLen) { diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index aed5f023..95e988ed 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -24,13 +24,11 @@ + static void topaz_switch_on_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, 0, 0}}; SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK, &resp); } @@ -38,13 +36,10 @@ static void topaz_switch_off_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK, &resp); } -static void topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) +static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, len, 0}}; memcpy(c.d.asBytes, cmd, len); @@ -53,39 +48,310 @@ static void topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) UsbCommand resp; WaitForResponse(CMD_ACK, &resp); - memcpy(response, resp.d.asBytes, resp.arg[0]); + if (resp.arg[0] > 0) { + memcpy(response, resp.d.asBytes, resp.arg[0]); + } + + return resp.arg[0]; } -static void topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response) +static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response) { if (len > 1) { uint8_t first, second; - ComputeCrc14443(CRC_14443_B, cmd, len, &first, &second); - cmd[len] = first; - cmd[len+1] = second; + ComputeCrc14443(CRC_14443_B, cmd, len-2, &first, &second); + cmd[len-2] = first; + cmd[len-1] = second; } - topaz_send_cmd_raw(cmd, len+2, response); + return topaz_send_cmd_raw(cmd, len, response); } -static void topaz_select(uint8_t *atqa, uint8_t *uid) +static int topaz_select(uint8_t *atqa, uint8_t *rid_response) { // ToDo: implement anticollision - uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t wupa_cmd[] = {TOPAZ_WUPA}; - + uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0}; + topaz_switch_on_field(); - topaz_send_cmd(wupa_cmd, sizeof(wupa_cmd), atqa); - topaz_send_cmd(rid_cmd, sizeof(rid_cmd) - 2, uid); - topaz_switch_off_field(); + + if (!topaz_send_cmd(wupa_cmd, sizeof(wupa_cmd), atqa)) { + topaz_switch_off_field(); + return -1; // WUPA failed + } + + if (!topaz_send_cmd(rid_cmd, sizeof(rid_cmd), rid_response)) { + topaz_switch_off_field(); + return -2; // RID failed + } + + return 0; // OK } +static int topaz_rall(uint8_t *uid, uint8_t *rall_response) +{ + uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0}; + + memcpy(&rall_cmd[3], uid, 4); + if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), rall_response)) { + topaz_switch_off_field(); + return -1; // RALL failed + } + + return 0; +} + + +static bool topaz_block_is_locked(uint8_t blockno, uint8_t *lockbits) +{ + if(lockbits[blockno/8] >> (blockno % 8) & 0x01) { + return true; + } else { + return false; + } +} + + +static int topaz_print_CC(uint8_t *data) +{ + if(data[0] != 0xe1) { + return -1; // no NDEF message + } + + PrintAndLog("Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); + PrintAndLog(" %02x: NDEF Magic Number", data[0]); + PrintAndLog(" %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLog(" %02x: Physical Memory Size of this tag: %d bytes", data[2], (data[2] + 1) * 8); + PrintAndLog(" %02x: %s / %s", data[3], + (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", + (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)"); + return 0; +} + + +static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t **value) +{ + *length = 0; + *value = NULL; + + *tag = **TLV_ptr; + *TLV_ptr += 1; + switch (*tag) { + case 0x00: // NULL TLV. + case 0xFE: // Terminator TLV. + break; + case 0x01: // Lock Control TLV + case 0x02: // Reserved Memory TLV + case 0x03: // NDEF message TLV + case 0xFD: // proprietary TLV + *length = **TLV_ptr; + *TLV_ptr += 1; + if (*length == 0xff) { + *length = **TLV_ptr << 8; + *TLV_ptr += 1; + *length |= **TLV_ptr; + *TLV_ptr += 1; + } + *value = *TLV_ptr; + *TLV_ptr += *length; + break; + default: // RFU + break; + } +} + + +static bool topaz_print_lock_control_TLVs(uint8_t *memory) +{ + uint8_t *TLV_ptr = memory; + uint8_t tag = 0; + uint16_t length; + uint8_t *value; + bool lock_TLV_present = false; + + while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) { + // all Lock Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV) + get_TLV(&TLV_ptr, &tag, &length, &value); + if (tag == 0x01) { // the Lock Control TLV + uint8_t pages_addr = value[0] >> 4; + uint8_t byte_offset = value[0] & 0x0f; + uint8_t size_in_bits = value[1] ? value[1] : 256; + uint8_t bytes_per_page = 1 << (value[2] & 0x0f); + uint8_t bytes_locked_per_bit = 1 << (value[2] >> 4); + PrintAndLog("Lock Area of %d bits at byte offset 0x%02x. Each Lock Bit locks %d bytes.", + size_in_bits, + pages_addr * bytes_per_page + byte_offset, + bytes_locked_per_bit); + lock_TLV_present = true; + } + } + + if (!lock_TLV_present) { + PrintAndLog("(No Lock Control TLV present)"); + return -1; + } else { + return 0; + } +} + + +static int topaz_print_reserved_memory_control_TLVs(uint8_t *memory) +{ + uint8_t *TLV_ptr = memory; + uint8_t tag = 0; + uint16_t length; + uint8_t *value; + bool reserved_memory_control_TLV_present = false; + + while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) { + // all Reserved Memory Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV) + get_TLV(&TLV_ptr, &tag, &length, &value); + if (tag == 0x02) { // the Reserved Memory Control TLV + uint8_t pages_addr = value[0] >> 4; + uint8_t byte_offset = value[0] & 0x0f; + uint8_t size_in_bytes = value[1] ? value[1] : 256; + uint8_t bytes_per_page = 1 << (value[2] & 0x0f); + PrintAndLog("Reserved Memory of %d bytes at byte offset 0x%02x.", + size_in_bytes, + pages_addr * bytes_per_page + byte_offset); + reserved_memory_control_TLV_present = true; + } + } + + if (!reserved_memory_control_TLV_present) { + PrintAndLog("(No Reserved Memory Control TLV present)"); + return -1; + } else { + return 0; + } +} + + +static void topaz_print_lifecycle_state(uint8_t *data) +{ + +} + + +static void topaz_print_NDEF(uint8_t *data) +{ + +} + + int CmdHFTopazReader(const char *Cmd) { - PrintAndLog("not yet implemented"); + int status; + uint8_t atqa[2]; + uint8_t rid_response[8]; + uint8_t *uid_echo = &rid_response[2]; + union { + uint8_t raw_content[124]; + struct { + uint8_t HR[2]; + uint8_t data_block[15][8]; + uint8_t CRC[2]; + } static_memory; + } rall_response; + uint8_t *static_lock_bytes = rall_response.static_memory.data_block[0x0e]; + + status = topaz_select(atqa, rid_response); + + if (status == -1) { + PrintAndLog("Error: couldn't receive ATQA"); + return -1; + } + + PrintAndLog("ATQA : %02x %02x", atqa[1], atqa[0]); + if (atqa[1] != 0x0c && atqa[0] != 0x00) { + PrintAndLog("Tag doesn't support the Topaz protocol."); + topaz_switch_off_field(); + return -1; + } + + if (status == -2) { + PrintAndLog("Error: tag didn't answer to RID"); + topaz_switch_off_field(); + return -1; + } + + // ToDo: CRC check + PrintAndLog("HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], + (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", + (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", + (rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic"); + PrintAndLog("HR1 : %02x", rid_response[1]); + + status = topaz_rall(uid_echo, rall_response.raw_content); + + if(status == -1) { + PrintAndLog("Error: tag didn't answer to RALL"); + topaz_switch_off_field(); + return -1; + } + + PrintAndLog("UID : %02x %02x %02x %02x %02x %02x %02x", + rall_response.static_memory.data_block[0][6], + rall_response.static_memory.data_block[0][5], + rall_response.static_memory.data_block[0][4], + rall_response.static_memory.data_block[0][3], + rall_response.static_memory.data_block[0][2], + rall_response.static_memory.data_block[0][1], + rall_response.static_memory.data_block[0][0]); + PrintAndLog(" UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s", + rall_response.static_memory.data_block[0][6], + getTagInfo(rall_response.static_memory.data_block[0][6])); + + PrintAndLog(""); + PrintAndLog("Static Data blocks 00 to 0c:"); + PrintAndLog("block# | offset | Data | Locked?"); + char line[80]; + for (uint16_t i = 0; i <= 0x0c; i++) { + for (uint16_t j = 0; j < 8; j++) { + sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[i][j] /*rall_response[2 + 8*i + j]*/); + } + PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", i, i*8, line, topaz_block_is_locked(i, static_lock_bytes) ? "yes" : "no"); + } + + PrintAndLog(""); + PrintAndLog("Static Reserved block 0d:"); + for (uint16_t j = 0; j < 8; j++) { + sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[0x0d][j]); + } + PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d*8, line, "n/a"); + + PrintAndLog(""); + PrintAndLog("Static Lockbits / OTP block 0e:"); + for (uint16_t j = 0; j < 8; j++) { + sprintf(&line[3*j], "%02x ", static_lock_bytes[j]); + } + PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0e, 0x0e*8, line, "n/a"); + + PrintAndLog(""); + + status = topaz_print_CC(&rall_response.static_memory.data_block[1][0]); + + if (status == -1) { + PrintAndLog("No NDEF message present"); + topaz_switch_off_field(); + return 0; + } + + PrintAndLog(""); + bool lock_TLV_present = topaz_print_lock_control_TLVs(&rall_response.static_memory.data_block[1][4]); + + PrintAndLog(""); + bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&rall_response.static_memory.data_block[1][4]); + + topaz_print_lifecycle_state(&rall_response.static_memory.data_block[1][0]); + + topaz_print_NDEF(&rall_response.static_memory.data_block[1][0]); + + topaz_switch_off_field(); return 0; } From c5847ae8af8d567da6cb905bd59c886e3d0c040b Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 28 Mar 2015 18:06:21 +0100 Subject: [PATCH 7/9] refactoring hf topaz reader --- client/cmdhftopaz.c | 70 ++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index 95e988ed..e76b3fb5 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -22,7 +22,16 @@ #include "iso14443crc.h" #include "protocols.h" +#define TOPAZ_MAX_MEMORY 2048 +static struct { + uint8_t HR01[2]; + uint8_t uid[7]; + uint8_t size; + uint8_t data_blocks[TOPAZ_MAX_MEMORY/8][8]; + uint8_t *dynamic_lock_areas; + uint8_t *dynamic_reserved_areas; +} topaz_tag; static void topaz_switch_on_field(void) @@ -92,12 +101,12 @@ static int topaz_select(uint8_t *atqa, uint8_t *rid_response) } -static int topaz_rall(uint8_t *uid, uint8_t *rall_response) +static int topaz_rall(uint8_t *uid, uint8_t *response) { uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0}; memcpy(&rall_cmd[3], uid, 4); - if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), rall_response)) { + if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), response)) { topaz_switch_off_field(); return -1; // RALL failed } @@ -249,15 +258,7 @@ int CmdHFTopazReader(const char *Cmd) uint8_t atqa[2]; uint8_t rid_response[8]; uint8_t *uid_echo = &rid_response[2]; - union { - uint8_t raw_content[124]; - struct { - uint8_t HR[2]; - uint8_t data_block[15][8]; - uint8_t CRC[2]; - } static_memory; - } rall_response; - uint8_t *static_lock_bytes = rall_response.static_memory.data_block[0x0e]; + uint8_t rall_response[124]; status = topaz_select(atqa, rid_response); @@ -279,6 +280,9 @@ int CmdHFTopazReader(const char *Cmd) return -1; } + topaz_tag.HR01[0] = rid_response[0]; + topaz_tag.HR01[1] = rid_response[1]; + // ToDo: CRC check PrintAndLog("HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", @@ -286,7 +290,7 @@ int CmdHFTopazReader(const char *Cmd) (rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic"); PrintAndLog("HR1 : %02x", rid_response[1]); - status = topaz_rall(uid_echo, rall_response.raw_content); + status = topaz_rall(uid_echo, rall_response); if(status == -1) { PrintAndLog("Error: tag didn't answer to RALL"); @@ -294,46 +298,48 @@ int CmdHFTopazReader(const char *Cmd) return -1; } + memcpy(topaz_tag.uid, rall_response+2, 7); PrintAndLog("UID : %02x %02x %02x %02x %02x %02x %02x", - rall_response.static_memory.data_block[0][6], - rall_response.static_memory.data_block[0][5], - rall_response.static_memory.data_block[0][4], - rall_response.static_memory.data_block[0][3], - rall_response.static_memory.data_block[0][2], - rall_response.static_memory.data_block[0][1], - rall_response.static_memory.data_block[0][0]); + topaz_tag.uid[6], + topaz_tag.uid[5], + topaz_tag.uid[4], + topaz_tag.uid[3], + topaz_tag.uid[2], + topaz_tag.uid[1], + topaz_tag.uid[0]); PrintAndLog(" UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s", - rall_response.static_memory.data_block[0][6], - getTagInfo(rall_response.static_memory.data_block[0][6])); - + topaz_tag.uid[6], + getTagInfo(topaz_tag.uid[6])); + + memcpy(topaz_tag.data_blocks, rall_response+2, 0x10*8); PrintAndLog(""); PrintAndLog("Static Data blocks 00 to 0c:"); PrintAndLog("block# | offset | Data | Locked?"); char line[80]; for (uint16_t i = 0; i <= 0x0c; i++) { for (uint16_t j = 0; j < 8; j++) { - sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[i][j] /*rall_response[2 + 8*i + j]*/); + sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[i][j] /*rall_response[2 + 8*i + j]*/); } - PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", i, i*8, line, topaz_block_is_locked(i, static_lock_bytes) ? "yes" : "no"); + PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", i, i*8, line, topaz_block_is_locked(i, &topaz_tag.data_blocks[0x0d][0]) ? "yes" : "no"); } PrintAndLog(""); PrintAndLog("Static Reserved block 0d:"); for (uint16_t j = 0; j < 8; j++) { - sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[0x0d][j]); + sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0d][j]); } PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d*8, line, "n/a"); PrintAndLog(""); - PrintAndLog("Static Lockbits / OTP block 0e:"); + PrintAndLog("Static Lockbits and OTP Bytes:"); for (uint16_t j = 0; j < 8; j++) { - sprintf(&line[3*j], "%02x ", static_lock_bytes[j]); + sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0e][j]); } PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0e, 0x0e*8, line, "n/a"); PrintAndLog(""); - status = topaz_print_CC(&rall_response.static_memory.data_block[1][0]); + status = topaz_print_CC(&topaz_tag.data_blocks[1][0]); if (status == -1) { PrintAndLog("No NDEF message present"); @@ -342,14 +348,14 @@ int CmdHFTopazReader(const char *Cmd) } PrintAndLog(""); - bool lock_TLV_present = topaz_print_lock_control_TLVs(&rall_response.static_memory.data_block[1][4]); + bool lock_TLV_present = topaz_print_lock_control_TLVs(&topaz_tag.data_blocks[1][4]); PrintAndLog(""); - bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&rall_response.static_memory.data_block[1][4]); + bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&topaz_tag.data_blocks[1][4]); - topaz_print_lifecycle_state(&rall_response.static_memory.data_block[1][0]); + topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]); - topaz_print_NDEF(&rall_response.static_memory.data_block[1][0]); + topaz_print_NDEF(&topaz_tag.data_blocks[1][0]); topaz_switch_off_field(); return 0; From 6e6f1099c83989b45c494d18cf701ffcff4af5ee Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 1 Jul 2015 07:12:10 +0200 Subject: [PATCH 8/9] hf topaz reader: add support for dynamic lock areas --- client/cmdhftopaz.c | 93 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index 4e515f78..ebe3a571 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -22,15 +22,25 @@ #include "iso14443crc.h" #include "protocols.h" -#define TOPAZ_MAX_MEMORY 2048 +#define TOPAZ_STATIC_MEMORY (0x0f * 8) + +typedef struct dynamic_lock_area { + struct dynamic_lock_area *next; + uint16_t byte_offset; + uint16_t size_in_bits; + uint16_t first_locked_byte; + uint16_t bytes_locked_per_bit; +} dynamic_lock_area_t; + static struct { uint8_t HR01[2]; uint8_t uid[7]; uint8_t size; - uint8_t data_blocks[TOPAZ_MAX_MEMORY/8][8]; - uint8_t *dynamic_lock_areas; + uint8_t data_blocks[TOPAZ_STATIC_MEMORY/8][8]; + dynamic_lock_area_t *dynamic_lock_areas; uint8_t *dynamic_reserved_areas; + uint8_t *dynamic_memory; } topaz_tag; @@ -115,8 +125,46 @@ static int topaz_rall(uint8_t *uid, uint8_t *response) } -static bool topaz_block_is_locked(uint8_t blockno, uint8_t *lockbits) +static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) { + dynamic_lock_area_t *lock_area; + + lock_area = topaz_tag.dynamic_lock_areas; + + while (lock_area != NULL) { + if (byteno < lock_area->first_locked_byte) { + lock_area = lock_area->next; + } else { + return lock_area; + } + } + + return NULL; +} + + +// check if a memory block (8 Bytes) is locked. +// TODO: support other sizes of locked_bytes_per_bit (current assumption: each lock bit locks 8 Bytes) +static bool topaz_byte_is_locked(uint16_t byteno) +{ + uint8_t *lockbits; + uint16_t locked_bytes_per_bit; + dynamic_lock_area_t *lock_area; + + if (byteno < TOPAZ_STATIC_MEMORY) { + lockbits = &topaz_tag.data_blocks[0x0e][0]; + locked_bytes_per_bit = 8; + } else { + lock_area = get_dynamic_lock_area(byteno); + if (lock_area == NULL) { + return false; + } + locked_bytes_per_bit = lock_area->bytes_locked_per_bit; + byteno = byteno - lock_area->first_locked_byte; + lockbits = &topaz_tag.dynamic_memory[lock_area->byte_offset - TOPAZ_STATIC_MEMORY]; + } + + uint16_t blockno = byteno / locked_bytes_per_bit; if(lockbits[blockno/8] >> (blockno % 8) & 0x01) { return true; } else { @@ -134,7 +182,9 @@ static int topaz_print_CC(uint8_t *data) PrintAndLog("Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); PrintAndLog(" %02x: NDEF Magic Number", data[0]); PrintAndLog(" %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); - PrintAndLog(" %02x: Physical Memory Size of this tag: %d bytes", data[2], (data[2] + 1) * 8); + uint16_t memsize = (data[2] + 1) * 8; + topaz_tag.dynamic_memory = malloc(memsize - TOPAZ_STATIC_MEMORY); + PrintAndLog(" %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); PrintAndLog(" %02x: %s / %s", data[3], (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)"); @@ -181,6 +231,7 @@ static bool topaz_print_lock_control_TLVs(uint8_t *memory) uint16_t length; uint8_t *value; bool lock_TLV_present = false; + uint16_t first_locked_byte = 0x0f * 8; while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) { // all Lock Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV) @@ -188,14 +239,30 @@ static bool topaz_print_lock_control_TLVs(uint8_t *memory) if (tag == 0x01) { // the Lock Control TLV uint8_t pages_addr = value[0] >> 4; uint8_t byte_offset = value[0] & 0x0f; - uint8_t size_in_bits = value[1] ? value[1] : 256; - uint8_t bytes_per_page = 1 << (value[2] & 0x0f); - uint8_t bytes_locked_per_bit = 1 << (value[2] >> 4); - PrintAndLog("Lock Area of %d bits at byte offset 0x%02x. Each Lock Bit locks %d bytes.", + uint16_t size_in_bits = value[1] ? value[1] : 256; + uint16_t bytes_per_page = 1 << (value[2] & 0x0f); + uint16_t bytes_locked_per_bit = 1 << (value[2] >> 4); + PrintAndLog("Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", size_in_bits, pages_addr * bytes_per_page + byte_offset, bytes_locked_per_bit); lock_TLV_present = true; + dynamic_lock_area_t *old = topaz_tag.dynamic_lock_areas; + dynamic_lock_area_t *new = topaz_tag.dynamic_lock_areas; + if (old == NULL) { + new = topaz_tag.dynamic_lock_areas = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t)); + } else { + while(old->next != NULL) { + old = old->next; + } + new = old->next = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t)); + } + new->next = NULL; + new->first_locked_byte = first_locked_byte; + new->byte_offset = pages_addr * bytes_per_page + byte_offset; + new->size_in_bits = size_in_bits; + new->bytes_locked_per_bit = bytes_locked_per_bit; + first_locked_byte = first_locked_byte + size_in_bits*bytes_locked_per_bit; } } @@ -314,13 +381,13 @@ int CmdHFTopazReader(const char *Cmd) memcpy(topaz_tag.data_blocks, rall_response+2, 0x10*8); PrintAndLog(""); PrintAndLog("Static Data blocks 00 to 0c:"); - PrintAndLog("block# | offset | Data | Locked?"); + PrintAndLog("block# | offset | Data | Locked(y/n)"); char line[80]; for (uint16_t i = 0; i <= 0x0c; i++) { for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[i][j] /*rall_response[2 + 8*i + j]*/); } - PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", i, i*8, line, topaz_block_is_locked(i, &topaz_tag.data_blocks[0x0e][0]) ? "yes" : "no"); + PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", i, i*8, line, topaz_byte_is_locked(i*8) ? "yyyyyyyy" : "nnnnnnnn"); } PrintAndLog(""); @@ -328,14 +395,14 @@ int CmdHFTopazReader(const char *Cmd) for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0d][j]); } - PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d*8, line, "n/a"); + PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", 0x0d, 0x0d*8, line, "n/a"); PrintAndLog(""); PrintAndLog("Static Lockbits and OTP Bytes:"); for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0e][j]); } - PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0e, 0x0e*8, line, "n/a"); + PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", 0x0e, 0x0e*8, line, "n/a"); PrintAndLog(""); From 7624e8b21bfb8468ae332a891a20df17f5077e58 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 28 Sep 2015 08:26:00 +0200 Subject: [PATCH 9/9] hf topaz reader implementation: - read and display dynamic memory as well - display "locked" status per byte instead per block --- client/cmdhf.c | 17 +-- client/cmdhftopaz.c | 274 ++++++++++++++++++++++++++++++-------------- 2 files changed, 186 insertions(+), 105 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index ee0b4fd8..caae08e5 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -690,7 +690,6 @@ int CmdHFSearch(const char *Cmd){ static command_t CommandTable[] = { -<<<<<<< HEAD {"help", CmdHelp, 1, "This help"}, {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, @@ -703,22 +702,8 @@ static command_t CommandTable[] = {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {"list", CmdHFList, 1, "List protocol data in trace buffer"}, + {"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"}, {NULL, NULL, 0, NULL} -======= - {"help", CmdHelp, 1, "This help"}, - {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, - {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, - {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, - {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, - {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, - {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {"list", CmdHFList, 1, "List protocol data in trace buffer"}, - {"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"}, - {NULL, NULL, 0, NULL} ->>>>>>> master }; int CmdHF(const char *Cmd) diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index ebe3a571..bf0f5dcf 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -22,13 +22,14 @@ #include "iso14443crc.h" #include "protocols.h" -#define TOPAZ_STATIC_MEMORY (0x0f * 8) +#define TOPAZ_STATIC_MEMORY (0x0f * 8) // 15 blocks with 8 Bytes each +// a struct to describe a memory area which contains lock bits and the corresponding lockable memory area typedef struct dynamic_lock_area { struct dynamic_lock_area *next; - uint16_t byte_offset; + uint16_t byte_offset; // the address of the lock bits uint16_t size_in_bits; - uint16_t first_locked_byte; + uint16_t first_locked_byte; // the address of the lockable area uint16_t bytes_locked_per_bit; } dynamic_lock_area_t; @@ -36,11 +37,10 @@ typedef struct dynamic_lock_area { static struct { uint8_t HR01[2]; uint8_t uid[7]; - uint8_t size; - uint8_t data_blocks[TOPAZ_STATIC_MEMORY/8][8]; - dynamic_lock_area_t *dynamic_lock_areas; - uint8_t *dynamic_reserved_areas; - uint8_t *dynamic_memory; + uint16_t size; + uint8_t data_blocks[TOPAZ_STATIC_MEMORY/8][8]; // this memory is always there + uint8_t *dynamic_memory; // this memory can be there + dynamic_lock_area_t *dynamic_lock_areas; // lock area descriptors } topaz_tag; @@ -58,6 +58,7 @@ static void topaz_switch_off_field(void) } +// send a raw topaz command, returns the length of the response (0 in case of error) static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, len, 0}}; @@ -75,6 +76,7 @@ static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response) } +// calculate CRC bytes and send topaz command, returns the length of the response (0 in case of error) static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response) { if (len > 1) { @@ -88,6 +90,7 @@ static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response) } +// select a topaz tag. Send WUPA and RID. static int topaz_select(uint8_t *atqa, uint8_t *rid_response) { // ToDo: implement anticollision @@ -111,6 +114,7 @@ static int topaz_select(uint8_t *atqa, uint8_t *rid_response) } +// read all of the static memory of a selected Topaz tag. static int topaz_rall(uint8_t *uid, uint8_t *response) { uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -125,6 +129,45 @@ static int topaz_rall(uint8_t *uid, uint8_t *response) } +// read a block (8 Bytes) of a selected Topaz tag. +static int topaz_read_block(uint8_t *uid, uint8_t blockno, uint8_t *block_data) +{ + uint8_t read8_cmd[] = {TOPAZ_READ8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t read8_response[11]; + + read8_cmd[1] = blockno; + memcpy(&read8_cmd[10], uid, 4); + if (!topaz_send_cmd(read8_cmd, sizeof(read8_cmd), read8_response)) { + topaz_switch_off_field(); + return -1; // READ8 failed + } + + memcpy(block_data, &read8_response[1], 8); + + return 0; +} + + +// read a segment (16 blocks = 128 Bytes) of a selected Topaz tag. Works only for tags with dynamic memory. +static int topaz_read_segment(uint8_t *uid, uint8_t segno, uint8_t *segment_data) +{ + uint8_t rseg_cmd[] = {TOPAZ_RSEG, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t rseg_response[131]; + + rseg_cmd[1] = segno << 4; + memcpy(&rseg_cmd[10], uid, 4); + if (!topaz_send_cmd(rseg_cmd, sizeof(rseg_cmd), rseg_response)) { + topaz_switch_off_field(); + return -1; // RSEG failed + } + + memcpy(segment_data, &rseg_response[1], 128); + + return 0; +} + + +// search for the lock area descriptor for the lockable area including byteno static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) { dynamic_lock_area_t *lock_area; @@ -143,8 +186,7 @@ static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) } -// check if a memory block (8 Bytes) is locked. -// TODO: support other sizes of locked_bytes_per_bit (current assumption: each lock bit locks 8 Bytes) +// check if a memory byte is locked. static bool topaz_byte_is_locked(uint16_t byteno) { uint8_t *lockbits; @@ -158,14 +200,15 @@ static bool topaz_byte_is_locked(uint16_t byteno) lock_area = get_dynamic_lock_area(byteno); if (lock_area == NULL) { return false; + } else { + lockbits = &topaz_tag.dynamic_memory[lock_area->byte_offset - TOPAZ_STATIC_MEMORY]; + locked_bytes_per_bit = lock_area->bytes_locked_per_bit; + byteno = byteno - lock_area->first_locked_byte; } - locked_bytes_per_bit = lock_area->bytes_locked_per_bit; - byteno = byteno - lock_area->first_locked_byte; - lockbits = &topaz_tag.dynamic_memory[lock_area->byte_offset - TOPAZ_STATIC_MEMORY]; } uint16_t blockno = byteno / locked_bytes_per_bit; - if(lockbits[blockno/8] >> (blockno % 8) & 0x01) { + if(lockbits[blockno/8] & (0x01 << (blockno % 8))) { return true; } else { return false; @@ -173,9 +216,11 @@ static bool topaz_byte_is_locked(uint16_t byteno) } +// read and print the Capability Container static int topaz_print_CC(uint8_t *data) { if(data[0] != 0xe1) { + topaz_tag.size = TOPAZ_STATIC_MEMORY; return -1; // no NDEF message } @@ -183,6 +228,7 @@ static int topaz_print_CC(uint8_t *data) PrintAndLog(" %02x: NDEF Magic Number", data[0]); PrintAndLog(" %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); uint16_t memsize = (data[2] + 1) * 8; + topaz_tag.size = memsize; topaz_tag.dynamic_memory = malloc(memsize - TOPAZ_STATIC_MEMORY); PrintAndLog(" %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); PrintAndLog(" %02x: %s / %s", data[3], @@ -192,14 +238,15 @@ static int topaz_print_CC(uint8_t *data) } -static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t **value) +// return type, length and value of a TLV, starting at memory position *TLV_ptr +static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) { - *length = 0; - *value = NULL; + *TLV_length = 0; + *TLV_value = NULL; - *tag = **TLV_ptr; + *TLV_type = **TLV_ptr; *TLV_ptr += 1; - switch (*tag) { + switch (*TLV_type) { case 0x00: // NULL TLV. case 0xFE: // Terminator TLV. break; @@ -207,16 +254,16 @@ static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t * case 0x02: // Reserved Memory TLV case 0x03: // NDEF message TLV case 0xFD: // proprietary TLV - *length = **TLV_ptr; + *TLV_length = **TLV_ptr; *TLV_ptr += 1; - if (*length == 0xff) { - *length = **TLV_ptr << 8; + if (*TLV_length == 0xff) { + *TLV_length = **TLV_ptr << 8; *TLV_ptr += 1; - *length |= **TLV_ptr; + *TLV_length |= **TLV_ptr; *TLV_ptr += 1; } - *value = *TLV_ptr; - *TLV_ptr += *length; + *TLV_value = *TLV_ptr; + *TLV_ptr += *TLV_length; break; default: // RFU break; @@ -224,27 +271,46 @@ static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t * } -static bool topaz_print_lock_control_TLVs(uint8_t *memory) +// lock area TLVs contain no information on the start of the respective lockable area. Lockable areas +// do not include the lock bits and reserved memory. We therefore need to adjust the start of the +// respective lockable areas accordingly +static void adjust_lock_areas(uint16_t block_start, uint16_t block_size) +{ + dynamic_lock_area_t *lock_area = topaz_tag.dynamic_lock_areas; + while (lock_area != NULL) { + if (lock_area->first_locked_byte <= block_start) { + lock_area->first_locked_byte += block_size; + } + lock_area = lock_area->next; + } +} + + +// read and print the lock area and reserved memory TLVs +static void topaz_print_control_TLVs(uint8_t *memory) { uint8_t *TLV_ptr = memory; - uint8_t tag = 0; - uint16_t length; - uint8_t *value; + uint8_t TLV_type = 0; + uint16_t TLV_length; + uint8_t *TLV_value; bool lock_TLV_present = false; - uint16_t first_locked_byte = 0x0f * 8; + bool reserved_memory_control_TLV_present = false; + uint16_t next_lockable_byte = 0x0f * 8; // first byte after static memory area while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) { // all Lock Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV) - get_TLV(&TLV_ptr, &tag, &length, &value); - if (tag == 0x01) { // the Lock Control TLV - uint8_t pages_addr = value[0] >> 4; - uint8_t byte_offset = value[0] & 0x0f; - uint16_t size_in_bits = value[1] ? value[1] : 256; - uint16_t bytes_per_page = 1 << (value[2] & 0x0f); - uint16_t bytes_locked_per_bit = 1 << (value[2] >> 4); + get_TLV(&TLV_ptr, &TLV_type, &TLV_length, &TLV_value); + if (TLV_type == 0x01) { // a Lock Control TLV + uint8_t pages_addr = TLV_value[0] >> 4; + uint8_t byte_offset = TLV_value[0] & 0x0f; + uint16_t size_in_bits = TLV_value[1] ? TLV_value[1] : 256; + uint16_t size_in_bytes = (size_in_bits + 7)/8; + uint16_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); + uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4); + uint16_t area_start = pages_addr * bytes_per_page + byte_offset; PrintAndLog("Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", size_in_bits, - pages_addr * bytes_per_page + byte_offset, + area_start, bytes_locked_per_bit); lock_TLV_present = true; dynamic_lock_area_t *old = topaz_tag.dynamic_lock_areas; @@ -258,67 +324,101 @@ static bool topaz_print_lock_control_TLVs(uint8_t *memory) new = old->next = (dynamic_lock_area_t *)malloc(sizeof(dynamic_lock_area_t)); } new->next = NULL; - new->first_locked_byte = first_locked_byte; - new->byte_offset = pages_addr * bytes_per_page + byte_offset; + if (area_start <= next_lockable_byte) { + // lock areas are not lockable + next_lockable_byte += size_in_bytes; + } + new->first_locked_byte = next_lockable_byte; + new->byte_offset = area_start; new->size_in_bits = size_in_bits; new->bytes_locked_per_bit = bytes_locked_per_bit; - first_locked_byte = first_locked_byte + size_in_bits*bytes_locked_per_bit; + next_lockable_byte += size_in_bits * bytes_locked_per_bit; + } + if (TLV_type == 0x02) { // a Reserved Memory Control TLV + uint8_t pages_addr = TLV_value[0] >> 4; + uint8_t byte_offset = TLV_value[0] & 0x0f; + uint8_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256; + uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); + uint16_t area_start = pages_addr * bytes_per_page + byte_offset; + PrintAndLog("Reserved Memory of %d bytes at byte offset 0x%02x.", + size_in_bytes, + area_start); + reserved_memory_control_TLV_present = true; + adjust_lock_areas(area_start, size_in_bytes); // reserved memory areas are not lockable + if (area_start <= next_lockable_byte) { + next_lockable_byte += size_in_bytes; + } } } if (!lock_TLV_present) { PrintAndLog("(No Lock Control TLV present)"); - return -1; - } else { - return 0; - } -} - - -static int topaz_print_reserved_memory_control_TLVs(uint8_t *memory) -{ - uint8_t *TLV_ptr = memory; - uint8_t tag = 0; - uint16_t length; - uint8_t *value; - bool reserved_memory_control_TLV_present = false; - - while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) { - // all Reserved Memory Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV) - get_TLV(&TLV_ptr, &tag, &length, &value); - if (tag == 0x02) { // the Reserved Memory Control TLV - uint8_t pages_addr = value[0] >> 4; - uint8_t byte_offset = value[0] & 0x0f; - uint8_t size_in_bytes = value[1] ? value[1] : 256; - uint8_t bytes_per_page = 1 << (value[2] & 0x0f); - PrintAndLog("Reserved Memory of %d bytes at byte offset 0x%02x.", - size_in_bytes, - pages_addr * bytes_per_page + byte_offset); - reserved_memory_control_TLV_present = true; - } } if (!reserved_memory_control_TLV_present) { PrintAndLog("(No Reserved Memory Control TLV present)"); + } +} + + +// read all of the dynamic memory +static int topaz_read_dynamic_data(void) +{ + // first read the remaining block of segment 0 + if(topaz_read_block(topaz_tag.uid, 0x0f, &topaz_tag.dynamic_memory[0]) == -1) { + PrintAndLog("Error while reading dynamic memory block %02x. Aborting...", 0x0f); return -1; - } else { - return 0; + } + + // read the remaining segments + uint8_t max_segment = topaz_tag.size / 128 - 1; + for(uint8_t segment = 1; segment <= max_segment; segment++) { + if(topaz_read_segment(topaz_tag.uid, segment, &topaz_tag.dynamic_memory[(segment-1)*128+8]) == -1) { + PrintAndLog("Error while reading dynamic memory block %02x. Aborting...", 0x0f); + return -1; + } + } + + return 0; +} + + +// read and print the dynamic memory +static void topaz_print_dynamic_data(void) +{ + if (topaz_tag.size > TOPAZ_STATIC_MEMORY) { + PrintAndLog("Dynamic Data blocks:"); + if (topaz_read_dynamic_data() == 0) { + PrintAndLog("block# | offset | Data | Locked(y/n)"); + char line[80]; + for (uint16_t blockno = 0x0f; blockno < topaz_tag.size/8; blockno++) { + uint8_t *block_data = &topaz_tag.dynamic_memory[(blockno-0x0f)*8]; + char lockbits[9]; + for (uint16_t j = 0; j < 8; j++) { + sprintf(&line[3*j], "%02x ", block_data[j]); + lockbits[j] = topaz_byte_is_locked(blockno*8+j) ? 'y' : 'n'; + } + lockbits[8] = '\0'; + PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", blockno, blockno*8, line, lockbits); + } + } } } static void topaz_print_lifecycle_state(uint8_t *data) { - + // to be done } static void topaz_print_NDEF(uint8_t *data) { - + // to be done. } - + +// read a Topaz tag and print some usefull information int CmdHFTopazReader(const char *Cmd) { int status; @@ -378,16 +478,19 @@ int CmdHFTopazReader(const char *Cmd) topaz_tag.uid[6], getTagInfo(topaz_tag.uid[6])); - memcpy(topaz_tag.data_blocks, rall_response+2, 0x10*8); + memcpy(topaz_tag.data_blocks, rall_response+2, 0x0f*8); PrintAndLog(""); PrintAndLog("Static Data blocks 00 to 0c:"); PrintAndLog("block# | offset | Data | Locked(y/n)"); char line[80]; for (uint16_t i = 0; i <= 0x0c; i++) { + char lockbits[9]; for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[i][j] /*rall_response[2 + 8*i + j]*/); + lockbits[j] = topaz_byte_is_locked(i*8+j) ? 'y' : 'n'; } - PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", i, i*8, line, topaz_byte_is_locked(i*8) ? "yyyyyyyy" : "nnnnnnnn"); + lockbits[8] = '\0'; + PrintAndLog(" 0x%02x | 0x%04x | %s| %-3s", i, i*8, line, lockbits); } PrintAndLog(""); @@ -409,17 +512,17 @@ int CmdHFTopazReader(const char *Cmd) status = topaz_print_CC(&topaz_tag.data_blocks[1][0]); if (status == -1) { - PrintAndLog("No NDEF message present"); + PrintAndLog("No NDEF message data present"); topaz_switch_off_field(); return 0; } PrintAndLog(""); - bool lock_TLV_present = topaz_print_lock_control_TLVs(&topaz_tag.data_blocks[1][4]); + topaz_print_control_TLVs(&topaz_tag.data_blocks[1][4]); PrintAndLog(""); - bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&topaz_tag.data_blocks[1][4]); - + topaz_print_dynamic_data(); + topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]); topaz_print_NDEF(&topaz_tag.data_blocks[1][0]); @@ -429,16 +532,9 @@ int CmdHFTopazReader(const char *Cmd) } -int CmdHFTopazSim(const char *Cmd) -{ - PrintAndLog("not yet implemented"); - return 0; -} - - int CmdHFTopazCmdRaw(const char *Cmd) { - PrintAndLog("not yet implemented"); + PrintAndLog("not yet implemented. Use hf 14 raw with option -T."); return 0; } @@ -450,7 +546,6 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"reader", CmdHFTopazReader, 0, "Act like a Topaz reader"}, - {"sim", CmdHFTopazSim, 0, " -- Simulate Topaz tag"}, {"snoop", CmdHF14ASnoop, 0, "Eavesdrop a Topaz reader-tag communication"}, {"raw", CmdHFTopazCmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} @@ -466,6 +561,7 @@ int CmdHFTopaz(const char *Cmd) { return 0; } + static int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable);