X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/15c4dc5ace24e6081d1597b011148f156cdd599e..9f975d42e8a1deca182270642c365ba11f565259:/armsrc/iso15693.c?ds=sidebyside diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e36baad2..47364451 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1,71 +1,98 @@ //----------------------------------------------------------------------------- +// Jonathan Westhues, split Nov 2006 +// Modified by Greg Jones, Jan 2009 +// Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 +// +// 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. +//----------------------------------------------------------------------------- // Routines to support ISO 15693. This includes both the reader software and // the `fake tag' modes, but at the moment I've implemented only the reader // stuff, and that barely. -// Jonathan Westhues, split Nov 2006 - -// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC +// Modified to perform modulation onboard in arm rather than on PC // Also added additional reader commands (SELECT, READ etc.) - //----------------------------------------------------------------------------- -#include <proxmark3.h> +// 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 +// *) read security status of a block +// *) 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 + +#define Crc(data,datalen) Iso15693Crc(data,datalen) +#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) +#define sprintUID(target,uid) Iso15693sprintUID(target,uid) + +int DEBUG=0; - // 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 - }; - -static void CodeIso15693AsReader(BYTE *cmd, int n) + +// --------------------------- +// 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; @@ -76,6 +103,7 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) ToSendStuffBit(1); } + // SOF for 1of4 ToSendStuffBit(0); ToSendStuffBit(1); ToSendStuffBit(1); @@ -131,6 +159,7 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) } } } + // EOF ToSendStuffBit(1); ToSendStuffBit(1); ToSendStuffBit(0); @@ -142,332 +171,56 @@ static void CodeIso15693AsReader(BYTE *cmd, int n) } } -//----------------------------------------------------------------------------- -// The CRC used by ISO 15693. -//----------------------------------------------------------------------------- -static WORD Crc(BYTE *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) { - DWORD 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 ^ ((DWORD)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<j; i++, j--) { - c = s[i]; - s[i] = s[j]; - s[j] = c; - } -} - -/* itoa: convert n to characters in s */ -void itoa(int n, char s[]) -{ - int i, sign; - - if ((sign = n) < 0) /* record sign */ - n = -n; /* make n positive */ - i = 0; - do { /* generate digits in reverse order */ - s[i++] = n % 10 + '0'; /* get next digit */ - } while ((n /= 10) > 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) -{ - BYTE cmd[5]; - - WORD 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(BYTE *uid) -{ - BYTE cmd[12]; - - WORD 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( BYTE uid[]) -{ - -// uid[6]=0x31; // this is getting ignored - the uid array is not happening... - BYTE cmd[12]; - - WORD 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(BYTE *uid, BYTE blockNumber ) -{ - BYTE cmd[13]; - - WORD 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(BYTE *uid) -{ - BYTE cmd[14]; - - WORD 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(BYTE *uid,BYTE CmdCode) -{ - BYTE cmd[14]; - - WORD 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(BYTE uid[], BYTE CmdCode) -{ - BYTE cmd[14]; - - WORD 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) -{ - BYTE cmd[12]; - - WORD 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 BYTE *cmd, int len, int *samples, int *wait) +static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) { int c; @@ -481,7 +234,7 @@ static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait // c++; // } // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { -// volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; +// volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; // (void)r; // } // WDT_HIT(); @@ -497,7 +250,7 @@ static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait } } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; (void)r; } WDT_HIT(); @@ -508,7 +261,7 @@ static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait //----------------------------------------------------------------------------- // Transmit the command (to the reader) that was placed in ToSend[]. //----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait) +static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) { int c; @@ -526,7 +279,7 @@ static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *w } } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; (void)r; } WDT_HIT(); @@ -534,13 +287,22 @@ static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *w *samples = (c + *wait) << 3; } -static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) + +// 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; - BYTE *dest = (BYTE *)BigBuf; + uint8_t *dest = (uint8_t *)BigBuf; int getNext = 0; - SBYTE prev = 0; + int8_t prev = 0; // NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); @@ -552,15 +314,15 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam AT91C_BASE_SSC->SSC_THR = 0x43; } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - SBYTE b; - b = (SBYTE)AT91C_BASE_SSC->SSC_RHR; + 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) { - SBYTE r; + int8_t r; if(b < 0) { r = -b; @@ -573,7 +335,7 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam r += prev; } - dest[c++] = (BYTE)r; + dest[c++] = (uint8_t)r; if(c >= 2000) { break; @@ -586,16 +348,16 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam } } -////////////////////////////////////////// -/////////// 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++) { @@ -608,7 +370,7 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam 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 @@ -616,63 +378,65 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam if ((max/(arraylen(FrameSOF)/skip)) >= 1) { - i = maxPos + arraylen(FrameSOF)/skip; - - BYTE outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - BYTE 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); - } -// BYTE 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 @@ -680,14 +444,15 @@ static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *sam } + // Now the GetISO15693 message from sniffing command -static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) +static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { int c = 0; - BYTE *dest = (BYTE *)BigBuf; + uint8_t *dest = (uint8_t *)BigBuf; int getNext = 0; - SBYTE prev = 0; + int8_t prev = 0; // NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); @@ -699,15 +464,15 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s AT91C_BASE_SSC->SSC_THR = 0x43; } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - SBYTE b; - b = (SBYTE)AT91C_BASE_SSC->SSC_RHR; + 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) { - SBYTE r; + int8_t r; if(b < 0) { r = -b; @@ -720,7 +485,7 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s r += prev; } - dest[c++] = (BYTE)r; + dest[c++] = (uint8_t)r; if(c >= 20000) { break; @@ -733,9 +498,9 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s } } -////////////////////////////////////////// -/////////// DEMODULATE /////////////////// -////////////////////////////////////////// + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// int i, j; int max = 0, maxPos=0; @@ -762,160 +527,472 @@ static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *s // 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; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if((i+(int)arraylen(FrameEOF)) >= 2000) { + DbpString("ran off end!"); + break; + } + } + if(mask != 0x01) { + DbpString("sniff: error, uneven octet! (discard extra bits!)"); + /// DbpString(" mask=%02x", mask); + } + // 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]; + } + } // "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 +// so that it can be downloaded to a PC and processed there. +//----------------------------------------------------------------------------- +void AcquireRawAdcSamplesIso15693(void) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; + + int8_t prev = 0; + + BuildIdentifyRequest(); - i = maxPos + arraylen(FrameSOF)/skip; + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(100); + + // Now send the command + FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - BYTE outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - BYTE mask = 0x01; + c = 0; for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + c++; + if(c == ToSendMax+3) { + break; + } } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + WDT_HIT(); + } + + 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; } - // 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; + 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 >= 2000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; + } +} + + +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((i+(int)arraylen(FrameEOF)) >= 2000) { - DbpString("ran off end!"); - break; + 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(); } } - if(mask != 0x01) { - DbpString("error, uneven octet! (discard extra bits!)"); -/// DbpString(" mask=%02x", mask); - } -// BYTE str1 [8]; -// itoa(k,str1); -// strcat(str1," octets read"); + Dbprintf("fin record"); +} + + +// Initialize the proxmark as iso15k reader +// (this might produces glitches that confuse some tags +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(10); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(250); + + 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; -// DbpString( str1); // DbpString("%d octets", k); + CodeIso15693AsReader(cmd, sizeof(cmd)); +} -// for(i = 0; i < k; i+=3) { -// //DbpString("# %2d: %02x ", i, outBuf[i]); -// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); -// } +// Universal Method for sending to and recv bytes 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) { - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; + 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; } - } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) - return k; // return the number of bytes demodulated -/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + + return answerLen; } -//----------------------------------------------------------------------------- -// 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 -// so that it can be downloaded to a PC and processed there. -//----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso15693(void) -{ - int c = 0; - BYTE *dest = (BYTE *)BigBuf; - int getNext = 0; - - SBYTE prev = 0; - - BuildIdentifyRequest(); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(100); - - // Now send the command - FpgaSetupSsc(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c]; - c++; - if(c == ToSendMax+3) { - break; +// -------------------------------------------------------------------- +// Debug Functions +// -------------------------------------------------------------------- + +// 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; + 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); } + strncat(status," ",DBD15STATLEN); + } else { + strncat(status,"NoErr ",DBD15STATLEN); } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile DWORD r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); + + 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); } +} - 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)) { - SBYTE b; - b = (SBYTE)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) { - SBYTE r; - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } +/////////////////////////////////////////////////////////////////////// +// Functions called via USB/Client +/////////////////////////////////////////////////////////////////////// - dest[c++] = (BYTE)r; +void SetDebugIso15693(uint32_t debug) { + DEBUG=debug; + Dbprintf("Iso15693 Debug is now %s",DEBUG?"on":"off"); + return; +} - if(c >= 2000) { - break; - } - } else { - prev = b; - } - getNext = !getNext; - } - } -} //----------------------------------------------------------------------------- // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg //----------------------------------------------------------------------------- -void ReaderIso15693(DWORD parameter) +void ReaderIso15693(uint32_t parameter) { LED_A_ON(); LED_B_ON(); @@ -924,15 +1001,16 @@ void ReaderIso15693(DWORD parameter) //DbpString(parameter); - //BYTE *answer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) - BYTE *answer1 = (((BYTE *)BigBuf) + 3660); // - BYTE *answer2 = (((BYTE *)BigBuf) + 3760); - BYTE *answer3 = (((BYTE *)BigBuf) + 3860); - //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader + //uint8_t *answer0 = (((uint8_t *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) + uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // + uint8_t *answer2 = (((uint8_t *)BigBuf) + 3760); + uint8_t *answer3 = (((uint8_t *)BigBuf) + 3860); + //uint8_t *TagUID= (((uint8_t *)BigBuf) + 3960); // where we hold the uid for hi15reader // int answerLen0 = 0; int answerLen1 = 0; int answerLen2 = 0; int answerLen3 = 0; + int i=0; // counter // Blank arrays memset(BigBuf + 3660, 0, 300); @@ -963,7 +1041,7 @@ void ReaderIso15693(DWORD parameter) // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - BYTE 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); @@ -1001,45 +1079,68 @@ void ReaderIso15693(DWORD 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 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: %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 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); @@ -1049,18 +1150,16 @@ void ReaderIso15693(DWORD 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(DWORD parameter) +void SimTagIso15693(uint32_t parameter) { LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_OFF(); - BYTE *answer1 = (((BYTE *)BigBuf) + 3660); // + uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // int answerLen1 = 0; // Blank arrays @@ -1109,3 +1208,231 @@ void SimTagIso15693(DWORD 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)) 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)); +} + + + + +*/ + +