From: adam@algroup.co.uk Date: Tue, 19 Oct 2010 14:25:17 +0000 (+0000) Subject: Issue 20 patch (refactored code of the iso15693 implementation as well as several... X-Git-Tag: v1.0.0~267 X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/9455b51c2a0554ea2bd55a28dee5a5c2a6707fc6 Issue 20 patch (refactored code of the iso15693 implementation as well as several enhancements) [Adrian Dabrowski "atrox"] --- diff --git a/COMPILING.txt b/COMPILING.txt index 0d228c43..536aa229 100644 --- a/COMPILING.txt +++ b/COMPILING.txt @@ -87,4 +87,24 @@ macport stuff should do ;) = Linux = ============ +1 - Download + +A precompiled DevKitARM cross compiler tool chain package can be found at +http://sourceforge.net/projects/devkitpro/files/devkitARM +Select the one you need (32bit or 64bit) and unpack to a convinient place, eg +$HOME/proxmark3/. It will create a devkitARM/ subdirectory. + +Of course, you will need a general compiling environment on your computer for +the client and the libusb headers. In most distributions you will get all you +need with the lsb-package (Linux Standard Base). In debian/ubuntu you simply +call `aptitude install lsb libusb-dev`. + +For the graphical plot view, you might need the qtlibs (debian/ubuntu: +libqt4-dev), too. + +2 - Set Environment + +export DEVKITPRO=$HOME/proxmark3/ +export DEVKITARM=$DEVKITPRO/devkitARM +export PATH=${PATH}:${DEVKITARM}/bin diff --git a/armsrc/Makefile b/armsrc/Makefile index bf13008a..8d9e2b4a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -15,7 +15,7 @@ APP_CFLAGS = -O2 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.c -SRC_ISO15693 = iso15693.c +SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = iso14443a.c SRC_ISO14443b = iso14443.c @@ -35,7 +35,7 @@ ARMSRC = fpgaloader.c \ crc16.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ - legic_prng.c \ + legic_prng.c \ crc.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dcbef113..aa70e677 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -124,6 +124,29 @@ void Dbprintf(const char *fmt, ...) { DbpString(output_string); } +// prints HEX & ASCII +void Dbhexdump(int len, uint8_t *d) { + int l=0,i; + char ascii[9]; + + while (len>0) { + if (len>8) l=8; + else l=len; + + memcpy(ascii,d,l); + ascii[l]=0; + + // filter safe ascii + for (i=0;i126) ascii[i]='.'; + + Dbprintf("%-8s %*D",ascii,l,d," "); + + len-=8; + d+=8; + } +} + //----------------------------------------------------------------------------- // Read an ADC channel and block till it completes, then return the result // in ADC units (0 to 1023). Also a routine to average 32 samples and @@ -598,6 +621,24 @@ void UsbPacketReceived(uint8_t *packet, int len) break; #endif +#ifdef WITH_ISO15693 + case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693: + RecordRawAdcSamplesIso15693(); + break; + + case CMD_ISO_15693_COMMAND: + DirectTag15693Command(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); + break; + + case CMD_ISO_15693_FIND_AFI: + BruteforceIso15693Afi(c->arg[0]); + break; + + case CMD_ISO_15693_DEBUG: + SetDebugIso15693(c->arg[0]); + break; + +#endif case CMD_BUFF_CLEAR: BufferClear(); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 5ecd1753..7fdde6f1 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -31,6 +31,7 @@ void SamyRun(void); //void DbpIntegers(int a, int b, int c); void DbpString(char *str); void Dbprintf(const char *fmt, ...); +void Dbhexdump(int len, uint8_t *d); void ToSendStuffBit(int b); void ToSendReset(void); @@ -107,9 +108,13 @@ void ReaderIso14443a(UsbCommand * c, UsbCommand * ack); void ReaderMifare(uint32_t parameter); /// iso15693.h +void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg void SimTagIso15693(uint32_t parameter); // simulate an ISO15693 tag - greg +void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox +void SetDebugIso15693(uint32_t flag); /// util.h diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index c286d634..7f4cbf8a 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Jonathan Westhues, split Nov 2006 // Modified by Greg Jones, Jan 2009 +// Modified by Adrian Dabrowski "atrox", Mar-Sept 2010 // // 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 @@ -12,66 +13,84 @@ // Modified to perform modulation onboard in arm rather than on PC // Also added additional reader commands (SELECT, READ etc.) //----------------------------------------------------------------------------- +// The ISO 15693 describes two transmission modes from reader to tag, and 4 +// transmission modes from tag to reader. As of Mar 2010 this code only +// supports one of each: "1of4" mode from reader to tag, and the highspeed +// variant with one subcarrier from card to reader. +// As long, as the card fully support ISO 15693 this is no problem, since the +// reader chooses both data rates, but some non-standard tags do not. Further for +// the simulation to work, we will need to support all data rates. +// +// VCD (reader) -> VICC (tag) +// 1 out of 256: +// data rate: 1,66 kbit/s (fc/8192) +// used for long range +// 1 out of 4: +// data rate: 26,48 kbit/s (fc/512) +// used for short range, high speed +// +// VICC (tag) -> VCD (reader) +// Modulation: +// ASK / one subcarrier (423,75 khz) +// FSK / two subcarriers (423,75 khz && 484,28 khz) +// Data Rates / Modes: +// low ASK: 6,62 kbit/s +// low FSK: 6.67 kbit/s +// high ASK: 26,48 kbit/s +// high FSK: 26,69 kbit/s +//----------------------------------------------------------------------------- +// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911 + + +// Random Remarks: +// *) UID is always used "transmission order" (LSB), which is reverse to display order + +// TODO / BUGS / ISSUES: +// *) writing to tags takes longer: we miss the answer from the tag in most cases +// -> tweak the read-timeout times +// *) signal decoding from the card is still a bit shaky. +// *) signal decoding is unable to detect collissions. +// *) add anti-collission support for inventory-commands +// *) sniffing and simulation do only support one transmission mode. need to support +// all 8 transmission combinations +// *) remove or refactor code under "depricated" +// *) document all the functions + #include "proxmark3.h" #include "util.h" #include "apps.h" #include "string.h" +#include "iso15693tools.h" + -// FROM winsrc\prox.h ////////////////////////////////// #define arraylen(x) (sizeof(x)/sizeof((x)[0])) -//----------------------------------------------------------------------------- -// Map a sequence of octets (~layer 2 command) into the set of bits to feed -// to the FPGA, to transmit that command to the tag. -//----------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////// +// ISO 15693 Part 2 - Air Interface +// This section basicly contains transmission and receiving of bits +/////////////////////////////////////////////////////////////////////// + +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF - // The sampling rate is 106.353 ksps/s, for T = 18.8 us - - // SOF defined as - // 1) Unmodulated time of 56.64us - // 2) 24 pulses of 423.75khz - // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) - - static const int FrameSOF[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - static const int Logic0[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1 - }; - static const int Logic1[] = { - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - - // EOF defined as - // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) - // 2) 24 pulses of 423.75khz - // 3) Unmodulated time of 56.64us - - static const int FrameEOF[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; +#define Crc(data,datalen) Iso15693Crc(data,datalen) +#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) +#define sprintUID(target,uid) Iso15693sprintUID(target,uid) +int DEBUG=0; + + +// --------------------------- +// Signal Processing +// --------------------------- + +// prepare data using "1 out of 4" code for later transmission +// resulting data rate is 26,48 kbit/s (fc/512) +// cmd ... data +// n ... length of data static void CodeIso15693AsReader(uint8_t *cmd, int n) { int i, j; @@ -83,6 +102,7 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) ToSendStuffBit(1); } + // SOF for 1of4 ToSendStuffBit(0); ToSendStuffBit(1); ToSendStuffBit(1); @@ -138,6 +158,7 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) } } } + // EOF ToSendStuffBit(1); ToSendStuffBit(1); ToSendStuffBit(0); @@ -149,331 +170,55 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) } } -//----------------------------------------------------------------------------- -// The CRC used by ISO 15693. -//----------------------------------------------------------------------------- -static uint16_t Crc(uint8_t *v, int n) +// encode data using "1 out of 256" sheme +// data rate is 1,66 kbit/s (fc/8192) +// is designed for more robust communication over longer distances +static void CodeIso15693AsReader256(uint8_t *cmd, int n) { - uint32_t reg; int i, j; - reg = 0xffff; + ToSendReset(); + + // Give it a bit of slack at the beginning + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } + + // SOF for 1of256 + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + for(i = 0; i < n; i++) { - reg = reg ^ ((uint32_t)v[i]); - for (j = 0; j < 8; j++) { - if (reg & 0x0001) { - reg = (reg >> 1) ^ 0x8408; + for (j = 0; j<=255; j++) { + if (cmd[i]==j) { + ToSendStuffBit(1); + ToSendStuffBit(0); } else { - reg = (reg >> 1); - } - } + ToSendStuffBit(1); + ToSendStuffBit(1); + } + } } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); - return ~reg; -} - -char *strcat(char *dest, const char *src) -{ - size_t dest_len = strlen(dest); - size_t i; - - for (i = 0 ; src[i] != '\0' ; i++) - dest[dest_len + i] = src[i]; - dest[dest_len + i] = '\0'; - - return dest; -} - -////////////////////////////////////////// code to do 'itoa' - -/* reverse: reverse string s in place */ -void reverse(char s[]) -{ - int c, i, j; - - for (i = 0, j = strlen(s)-1; i 0); /* delete it */ - if (sign < 0) - s[i++] = '-'; - s[i] = '\0'; - reverse(s); -} - -//////////////////////////////////////// END 'itoa' CODE - -//----------------------------------------------------------------------------- -// Encode (into the ToSend buffers) an identify request, which is the first -// thing that you must send to a tag to get a response. -//----------------------------------------------------------------------------- -static void BuildIdentifyRequest(void) -{ - uint8_t cmd[5]; - - uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); - // inventory command code - cmd[1] = 0x01; - // no mask - cmd[2] = 0x00; - //Now the CRC - crc = Crc(cmd, 3); - cmd[3] = crc & 0xff; - cmd[4] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) -{ - uint8_t cmd[12]; - - uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // System Information command code - cmd[1] = 0x2B; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - //Now the CRC - crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void BuildSelectRequest( uint8_t uid[]) -{ - -// uid[6]=0x31; // this is getting ignored - the uid array is not happening... - uint8_t cmd[12]; - - uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS - cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS - // SELECT command code - cmd[1] = 0x25; - // 64-bit UID -// cmd[2] = uid[0];//0x32; -// cmd[3]= uid[1];//0x4b; -// cmd[4] = uid[2];//0x03; -// cmd[5] = uid[3];//0x01; -// cmd[6] = uid[4];//0x00; -// cmd[7] = uid[5];//0x10; -// cmd[8] = uid[6];//0x05; - cmd[2] = 0x32;// - cmd[3] = 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; // infineon? - - cmd[9]= 0xe0; // always e0 (not exactly unique) - -// DbpIntegers(cmd[8],cmd[7],cmd[6]); - // Now the CRC - crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void __attribute__((unused)) BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) -{ - uint8_t cmd[13]; - - uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = 0x20; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Block number to read - cmd[10] = blockNumber;//0x00; - //Now the CRC - crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes - cmd[11] = crc & 0xff; - cmd[12] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) -{ - uint8_t cmd[14]; - - uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ Multi BLOCK command code - cmd[1] = 0x23; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // First Block number to read - cmd[10] = 0x00; - // Number of Blocks to read - cmd[11] = 0x2f; // read quite a few - //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t CmdCode) -{ - uint8_t cmd[14]; - - uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = CmdCode; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Parameter - cmd[10] = 0x00; - cmd[11] = 0x0a; - -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], uint8_t CmdCode) -{ - uint8_t cmd[14]; - - uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit - // READ BLOCK command code - cmd[1] = CmdCode; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; // always e0 (not exactly unique) - // Parameter - cmd[10] = 0x05; // for custom codes this must be manufcturer code - cmd[11] = 0x00; - -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes - cmd[12] = crc & 0xff; - cmd[13] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} - -///////////////////////////////////////////////////////////////////////// -// Now the VICC>VCD responses when we are simulating a tag -//////////////////////////////////////////////////////////////////// - - static void BuildInventoryResponse(void) -{ - uint8_t cmd[12]; - - uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); - cmd[1] = 0; - // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; - //Now the CRC - crc = Crc(cmd, 10); - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); + // And slack at the end, too. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } } -//----------------------------------------------------------------------------- + // Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) { int c; @@ -541,6 +286,15 @@ static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *samples = (c + *wait) << 3; } + +// Read from Tag +// Parameters: +// receivedResponse +// maxLen +// samples +// elapsed +// returns: +// number of decoded bytes static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { int c = 0; @@ -593,16 +347,16 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * } } -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// int i, j; int max = 0, maxPos=0; int skip = 4; -// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL // First, correlate for SOF for(i = 0; i < 100; i++) { @@ -615,7 +369,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * maxPos = i; } } -// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); + // DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); int k = 0; // this will be our return value @@ -623,63 +377,65 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * if ((max/(arraylen(FrameSOF)/skip)) >= 1) { - i = maxPos + arraylen(FrameSOF)/skip; - - uint8_t outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; - for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr0) { -// DbpString("EOF at %d", i); - break; - } else if(corr1 > corr0) { - i += arraylen(Logic1)/skip; - outBuf[k] |= mask; - } else { - i += arraylen(Logic0)/skip; + i = maxPos + arraylen(FrameSOF)/skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += arraylen(Logic1)/skip; + outBuf[k] |= mask; + } else { + i += arraylen(Logic0)/skip; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if((i+(int)arraylen(FrameEOF)) >= 2000) { + DbpString("ran off end!"); + break; + } } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; + if(mask != 0x01) { // this happens, when we miss the EOF + // TODO: for some reason this happens quite often + if (DEBUG) Dbprintf("error, uneven octet! (extra bits!) mask=%02x", mask); + if (mask<0x08) k--; // discard the last uneven octet; + // 0x08 is an assumption - but works quite often } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; } - } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// uint8_t str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); - -// DbpString( str1); // DbpString("%d octets", k); - -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } - - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; - } } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) return k; // return the number of bytes demodulated @@ -687,6 +443,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * } + // Now the GetISO15693 message from sniffing command static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { @@ -740,9 +497,9 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int } } -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// int i, j; int max = 0, maxPos=0; @@ -769,70 +526,72 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int // greg - If correlation is less than 1 then there's little point in continuing if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 { - - i = maxPos + arraylen(FrameSOF)/skip; - - uint8_t outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; - for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr0) { -// DbpString("EOF at %d", i); - break; - } else if(corr1 > corr0) { - i += arraylen(Logic1)/skip; - outBuf[k] |= mask; - } else { - i += arraylen(Logic0)/skip; + + i = maxPos + arraylen(FrameSOF)/skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += arraylen(Logic1)/skip; + outBuf[k] |= mask; + } else { + i += arraylen(Logic0)/skip; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if((i+(int)arraylen(FrameEOF)) >= 2000) { + DbpString("ran off end!"); + break; + } } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; + if(mask != 0x01) { + DbpString("sniff: error, uneven octet! (discard extra bits!)"); + /// DbpString(" mask=%02x", mask); } - if((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; } - } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// uint8_t str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); - -// DbpString( str1); // DbpString("%d octets", k); - -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } - - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; - } } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) return k; // return the number of bytes demodulated /// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); } + +static void BuildIdentifyRequest(void); //----------------------------------------------------------------------------- // Start to read an ISO 15693 tag. We send an identify request, then wait // for the response. The response is not demodulated, just left in the buffer @@ -886,38 +645,347 @@ void AcquireRawAdcSamplesIso15693(void) int8_t b; b = (int8_t)AT91C_BASE_SSC->SSC_RHR; - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if(getNext) { - int8_t r; + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; + + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 2000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + } + } +} + + +void RecordRawAdcSamplesIso15693(void) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; + + int8_t prev = 0; + + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + SpinDelay(100); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + + c = 0; + getNext = FALSE; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; + + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 7000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + WDT_HIT(); + } + } + Dbprintf("fin record"); +} + + +// Initialize the proxmark as iso15k reader +void Iso15693InitReader() { + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(200); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} + +/////////////////////////////////////////////////////////////////////// +// ISO 15693 Part 3 - Air Interface +// This section basicly contains transmission and receiving of bits +/////////////////////////////////////////////////////////////////////// + +// Encode (into the ToSend buffers) an identify request, which is the first +// thing that you must send to a tag to get a response. +static void BuildIdentifyRequest(void) +{ + uint8_t cmd[5]; + + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); + // inventory command code + cmd[1] = 0x01; + // no mask + cmd[2] = 0x00; + //Now the CRC + crc = Crc(cmd, 3); + cmd[3] = crc & 0xff; + cmd[4] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// uid is in transmission order (which is reverse of display order) +static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) +{ + uint8_t cmd[13]; + + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit + // READ BLOCK command code + cmd[1] = 0x20; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = uid[0]; + cmd[3] = uid[1]; + cmd[4] = uid[2]; + cmd[5] = uid[3]; + cmd[6] = uid[4]; + cmd[7] = uid[5]; + cmd[8] = uid[6]; + cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) + // Block number to read + cmd[10] = blockNumber;//0x00; + //Now the CRC + crc = Crc(cmd, 11); // the crc needs to be calculated over 12 bytes + cmd[11] = crc & 0xff; + cmd[12] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// Now the VICC>VCD responses when we are simulating a tag + static void BuildInventoryResponse(void) +{ + uint8_t cmd[12]; + + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); + cmd[1] = 0; + // 64-bit UID + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; + //Now the CRC + crc = Crc(cmd, 10); + cmd[10] = crc & 0xff; + cmd[11] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// Universal Method for sending to and recv from a tag +// init ... should we initialize the reader? +// speed ... 0 low speed, 1 hi speed +// **recv will return you a pointer to the received data +// If you do not need the answer use NULL for *recv[] +// return: lenght of received data +int SendDataTag(uint8_t *send, int sendlen, int init, int speed, uint8_t **recv) { + + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + int answerLen=0; + uint8_t *answer = (((uint8_t *)BigBuf) + 3660); + if (recv!=NULL) memset(BigBuf + 3660, 0, 100); + + if (init) Iso15693InitReader(); + + if (!speed) { + // low speed (1 out of 256) + CodeIso15693AsReader256(send, sendlen); + } else { + // high speed (1 out of 4) + CodeIso15693AsReader(send, sendlen); + } + + LED_A_ON(); + LED_B_OFF(); + + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + // Now wait for a response + if (recv!=NULL) { + LED_A_OFF(); + LED_B_ON(); + answerLen = GetIso15693AnswerFromTag(answer, 100, &samples, &elapsed) ; + *recv=answer; + } + + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + + return answerLen; +} - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } - dest[c++] = (uint8_t)r; +// -------------------------------------------------------------------- +// Debug Functions +// -------------------------------------------------------------------- - if(c >= 2000) { +// Decodes a message from a tag and displays its metadata and content +#define DBD15STATLEN 48 +void DbdecodeIso15693Answer(int len, uint8_t *d) { + char status[DBD15STATLEN+1]={0}; + uint16_t crc; + + if (len>3) { + if (d[0]&(1<<3)) + strncat(status,"ProtExt ",DBD15STATLEN); + if (d[0]&1) { + // error + strncat(status,"Error ",DBD15STATLEN); + switch (d[1]) { + case 0x01: + strncat(status,"01:notSupp",DBD15STATLEN); break; - } - } else { - prev = b; + case 0x02: + strncat(status,"02:notRecog",DBD15STATLEN); + break; + case 0x03: + strncat(status,"03:optNotSupp",DBD15STATLEN); + break; + case 0x0f: + strncat(status,"0f:noInfo",DBD15STATLEN); + break; + case 0x10: + strncat(status,"10:dontExist",DBD15STATLEN); + break; + case 0x11: + strncat(status,"11:lockAgain",DBD15STATLEN); + break; + case 0x12: + strncat(status,"12:locked",DBD15STATLEN); + break; + case 0x13: + strncat(status,"13:progErr",DBD15STATLEN); + break; + case 0x14: + strncat(status,"14:lockErr",DBD15STATLEN); + break; + default: + strncat(status,"unknownErr",DBD15STATLEN); } - - getNext = !getNext; + strncat(status," ",DBD15STATLEN); + } else { + strncat(status,"NoErr ",DBD15STATLEN); } + + crc=Crc(d,len-2); + if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) + strncat(status,"CrcOK",DBD15STATLEN); + else + strncat(status,"CrcFail!",DBD15STATLEN); + + Dbprintf("%s",status); } } + + +/////////////////////////////////////////////////////////////////////// +// Functions called via USB/Client +/////////////////////////////////////////////////////////////////////// + +void SetDebugIso15693(uint32_t debug) { + DEBUG=debug; + Dbprintf("Iso15693 Debug is now %s",DEBUG?"on":"off"); + return; +} + + + //----------------------------------------------------------------------------- // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg @@ -940,6 +1008,7 @@ void ReaderIso15693(uint32_t parameter) int answerLen1 = 0; int answerLen2 = 0; int answerLen3 = 0; + int i=0; // counter // Blank arrays memset(BigBuf + 3660, 0, 300); @@ -970,7 +1039,7 @@ void ReaderIso15693(uint32_t parameter) // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - uint8_t TagUID[7]; // where we hold the uid for hi15reader + uint8_t TagUID[8]; // where we hold the uid for hi15reader // BuildIdentifyRequest(); // //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); @@ -1008,45 +1077,68 @@ void ReaderIso15693(uint32_t parameter) TagUID[4] = answer1[6]; TagUID[5] = answer1[7]; TagUID[6] = answer1[8]; // IC Manufacturer code + TagUID[7] = answer1[9]; // always E0 // Now send the SELECT command - BuildSelectRequest(TagUID); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 + // since the SELECT command is optional, we should not rely on it. +//// BuildSelectRequest(TagUID); +// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 // Now wait for a response - answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); +/// answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); // Now send the MULTI READ command // BuildArbitraryRequest(*TagUID,parameter); - BuildArbitraryCustomRequest(TagUID,parameter); +/// BuildArbitraryCustomRequest(TagUID,parameter); // BuildReadBlockRequest(*TagUID,parameter); // BuildSysInfoRequest(*TagUID); //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 +/// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 // Now wait for a response - answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ; +/// answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ; } - Dbprintf("%d octets read from IDENTIFY request: %x %x %x %x %x %x %x %x %x", answerLen1, - answer1[0], answer1[1], answer1[2], - answer1[3], answer1[4], answer1[5], - answer1[6], answer1[7], answer1[8]); - - Dbprintf("%d octets read from SELECT request: %x %x %x %x %x %x %x %x %x", answerLen2, - answer2[0], answer2[1], answer2[2], - answer2[3], answer2[4], answer2[5], - answer2[6], answer2[7], answer2[8]); - - Dbprintf("%d octets read from XXX request: %x %x %x %x %x %x %x %x %x", answerLen3, - answer3[0], answer3[1], answer3[2], - answer3[3], answer3[4], answer3[5], - answer3[6], answer3[7], answer3[8]); - + Dbprintf("%d octets read from IDENTIFY request:", answerLen1); + DbdecodeIso15693Answer(answerLen1,answer1); + Dbhexdump(answerLen1,answer1); + + // UID is reverse + if (answerLen1>=12) + //Dbprintf("UID = %*D",8,TagUID," "); + Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX",TagUID[7],TagUID[6],TagUID[5], + TagUID[4],TagUID[3],TagUID[2],TagUID[1],TagUID[0]); + + + Dbprintf("%d octets read from SELECT request:", answerLen2); + DbdecodeIso15693Answer(answerLen2,answer2); + Dbhexdump(answerLen2,answer2); + + Dbprintf("%d octets read from XXX request:", answerLen3); + DbdecodeIso15693Answer(answerLen3,answer3); + Dbhexdump(answerLen3,answer3); + + + // read all pages + if (answerLen1>=12 && DEBUG) { + i=0; + while (i<32) { // sanity check, assume max 32 pages + BuildReadBlockRequest(TagUID,i); + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + if (answerLen2>0) { + Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); + DbdecodeIso15693Answer(answerLen2,answer2); + Dbhexdump(answerLen2,answer2); + if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr + } + i++; + } + } // str2[0]=0; // for(i = 0; i < responseLen3; i++) { // itoa(str1,receivedAnswer3[i]); -// strcat(str2,str1); +// strncat(str2,str1,8); // } // DbpString(str2); @@ -1056,10 +1148,8 @@ void ReaderIso15693(uint32_t parameter) LED_D_OFF(); } -//----------------------------------------------------------------------------- // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands // all demodulation performed in arm rather than host. - greg -//----------------------------------------------------------------------------- void SimTagIso15693(uint32_t parameter) { LED_A_ON(); @@ -1116,3 +1206,271 @@ void SimTagIso15693(uint32_t parameter) LED_C_OFF(); LED_D_OFF(); } + + +// Since there is no standardized way of reading the AFI out of a tag, we will brute force it +// (some manufactures offer a way to read the AFI, though) +void BruteforceIso15693Afi(uint32_t speed) +{ + uint8_t data[20]; + uint8_t *recv=data; + int datalen=0, recvlen=0; + + Iso15693InitReader(); + + // first without AFI + // Tags should respond wihtout AFI and with AFI=0 even when AFI is active + + data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + data[1]=ISO15_CMD_INVENTORY; + data[2]=0; // mask length + datalen=AddCrc(data,3); + recvlen=SendDataTag(data,datalen,0,speed,&recv); + WDT_HIT(); + if (recvlen>=12) { + Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2])); + } + + // now with AFI + + data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_AFI | ISO15_REQINV_SLOT1; + data[1]=ISO15_CMD_INVENTORY; + data[2]=0; // AFI + data[3]=0; // mask length + + for (int i=0;i<256;i++) { + data[2]=i & 0xFF; + datalen=AddCrc(data,4); + recvlen=SendDataTag(data,datalen,0,speed,&recv); + WDT_HIT(); + if (recvlen>=12) { + Dbprintf("AFI=%i UID=%s",i,sprintUID(NULL,&recv[2])); + } + } + Dbprintf("AFI Bruteforcing done."); + +} + +// Allows to directly send commands to the tag via the client +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]) { + + int recvlen=0; + uint8_t *recvbuf=(uint8_t *)BigBuf; + UsbCommand n; + + if (DEBUG) { + Dbprintf("SEND"); + Dbhexdump(datalen,data); + } + + recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL)); + + if (recv) { + n.cmd=/* CMD_ISO_15693_COMMAND_DONE */ CMD_ACK; + n.arg[0]=recvlen>48?48:recvlen; + memcpy(n.d.asBytes, recvbuf, 48); + LED_B_ON(); + UsbSendPacket((uint8_t *)&n, sizeof(n)); + LED_B_OFF(); + + if (DEBUG) { + Dbprintf("RECV"); + DbdecodeIso15693Answer(recvlen,recvbuf); + Dbhexdump(recvlen,recvbuf); + } + } + +} + + + + +// -------------------------------------------------------------------- +// -- Misc & deprecated functions +// -------------------------------------------------------------------- + + +// do not use; has a fix UID +static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) +{ + uint8_t cmd[12]; + + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit + // System Information command code + cmd[1] = 0x2B; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; // always e0 (not exactly unique) + //Now the CRC + crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes + cmd[10] = crc & 0xff; + cmd[11] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// do not use; has a fix UID +static void __attribute__((unused)) BuildSelectRequest( uint8_t uid[]) +{ + +// uid[6]=0x31; // this is getting ignored - the uid array is not happening... + uint8_t cmd[12]; + + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS + cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS + // SELECT command code + cmd[1] = 0x25; + // 64-bit UID +// cmd[2] = uid[0];//0x32; +// cmd[3]= uid[1];//0x4b; +// cmd[4] = uid[2];//0x03; +// cmd[5] = uid[3];//0x01; +// cmd[6] = uid[4];//0x00; +// cmd[7] = uid[5];//0x10; +// cmd[8] = uid[6];//0x05; + cmd[2] = 0x32;// + cmd[3] = 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; // infineon? + + cmd[9]= 0xe0; // always e0 (not exactly unique) + +// DbpIntegers(cmd[8],cmd[7],cmd[6]); + // Now the CRC + crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes + cmd[10] = crc & 0xff; + cmd[11] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + + + +// do not use; has a fix UID +static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) +{ + uint8_t cmd[14]; + + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit + // READ Multi BLOCK command code + cmd[1] = 0x23; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; // always e0 (not exactly unique) + // First Block number to read + cmd[10] = 0x00; + // Number of Blocks to read + cmd[11] = 0x2f; // read quite a few + //Now the CRC + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + cmd[12] = crc & 0xff; + cmd[13] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// do not use; has a fix UID +static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t CmdCode) +{ + uint8_t cmd[14]; + + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit + // READ BLOCK command code + cmd[1] = CmdCode; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; // always e0 (not exactly unique) + // Parameter + cmd[10] = 0x00; + cmd[11] = 0x0a; + +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + cmd[12] = crc & 0xff; + cmd[13] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + +// do not use; has a fix UID +static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], uint8_t CmdCode) +{ + uint8_t cmd[14]; + + uint16_t crc; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit + // READ BLOCK command code + cmd[1] = CmdCode; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; // always e0 (not exactly unique) + // Parameter + cmd[10] = 0x05; // for custom codes this must be manufcturer code + cmd[11] = 0x00; + +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + cmd[12] = crc & 0xff; + cmd[13] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + + + + + + + diff --git a/armsrc/string.c b/armsrc/string.c index 4e66c95b..cc71276c 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -69,3 +69,47 @@ char* strncat(char *dest, const char *src, unsigned int n) return dest; } + +char* strcat(char *dest, const char *src) +{ + unsigned int dest_len = strlen(dest); + unsigned int i; + + for (i = 0 ; src[i] != '\0' ; i++) + dest[dest_len + i] = src[i]; + dest[dest_len + i] = '\0'; + + return dest; +} +////////////////////////////////////////// code to do 'itoa' + +/* reverse: reverse string s in place */ +void strreverse(char s[]) +{ + int c, i, j; + + for (i = 0, j = strlen(s)-1; i 0); /* delete it */ + if (sign < 0) + s[i++] = '-'; + s[i] = '\0'; + strreverse(s); +} + +//////////////////////////////////////// END 'itoa' CODE diff --git a/armsrc/string.h b/armsrc/string.h index 25fac909..46ee218d 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -17,5 +17,9 @@ void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); int memcmp(const void *av, const void *bv, int len); char *strncat(char *dest, const char *src, unsigned int n); +char *strcat(char *dest, const char *src); +void strreverse(char s[]); +void itoa(int n, char s[]); + #endif /* __STRING_H */ diff --git a/client/Makefile b/client/Makefile index 0d323424..7ca03ce1 100644 --- a/client/Makefile +++ b/client/Makefile @@ -42,6 +42,7 @@ endif CMDSRCS = \ crc16.c \ iso14443crc.c \ + iso15693tools.c \ data.c \ graph.c \ ui.c \ diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 576bd944..886e5c51 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh +// Modified 2010 by // // 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 @@ -7,6 +8,18 @@ //----------------------------------------------------------------------------- // High frequency ISO15693 commands //----------------------------------------------------------------------------- +// There are three basic operation modes, depending on which device (proxmark/pc) +// the signal processing, (de)modulation, transmission protocol and logic is done. +// Mode 1: +// All steps are done on the proxmark, the output of the commands is returned via +// USB-debug-print commands. +// Mode 2: +// The protocol is done on the PC, passing only Iso15693 data frames via USB. This +// allows direct communication with a tag on command level +// Mode 3: +// The proxmark just samples the antenna and passes this "analog" data via USB to +// the client. Signal Processing & decoding is done on the pc. This is the slowest +// variant, but offers the possibility to analyze the waveforms directly. #include #include @@ -18,189 +31,746 @@ #include "ui.h" #include "cmdparser.h" #include "cmdhf15.h" +#include "iso15693tools.h" +#include "cmdmain.h" + +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF + +#define Crc(data,datalen) Iso15693Crc(data,datalen) +#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) +#define sprintUID(target,uid) Iso15693sprintUID(target,uid) static int CmdHelp(const char *Cmd); -static uint16_t Iso15693Crc(uint8_t *v, int n) +// structure and database for uid -> tagtype lookups +typedef struct { + uint64_t uid; + int mask; // how many MSB bits used + char* desc; +} productName; + + +const productName uidmapping[] = { + { 0xE007000000000000LL, 16, "Texas Instrument; " }, + { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" }, + { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" }, + { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" }, + { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" }, + { 0xE005000000000000LL, 16, "Infineon" }, + { 0xE005400000000000LL, 24, "Infineon; 56x32bit" }, + { 0xE004000000000000LL, 16, "Philips" }, + { 0xE002000000000000LL, 16, "STMicroelectronics" }, + { 0xE016000000000000LL, 16, "EM-Marin SA (Skidata)" }, + { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); no memory" }, + { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135; 36x64bit start page 13" }, + { 0,0,"no tag-info available" } // must be the last entry +}; + + +// fast method to just read the UID of an tag (collission detection not supported) +// *buf shouls be large enough to fit the 64bit uid +// returns 1 if suceeded +int getUID(uint8_t *buf) { - uint32_t reg; - int i, j; + UsbCommand *r; + uint8_t *recv; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + uint8_t *req=c.d.asBytes; + int reqlen=0; + + for (int retry=0;retry<3; retry++) { // don't give up the at the first try + + req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + req[1]=ISO15_CMD_INVENTORY; + req[2]=0; // mask length + reqlen=AddCrc(req,3); + c.arg[0]=reqlen; + + SendCommand(&c); + + r=WaitForResponseTimeout(CMD_ACK,1000); + + if (r!=NULL) { + recv = r->d.asBytes; + if (r->arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) { + memcpy(buf,&recv[2],8); + return 1; + } + } + } // retry + return 0; +} + + - reg = 0xffff; - for (i = 0; i < n; i++) { - reg = reg ^ ((uint32_t)v[i]); - for (j = 0; j < 8; j++) { - if (reg & 0x0001) { - reg = (reg >> 1) ^ 0x8408; - } else { - reg = (reg >> 1); - } - } - } +// get a product description based on the UID +// uid[8] tag uid +// returns description of the best match +static char* getTagInfo(uint8_t *uid) { + uint64_t myuid,mask,t; + int i=0, best=-1; + memcpy(&myuid,uid,sizeof(uint64_t)); + while (uidmapping[i].mask>0) { + mask=(~0LL) <<(64-uidmapping[i].mask); + if ((myuid & mask) == uidmapping[i].uid) { + if (best==-1) { + best=i; + } else { + if (uidmapping[i].mask>uidmapping[best].mask) { + best=i; + } + } + } + i++; + } - return (uint16_t)~reg; + if (best>=0) return uidmapping[best].desc; + + return uidmapping[i].desc; } + +// will return a clear-text message to an errorcode +static char* TagErrorStr(uint8_t error) { + // TODO + return NULL; +} + + +// Mode 3 int CmdHF15Demod(const char *Cmd) { - // The sampling rate is 106.353 ksps/s, for T = 18.8 us - - // SOF defined as - // 1) Unmodulated time of 56.64us - // 2) 24 pulses of 423.75khz - // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) - - static const int FrameSOF[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - static const int Logic0[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1 - }; - static const int Logic1[] = { - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - - // EOF defined as - // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) - // 2) 24 pulses of 423.75khz - // 3) Unmodulated time of 56.64us - - static const int FrameEOF[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - int i, j; - int max = 0, maxPos = 0; - - int skip = 4; - - if (GraphTraceLen < 1000) return 0; - - // First, correlate for SOF - for (i = 0; i < 100; i++) { - int corr = 0; - for (j = 0; j < arraylen(FrameSOF); j += skip) { - corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; - } - if (corr > max) { - max = corr; - maxPos = i; - } - } - PrintAndLog("SOF at %d, correlation %d", maxPos, - max / (arraylen(FrameSOF) / skip)); - - i = maxPos + arraylen(FrameSOF) / skip; - int k = 0; - uint8_t outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; - for (;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for (j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j] * GraphBuffer[i + (j / skip)]; - } - for (j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j] * GraphBuffer[i + (j / skip)]; - } - for (j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if (corrEOF > corr1 && corrEOF > corr0) { - PrintAndLog("EOF at %d", i); - break; - } else if (corr1 > corr0) { - i += arraylen(Logic1) / skip; - outBuf[k] |= mask; - } else { - i += arraylen(Logic0) / skip; - } - mask <<= 1; - if (mask == 0) { - k++; - mask = 0x01; - } - if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) { - PrintAndLog("ran off end!"); - break; - } - } - if (mask != 0x01) { - PrintAndLog("error, uneven octet! (discard extra bits!)"); - PrintAndLog(" mask=%02x", mask); - } - PrintAndLog("%d octets", k); - - for (i = 0; i < k; i++) { - PrintAndLog("# %2d: %02x ", i, outBuf[i]); - } - PrintAndLog("CRC=%04x", Iso15693Crc(outBuf, k - 2)); - return 0; + // The sampling rate is 106.353 ksps/s, for T = 18.8 us + + int i, j; + int max = 0, maxPos = 0; + + int skip = 4; + + if (GraphTraceLen < 1000) return 0; + + // First, correlate for SOF + for (i = 0; i < 100; i++) { + int corr = 0; + for (j = 0; j < arraylen(FrameSOF); j += skip) { + corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; + } + if (corr > max) { + max = corr; + maxPos = i; + } + } + PrintAndLog("SOF at %d, correlation %d", maxPos, + max / (arraylen(FrameSOF) / skip)); + + i = maxPos + arraylen(FrameSOF) / skip; + int k = 0; + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for (;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for (j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j] * GraphBuffer[i + (j / skip)]; + } + for (j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j] * GraphBuffer[i + (j / skip)]; + } + for (j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if (corrEOF > corr1 && corrEOF > corr0) { + PrintAndLog("EOF at %d", i); + break; + } else if (corr1 > corr0) { + i += arraylen(Logic1) / skip; + outBuf[k] |= mask; + } else { + i += arraylen(Logic0) / skip; + } + mask <<= 1; + if (mask == 0) { + k++; + mask = 0x01; + } + if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) { + PrintAndLog("ran off end!"); + break; + } + } + if (mask != 0x01) { + PrintAndLog("error, uneven octet! (discard extra bits!)"); + PrintAndLog(" mask=%02x", mask); + } + PrintAndLog("%d octets", k); + + for (i = 0; i < k; i++) { + PrintAndLog("# %2d: %02x ", i, outBuf[i]); + } + PrintAndLog("CRC=%04x", Iso15693Crc(outBuf, k - 2)); + return 0; } + + +// * Acquire Samples as Reader (enables carrier, sends inquiry) int CmdHF15Read(const char *Cmd) { - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693}; + SendCommand(&c); + return 0; +} + +// Record Activity without enabeling carrier +int CmdHF15Record(const char *Cmd) +{ + UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693}; + SendCommand(&c); + return 0; } int CmdHF15Reader(const char *Cmd) { - UsbCommand c = {CMD_READER_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_READER_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; + SendCommand(&c); + return 0; } +// Simulation is still not working very good int CmdHF15Sim(const char *Cmd) { - UsbCommand c = {CMD_SIMTAG_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_SIMTAG_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; + SendCommand(&c); + return 0; } -static command_t CommandTable[] = +// finds the AFI (Application Family Idendifier) of a card, by trying all values +// (There is no standard way of reading the AFI, allthough some tags support this) +int CmdHF15Afi(const char *Cmd) { - {"help", CmdHelp, 1, "This help"}, - {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"}, - {"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"}, - {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, - {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, - {NULL, NULL, 0, NULL} + UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}}; + SendCommand(&c); + return 0; +} + +// Reads all memory pages +int CmdHF15DumpMem(const char*Cmd) { + UsbCommand *r; + uint8_t uid[8]; + uint8_t *recv=NULL; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + uint8_t *req=c.d.asBytes; + int reqlen=0; + int blocknum=0; + char output[80]; + + if (!getUID(uid)) { + PrintAndLog("No Tag found."); + return 0; + } + + PrintAndLog("Reading memory from tag UID=%s",sprintUID(NULL,uid)); + PrintAndLog("Tag Info: %s",getTagInfo(uid)); + + for (int retry=0; retry<5; retry++) { + + req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[1]=ISO15_CMD_READ; + memcpy(&req[2],uid,8); + req[10]=blocknum; + reqlen=AddCrc(req,11); + c.arg[0]=reqlen; + + SendCommand(&c); + + r=WaitForResponseTimeout(CMD_ACK,1000); + + if (r!=NULL) { + recv = r->d.asBytes; + if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { + retry=0; + *output=0; // reset outputstring + sprintf(output, "Block %2i ",blocknum); + for ( int i=1; iarg[0]-2; i++) { // data in hex + sprintf(output+strlen(output),"%02hX ",recv[i]); + } + strcat(output," "); + for ( int i=1; iarg[0]-2; i++) { // data in cleaned ascii + sprintf(output+strlen(output),"%c",(recv[i]>31 && recv[i]<127)?recv[i]:'.'); + } + PrintAndLog("%s",output); + blocknum++; + // PrintAndLog("bn=%i",blocknum); + } else { + PrintAndLog("Tag returned Error %i: %s",recv[0],TagErrorStr(recv[0])); + return 0; + } + } // else PrintAndLog("crc"); + } // else PrintAndLog("r null"); + + } // retry + if (r && r->arg[0]<3) + PrintAndLog("Lost Connection"); + else if (r && ISO15_CRC_CHECK!=Crc(r->d.asBytes,r->arg[0])) + PrintAndLog("CRC Failed"); + else + PrintAndLog("Tag returned Error %i: %s",recv[0],TagErrorStr(recv[0])); + return 0; +} + + +// "HF 15" interface + +static command_t CommandTable15[] = +{ + {"help", CmdHF15Help, 1, "This help"}, + {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"}, + {"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"}, + {"record", CmdHF15Record, 0, "Record Samples (ISO 15693)"}, // atrox + {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, + {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, + {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, + {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, + {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"}, + {NULL, NULL, 0, NULL} }; int CmdHF15(const char *Cmd) { - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable15, Cmd); + return 0; } -int CmdHelp(const char *Cmd) +int CmdHF15Help(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable15); + return 0; } + + +// "HF 15 Cmd" Interface +// Allows direct communication with the tag on command level + +int CmdHF15CmdInquiry(const char *Cmd) +{ + UsbCommand *r; + uint8_t *recv; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + uint8_t *req=c.d.asBytes; + int reqlen=0; + + req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + req[1]=ISO15_CMD_INVENTORY; + req[2]=0; // mask length + reqlen=AddCrc(req,3); + c.arg[0]=reqlen; + + SendCommand(&c); + + r=WaitForResponseTimeout(CMD_ACK,1000); + + if (r!=NULL) { + if (r->arg[0]>=12) { + recv = r->d.asBytes; + PrintAndLog("UID=%s",sprintUID(NULL,&recv[2])); + PrintAndLog("Tag Info: %s",getTagInfo(&recv[2])); + } else { + PrintAndLog("Response to short, just %i bytes. No tag?\n",r->arg[0]); + } + } else { + PrintAndLog("timeout."); + } + return 0; +} + + +// Turns debugging on(1)/off(0) +int CmdHF15CmdDebug( const char *cmd) { + int debug=atoi(cmd); + if (strlen(cmd)<1) { + PrintAndLog("Usage: hf 15 cmd debug <0/1>"); + PrintAndLog(" 0..no debugging output 1..turn debugging on"); + return 0; + } + + UsbCommand c = {CMD_ISO_15693_DEBUG, {debug, 0, 0}}; + SendCommand(&c); + return 0; +} + + +int CmdHF15CmdRaw (const char *cmd) { + UsbCommand *r; + uint8_t *recv; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + int reply=1; + int fast=1; + int crc=0; + char buf[5]=""; + int i=0; + uint8_t data[100]; + unsigned int datalen=0, temp; + + + if (strlen(cmd)<3) { + PrintAndLog("Usage: hf 15 cmd raw [-r] [-2] [-c] <0A 0B 0C ... hex>"); + PrintAndLog(" -r do not read response"); + PrintAndLog(" -2 use slower '1 out of 256' mode"); + PrintAndLog(" -c calculate and append CRC"); + PrintAndLog(" Tip: turn on debugging for verbose output"); + return 0; + } + + // strip + while (*cmd==' ' || *cmd=='\t') cmd++; + + while (cmd[i]!='\0') { + if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; } + if (cmd[i]=='-') { + switch (cmd[i+1]) { + case 'r': + case 'R': + reply=0; + break; + case '2': + fast=0; + break; + case 'c': + case 'C': + crc=1; + break; + default: + PrintAndLog("Invalid option"); + return 0; + } + i+=2; + continue; + } + if ((cmd[i]>='0' && cmd[i]<='9') || + (cmd[i]>='a' && cmd[i]<='f') || + (cmd[i]>='A' && cmd[i]<='F') ) { + buf[strlen(buf)+1]=0; + buf[strlen(buf)]=cmd[i]; + i++; + + if (strlen(buf)>=2) { + sscanf(buf,"%x",&temp); + data[datalen]=(uint8_t)(temp & 0xff); + datalen++; + *buf=0; + } + continue; + } + PrintAndLog("Invalid char on input"); + return 0; + } + if (crc) datalen=AddCrc(data,datalen); + + c.arg[0]=datalen; + c.arg[1]=fast; + c.arg[2]=reply; + memcpy(c.d.asBytes,data,datalen); + + SendCommand(&c); + + if (reply) { + r=WaitForResponseTimeout(CMD_ACK,1000); + + if (r!=NULL) { + recv = r->d.asBytes; + PrintAndLog("received %i octets",r->arg[0]); + // TODO: output + } else { + PrintAndLog("timeout while waiting for reply."); + } + + } // if reply + return 0; +} + + +int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) { + int temp; + uint8_t *req=c->d.asBytes, uid[8]; + uint32_t reqlen=0; + + // strip + while (**cmd==' ' || **cmd=='\t') (*cmd)++; + + if (strstr(*cmd,"-2")==*cmd) { + c->arg[1]=0; // quse 1of256 + (*cmd)+=2; + } + + // strip + while (**cmd==' ' || **cmd=='\t') (*cmd)++; + + if (strstr(*cmd,"-o")==*cmd) { + req[reqlen]=ISO15_REQ_OPTION; + (*cmd)+=2; + } + + // strip + while (**cmd==' ' || **cmd=='\t') (*cmd)++; + + switch (**cmd) { + case 0: + PrintAndLog("missing addr"); + return 0; + break; + case 's': + case 'S': + // you must have selected the tag earlier + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; + break; + case 'u': + case 'U': + // unaddressed mode may not be supported by all vendors + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; + break; + case '*': + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; + if (!getUID(uid)) { + PrintAndLog("No Tag found"); + return 0; + } + memcpy(req+reqlen,uid,8); + PrintAndLog("Detected UID %s",sprintUID(NULL,uid)); + reqlen+=8; + break; + default: + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; + +/* sscanf(cmd,"%hX%hX%hX%hX%hX%hX%hX%hX", + (short unsigned int *)&uid[7],(short unsigned int *)&uid[6], + (short unsigned int *)&uid[5],(short unsigned int *)&uid[4], + (short unsigned int *)&uid[3],(short unsigned int *)&uid[2], + (short unsigned int *)&uid[1],(short unsigned int *)&uid[0]); */ + for (int i=0;i<8 && (*cmd)[i*2] && (*cmd)[i*2+1];i++) { // parse UID + sscanf((char[]){(*cmd)[i*2],(*cmd)[i*2+1],0},"%X",&temp); + uid[7-i]=temp&0xff; + } + + PrintAndLog("Using UID %s",sprintUID(NULL,uid)); + memcpy(&req[reqlen],&uid[0],8); + reqlen+=8; + } + // skip to next space + while (**cmd!=' ' && **cmd!='\t') (*cmd)++; + // skip over the space + while (**cmd==' ' || **cmd=='\t') (*cmd)++; + + c->arg[0]=reqlen; + return 1; +} + + + +int CmdHF15CmdRead(const char *Cmd) { + UsbCommand *r; + uint8_t *recv; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + uint8_t *req=c.d.asBytes; + int reqlen=0, pagenum; + char cmdbuf[100]; + char *cmd=cmdbuf; + char output[100]=""; + + strncpy(cmd,Cmd,99); + + // usage: + if (strlen(cmd)<3) { + PrintAndLog("Usage: hf 15 cmd read [options] "); + PrintAndLog(" options:"); + PrintAndLog(" -2 use slower '1 out of 256' mode"); + PrintAndLog(" uid (either): "); + PrintAndLog(" <8B hex> full UID eg E011223344556677"); + PrintAndLog(" s selected tag"); + PrintAndLog(" u unaddressed mode"); + PrintAndLog(" * scan for tag"); + PrintAndLog(" page#: page number 0-255"); + return 0; + } + + prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READ},1); + reqlen=c.arg[0]; + + pagenum=strtol(cmd,NULL,0); + /*if (pagenum<0) { + PrintAndLog("invalid pagenum"); + return 0; + } */ + + req[reqlen++]=(uint8_t)pagenum; + + reqlen=AddCrc(req,reqlen); + + c.arg[0]=reqlen; + + SendCommand(&c); + + r=WaitForResponseTimeout(CMD_ACK,1000); + + if (r!=NULL && r->arg[0]>2) { + recv = r->d.asBytes; + if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { + *output=0; // reset outputstring + //sprintf(output, "Block %2i ",blocknum); + for ( int i=1; iarg[0]-2; i++) { + sprintf(output+strlen(output),"%02hX ",recv[i]); + } + strcat(output," "); + for ( int i=2; iarg[0]-2; i++) { + sprintf(output+strlen(output),"%c",recv[i]>31 || recv[i]<127?recv[i]:'.'); + } + PrintAndLog("%s",output); + } else { + PrintAndLog("Tag returned Error %i: %s",recv[0],TagErrorStr(recv[0])); + } + } else { + PrintAndLog("CRC failed"); + } + } else { + PrintAndLog("no answer"); + } + + return 0; +} + + +int CmdHF15CmdWrite(const char *Cmd) { + UsbCommand *r; + uint8_t *recv; + UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + uint8_t *req=c.d.asBytes; + int reqlen=0, pagenum, temp; + char cmdbuf[100]; + char *cmd=cmdbuf; + char *cmd2; + + strncpy(cmd,Cmd,99); + + // usage: + if (strlen(cmd)<3) { + PrintAndLog("Usage: hf 15 cmd write [options] "); + PrintAndLog(" options:"); + PrintAndLog(" -2 use slower '1 out of 256' mode"); + PrintAndLog(" -o set OPTION Flag (needed for TI)"); + PrintAndLog(" uid (either): "); + PrintAndLog(" <8B hex> full UID eg E011223344556677"); + PrintAndLog(" s selected tag"); + PrintAndLog(" u unaddressed mode"); + PrintAndLog(" * scan for tag"); + PrintAndLog(" page#: page number 0-255"); + PrintAndLog(" hexdata: data to be written eg AA BB CC DD"); + return 0; + } + + prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_WRITE},1); + reqlen=c.arg[0]; + + // *cmd -> page num ; *cmd2 -> data + cmd2=cmd; + while (*cmd2!=' ' && *cmd2!='\t' && *cmd2) cmd2++; + *cmd2=0; + cmd2++; + + pagenum=strtol(cmd,NULL,0); + /*if (pagenum<0) { + PrintAndLog("invalid pagenum"); + return 0; + } */ + req[reqlen++]=(uint8_t)pagenum; + + + while (cmd2[0] && cmd2[1]) { // hexdata, read by 2 hexchars + if (*cmd2==' ') { + cmd2++; + continue; + } + sscanf((char[]){cmd2[0],cmd2[1],0},"%X",&temp); + req[reqlen++]=temp & 0xff; + cmd2+=2; + } + + reqlen=AddCrc(req,reqlen); + + c.arg[0]=reqlen; + + SendCommand(&c); + + r=WaitForResponseTimeout(CMD_ACK,2000); + + if (r!=NULL && r->arg[0]>2) { + recv = r->d.asBytes; + if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { + PrintAndLog("OK"); + } else { + PrintAndLog("Tag returned Error %i: %s",recv[0],TagErrorStr(recv[0])); + } + } else { + PrintAndLog("CRC failed"); + } + } else { + PrintAndLog("no answer"); + } + + return 0; +} + + + +static command_t CommandTable15Cmd[] = +{ + {"help", CmdHF15CmdHelp, 1, "This Help"}, + {"inquiry", CmdHF15CmdInquiry, 0, "Search for tags in range"}, + /* + {"select", CmdHF15CmdSelect, 0, "Select an tag with a specific UID for further commands"}, + */ + {"read", CmdHF15CmdRead, 0, "Read a block"}, + {"write", CmdHF15CmdWrite, 0, "Write a block"}, +/* + {"readmulti",CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"}, +*/ + {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHF15Cmd(const char *Cmd) +{ + CmdsParse(CommandTable15Cmd, Cmd); + return 0; +} + +int CmdHF15CmdHelp(const char *Cmd) +{ + CmdsHelp(CommandTable15Cmd); + return 0; +} + diff --git a/client/cmdhf15.h b/client/cmdhf15.h index 4b9822b7..8d78e13f 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -17,5 +17,9 @@ int CmdHF15Demod(const char *Cmd); int CmdHF15Read(const char *Cmd); int CmdHF15Reader(const char *Cmd); int CmdHF15Sim(const char *Cmd); +int CmdHF15Record(const char *Cmd); +int CmdHF15Cmd(const char*Cmd); +int CmdHF15CmdHelp(const char*Cmd); +int CmdHF15Help(const char*Cmd); #endif diff --git a/common/iso15693tools.c b/common/iso15693tools.c new file mode 100644 index 00000000..6d8ae5b1 --- /dev/null +++ b/common/iso15693tools.c @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// ISO15693 CRC & other commons +//----------------------------------------------------------------------------- + + +#include "proxmark3.h" +#include +#include +//#include "iso15693tools.h" + +// The CRC as described in ISO 15693-Part 3-Annex C +// v buffer with data +// n length +// returns crc as 16bit value +uint16_t Iso15693Crc(uint8_t *v, int n) +{ + uint32_t reg; + int i, j; + + reg = 0xffff; + for(i = 0; i < n; i++) { + reg = reg ^ ((uint32_t)v[i]); + for (j = 0; j < 8; j++) { + if (reg & 0x0001) { + reg = (reg >> 1) ^ 0x8408; + } else { + reg = (reg >> 1); + } + } + } + + return ~(uint16_t)(reg & 0xffff); +} + +// adds a CRC to a dataframe +// req[] iso15963 frame without crc +// n length without crc +// returns the new length of the dataframe. +int Iso15693AddCrc(uint8_t *req, int n) { + uint16_t crc=Iso15693Crc(req,n); + req[n] = crc & 0xff; + req[n+1] = crc >> 8; + return n+2; +} + + +int sprintf(char *str, const char *format, ...); + +// returns a string representation of the UID +// UID is transmitted and stored LSB first, displayed MSB first +// target char* buffer, where to put the UID, if NULL a static buffer is returned +// uid[] the UID in transmission order +// return: ptr to string +char* Iso15693sprintUID(char *target,uint8_t *uid) { + static char tempbuf[9]=""; + if (target==NULL) target=tempbuf; + sprintf(target,"%02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", + uid[7],uid[6],uid[5],uid[4],uid[3],uid[2],uid[1],uid[0]); + return target; +} + + + diff --git a/common/iso15693tools.h b/common/iso15693tools.h new file mode 100644 index 00000000..fff008ff --- /dev/null +++ b/common/iso15693tools.h @@ -0,0 +1,127 @@ +// ISO15693 commons +// Adrian Dabrowski 2010, GPLv2 + +#ifndef ISO15693_H__ +#define ISO15693_H__ + +// ISO15693 CRC +#define ISO15_CRC_PRESET (uint16_t)0xFFFF +#define ISO15_CRC_POLY (uint16_t)0x8408 +#define ISO15_CRC_CHECK ((uint16_t)(~0xF0B8 & 0xFFFF)) // use this for checking of a correct crc + +// REQUEST FLAGS + +#define ISO15_REQ_SUBCARRIER_SINGLE 0x00 // Tag should respond using one subcarrier (ASK) +#define ISO15_REQ_SUBCARRIER_TWO 0x01 // Tag should respond using two subcarriers (FSK) +#define ISO15_REQ_DATARATE_LOW 0x00 // Tag should respond using low data rate +#define ISO15_REQ_DATARATE_HIGH 0x02 // Tag should respond using high data rate +#define ISO15_REQ_NONINVENTORY 0x00 +#define ISO15_REQ_INVENTORY 0x04 // This is an inventory request - see inventory flags +#define ISO15_REQ_PROTOCOL_NONEXT 0x00 +#define ISO15_REQ_PROTOCOL_EXT 0x08 // RFU + +// REQUEST FLAGS when INVENTORY is not set + +#define ISO15_REQ_SELECT 0x10 // only selected cards response +#define ISO15_REQ_ADDRESS 0x20 // this req contains an address +#define ISO15_REQ_OPTION 0x40 // Command specific option selector + +//REQUEST FLAGS when INVENTORY is set + +#define ISO15_REQINV_AFI 0x10 // AFI Field is present +#define ISO15_REQINV_SLOT1 0x20 // 1 Slot +#define ISO15_REQINV_SLOT16 0x00 // 16 Slots +#define ISO15_REQINV_OPTION 0x40 // Command specific option selector + +//RESPONSE FLAGS +#define ISO15_RES_ERROR 0x01 +#define ISO15_RES_EXT 0x08 // Protocol Extention + +// RESPONSE ERROR CODES +#define ISO15_NOERROR 0x00 +#define ISO15_ERROR_CMD_NOT_SUP 0x01 // Command not supported +#define ISO15_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) +#define ISO15_ERROR_CMD_OPTION 0x03 // Command option not supported +#define ISO15_ERROR_GENERIC 0x0F // No additional Info about this error +#define ISO15_ERROR_BLOCK_UNAVAILABLE 0x10 +#define ISO15_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again +#define ISO15_ERROR_BLOCK_LOCKED 0x12 // cannot be changed +#define ISO15_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful +#define ISO15_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful + +// COMMAND CODES +#define ISO15_CMD_INVENTORY 0x01 +#define ISO15_CMD_STAYQUIET 0x02 +#define ISO15_CMD_READ 0x20 +#define ISO15_CMD_WRITE 0x21 +#define ISO15_CMD_LOCK 0x22 +#define ISO15_CMD_READMULTI 0x23 +#define ISO15_CMD_WRITEMULTI 0x24 +#define ISO15_CMD_SELECT 0x25 +#define ISO15_CMD_RESET 0x26 +#define ISO15_CMD_WRITEAFI 0x27 +#define ISO15_CMD_LOCKAFI 0x28 +#define ISO15_CMD_WRITEDSFID 0x29 +#define ISO15_CMD_LOCKDSFID 0x2A +#define ISO15_CMD_SYSINFO 0x2B +#define ISO15_CMD_SECSTATUS 0x2C + + +uint16_t Iso15693Crc(uint8_t *v, int n); +int Iso15693AddCrc(uint8_t *req, int n); +char* Iso15693sprintUID(char *target,uint8_t *uid); + +//----------------------------------------------------------------------------- +// Map a sequence of octets (~layer 2 command) into the set of bits to feed +// to the FPGA, to transmit that command to the tag. +// Mode: highspeed && one subcarrier (ASK) +//----------------------------------------------------------------------------- + + // The sampling rate is 106.353 ksps/s, for T = 18.8 us + + // SOF defined as + // 1) Unmodulated time of 56.64us + // 2) 24 pulses of 423.75khz + // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) + + static const int Iso15693FrameSOF[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }; + static const int Iso15693Logic0[] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1 + }; + static const int Iso15693Logic1[] = { + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }; + + // EOF defined as + // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) + // 2) 24 pulses of 423.75khz + // 3) Unmodulated time of 56.64us + + static const int Iso15693FrameEOF[] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + +#endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index f27f98ce..5e514355 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -75,6 +75,11 @@ typedef struct { #define CMD_READ_SRIX4K_TAG 0x0304 #define CMD_READER_ISO_15693 0x0310 #define CMD_SIMTAG_ISO_15693 0x0311 +#define CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693 0x0312 +#define CMD_ISO_15693_COMMAND 0x0313 +#define CMD_ISO_15693_COMMAND_DONE 0x0314 +#define CMD_ISO_15693_FIND_AFI 0x0315 +#define CMD_ISO_15693_DEBUG 0x0316 #define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 #define CMD_SIMULATE_TAG_ISO_14443 0x0381 #define CMD_SNOOP_ISO_14443 0x0382 diff --git a/tools/findbits.py b/tools/findbits.py index b753f8f4..f5d2dbd6 100755 --- a/tools/findbits.py +++ b/tools/findbits.py @@ -37,7 +37,7 @@ def invert(data): return out # do the actual search -def search(data,target): +def search(target,data): location= string.find(data,target) if location >= 0: print '*** Match at bit %d:' % location,