]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge branch 'master' into topaz. Update Changelog. 142/head
authorpwpiwi <pwpiwi@users.noreply.github.com>
Tue, 27 Oct 2015 19:44:48 +0000 (20:44 +0100)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Tue, 27 Oct 2015 19:57:16 +0000 (20:57 +0100)
12 files changed:
CHANGELOG.md
armsrc/BigBuf.c
armsrc/iso14443a.c
armsrc/iso14443a.h
client/Makefile
client/cmdhf.c
client/cmdhf14a.c
client/cmdhftopaz.c [new file with mode: 0644]
client/cmdhftopaz.h [new file with mode: 0644]
common/Makefile.common
common/protocols.h
include/mifare.h

index e2196a39afb8ed1c1d54fdf2311d4bb813cae4db..33824bbb32a0969602c3e2e01af386c53c179f3b 100644 (file)
@@ -10,6 +10,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added 'hw status'. This command makes the ARM print out some runtime information. (holiman) 
 - Added 'hw ping'. This command just sends a usb packets and checks if the pm3 is responsive. Can be used to abort certain operations which supports abort over usb. (holiman)
 - Added `data hex2bin` and `data bin2hex` for command line conversion between binary and hexadecimal (holiman)
+- Added Topaz (NFC type 1) protocol support ('hf topaz reader', 'hf list topaz', 'hf 14a raw -T', 'hf topaz snoop'). (piwi)
+- Added option c to 'hf list' (mark CRC bytes) (piwi)
+
 
 ### Changed
 - Revised workflow for StandAloneMode14a (Craig Young)
index a938d5c68db9a193463700f315564ca45dfd3267..6b52a5894545beaa352273aeea608945a6ada7b0 100644 (file)
@@ -178,8 +178,12 @@ 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;
 
@@ -228,6 +232,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();
index bb7ab015e65da6d3ba1770f33a607db9311891cb..27574dad2601cceda2f59b785445a1915a958892 100644 (file)
@@ -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
 //=============================================================================
@@ -232,13 +238,17 @@ 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
+       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,8 +258,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.twoBits = 0x0000;                          // buffer for 2 Bits
-       Uart.highCnt = 0;
        Uart.startTime = 0;
        Uart.endTime = 0;
 }
@@ -258,6 +266,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();
 }
 
@@ -265,40 +274,37 @@ 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 < 2) {                                                                                                 // 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
+               // 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;
+                       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 +328,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 +364,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
@@ -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);
@@ -1336,7 +1343,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
@@ -1630,6 +1637,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);
@@ -1645,11 +1653,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
@@ -1658,6 +1668,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
@@ -1718,6 +1729,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.
@@ -1926,15 +1942,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));
@@ -2893,7 +2932,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();
@@ -2910,6 +2949,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);
                        }
index 1e978e8808fa683f7744211e8bd4060c32eb59c5..ec99ab99a4f7426628d73ace74f10237b81838c3 100644 (file)
@@ -56,15 +56,14 @@ typedef struct {
                // DROP_FIRST_HALF,
                } state;
        uint16_t shiftReg;
-       uint16_t bitCount;
+       int16_t  bitCount;
        uint16_t len;
        uint16_t byteCntMax;
        uint16_t posCnt;
        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;
index 15b1cbca3cd76660fbdb69b7841dc199334a70f1..903cbf9ef35fa315a3a2f82ee5331d3a636c6cf6 100644 (file)
@@ -57,14 +57,14 @@ CORESRCS =  uart.c \
 
 
 CMDSRCS =      nonce2key/crapto1.c\
-               nonce2key/crypto1.c\
-               nonce2key/nonce2key.c\
-               loclass/cipher.c \
-               loclass/cipherutils.c \
-               loclass/des.c \
-               loclass/ikeys.c \
-               loclass/elite_crack.c\
-               loclass/fileutils.c\
+                       nonce2key/crypto1.c\
+                       nonce2key/nonce2key.c\
+                       loclass/cipher.c \
+                       loclass/cipherutils.c \
+                       loclass/des.c \
+                       loclass/ikeys.c \
+                       loclass/elite_crack.c\
+                       loclass/fileutils.c\
                        mifarehost.c\
                        crc.c \
                        crc16.c \
@@ -85,6 +85,7 @@ CMDSRCS =     nonce2key/crapto1.c\
                        cmdhficlass.c \
                        cmdhfmf.c \
             cmdhfmfu.c \
+                       cmdhftopaz.c \
                        cmdhw.c \
                        cmdlf.c \
                        cmdlfio.c \
index f8daff7e5ef106f20721ef1dfd53a706648da8f2..caae08e5dba137c1c96529e3a0fbd6e86fa60b19 100644 (file)
@@ -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);
@@ -187,6 +188,26 @@ 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;
+               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;
+       }
+}
+
+
 /**
 06 00 = INITIATE
 0E xx = SELECT ID (xx = Chip-ID)
@@ -218,7 +239,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
@@ -235,9 +283,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;
 }
 
 /**
@@ -301,11 +350,66 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
        }
 }
 
-uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles)
+
+bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen)
 {
-       bool isResponse;
-       uint16_t duration, data_len, parity_len;
+       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);
+}
+
+
+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       16
+
+       uint32_t last_timestamp = timestamp + *duration;
+
+       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);
+               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 ((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;
+}
+
+
+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;
+       uint32_t duration;
+       uint8_t topaz_reader_command[9];
        uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
        char explanation[30] = {0};
 
@@ -336,29 +440,31 @@ 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 7 or 8 Bits each.
+               // merge them:
+               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;
-               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)))
-                               {
-                                               crcStatus = 0;
-                               }
-                       }
+               switch (protocol) {
+                       case ICLASS:
+                               crcStatus = iclass_CRC_check(isResponse, frame, data_len);
+                               break;
+                       case ISO_14443B:
+                       case TOPAZ:
+                               crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); 
+                               break;
+                       case ISO_14443A:
+                               crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
+                               break;
+                       default: 
+                               break;
                }
        }
        //0 CRC-command, CRC not ok
@@ -380,19 +486,22 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
                uint8_t parityBits = parityBytes[j>>3];
                if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
                        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)
-       {//CRC-command
-               char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4)-1;
-               (*pos1) = '[';
-               char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4)-2;
-               (*pos2) = ']';
+
+       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){
@@ -407,18 +516,19 @@ 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);
        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"),
@@ -426,26 +536,22 @@ 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) ? crc : "    ",
                                (j == num_lines-1) ? explanation : "");
                }
        }
 
-       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;
@@ -455,49 +561,52 @@ 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(strcmp(type, "iclass") == 0)
-               {
+
+       if(!errors) {
+               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;
                }
        }
 
        if (errors) {
                PrintAndLog("List protocol data in trace buffer.");
-               PrintAndLog("Usage:  hf list <protocol> [f]");
+               PrintAndLog("Usage:  hf list <protocol> [f][c]");
                PrintAndLog("    f      - show frame delay times as well");
+               PrintAndLog("    c      - mark CRC bytes");
                PrintAndLog("Supported <protocol> values:");
                PrintAndLog("    raw    - just show raw data without annotations");
                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");
@@ -505,10 +614,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;
@@ -537,12 +649,12 @@ 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)
        {
-               tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles);
+               tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes);
        }
 
        free(trace);
@@ -578,19 +690,20 @@ int CmdHFSearch(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"},
-  {"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... }"},
+       {"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}
 };
 
 int CmdHF(const char *Cmd)
index 9a761864b3fbc984ef21d839b0db886a69aeb647..cba179ec75cf55ae03a268525f0b0d1d00afb002 100644 (file)
@@ -141,7 +141,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) {
                if (Cmd[0] != 's') PrintAndLog("iso14443a card select failed");
@@ -565,20 +565,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) {
@@ -590,9 +592,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++;
 
@@ -601,19 +605,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);
@@ -623,13 +627,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;
@@ -659,10 +666,15 @@ int CmdHF14ACmdRaw(const char *cmd) {
         PrintAndLog("Invalid char on input");
         return 0;
     }
+
     if(crc && datalen>0 && datalen<sizeof(data)-2)
     {
         uint8_t first, second;
-        ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
+               if (topazmode) {
+                       ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second);
+               } else {
+                       ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
+               }
         data[datalen++] = first;
         data[datalen++] = second;
     }
@@ -675,7 +687,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
     }
 
        if(bTimeout){
-           #define MAX_TIMEOUT 40542464        // (2^32-1) * (8*16) / 13560000Hz * 1000ms/s = 
+           #define MAX_TIMEOUT 40542464        // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
         c.arg[0] |= ISO14A_SET_TIMEOUT;
         if(timeout > MAX_TIMEOUT) {
             timeout = MAX_TIMEOUT;
@@ -683,11 +695,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);
@@ -703,6 +720,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
     return 0;
 }
 
+
 static void waitCmd(uint8_t iSelect)
 {
     uint8_t *recv;
@@ -712,7 +730,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
new file mode 100644 (file)
index 0000000..bf0f5dc
--- /dev/null
@@ -0,0 +1,571 @@
+//-----------------------------------------------------------------------------
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "cmdmain.h"
+#include "cmdparser.h"
+#include "cmdhftopaz.h"
+#include "cmdhf14a.h"
+#include "ui.h"
+#include "mifare.h"
+#include "proxmark3.h"
+#include "iso14443crc.h"
+#include "protocols.h"
+
+#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;                    // the address of the lock bits
+       uint16_t        size_in_bits;
+       uint16_t        first_locked_byte;              // the address of the lockable area
+       uint16_t        bytes_locked_per_bit;
+} dynamic_lock_area_t;
+
+
+static struct {
+       uint8_t HR01[2];
+       uint8_t uid[7];
+       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;
+
+
+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);
+}
+
+
+static void topaz_switch_off_field(void)
+{
+       UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
+       SendCommand(&c);
+}
+
+
+// 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}};
+       memcpy(c.d.asBytes, cmd, len);
+       SendCommand(&c);
+
+       UsbCommand resp;
+       WaitForResponse(CMD_ACK, &resp);
+
+       if (resp.arg[0] > 0) {
+               memcpy(response, resp.d.asBytes, resp.arg[0]);
+       }
+       
+       return resp.arg[0];
+}
+
+
+// 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) {
+        uint8_t first, second;
+               ComputeCrc14443(CRC_14443_B, cmd, len-2, &first, &second);
+        cmd[len-2] = first;
+        cmd[len-1] = second;
+       }
+
+       return topaz_send_cmd_raw(cmd, len, response);
+}
+
+
+// select a topaz tag. Send WUPA and RID.
+static int topaz_select(uint8_t *atqa, uint8_t *rid_response)
+{
+       // ToDo: implement anticollision
+
+       uint8_t wupa_cmd[] = {TOPAZ_WUPA};
+       uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       topaz_switch_on_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
+}
+
+
+// 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};
+
+       memcpy(&rall_cmd[3], uid, 4);
+       if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), response)) {
+               topaz_switch_off_field();
+               return -1;              // RALL failed
+       }
+       
+       return 0;
+}
+
+
+// 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;
+       
+       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 byte is locked.
+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;
+               } 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;
+               }
+       }
+
+       uint16_t blockno = byteno / locked_bytes_per_bit;
+       if(lockbits[blockno/8] & (0x01 << (blockno % 8))) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+
+// 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
+       }
+
+       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);
+       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], 
+                               (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;                               
+}
+
+
+// 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)
+{
+       *TLV_length = 0;
+       *TLV_value = NULL;
+
+       *TLV_type = **TLV_ptr;
+       *TLV_ptr += 1;
+       switch (*TLV_type) {
+               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
+                       *TLV_length = **TLV_ptr;
+                       *TLV_ptr += 1;
+                       if (*TLV_length == 0xff) {
+                               *TLV_length = **TLV_ptr << 8;
+                               *TLV_ptr += 1;
+                               *TLV_length |= **TLV_ptr;
+                               *TLV_ptr += 1;
+                       }
+                       *TLV_value = *TLV_ptr;
+                       *TLV_ptr += *TLV_length;
+                       break;
+               default:                        // RFU
+                       break;
+       }
+}
+
+
+// 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 TLV_type = 0;
+       uint16_t TLV_length;
+       uint8_t *TLV_value;
+       bool lock_TLV_present = false;
+       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, &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,
+                                               area_start,
+                                               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;
+                       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;
+                       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)");
+       }
+       
+       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;
+       }
+       
+       // 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;
+       uint8_t atqa[2];
+       uint8_t rid_response[8];
+       uint8_t *uid_echo = &rid_response[2];
+       uint8_t rall_response[124];
+       
+       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;
+       }
+
+       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 ",
+                                               (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);
+
+       if(status == -1) {
+               PrintAndLog("Error: tag didn't answer to RALL");
+               topaz_switch_off_field();
+               return -1;
+       }
+
+       memcpy(topaz_tag.uid, rall_response+2, 7);
+       PrintAndLog("UID  : %02x %02x %02x %02x %02x %02x %02x", 
+                       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", 
+                       topaz_tag.uid[6], 
+                       getTagInfo(topaz_tag.uid[6]));
+
+       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';
+               }
+               lockbits[8] = '\0';
+               PrintAndLog("  0x%02x | 0x%04x | %s|   %-3s", i, i*8, line, lockbits);
+       }
+       
+       PrintAndLog("");
+       PrintAndLog("Static Reserved block 0d:");
+       for (uint16_t j = 0; j < 8; j++) {
+               sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0d][j]);
+       }
+       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%04x | %s|   %-3s", 0x0e, 0x0e*8, line, "n/a");
+
+       PrintAndLog("");
+
+       status = topaz_print_CC(&topaz_tag.data_blocks[1][0]);
+       
+       if (status == -1) {
+               PrintAndLog("No NDEF message data present");
+               topaz_switch_off_field();
+               return 0;
+       }
+
+       PrintAndLog("");
+       topaz_print_control_TLVs(&topaz_tag.data_blocks[1][4]);
+
+       PrintAndLog("");
+       topaz_print_dynamic_data();
+       
+       topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]);
+
+       topaz_print_NDEF(&topaz_tag.data_blocks[1][0]);
+       
+       topaz_switch_off_field();
+       return 0;
+}
+
+
+int CmdHFTopazCmdRaw(const char *Cmd)
+{
+       PrintAndLog("not yet implemented. Use hf 14 raw with option -T.");
+       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"},
+       {"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 (file)
index 0000000..8d5428d
--- /dev/null
@@ -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
index 98ff4d0d8aa2ae64b5caf4d74b63c6d22d0a77f7..7c94e041cee0551313f7494d74dc5e1752089d17 100644 (file)
@@ -67,7 +67,7 @@ VPATH = . ../common ../fpga ../zlib
 
 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
index 580342728b866ee7f76d3f09537580da1c43c72d..169cee47d599023dc94ceef3adc60531d48886e5 100644 (file)
@@ -180,9 +180,25 @@ 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)
+// 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
+#define ICLASS         1
+#define ISO_14443B     2
+#define TOPAZ          3
 
 //-- Picopass fuses
 #define FUSE_FPERS   0x80
index e2b7a7c5548e2fd37dde3864173cfe08ea95a8b7..ad86886dbc0b69afc29ce453b08ec94be5cd23fb 100644 (file)
@@ -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_
Impressum, Datenschutz