From: roel@libnfc.org Date: Tue, 18 Sep 2012 13:53:17 +0000 (+0000) Subject: MAJOR update, added hitag2 reader, emulation and eavesdropping, lots of new code... X-Git-Tag: v1.0.0~145 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/d19929cbe8d681b60496ca6d9d9cbd806822e163 MAJOR update, added hitag2 reader, emulation and eavesdropping, lots of new code, including FPGA tweaks, part 2 --- diff --git a/armsrc/Makefile b/armsrc/Makefile index e2d71324..715eba0a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,7 +10,7 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -O2 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF +APP_CFLAGS = -O2 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG #-DWITH_LCD #SRC_LCD = fonts.c LCD.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index d3544861..dac87677 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -19,6 +19,7 @@ #include #include "legicrf.h" +#include #ifdef WITH_LCD # include "fonts.h" @@ -125,23 +126,27 @@ void Dbprintf(const char *fmt, ...) { } // prints HEX & ASCII -void Dbhexdump(int len, uint8_t *d) { +void Dbhexdump(int len, uint8_t *d, bool bAsci) { 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; + ascii[l]=0; // filter safe ascii - for (i=0;i126) ascii[i]='.'; - - Dbprintf("%-8s %*D",ascii,l,d," "); - + + if (bAsci) { + Dbprintf("%-8s %*D",ascii,l,d," "); + } else { + Dbprintf("%*D",l,d," "); + } + len-=8; d+=8; } @@ -185,14 +190,15 @@ int AvgAdc(int ch) // was static - merlok void MeasureAntennaTuning(void) { - uint8_t *dest = (uint8_t *)BigBuf; + uint8_t *dest = (uint8_t *)BigBuf+FREE_BUFFER_OFFSET; int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV UsbCommand c; - DbpString("Measuring antenna characteristics, please wait."); - memset(BigBuf,0,sizeof(BigBuf)); + LED_B_ON(); + DbpString("Measuring antenna characteristics, please wait..."); + memset(dest,0,sizeof(FREE_BUFFER_SIZE)); /* * Sweeps the useful LF range of the proxmark from @@ -202,8 +208,10 @@ void MeasureAntennaTuning(void) * the resonating frequency of your LF antenna * ( hopefully around 95 if it is tuned to 125kHz!) */ + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); for (i=255; i>19; i--) { + WDT_HIT(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); SpinDelay(20); // Vref = 3.3V, and a 10000:240 voltage divider on the input @@ -221,6 +229,7 @@ void MeasureAntennaTuning(void) } } + LED_A_ON(); // Let the FPGA drive the high-frequency antenna around 13.56 MHz. FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(20); @@ -232,7 +241,14 @@ void MeasureAntennaTuning(void) c.arg[0] = (vLf125 << 0) | (vLf134 << 16); c.arg[1] = vHf; c.arg[2] = peakf | (peakv << 16); + + DbpString("Measuring complete, sending report back to host"); + UsbSendPacket((uint8_t *)&c, sizeof(c)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + LED_B_OFF(); + return; } void MeasureAntennaTuningHf(void) @@ -258,8 +274,7 @@ void MeasureAntennaTuningHf(void) void SimulateTagHfListen(void) { - uint8_t *dest = (uint8_t *)BigBuf; - int n = sizeof(BigBuf); + uint8_t *dest = (uint8_t *)BigBuf+FREE_BUFFER_OFFSET; uint8_t v = 0; int i; int p = 0; @@ -293,7 +308,7 @@ void SimulateTagHfListen(void) p = 0; i++; - if(i >= n) { + if(i >= FREE_BUFFER_SIZE) { break; } } @@ -644,6 +659,18 @@ void UsbPacketReceived(uint8_t *packet, int len) break; #endif +#ifdef WITH_HITAG + case CMD_SNOOP_HITAG: // Eavesdrop Hitag tag, args = type + SnoopHitag(c->arg[0]); + break; + case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content + SimulateHitagTag((bool)c->arg[0],(byte_t*)c->d.asBytes); + break; + case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function + ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); + break; +#endif + #ifdef WITH_ISO15693 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: AcquireRawAdcSamplesIso15693(); @@ -822,16 +849,14 @@ void UsbPacketReceived(uint8_t *packet, int len) LED_B_ON(); UsbSendPacket((uint8_t *)&n, sizeof(n)); LED_B_OFF(); - break; - } + } break; case CMD_DOWNLOADED_SIM_SAMPLES_125K: { uint8_t *b = (uint8_t *)BigBuf; memcpy(b+c->arg[0], c->d.asBytes, 48); //Dbprintf("copied 48 bytes to %i",b+c->arg[0]); UsbSendPacket((uint8_t*)&ack, sizeof(ack)); - break; - } + } break; case CMD_READ_MEM: ReadMem(c->arg[0]); @@ -854,10 +879,6 @@ void UsbPacketReceived(uint8_t *packet, int len) SendVersion(); break; -#ifdef WITH_LF - -#endif - #ifdef WITH_LCD case CMD_LCD_RESET: LCDReset(); @@ -868,7 +889,7 @@ void UsbPacketReceived(uint8_t *packet, int len) #endif case CMD_SETUP_WRITE: case CMD_FINISH_WRITE: - case CMD_HARDWARE_RESET: + case CMD_HARDWARE_RESET: { USB_D_PLUS_PULLUP_OFF(); SpinDelay(1000); SpinDelay(1000); @@ -876,16 +897,16 @@ void UsbPacketReceived(uint8_t *packet, int len) for(;;) { // We're going to reset, and the bootrom will take control. } - break; + } break; - case CMD_START_FLASH: + case CMD_START_FLASH: { if(common_area.flags.bootrom_present) { common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE; } USB_D_PLUS_PULLUP_OFF(); AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; for(;;); - break; + } break; case CMD_DEVICE_INFO: { UsbCommand c; @@ -893,11 +914,11 @@ void UsbPacketReceived(uint8_t *packet, int len) c.arg[0] = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS; if(common_area.flags.bootrom_present) c.arg[0] |= DEVICE_INFO_FLAG_BOOTROM_PRESENT; UsbSendPacket((uint8_t*)&c, sizeof(c)); - } - break; - default: + } break; + + default: { Dbprintf("%s: 0x%04x","unknown command:",c->cmd); - break; + } break; } } diff --git a/armsrc/apps.h b/armsrc/apps.h index 6e98311a..f3f90237 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -14,7 +14,8 @@ #include #include -typedef unsigned char byte_t; +#include "common.h" +#include "hitag2.h" // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. @@ -49,7 +50,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 Dbhexdump(int len, uint8_t *d, bool bAsci); int AvgAdc(int ch); @@ -69,13 +70,9 @@ void FpgaDownloadAndGo(void); void FpgaGatherVersion(char *dst, int len); void FpgaSetupSsc(void); void SetupSpi(int mode); -void FpgaSetupSscDma(uint8_t *buf, int len); -void inline FpgaDisableSscDma(void){ - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; -} -void inline FpgaEnableSscDma(void){ - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; -} +bool FpgaSetupSscDma(uint8_t *buf, int len); +#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; +#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; void SetAdcMuxFor(uint32_t whichGpio); // Definitions for the FPGA commands. @@ -83,19 +80,21 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_CMD_SET_DIVISOR (2<<12) // Definitions for the FPGA configuration word. #define FPGA_MAJOR_MODE_LF_READER (0<<5) -#define FPGA_MAJOR_MODE_LF_SIMULATOR (1<<5) +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) #define FPGA_MAJOR_MODE_HF_READER_TX (2<<5) #define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5) #define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5) #define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5) #define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5) #define FPGA_MAJOR_MODE_OFF (7<<5) +// Options for LF_EDGE_DETECT +#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) // Options for the HF reader, tx to tag #define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) // Options for the HF reader, correlating against rx from tag #define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) #define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) -#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) +#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) #define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) @@ -139,7 +138,7 @@ void ReaderIso14443a(UsbCommand * c, UsbCommand * ack); int RAMFUNC LogTrace(const uint8_t * btBytes, int iLen, int iSamples, uint32_t dwParity, int bReader); uint32_t GetParity(const uint8_t * pbtCmd, int iLen); void iso14a_set_trigger(int enable); -void iso14a_clear_tracelen(void); +void iso14a_clear_trace(void); void iso14a_set_tracing(int enable); void RAMFUNC SniffMifare(uint8_t param); @@ -176,6 +175,11 @@ void RAMFUNC SnoopIClass(void); void SimulateIClass(uint8_t arg0, uint8_t *datain); void ReaderIClass(uint8_t arg0); +// hitag2.h +void SnoopHitag(uint32_t type); +void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); +void ReaderHitag(hitag_function htf, hitag_data* htd); + /// util.h #endif diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index c199b9a8..a719f5ed 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -136,18 +136,20 @@ void FpgaSetupSsc(void) // ourselves, not to another buffer). The stuff to manipulate those buffers // is in apps.h, because it should be inlined, for speed. //----------------------------------------------------------------------------- -void FpgaSetupSscDma(uint8_t *buf, int len) +bool FpgaSetupSscDma(uint8_t *buf, int len) { + if (buf == NULL) { + return false; + } + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; AT91C_BASE_PDC_SSC->PDC_RCR = len; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; AT91C_BASE_PDC_SSC->PDC_RNCR = len; - - if (buf != NULL) { - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; - } + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; + + return true; } static void DownloadFPGA_byte(unsigned char w) diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 15daa25e..75513232 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -1,14 +1,19 @@ //----------------------------------------------------------------------------- -// (c) 2009 Henryk Plötz -// // 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. //----------------------------------------------------------------------------- -// Hitag2 emulation +// Hitag2 emulation (preliminary test version) // -// Contains state and functions for an emulated Hitag2 tag. Offers an entry -// point to handle commands, needs a callback to send response. +// (c) 2009 Henryk Plötz +//----------------------------------------------------------------------------- +// Hitag2 complete rewrite of the code +// - Fixed modulation/encoding issues +// - Rewrote code for transponder emulation +// - Added snooping of transponder communication +// - Added reader functionality +// +// (c) 2012 Roel Verdult //----------------------------------------------------------------------------- #include "proxmark3.h" @@ -17,166 +22,57 @@ #include "hitag2.h" #include "string.h" -struct hitag2_cipher_state { - uint64_t state; -}; +static bool bQuiet; + +bool bCrypto; +bool bPwd; struct hitag2_tag { uint32_t uid; enum { - TAG_STATE_RESET, // Just powered up, awaiting GetSnr - TAG_STATE_ACTIVATING, // In activation phase (password mode), sent UID, awaiting reader password - TAG_STATE_AUTHENTICATING, // In activation phase (crypto mode), awaiting reader authentication - TAG_STATE_ACTIVATED, // Activation complete, awaiting read/write commands - TAG_STATE_WRITING, // In write command, awaiting sector contents to be written + TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr + TAG_STATE_ACTIVATING = 0x02 , // In activation phase (password mode), sent UID, awaiting reader password + TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands + TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written } state; unsigned int active_sector; - char crypto_active; - struct hitag2_cipher_state cs; - char sectors[8][4]; + byte_t crypto_active; + uint64_t cs; + byte_t sectors[12][4]; }; -static void hitag2_cipher_reset(struct hitag2_tag *tag, const char *challenge); -static int hitag2_cipher_authenticate(struct hitag2_cipher_state *cs, const char *authenticator); -static int hitag2_cipher_transcrypt(struct hitag2_cipher_state *cs, char *data, unsigned int bytes, unsigned int bits); - static struct hitag2_tag tag; static const struct hitag2_tag resetdata = { - .state = TAG_STATE_RESET, - .sectors = { // Password mode: | Crypto mode: - [0] = { 0x35, 0x33, 0x70, 0x11}, // UID | UID - [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key - [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved - [3] = { 0x0e, 0xaa, 'H', 'T'}, // Configuration, password TAG | Configuration, password TAG - }, + .state = TAG_STATE_RESET, + .sectors = { // Password mode: | Crypto mode: + [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID + [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key + [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved + [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG + [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK + [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... + [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low + [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High + [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF + [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC + }, }; -int hitag2_reset(void) -{ - tag.state = TAG_STATE_RESET; - tag.crypto_active = 0; - return 0; -} - -int hitag2_init(void) -{ - memcpy(&tag, &resetdata, sizeof(tag)); - hitag2_reset(); - return 0; -} - -int hitag2_handle_command(const char* data, const int length, hitag2_response_callback_t cb, void *cb_cookie) -{ - (void)data; (void)length; (void)cb; (void)cb_cookie; - int retry = 0, done = 0, result=0; - char temp[10]; - - if(tag.crypto_active && length < sizeof(temp)*8) { - /* Decrypt command */ - memcpy(temp, data, (length+7)/8); - hitag2_cipher_transcrypt(&(tag.cs), temp, length/8, length%8); - data = temp; - } - - -handle_command_retry: - switch(tag.state) { - case TAG_STATE_RESET: - if(length == 5 && data[0] == 0xC0) { - /* Received 11000 from the reader, request for UID, send UID */ - result=cb(tag.sectors[0], sizeof(tag.sectors[0])*8, 208, cb_cookie); - done=1; - if(tag.sectors[3][0] & 0x08) { - tag.state=TAG_STATE_AUTHENTICATING; - } else { - tag.state=TAG_STATE_ACTIVATING; - } - } - break; - case TAG_STATE_ACTIVATING: - if(length == 0x20) { - /* Received RWD password, respond with configuration and our password */ - result=cb(tag.sectors[3], sizeof(tag.sectors[3])*8, 208, cb_cookie); - done=1; - tag.state=TAG_STATE_ACTIVATED; - } - break; - case TAG_STATE_AUTHENTICATING: - if(length == 0x40) { - /* Received initialisation vector || authentication token, fire up cipher, send our password */ - hitag2_cipher_reset(&tag, data); - if(hitag2_cipher_authenticate(&(tag.cs), data+4)) { - char response_enc[4]; - memcpy(response_enc, tag.sectors[3], 4); - hitag2_cipher_transcrypt(&(tag.cs), response_enc, 4, 0); - result=cb(response_enc, 4*8, 208, cb_cookie); - done=1; - tag.crypto_active = 1; - tag.state = TAG_STATE_ACTIVATED; - } else { - /* The reader failed to authenticate, do nothing */ - DbpString("Reader authentication failed"); - } - } - break; - case TAG_STATE_ACTIVATED: - if(length == 10) { - if( ((data[0] & 0xC0) == 0xC0) && ((data[0] & 0x06) == 0) ) { - /* Read command: 11xx x00y yy with yyy == ~xxx, xxx is sector number */ - unsigned int sector = (~( ((data[0]<<2)&0x04) | ((data[1]>>6)&0x03) ) & 0x07); - if(sector == ( (data[0]>>3)&0x07 ) ) { - memcpy(temp, tag.sectors[sector], 4); - if(tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs), temp, 4, 0); - } - /* Respond with contents of sector sector */ - result = cb(temp, 4*8, 208, cb_cookie); - done=1; - } else { - /* transmission error */ - DbpString("Transmission error (read) in activated state"); - } - } else if( ((data[0] & 0xC0) == 0x80) && ((data[0] & 0x06) == 2) ) { - /* Write command: 10xx x01y yy with yyy == ~xxx, xxx is sector number */ - unsigned int sector = (~( ((data[0]<<2)&0x04) | ((data[1]>>6)&0x03) ) & 0x07); - if(sector == ( (data[0]>>3)&0x07 ) ) { - /* Prepare write, acknowledge by repeating command */ - if(tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs), temp, length/8, length%8); - } - result = cb(data, length, 208, cb_cookie); - done=1; - tag.active_sector = sector; - tag.state=TAG_STATE_WRITING; - } else { - /* transmission error */ - DbpString("Transmission error (write) in activated state"); - } - } - - } - case TAG_STATE_WRITING: - if(length == 32) { - /* These are the sector contents to be written. We don't have to do anything else. */ - memcpy(tag.sectors[tag.active_sector], data, length/8); - tag.state=TAG_STATE_ACTIVATED; - done=1; - } - } +//#define TRACE_LENGTH 3000 +//uint8_t *trace = (uint8_t *) BigBuf; +//int traceLen = 0; +//int rsamples = 0; - if(!done && !retry) { - /* We didn't respond, maybe our state is faulty. Reset and try again. */ - retry=1; - if(tag.crypto_active) { - /* Restore undeciphered data */ - memcpy(temp, data, (length+7)/8); - } - hitag2_reset(); - goto handle_command_retry; - } +#define AUTH_TABLE_OFFSET FREE_BUFFER_OFFSET +#define AUTH_TABLE_LENGTH FREE_BUFFER_SIZE +byte_t* auth_table = (byte_t *)BigBuf+AUTH_TABLE_OFFSET; +size_t auth_table_pos = 0; +size_t auth_table_len = AUTH_TABLE_LENGTH; - return result; -} +byte_t password[4]; +byte_t NrAr[8]; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ // Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007. @@ -254,10 +150,25 @@ static u32 _hitag2_byte (u64 * x) return c; } +size_t nbytes(size_t nbits) { + return (nbits/8)+((nbits%8)>0); +} + +int hitag2_reset(void) +{ + tag.state = TAG_STATE_RESET; + tag.crypto_active = 0; + return 0; +} -/* Cipher/tag glue code: */ +int hitag2_init(void) +{ + memcpy(&tag, &resetdata, sizeof(tag)); + hitag2_reset(); + return 0; +} -static void hitag2_cipher_reset(struct hitag2_tag *tag, const char *iv) +static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) { uint64_t key = ((uint64_t)tag->sectors[2][2]) | ((uint64_t)tag->sectors[2][3] << 8) | @@ -273,23 +184,1051 @@ static void hitag2_cipher_reset(struct hitag2_tag *tag, const char *iv) (((uint32_t)(iv[1])) << 8) | (((uint32_t)(iv[2])) << 16) | (((uint32_t)(iv[3])) << 24); - tag->cs.state = _hitag2_init(rev64(key), rev32(uid), rev32(iv_)); + tag->cs = _hitag2_init(rev64(key), rev32(uid), rev32(iv_)); } -static int hitag2_cipher_authenticate(struct hitag2_cipher_state *cs, const char *authenticator_is) +static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_is) { - char authenticator_should[4]; - authenticator_should[0] = ~_hitag2_byte(&(cs->state)); - authenticator_should[1] = ~_hitag2_byte(&(cs->state)); - authenticator_should[2] = ~_hitag2_byte(&(cs->state)); - authenticator_should[3] = ~_hitag2_byte(&(cs->state)); - return memcmp(authenticator_should, authenticator_is, 4) == 0; + byte_t authenticator_should[4]; + authenticator_should[0] = ~_hitag2_byte(cs); + authenticator_should[1] = ~_hitag2_byte(cs); + authenticator_should[2] = ~_hitag2_byte(cs); + authenticator_should[3] = ~_hitag2_byte(cs); + return (memcmp(authenticator_should, authenticator_is, 4) == 0); } -static int hitag2_cipher_transcrypt(struct hitag2_cipher_state *cs, char *data, unsigned int bytes, unsigned int bits) +static int hitag2_cipher_transcrypt(uint64_t* cs, byte_t *data, unsigned int bytes, unsigned int bits) { int i; - for(i=0; istate)); - for(i=0; istate)) << (7-i); + for(i=0; i 36 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ + +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 + +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 + +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 +#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 + + +static void hitag_send_bit(int bit) { + LED_A_ON(); + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + // Fixed modulation, earlier proxmark version used inverted signal + if(bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + } + LED_A_OFF(); +} + +static void hitag_send_frame(const byte_t* frame, size_t frame_len) +{ + // Send start of frame + for(size_t i=0; i<5; i++) { + hitag_send_bit(1); + } + + // Send the content of the frame + for(size_t i=0; i> (7-(i%8)))&1); + } + + // Drop the modulation + LOW(GPIO_SSC_DOUT); +} + +void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) +{ + byte_t rx_air[HITAG_FRAME_LEN]; + + // Copy the (original) received frame how it is send over the air + memcpy(rx_air,rx,nbytes(rxlen)); + + if(tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); + } + + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // Received 11000 from the reader, request for UID, send UID + case 05: { + // Always send over the air in the clear plaintext mode + if(rx_air[0] != 0xC0) { + // Unknown frame ? + return; + } + *txlen = 32; + memcpy(tx,tag.sectors[0],4); + tag.crypto_active = 0; + } + break; + + // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number + case 10: { + unsigned int sector = (~( ((rx[0]<<2)&0x04) | ((rx[1]>>6)&0x03) ) & 0x07); + // Verify complement of sector index + if(sector != ((rx[0]>>3)&0x07)) { + //DbpString("Transmission error (read/write)"); + return; + } + + switch (rx[0] & 0xC6) { + // Read command: 11xx x00y + case 0xC0: + memcpy(tx,tag.sectors[sector],4); + *txlen = 32; + break; + + // Inverted Read command: 01xx x10y + case 0x44: + for (size_t i=0; i<4; i++) { + tx[i] = tag.sectors[sector][i] ^ 0xff; + } + *txlen = 32; + break; + + // Write command: 10xx x01y + case 0x82: + // Prepare write, acknowledge by repeating command + memcpy(tx,rx,nbytes(rxlen)); + *txlen = rxlen; + tag.active_sector = sector; + tag.state=TAG_STATE_WRITING; + break; + + // Unknown command + default: + Dbprintf("Uknown command: %02x %02x",rx[0],rx[1]); + return; + break; + } + } + break; + + // Writing data or Reader password + case 32: { + if(tag.state == TAG_STATE_WRITING) { + // These are the sector contents to be written. We don't have to do anything else. + memcpy(tag.sectors[tag.active_sector],rx,nbytes(rxlen)); + tag.state=TAG_STATE_RESET; + return; + } else { + // Received RWD password, respond with configuration and our password + if(memcmp(rx,tag.sectors[1],4) != 0) { + DbpString("Reader password is wrong"); + return; + } + *txlen = 32; + memcpy(tx,tag.sectors[3],4); + } + } + break; + + // Received RWD authentication challenge and respnse + case 64: { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { + memcpy(auth_table+auth_table_len,rx,8); + auth_table_len += 8; + } + + // Reset the cipher state + hitag2_cipher_reset(&tag,rx); + // Check if the authentication was correct + if(!hitag2_cipher_authenticate(&(tag.cs),rx+4)) { + // The reader failed to authenticate, do nothing + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + return; + } + // Succesful, but commented out reporting back to the Host, this may delay to much. + // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + + // Activate encryption algorithm for all further communication + tag.crypto_active = 1; + + // Use the tag password as response + memcpy(tx,tag.sectors[3],4); + *txlen = 32; + } + break; + } + +// LogTrace(rx,nbytes(rxlen),0,0,false); +// LogTrace(tx,nbytes(*txlen),0,0,true); + + if(tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); + } +} + +static void hitag_reader_send_bit(int bit) { + LED_A_ON(); + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + // Binary puls length modulation (BPLM) is used to encode the data stream + // This means that a transmission of a one takes longer than that of a zero + + // Enable modulation, which means, drop the the field + HIGH(GPIO_SSC_DOUT); + + // Wait for 4-10 times the carrier period + while(AT91C_BASE_TC0->TC_CV < T0*6); + // SpinDelayUs(8*8); + + // Disable modulation, just activates the field again + LOW(GPIO_SSC_DOUT); + + if(bit == 0) { + // Zero bit: |_-| + while(AT91C_BASE_TC0->TC_CV < T0*22); + // SpinDelayUs(16*8); + } else { + // One bit: |_--| + while(AT91C_BASE_TC0->TC_CV < T0*28); + // SpinDelayUs(22*8); + } + LED_A_OFF(); +} + +static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) +{ + // Send the content of the frame + for(size_t i=0; i> (7-(i%8)))&1); + } + // Send EOF + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + // Enable modulation, which means, drop the the field + HIGH(GPIO_SSC_DOUT); + // Wait for 4-10 times the carrier period + while(AT91C_BASE_TC0->TC_CV < T0*6); + // Disable modulation, just activates the field again + LOW(GPIO_SSC_DOUT); +} + +bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer (after sending password) + if (bPwd) { + DbpString("Password failed!"); + return false; + } + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, tag password + case 32: { + if (!bPwd) { + *txlen = 32; + memcpy(tx,password,4); + bPwd = true; + } else { + DbpString("Password succesful!"); + // We are done... for now + return false; + } + } break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + return true; +} + +bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + DbpString("Authentication failed!"); + return false; + } + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + *txlen = 64; + memcpy(tx,NrAr,8); + bCrypto = true; + } else { + DbpString("Authentication succesful!"); + // We are done... for now + return false; + } + } break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + + return true; +} + +bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); + bCrypto = false; + if ((auth_table_pos+8) == auth_table_len) { + return false; + } + auth_table_pos += 8; + memcpy(NrAr,auth_table+auth_table_pos,8); + } + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, crypto tag answer, or read block response + case 32: { + if (!bCrypto) { + *txlen = 64; + memcpy(tx,NrAr,8); + bCrypto = true; + } else { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); + bCrypto = false; + if ((auth_table_pos+8) == auth_table_len) { + return false; + } + auth_table_pos += 8; + memcpy(NrAr,auth_table+auth_table_pos,8); + } + } break; + + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + + return true; +} + +void SnoopHitag(uint32_t type) { + int frame_count; + int response; + int overflow; + bool rising_edge; + bool reader_frame; + int lastbit; + bool bSkip; + int tag_sof; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + + // Clean up trace and prepare it for storing frames + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + + auth_table_len = 0; + auth_table_pos = 0; + memset(auth_table, 0x00, AUTH_TABLE_LENGTH); + + DbpString("Starting Hitag2 snoop"); + LED_D_ON(); + + // Set up eavesdropping mode, frequency divisor which will drive the FPGA + // and analog mux selection. + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + // Configure output pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + // Disable modulation, we are going to eavesdrop, not modulate ;) + LOW(GPIO_SSC_DOUT); + + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on rising edge of TIOA. + uint32_t t1_channel_mode = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; + AT91C_BASE_TC1->TC_CMR = t1_channel_mode; + + // Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Reset the received frame, frame count and timing info + memset(rx,0x00,sizeof(rx)); + frame_count = 0; + response = 0; + overflow = 0; + reader_frame = false; + lastbit = 1; + bSkip = true; + tag_sof = 4; + + while(!BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { + // Check if rising edge in modulation is detected + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA/T0); + + // Find out if we are dealing with a rising or falling edge + rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0; + + // Shorter periods will only happen with reader frames + if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { + // Switch from tag to reader capture + LED_C_OFF(); + reader_frame = true; + memset(rx,0x00,sizeof(rx)); + rxlen = 0; + } + + // Only handle if reader frame and rising edge, or tag frame and falling edge + if (reader_frame != rising_edge) { + overflow += ra; + continue; + } + + // Add the buffered timing values of earlier captured edges which were skipped + ra += overflow; + overflow = 0; + + if (reader_frame) { + LED_B_ON(); + // Capture reader frame + if(ra >= HITAG_T_STOP) { + if (rxlen != 0) { + //DbpString("wierd0?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + response = (ra - HITAG_T_LOW); + } else if(ra >= HITAG_T_1_MIN ) { + // '1' bit + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } else if(ra >= HITAG_T_0_MIN) { + // '0' bit + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + } else { + // Ignore wierd value, is to small to mean anything + } + } else { + LED_C_ON(); + // Capture tag frame (manchester decoding using only falling edges) + if(ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra-HITAG_T_TAG_HALF_PERIOD; + } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7-(rxlen%8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + } + } + + // Check if frame was captured + if(rxlen > 0) { + frame_count++; + if (!LogTrace(rx,nbytes(rxlen),response,0,reader_frame)) { + DbpString("Trace full"); + break; + } + + // Check if we recognize a valid authentication attempt + if (nbytes(rxlen) == 8) { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { + memcpy(auth_table+auth_table_len,rx,8); + auth_table_len += 8; + } + } + + // Reset the received frame and response timing info + memset(rx,0x00,sizeof(rx)); + response = 0; + reader_frame = false; + lastbit = 1; + bSkip = true; + tag_sof = 4; + overflow = 0; + + LED_B_OFF(); + LED_C_OFF(); + } else { + // Save the timer overflow, will be 0 when frame was received + overflow += (AT91C_BASE_TC1->TC_CV/T0); + } + // Reset the frame length + rxlen = 0; + // Reset the timer to restart while-loop that receives frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + } + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +// Dbprintf("frame received: %d",frame_count); +// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); +// DbpString("All done"); +} + +void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { + int frame_count; + int response; + int overflow; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + byte_t tx[HITAG_FRAME_LEN]; + size_t txlen=0; + bool bQuitTraceFull = false; + bQuiet = false; + + // Clean up trace and prepare it for storing frames + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + auth_table_len = 0; + auth_table_pos = 0; + memset(auth_table, 0x00, AUTH_TABLE_LENGTH); + + DbpString("Starting Hitag2 simulation"); + LED_D_ON(); + hitag2_init(); + + if (tag_mem_supplied) { + DbpString("Loading hitag2 memory..."); + memcpy((byte_t*)tag.sectors,data,48); + } + + uint32_t block = 0; + for (size_t i=0; i<12; i++) { + for (size_t j=0; j<4; j++) { + block <<= 8; + block |= tag.sectors[i][j]; + } + Dbprintf("| %d | %08x |",i,block); + } + + // Set up simulator mode, frequency divisor which will drive the FPGA + // and analog mux selection. + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + // Configure output pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + // Disable modulation at default, which means release resistance + LOW(GPIO_SSC_DOUT); + + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on rising edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; + + // Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Reset the received frame, frame count and timing info + memset(rx,0x00,sizeof(rx)); + frame_count = 0; + response = 0; + overflow = 0; + + while(!BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { + // Check if rising edge in modulation is detected + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; + overflow = 0; + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture reader frame + if(ra >= HITAG_T_STOP) { + if (rxlen != 0) { + //DbpString("wierd0?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + response = (ra - HITAG_T_LOW); + } else if(ra >= HITAG_T_1_MIN ) { + // '1' bit + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } else if(ra >= HITAG_T_0_MIN) { + // '0' bit + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + } else { + // Ignore wierd value, is to small to mean anything + } + } + } + + // Check if frame was captured + if(rxlen > 4) { + frame_count++; + if (!bQuiet) { + if (!LogTrace(rx,nbytes(rxlen),response,0,true)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + + // Disable timer 1 with external trigger to avoid triggers during our own modulation + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Process the incoming frame (rx) and prepare the outgoing frame (tx) + hitag2_handle_reader_command(rx,rxlen,tx,&txlen); + + // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, + // not that since the clock counts since the rising edge, but T_Wait1 is + // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) + // periods. The gap time T_Low varies (4..10). All timer values are in + // terms of T0 units + while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); + + // Send and store the tag answer (if there is any) + if (txlen) { + // Transmit the tag frame + hitag_send_frame(tx,txlen); + // Store the frame in the trace + if (!bQuiet) { + if (!LogTrace(tx,nbytes(txlen),0,0,false)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + // Reset the received frame and response timing info + memset(rx,0x00,sizeof(rx)); + response = 0; + + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + LED_B_OFF(); + } + // Reset the frame length + rxlen = 0; + // Save the timer overflow, will be 0 when frame was received + overflow += (AT91C_BASE_TC1->TC_CV/T0); + // Reset the timer to restart while-loop that receives frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + } + LED_B_OFF(); + LED_D_OFF(); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +// Dbprintf("frame received: %d",frame_count); +// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); +// DbpString("All done"); +} + +void ReaderHitag(hitag_function htf, hitag_data* htd) { + int frame_count; + int response; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + byte_t txbuf[HITAG_FRAME_LEN]; + byte_t* tx = txbuf; + size_t txlen=0; + int lastbit; + bool bSkip; + int reset_sof; + int tag_sof; + int t_wait = HITAG_T_WAIT_MAX; + bool bStop; + bool bQuitTraceFull = false; + + // Clean up trace and prepare it for storing frames + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + DbpString("Starting Hitag reader family"); + + // Check configuration + switch(htf) { + case RHT2F_PASSWORD: { + Dbprintf("List identifier in password mode"); + memcpy(password,htd->pwd.password,4); + bQuitTraceFull = false; + bQuiet = false; + bPwd = false; + } break; + case RHT2F_AUTHENTICATE: { + DbpString("Authenticating in crypto mode"); + memcpy(NrAr,htd->auth.NrAr,8); + Dbprintf("Reader-challenge:"); + Dbhexdump(8,NrAr,false); + bQuiet = false; + bCrypto = false; + bQuitTraceFull = true; + } break; + + case RHT2F_TEST_AUTH_ATTEMPTS: { + Dbprintf("Testing %d authentication attempts",(auth_table_len/8)); + auth_table_pos = 0; + memcpy(NrAr,auth_table,8); + bQuitTraceFull = false; + bQuiet = false; + bCrypto = false; + } break; + + default: { + Dbprintf("Error, unknown function: %d",htf); + return; + } break; + } + + LED_D_ON(); + hitag2_init(); + + // Configure output and enable pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + // Set fpga in edge detect with reader field, we can modulate as reader now + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + + // Set Frequency divisor which will drive the FPGA and analog mux selection + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(30); + + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on falling edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + + // Enable and reset counters + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Reset the received frame, frame count and timing info + frame_count = 0; + response = 0; + lastbit = 1; + bStop = false; + + // Tag specific configuration settings (sof, timings, etc.) + if (htf < 10){ + // hitagS settings + reset_sof = 1; + t_wait = 200; + DbpString("Configured for hitagS reader"); + } else if (htf < 20) { + // hitag1 settings + reset_sof = 1; + t_wait = 200; + DbpString("Configured for hitag1 reader"); + } else if (htf < 30) { + // hitag2 settings + reset_sof = 4; + t_wait = HITAG_T_WAIT_2; + DbpString("Configured for hitag2 reader"); + } else { + Dbprintf("Error, unknown hitag reader type: %d",htf); + return; + } + + while(!bStop && !BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Check if frame was captured and store it + if(rxlen > 0) { + frame_count++; + if (!bQuiet) { + if (!LogTrace(rx,nbytes(rxlen),response,0,false)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + // By default reset the transmission buffer + tx = txbuf; + switch(htf) { + case RHT2F_PASSWORD: { + bStop = !hitag2_password(rx,rxlen,tx,&txlen); + } break; + case RHT2F_AUTHENTICATE: { + bStop = !hitag2_authenticate(rx,rxlen,tx,&txlen); + } break; + case RHT2F_TEST_AUTH_ATTEMPTS: { + bStop = !hitag2_test_auth_attempts(rx,rxlen,tx,&txlen); + } break; + default: { + Dbprintf("Error, unknown function: %d",htf); + return; + } break; + } + + // Send and store the reader command + // Disable timer 1 with external trigger to avoid triggers during our own modulation + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, + // Since the clock counts since the last falling edge, a 'one' means that the + // falling edge occured halfway the period. with respect to this falling edge, + // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. + // All timer values are in terms of T0 units + while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + + // Transmit the reader frame + hitag_reader_send_frame(tx,txlen); + + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Add transmitted frame to total count + if(txlen > 0) { + frame_count++; + if (!bQuiet) { + // Store the frame in the trace + if (!LogTrace(tx,nbytes(txlen),HITAG_T_WAIT_2,0,true)) { + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + // Reset values for receiving frames + memset(rx,0x00,sizeof(rx)); + rxlen = 0; + lastbit = 1; + bSkip = true; + tag_sof = reset_sof; + response = 0; + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { + // Check if falling edge in tag modulation is detected + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA/T0); + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture tag frame (manchester decoding using only falling edges) + if(ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra-HITAG_T_TAG_HALF_PERIOD; + } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7-(rxlen%8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7-(rxlen%8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7-(rxlen%8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) { + if (rxlen>0) break; + } + } + } + LED_B_OFF(); + LED_D_OFF(); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + +// Dbprintf("frame received: %d",frame_count); +// DbpString("All done"); +} diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h deleted file mode 100644 index 7606e2ce..00000000 --- a/armsrc/hitag2.h +++ /dev/null @@ -1,19 +0,0 @@ -//----------------------------------------------------------------------------- -// (c) 2009 Henryk Plötz -// -// 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. -//----------------------------------------------------------------------------- -// Hitag2 emulation public interface -//----------------------------------------------------------------------------- - -#ifndef __HITAG2_H -#define __HITAG2_H - -typedef int (*hitag2_response_callback_t)(const char* response_data, const int response_length, const int fdt, void *cb_cookie); - -extern int hitag2_init(void); -extern int hitag2_handle_command(const char* data, const int length, hitag2_response_callback_t cb, void *cb_cookie); - -#endif diff --git a/armsrc/iclass.c b/armsrc/iclass.c index ced29424..c673bb54 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -691,7 +691,7 @@ void RAMFUNC SnoopIClass(void) // reset traceLen to 0 iso14a_set_tracing(TRUE); - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_trigger(FALSE); // The DMA buffer, used to stream samples from the FPGA diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 530418e5..af7b3545 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -21,7 +21,7 @@ #include "mifareutil.h" static uint32_t iso14a_timeout; -uint8_t *trace = (uint8_t *) BigBuf; +uint8_t *trace = (uint8_t *) BigBuf+TRACE_OFFSET; int traceLen = 0; int rsamples = 0; int tracing = TRUE; @@ -68,12 +68,15 @@ void iso14a_set_trigger(int enable) { trigger = enable; } -void iso14a_clear_tracelen(void) { +void iso14a_clear_trace(void) { + memset(trace, 0x44, TRACE_SIZE); traceLen = 0; } + void iso14a_set_tracing(int enable) { tracing = enable; } + void iso14a_set_timeout(uint32_t timeout) { iso14a_timeout = timeout; } @@ -580,8 +583,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { LEDsoff(); // init trace buffer - traceLen = 0; - memset(trace, 0x44, TRACE_SIZE); + iso14a_clear_trace(); // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a @@ -905,8 +907,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) { // Enable and clear the trace tracing = TRUE; - traceLen = 0; - memset(trace, 0x44, TRACE_SIZE); + iso14a_clear_trace(); // This function contains the tag emulation uint8_t sak; @@ -2379,8 +2380,7 @@ void RAMFUNC SniffMifare(uint8_t param) { // C(red) A(yellow) B(green) LEDsoff(); // init trace buffer - traceLen = 0; - memset(trace, 0x44, TRACE_SIZE); + iso14a_clear_trace(); // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 47364451..b73ee014 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1102,7 +1102,7 @@ void ReaderIso15693(uint32_t parameter) Dbprintf("%d octets read from IDENTIFY request:", answerLen1); DbdecodeIso15693Answer(answerLen1,answer1); - Dbhexdump(answerLen1,answer1); + Dbhexdump(answerLen1,answer1,true); // UID is reverse if (answerLen1>=12) @@ -1113,11 +1113,11 @@ void ReaderIso15693(uint32_t parameter) Dbprintf("%d octets read from SELECT request:", answerLen2); DbdecodeIso15693Answer(answerLen2,answer2); - Dbhexdump(answerLen2,answer2); + Dbhexdump(answerLen2,answer2,true); Dbprintf("%d octets read from XXX request:", answerLen3); DbdecodeIso15693Answer(answerLen3,answer3); - Dbhexdump(answerLen3,answer3); + Dbhexdump(answerLen3,answer3,true); // read all pages @@ -1130,7 +1130,7 @@ void ReaderIso15693(uint32_t parameter) if (answerLen2>0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); DbdecodeIso15693Answer(answerLen2,answer2); - Dbhexdump(answerLen2,answer2); + Dbhexdump(answerLen2,answer2,true); if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr } i++; @@ -1264,7 +1264,7 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8 if (DEBUG) { Dbprintf("SEND"); - Dbhexdump(datalen,data); + Dbhexdump(datalen,data,true); } recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL)); @@ -1280,7 +1280,7 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8 if (DEBUG) { Dbprintf("RECV"); DbdecodeIso15693Answer(recvlen,recvbuf); - Dbhexdump(recvlen,recvbuf); + Dbhexdump(recvlen,recvbuf,true); } } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 5ef01dcf..1b5f220e 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -433,17 +433,17 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { int i; uint8_t *tab = (uint8_t *)BigBuf; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); - + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; - + #define SHORT_COIL() LOW(GPIO_SSC_DOUT) #define OPEN_COIL() HIGH(GPIO_SSC_DOUT) - + i = 0; for(;;) { while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { @@ -453,18 +453,18 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) } WDT_HIT(); } - + if (ledcontrol) LED_D_ON(); - + if(tab[i]) OPEN_COIL(); else SHORT_COIL(); - + if (ledcontrol) LED_D_OFF(); - + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { if(BUTTON_PRESS()) { DbpString("Stopped"); @@ -472,7 +472,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) } WDT_HIT(); } - + i++; if(i == period) { i = 0; @@ -484,197 +484,9 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) } } -/* Provides a framework for bidirectional LF tag communication - * Encoding is currently Hitag2, but the general idea can probably - * be transferred to other encodings. - * - * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME - * (PA15) a thresholded version of the signal from the ADC. Setting the - * ADC path to the low frequency peak detection signal, will enable a - * somewhat reasonable receiver for modulation on the carrier signal - * that is generated by the reader. The signal is low when the reader - * field is switched off, and high when the reader field is active. Due - * to the way that the signal looks like, mostly only the rising edge is - * useful, your mileage may vary. - * - * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also - * TIOA1, which can be used as the capture input for timer 1. This should - * make it possible to measure the exact edge-to-edge time, without processor - * intervention. - * - * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz) - * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz) - * - * The following defines are in carrier periods: - */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */ -#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */ - -static void hitag_handle_frame(int t0, int frame_len, char *frame); -//#define DEBUG_RA_VALUES 1 #define DEBUG_FRAME_CONTENTS 1 void SimulateTagLowFrequencyBidir(int divisor, int t0) { -#if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS - int i = 0; -#endif - char frame[10]; - int frame_pos=0; - - DbpString("Starting Hitag2 emulator, press button to end"); - hitag2_init(); - - /* Set up simulator mode, frequency divisor which will drive the FPGA - * and analog mux selection. - */ - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - /* Set up Timer 1: - * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising - * edge of TIOA. Assign PA15 to TIOA1 (peripheral B) - */ - - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | - AT91C_TC_ETRGEDG_RISING | - AT91C_TC_ABETRG | - AT91C_TC_LDRA_RISING | - AT91C_TC_LDRB_RISING; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | - AT91C_TC_SWTRG; - - /* calculate the new value for the carrier period in terms of TC1 values */ - t0 = t0/2; - - int overflow = 0; - while(!BUTTON_PRESS()) { - WDT_HIT(); - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - int ra = AT91C_BASE_TC1->TC_RA; - if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1; -#if DEBUG_RA_VALUES - if(ra > 255 || overflow) ra = 255; - ((char*)BigBuf)[i] = ra; - i = (i+1) % 8000; -#endif - - if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) { - /* Ignore */ - } else if(ra >= t0*HITAG_T_1_MIN ) { - /* '1' bit */ - if(frame_pos < 8*sizeof(frame)) { - frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) ); - frame_pos++; - } - } else if(ra >= t0*HITAG_T_0_MIN) { - /* '0' bit */ - if(frame_pos < 8*sizeof(frame)) { - frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) ); - frame_pos++; - } - } - - overflow = 0; - LED_D_ON(); - } else { - if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) { - /* Minor nuisance: In Capture mode, the timer can not be - * stopped by a Compare C. There's no way to stop the clock - * in software, so we'll just have to note the fact that an - * overflow happened and the next loaded timer value might - * have wrapped. Also, this marks the end of frame, and the - * still running counter can be used to determine the correct - * time for the start of the reply. - */ - overflow = 1; - - if(frame_pos > 0) { - /* Have a frame, do something with it */ -#if DEBUG_FRAME_CONTENTS - ((char*)BigBuf)[i++] = frame_pos; - memcpy( ((char*)BigBuf)+i, frame, 7); - i+=7; - i = i % sizeof(BigBuf); -#endif - hitag_handle_frame(t0, frame_pos, frame); - memset(frame, 0, sizeof(frame)); - } - frame_pos = 0; - - } - LED_D_OFF(); - } - } - DbpString("All done"); -} - -static void hitag_send_bit(int t0, int bit) { - if(bit == 1) { - /* Manchester: Loaded, then unloaded */ - LED_A_ON(); - SHORT_COIL(); - while(AT91C_BASE_TC1->TC_CV < t0*15); - OPEN_COIL(); - while(AT91C_BASE_TC1->TC_CV < t0*31); - LED_A_OFF(); - } else if(bit == 0) { - /* Manchester: Unloaded, then loaded */ - LED_B_ON(); - OPEN_COIL(); - while(AT91C_BASE_TC1->TC_CV < t0*15); - SHORT_COIL(); - while(AT91C_BASE_TC1->TC_CV < t0*31); - LED_B_OFF(); - } - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */ - -} -static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt) -{ - OPEN_COIL(); - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - - /* Wait for HITAG_T_WRESP carrier periods after the last reader bit, - * not that since the clock counts since the rising edge, but T_wresp is - * with respect to the falling edge, we need to wait actually (T_wresp - T_g) - * periods. The gap time T_g varies (4..10). - */ - while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8)); - - int saved_cmr = AT91C_BASE_TC1->TC_CMR; - AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */ - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */ - - int i; - for(i=0; i<5; i++) - hitag_send_bit(t0, 1); /* Start of frame */ - - for(i=0; iTC_CMR = saved_cmr; -} - -/* Callback structure to cleanly separate tag emulation code from the radio layer. */ -static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie) -{ - hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt); - return 0; -} -/* Frame length in bits, frame contents in MSBit first format */ -static void hitag_handle_frame(int t0, int frame_len, char *frame) -{ - hitag2_handle_command(frame, frame_len, hitag_cb, &t0); } // compose fc/8 fc/10 waveform diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index daecf541..f18b75a0 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -35,7 +35,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) pcs = &mpcs; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); // iso14a_set_tracing(false); iso14443a_setup(); @@ -115,7 +115,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) pcs = &mpcs; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); // iso14a_set_tracing(false); iso14443a_setup(); @@ -213,7 +213,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) pcs = &mpcs; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); // iso14a_set_tracing(false); iso14443a_setup(); @@ -311,7 +311,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) for (i = 0; i < NES_MAX_INFO + 1; i++) nvectorcount[i] = 11; // 11 - empty block; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_tracing(false); iso14443a_setup(); @@ -539,7 +539,7 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) MF_DBGLEVEL = MF_DBG_NONE; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(); @@ -641,7 +641,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai uint8_t uid[8]; // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_tracing(false); iso14443a_setup(); @@ -759,7 +759,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (workFlags & 0x08) { // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(); @@ -890,7 +890,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (workFlags & 0x08) { // clear trace - iso14a_clear_tracelen(); + iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(); diff --git a/common/usb.c b/common/usb.c index 3f30d97f..e1fc9b25 100644 --- a/common/usb.c +++ b/common/usb.c @@ -401,12 +401,15 @@ void UsbSendPacket(uint8_t *packet, int len) } AT91C_BASE_UDP->UDP_CSR[2] |= AT91C_UDP_TXPKTRDY; - while(!(AT91C_BASE_UDP->UDP_CSR[2] & AT91C_UDP_TXCOMP)) - ; + while(!(AT91C_BASE_UDP->UDP_CSR[2] & AT91C_UDP_TXCOMP)) { + WDT_HIT(); + } + AT91C_BASE_UDP->UDP_CSR[2] &= ~AT91C_UDP_TXCOMP; - while(AT91C_BASE_UDP->UDP_CSR[2] & AT91C_UDP_TXCOMP) - ; + while(AT91C_BASE_UDP->UDP_CSR[2] & AT91C_UDP_TXCOMP) { + WDT_HIT(); + } len -= thisTime; packet += thisTime; @@ -426,8 +429,9 @@ static void HandleRxdData(void) } AT91C_BASE_UDP->UDP_CSR[1] &= ~AT91C_UDP_RX_DATA_BK0; - while(AT91C_BASE_UDP->UDP_CSR[1] & AT91C_UDP_RX_DATA_BK0) - ; + while(AT91C_BASE_UDP->UDP_CSR[1] & AT91C_UDP_RX_DATA_BK0) { + WDT_HIT(); + } if(UsbSoFarCount >= 64) { UsbPacketReceived(UsbBuffer, UsbSoFarCount); @@ -444,14 +448,17 @@ static void HandleRxdData(void) } AT91C_BASE_UDP->UDP_CSR[1] &= ~AT91C_UDP_RX_DATA_BK1; - while(AT91C_BASE_UDP->UDP_CSR[1] & AT91C_UDP_RX_DATA_BK1) - ; - + while(AT91C_BASE_UDP->UDP_CSR[1] & AT91C_UDP_RX_DATA_BK1) { + WDT_HIT(); + } + if(UsbSoFarCount >= 64) { UsbPacketReceived(UsbBuffer, UsbSoFarCount); UsbSoFarCount = 0; } } + + WDT_HIT(); } void UsbStart(void) diff --git a/fpga/Makefile b/fpga/Makefile index d598c8de..8759c22c 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -6,7 +6,7 @@ clean: $(DELETE) fpga.map fpga.ngc fpga_ngdbuild.xrpt fpga.pcf fpga-placed_pad.csv fpga-placed.ptwx fpga.rbt xlnx_auto_0_xdb $(DELETE) fpga.bld fpga.mrp fpga.ngc_xst.xrpt fpga.ngm fpga-placed.ncd fpga-placed_pad.txt fpga-placed.unroutes fpga_summary.xml netlist.lst xst -fpga.ngc: fpga.v fpga.ucf xst.scr util.v lo_simulate.v lo_read.v lo_passthru.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v +fpga.ngc: fpga.v fpga.ucf xst.scr util.v lo_edge_detect.v lo_read.v lo_passthru.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v $(DELETE) fpga.ngc $(XILINX_TOOLS_PREFIX)xst -ifn xst.scr diff --git a/fpga/fpga.bit b/fpga/fpga.bit index 4e65514d..3ea1560d 100644 Binary files a/fpga/fpga.bit and b/fpga/fpga.bit differ diff --git a/fpga/fpga.v b/fpga/fpga.v index 4002945b..d2d84a32 100644 --- a/fpga/fpga.v +++ b/fpga/fpga.v @@ -14,7 +14,7 @@ `include "lo_read.v" `include "lo_passthru.v" -`include "lo_simulate.v" +`include "lo_edge_detect.v" `include "hi_read_tx.v" `include "hi_read_rx_xcorr.v" `include "hi_simulate.v" @@ -111,6 +111,10 @@ assign hi_read_rx_xcorr_quarter = conf_word[2]; wire [2:0] hi_simulate_mod_type; assign hi_simulate_mod_type = conf_word[2:0]; +// For the high-frequency simulated tag: what kind of modulation to use. +wire lf_field; +assign lf_field = conf_word[0]; + //----------------------------------------------------------------------------- // And then we instantiate the modules corresponding to each of the FPGA's // major modes, and use muxes to connect the outputs of the active mode to @@ -136,13 +140,14 @@ lo_passthru lp( lp_dbg, divisor ); -lo_simulate ls( +lo_edge_detect ls( pck0, ck_1356meg, ck_1356megb, ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4, adc_d, ls_adc_clk, ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk, cross_hi, cross_lo, - ls_dbg, divisor + ls_dbg, divisor, + lf_field ); hi_read_tx ht( diff --git a/fpga/lo_edge_detect.v b/fpga/lo_edge_detect.v new file mode 100644 index 00000000..8458ee69 --- /dev/null +++ b/fpga/lo_edge_detect.v @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// The way that we connect things in low-frequency simulation mode. In this +// case just pass everything through to the ARM, which can bit-bang this +// (because it is so slow). +// +// Jonathan Westhues, April 2006 +//----------------------------------------------------------------------------- + +module lo_edge_detect( + pck0, ck_1356meg, ck_1356megb, + pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, + adc_d, adc_clk, + ssp_frame, ssp_din, ssp_dout, ssp_clk, + cross_hi, cross_lo, + dbg, + divisor, + lf_field +); + input pck0, ck_1356meg, ck_1356megb; + output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; + input [7:0] adc_d; + output adc_clk; + input ssp_dout; + output ssp_frame, ssp_din, ssp_clk; + input cross_hi, cross_lo; + output dbg; + input [7:0] divisor; + input lf_field; + +// Divide the clock to be used for the ADC +reg [7:0] pck_divider; +reg clk_state; + +wire tag_modulation; +assign tag_modulation = ssp_dout & !lf_field; +wire reader_modulation; +assign reader_modulation = !ssp_dout & lf_field & clk_state; + +// No logic, straight through. +assign pwr_oe1 = 1'b0; // not used in LF mode +assign pwr_oe2 = tag_modulation; +assign pwr_oe3 = tag_modulation; +assign pwr_oe4 = tag_modulation; +assign ssp_clk = cross_lo; +assign pwr_lo = reader_modulation; +assign pwr_hi = 1'b0; +assign dbg = ssp_frame; + +always @(posedge pck0) +begin + if(pck_divider == divisor[7:0]) + begin + pck_divider <= 8'd0; + clk_state = !clk_state; + end + else + begin + pck_divider <= pck_divider + 1; + end +end + +assign adc_clk = ~clk_state; + +// Toggle the output with hysteresis +// Set to high if the ADC value is above 200 +// Set to low if the ADC value is below 64 +reg is_high; +reg is_low; +reg output_state; + +always @(posedge pck0) +begin + if((pck_divider == 8'd7) && !clk_state) begin + is_high = (adc_d >= 8'd190); + is_low = (adc_d <= 8'd70); + end +end + +always @(posedge is_high or posedge is_low) +begin + if(is_high) + output_state <= 1'd1; + else if(is_low) + output_state <= 1'd0; +end + +assign ssp_frame = output_state; + +endmodule + diff --git a/include/common.h b/include/common.h index fd1a6a56..cfce1b9f 100644 --- a/include/common.h +++ b/include/common.h @@ -13,6 +13,7 @@ #define __COMMON_H #include +typedef unsigned char byte_t; //----------------------------------------------------------------------------- // ISO 14443A diff --git a/include/hitag2.h b/include/hitag2.h new file mode 100644 index 00000000..3ed2b9fc --- /dev/null +++ b/include/hitag2.h @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// (c) 2012 Roel Verdult +// +// 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. +//----------------------------------------------------------------------------- +// Hitag2 type prototyping +//----------------------------------------------------------------------------- + +#ifndef _HITAG2_H_ +#define _HITAG2_H_ + +typedef enum { + RHT2F_PASSWORD = 21, + RHT2F_AUTHENTICATE = 22, + RHT2F_TEST_AUTH_ATTEMPTS = 25, +} hitag_function; + +typedef struct { + byte_t password[4]; +} PACKED rht2d_password; + +typedef struct { + byte_t NrAr[8]; +} PACKED rht2d_authenticate; + +typedef union { + rht2d_password pwd; + rht2d_authenticate auth; +} hitag_data; + +#endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index a209497f..a7552b3e 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -86,6 +86,12 @@ typedef struct { #define CMD_ISO_15693_COMMAND_DONE 0x0314 #define CMD_ISO_15693_FIND_AFI 0x0315 #define CMD_ISO_15693_DEBUG 0x0316 + +// For Hitag2 transponders +#define CMD_SNOOP_HITAG 0x0370 +#define CMD_SIMULATE_HITAG 0x0371 +#define CMD_READER_HITAG 0x0372 + #define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 #define CMD_SIMULATE_TAG_ISO_14443 0x0381 #define CMD_SNOOP_ISO_14443 0x0382