From: Iceman Date: Sat, 8 Oct 2016 17:18:14 +0000 (+0200) Subject: Merge pull request #119 from marshmellow42/pm3+reveng X-Git-Tag: v3.0.0~76 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/d1057e7a2105d5e2696df185482176f22a5bd669?hp=7f0d5926362d50ed01ea04af95a1e03777fce47c Merge pull request #119 from marshmellow42/pm3+reveng add reveng 1.30 source to PM3 for CRC calculations & searches --- diff --git a/.gitignore b/.gitignore index fa74326e..4af73fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ flasher version.c lua luac +fpga_compress fpga/* !fpga/tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 795564ae..4b09e461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] ### Added +- Added lf pyramid commands (iceman) +- Added lf presco commands - some bits not fully understood... (iceman) +- Added experimental HitagS support (Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg) + see https://media.ccc.de/v/32c3-7166-sicherheit_von_125khz_transpondern_am_beispiel_hitag_s + English video available +- Added a LF ASK Sequence Terminator detection option to the standard ask demod - and applied it to `lf search u`, `lf t55xx detect`, and `data rawdemod am s` (marshmellow) - `lf t55xx bruteforce [i <*.dic>]` - Simple bruteforce attack to find password - (iceman and others) - `lf viking clone`- clone viking tag to t55x7 or Q5 from 4byte hex ID input - `lf viking sim` - sim full viking tag from 4byte hex ID input @@ -12,8 +18,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `lf t55xx wipe` - sets t55xx back to factory defaults - Added viking demod to `lf search` (marshmellow) - `data askvikingdemod` demod viking id tag from graphbuffer (marshmellow) -- `lf t55xx resetread` added reset then read command - should allow determining start -of stream transmissions (marshmellow) +- `lf t55xx resetread` added reset then read command - should allow determining start of stream transmissions (marshmellow) - `lf t55xx wakeup` added wake with password (AOR) to allow lf search or standard lf read after (iceman, marshmellow) - `hf iclass managekeys` to save, load and manage iclass keys. (adjusted most commands to accept a loaded key in memory) (marshmellow) - `hf iclass readblk` to select, authenticate, and read 1 block from an iclass card (marshmellow) @@ -29,23 +34,32 @@ of stream transmissions (marshmellow) - Added 'hf snoop'. This command take digitalized signal from FPGA and put in BigBuffer. (pwpiwi + enio) - Added Topaz (NFC type 1) protocol support ('hf topaz reader', 'hf list topaz', 'hf 14a raw -T', 'hf topaz snoop'). (piwi) - Added option c to 'hf list' (mark CRC bytes) (piwi) +- Added option `l` or `h` to `hw tune` to save time and unnecessary fpga writes if you are only interested in lf or hf. ### Changed -- Added `[l] ` option to data printdemodbuffer -- Adjusted lf awid clone to optionally clone to Q5 tags -- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7 -- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal) -- Adjusted lf pskindalademod to reduce false positive reads. -- Small adjustments to psk, nrz, and ask clock detect routines - more reliable. -- Adjusted lf em410x em410xsim to accept a clock argument +- Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow) +- Fixed bug in lf viking clone/sim (iceman) +- Fixed broken `data askedgedetect` (marshmellow) +- Adjusted hf mf sim command (marshmellow) + added auto run mfkey32 to extract all keys + also added f parameter to allow attacking with UIDs from a file (implies x and i parameters) + also added e parameter to allow adding the extracted keys to emulator memory for the next simulation + added 10 byte uid option +- Added `[l] ` option to data printdemodbuffer (marshmellow) +- Adjusted lf awid clone to optionally clone to Q5 tags (marshmellow) +- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7 (marshmellow) +- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal) (marshmellow) +- Adjusted lf pskindalademod to reduce false positive reads. (marshmellow) +- Small adjustments to psk, nrz, and ask clock detect routines - more reliable. (marshmellow) +- Adjusted lf em410x em410xsim to accept a clock argument (marshmellow) - Adjusted lf t55xx dump to allow overriding the safety check and warning text (marshmellow) - Adjusted lf t55xx write input variables (marshmellow) - Adjusted lf t55xx read with password safety check and warning text and adjusted the input variables (marshmellow & iceman) -- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. +- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. (marshmellow) - Adjusted timings for t55xx commands. more reliable now. (marshmellow & iceman) - `lf cmdread` adjusted input methods and added help text (marshmellow & iceman) - changed `lf config t ` to be 0 - 128 and will trigger on + or - threshold value (marshmellow) -- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) +- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) (marshmellow) - Revised workflow for StandAloneMode14a (Craig Young) - EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers) - 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi) diff --git a/COMPILING.txt b/COMPILING.txt index 1cc34a0f..e5abb25f 100644 --- a/COMPILING.txt +++ b/COMPILING.txt @@ -86,19 +86,22 @@ Tested on OSX 10.10 Yosemite 1 - Install Xcode and Xcode Command Line Tools 2 - Install Homebrew and dependencies - brew install readline - brew instal libusb + brew install readline libusb p7zip libusb-compat wget qt5 pkgconfig -3 - Download DevKitARM for OSX - http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/ - Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory. +3 - Install DevKitARM for OSX + Option 1: + http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/ + Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory. + Option 2: + brew tap nitsky/stm32 + brew install arm-none-eabi-gcc -4 - Edit proxmark3/client/Makefile adding path to readline +4 - Edit proxmark3/client/Makefile adding path to readline and qt5 - LDLIBS = -L/usr/local/Cellar/readline/6.3.8/lib/ -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm - CFLAGS = -std=c99 -I/usr/local/Cellar/readline/6.3.8/include/ -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 + LDLIBS = -L/usr/local/opt/readline/lib -L/usr/local/opt/qt5/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm + CFLAGS = -std=c99 -I/usr/local/opt/qt5/include -I/usr/local/opt/readline/include -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 - Replace path /usr/local/Cellar/readline/6.3.8 with your actuall readline path. See homebrew manuals. + If your old brew intallation use /usr/local/Cellar/ path replace /usr/local/opt/readline/lib with your actuall readline and qt5 path. See homebrew manuals. 5 - Set Environment diff --git a/README.txt b/README.txt index 1a4ddb6d..295d5741 100644 --- a/README.txt +++ b/README.txt @@ -45,6 +45,9 @@ following locations: * http://proxmark3.com/ * http://www.xfpga.com/ + * http://radiowar.taobao.com/ + * http://www.elechouse.com/ + * https://lab401.com/ Most of the ultra-low-volume contract assemblers could put something like this together with a reasonable yield. A run of around diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index da3b0ce2..851cf390 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -61,6 +61,10 @@ void BigBuf_Clear_ext(bool verbose) Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE); } +void BigBuf_Clear_keep_EM(void) +{ + memset(BigBuf,0,BigBuf_hi); +} // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory // at the beginning of BigBuf is always for traces/samples diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 13432e7e..928c50c4 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -12,6 +12,8 @@ #ifndef __BIGBUF_H #define __BIGBUF_H +#include // for bool +#include "common.h" // for ramfunc #define BIGBUF_SIZE 40000 #define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame @@ -26,6 +28,7 @@ extern uint8_t *BigBuf_get_EM_addr(void); extern uint16_t BigBuf_max_traceLen(void); extern void BigBuf_Clear(void); extern void BigBuf_Clear_ext(bool verbose); +extern void BigBuf_Clear_keep_EM(void); extern uint8_t *BigBuf_malloc(uint16_t); extern void BigBuf_free(void); extern void BigBuf_free_keep_EM(void); diff --git a/armsrc/Makefile b/armsrc/Makefile index 69ea2300..0b540b84 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -15,7 +15,7 @@ APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO144 #-DWITH_LCD #SRC_LCD = fonts.c LCD.c -SRC_LF = lfops.c hitag2.c lfsampling.c pcf7931.c lfdemod.c protocols.c +SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443b.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 782c57fa..aaa41f4a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -23,6 +23,7 @@ #include "legicrf.h" #include +#include #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" @@ -36,8 +37,6 @@ #include "iso14443a.h" #endif -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - //============================================================================= // A buffer where we can queue things up to be sent through the FPGA, for // any purpose (fake tag, as reader, whatever). We go MSB first, since that @@ -181,13 +180,9 @@ int AvgAdc(int ch) // was static - merlok return (a + 15) >> 5; } -void MeasureAntennaTuning(void) +void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[]) { - uint8_t LF_Results[256]; - int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 - int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV - - LED_B_ON(); + int i, adcval = 0, peak = 0; /* * Sweeps the useful LF range of the proxmark from @@ -197,38 +192,67 @@ void MeasureAntennaTuning(void) * the resonating frequency of your LF antenna * ( hopefully around 95 if it is tuned to 125kHz!) */ - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); for (i=255; i>=19; i--) { - WDT_HIT(); + WDT_HIT(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); SpinDelay(20); adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); - if (i==95) vLf125 = adcval; // voltage at 125Khz - if (i==89) vLf134 = adcval; // voltage at 134Khz + if (i==95) *vLf125 = adcval; // voltage at 125Khz + if (i==89) *vLf134 = adcval; // voltage at 134Khz LF_Results[i] = adcval>>8; // scale int to fit in byte for graphing purposes if(LF_Results[i] > peak) { - peakv = adcval; + *peakv = adcval; peak = LF_Results[i]; - peakf = i; + *peakf = i; //ptr = i; } } for (i=18; i >= 0; i--) LF_Results[i] = 0; - - LED_A_ON(); + + return; +} + +void MeasureAntennaTuningHfOnly(int *vHf) +{ // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + LED_A_ON(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(20); - vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + *vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + LED_A_OFF(); + + return; +} + +void MeasureAntennaTuning(int mode) +{ + uint8_t LF_Results[256] = {0}; + int peakv = 0, peakf = 0; + int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV + + LED_B_ON(); + + if (((mode & FLAG_TUNE_ALL) == FLAG_TUNE_ALL) && (FpgaGetCurrent() == FPGA_BITSTREAM_HF)) { + // Reverse "standard" order if HF already loaded, to avoid unnecessary swap. + MeasureAntennaTuningHfOnly(&vHf); + MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results); + } else { + if (mode & FLAG_TUNE_LF) { + MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results); + } + if (mode & FLAG_TUNE_HF) { + MeasureAntennaTuningHfOnly(&vHf); + } + } cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125 | (vLf134<<16), vHf, peakf | (peakv<<16), LF_Results, 256); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); LED_B_OFF(); return; } @@ -841,7 +865,7 @@ void ListenReaderField(int limit) if (limit != HF_ONLY) { if(mode == 1) { - if (abs(lf_av - lf_baseline) > REPORT_CHANGE) + if (ABS(lf_av - lf_baseline) > REPORT_CHANGE) LED_D_ON(); else LED_D_OFF(); @@ -849,7 +873,7 @@ void ListenReaderField(int limit) lf_av_new = AvgAdc(ADC_CHAN_LF); // see if there's a significant change - if(abs(lf_av - lf_av_new) > REPORT_CHANGE) { + if(ABS(lf_av - lf_av_new) > REPORT_CHANGE) { Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10); lf_av = lf_av_new; if (lf_av > lf_max) @@ -859,7 +883,7 @@ void ListenReaderField(int limit) if (limit != LF_ONLY) { if (mode == 1){ - if (abs(hf_av - hf_baseline) > REPORT_CHANGE) + if (ABS(hf_av - hf_baseline) > REPORT_CHANGE) LED_B_ON(); else LED_B_OFF(); @@ -867,7 +891,7 @@ void ListenReaderField(int limit) hf_av_new = AvgAdc(ADC_CHAN_HF); // see if there's a significant change - if(abs(hf_av - hf_av_new) > REPORT_CHANGE) { + if(ABS(hf_av - hf_av_new) > REPORT_CHANGE) { Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10); hf_av = hf_av_new; if (hf_av > hf_max) @@ -1016,6 +1040,18 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); break; + case CMD_SIMULATE_HITAG_S:// Simulate Hitag s tag, args = memory content + SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes); + break; + case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file + check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes); + break; + case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge + ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); + break; + case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge + WritePageHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes,c->arg[2]); + break; #endif #ifdef WITH_ISO15693 @@ -1218,7 +1254,7 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_MEASURE_ANTENNA_TUNING: - MeasureAntennaTuning(); + MeasureAntennaTuning(c->arg[0]); break; case CMD_MEASURE_ANTENNA_TUNING_HF: diff --git a/armsrc/apps.h b/armsrc/apps.h index c8397c38..4d4c8083 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -16,6 +16,7 @@ #include #include "common.h" #include "hitag2.h" +#include "hitagS.h" #include "mifare.h" #include "../common/crc32.h" #include "BigBuf.h" @@ -179,6 +180,13 @@ void SnoopHitag(uint32_t type); void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); void ReaderHitag(hitag_function htf, hitag_data* htd); +//hitagS.h +void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); +void ReadHitagS(hitag_function htf, hitag_data* htd); +void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); +void check_challenges(bool file_given, byte_t* data); + + // cmd.h bool cmd_receive(UsbCommand* cmd); bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 308dda8c..e211c12f 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -566,3 +566,7 @@ void Fpga_print_status(void) else if(downloaded_bitstream == FPGA_BITSTREAM_LF) Dbprintf(" mode.............LF"); else Dbprintf(" mode.............%d", downloaded_bitstream); } + +int FpgaGetCurrent() { + return downloaded_bitstream; +} diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 38724cdb..7dfc5c12 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -18,6 +18,7 @@ void FpgaSetupSsc(void); void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, int len); void Fpga_print_status(); +int FpgaGetCurrent(); #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); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 508157de..46432d83 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -1148,7 +1148,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { case RHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,4); //HACK; 4 or 6?? I read both in the code. + memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. Dbhexdump(6,key,false); blocknr = 0; bQuiet = false; diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c new file mode 100644 index 00000000..58e09a45 --- /dev/null +++ b/armsrc/hitagS.c @@ -0,0 +1,2146 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// HitagS emulation (preliminary test version) +// +// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg +// +//----------------------------------------------------------------------------- +// Some code was copied from Hitag2.c +//----------------------------------------------------------------------------- + + +#include +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "hitagS.h" +#include "hitag2.h" +#include "string.h" +#include "BigBuf.h" + +#define CRC_PRESET 0xFF +#define CRC_POLYNOM 0x1D + +#define u8 uint8_t +#define u32 uint32_t +#define u64 uint64_t +#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) +#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) +#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) +#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) +#define bit(x,n) (((x)>>(n))&1) +#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) +#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) +#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) + +static bool bQuiet; +static bool bSuccessful; +static struct hitagS_tag tag; +static byte_t page_to_be_written = 0; +static int block_data_left = 0; +typedef enum modulation { + AC2K = 0, AC4K, MC4K, MC8K +} MOD; +static MOD m = AC2K; //used modulation +static uint32_t temp_uid; +static int temp2 = 0; +static int sof_bits; //number of start-of-frame bits +static byte_t pwdh0, pwdl0, pwdl1; //password bytes +static uint32_t rnd = 0x74124485; //randomnumber +static int test = 0; +size_t blocknr; +bool end=false; + +// Single bit Hitag2 functions: +#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) +#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) +#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) +#define uf20bs u32 + +static u32 f20(const u64 x) { + u32 i5; + + i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 + + ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2 + + ((ht2_f4b >> i4(x, 16, 20, 22, 25)) & 1) * 4 + + ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8 + + ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16; + + return (ht2_f5c >> i5) & 1; +} +static u64 hitag2_round(u64 *state) { + u64 x = *state; + + x = (x >> 1) + + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8) + ^ (x >> 16) ^ (x >> 22) ^ (x >> 23) ^ (x >> 26) ^ (x >> 30) + ^ (x >> 41) ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) + & 1) << 47); + + *state = x; + return f20(x); +} +static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) { + u32 i; + u64 x = ((key & 0xFFFF) << 32) + serial; + for (i = 0; i < 32; i++) { + x >>= 1; + x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; + } + return x; +} +static u32 hitag2_byte(u64 *x) { + u32 i, c; + + for (i = 0, c = 0; i < 8; i++) + c += (u32) hitag2_round(x) << (i ^ 7); + return c; +} + +// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) +// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz +// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) +// T0 = TIMER_CLOCK1 / 125000 = 192 +#define T0 192 + +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + +#define HITAG_FRAME_LEN 20 +#define HITAG_T_STOP 36 /* T_EOF should be > 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 + +#define DEBUG 0 + +/* + * Implementation of the crc8 calculation from Hitag S + * from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf + */ +void calc_crc(unsigned char * crc, unsigned char data, unsigned char Bitcount) { + *crc ^= data; // crc = crc (exor) data + do { + if (*crc & 0x80) // if (MSB-CRC == 1) + { + *crc <<= 1; // CRC = CRC Bit-shift left + *crc ^= CRC_POLYNOM; // CRC = CRC (exor) CRC_POLYNOM + } else { + *crc <<= 1; // CRC = CRC Bit-shift left + } + } while (--Bitcount); +} + +static void hitag_send_bit(int bit) { + LED_A_ON(); + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + switch (m) { + case AC2K: + if (bit == 0) { + // AC Coding --__ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) + ; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 48) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) + ;; + } + LED_A_OFF(); + break; + case AC4K: + if (bit == 0) { + // AC Coding --__ + 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) + ; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 24) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ;; + } + LED_A_OFF(); + break; + case MC4K: + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + } + LED_A_OFF(); + break; + case MC8K: + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + } + LED_A_OFF(); + break; + default: + break; + } +} + +static void hitag_send_frame(const byte_t* frame, size_t frame_len) { +// Send start of frame + + for (size_t i = 0; i < sof_bits; i++) { + hitag_send_bit(1); + } + +// Send the content of the frame + for (size_t i = 0; i < frame_len; i++) { + hitag_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); + } +// Drop the modulation + LOW(GPIO_SSC_DOUT); +} + +static void hitag_reader_send_bit(int bit) { +//Dbprintf("BIT: %d",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); + if (test == 1) { + // 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 * 11) + ; + // SpinDelayUs(16*8); + } else { + // One bit: |_--| + while (AT91C_BASE_TC0->TC_CV < T0 * 14) + ; + // SpinDelayUs(22*8); + } + } else { + // 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 < frame_len; i++) { + if (frame[0] == 0xf8) { + //Dbprintf("BIT: %d",(frame[i / 8] >> (7 - (i % 8))) & 1); + } + hitag_reader_send_bit((frame[i / 8] >> (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); +} + +/* + * to check if the right uid was selected + */ +static int check_select(byte_t* rx, uint32_t uid) { + unsigned char resp[48]; + int i; + uint32_t ans = 0x0; + for (i = 0; i < 48; i++) + resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1; + for (i = 0; i < 32; i++) + ans += resp[5 + i] << (31 - i); + /*if (rx[0] == 0x01 && rx[1] == 0x15 && rx[2] == 0xc1 && rx[3] == 0x14 + && rx[4] == 0x65 && rx[5] == 0x38) + Dbprintf("got uid %X", ans);*/ + temp_uid = ans; + if (ans == tag.uid) + return 1; + return 0; +} + +/* + * handles all commands from a reader + */ +static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, + byte_t* tx, size_t* txlen) { + byte_t rx_air[HITAG_FRAME_LEN]; + byte_t page; + int i; + u64 state; + unsigned char crc; + +// Copy the (original) received frame how it is send over the air + memcpy(rx_air, rx, nbytes(rxlen)); +// Reset the transmission frame length + *txlen = 0; +// Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + case 5: { + //UID request with a selected response protocol mode + tag.pstate = READY; + tag.tstate = NO_OP; + if ((rx[0] & 0xf0) == 0x30) { + tag.mode = STANDARD; + sof_bits = 1; + m = AC2K; + } + if ((rx[0] & 0xf0) == 0xc0) { + tag.mode = ADVANCED; + sof_bits = 3; + m = AC2K; + } + + if ((rx[0] & 0xf0) == 0xd0) { + tag.mode = FAST_ADVANCED; + sof_bits = 3; + m = AC4K; + } + //send uid as a response + *txlen = 32; + for (i = 0; i < 4; i++) + tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff; + } + break; + case 45: { + //select command from reader received + if (check_select(rx, tag.uid) == 1) { + //if the right tag was selected + *txlen = 32; + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + + //send configuration + for (i = 0; i < 4; i++) + tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; + tx[3] = 0xff; + if (tag.mode != STANDARD) { + *txlen = 40; + crc = CRC_PRESET; + for (i = 0; i < 4; i++) + calc_crc(&crc, tx[i], 8); + tx[4] = crc; + } + } + } + break; + case 64: { + //challenge message received + Dbprintf("Challenge for UID: %X", temp_uid); + temp2++; + *txlen = 32; + state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]), + rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); + Dbprintf( + ",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", + rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + + for (i = 0; i < 4; i++) + hitag2_byte(&state); + //send con2,pwdh0,pwdl0,pwdl1 encrypted as a response + tx[0] = hitag2_byte(&state) ^ ((tag.pages[0][1] >> 16) & 0xff); + tx[1] = hitag2_byte(&state) ^ tag.pwdh0; + tx[2] = hitag2_byte(&state) ^ tag.pwdl0; + tx[3] = hitag2_byte(&state) ^ tag.pwdl1; + if (tag.mode != STANDARD) { + //add crc8 + *txlen = 40; + crc = CRC_PRESET; + calc_crc(&crc, ((tag.pages[0][1] >> 16) & 0xff), 8); + calc_crc(&crc, tag.pwdh0, 8); + calc_crc(&crc, tag.pwdl0, 8); + calc_crc(&crc, tag.pwdl1, 8); + tx[4] = (crc ^ hitag2_byte(&state)); + } + /* + * some readers do not allow to authenticate multiple times in a row with the same tag. + * use this to change the uid between authentications. + */ + + /* + if (temp2 % 2 == 0) { + tag.uid = 0x11223344; + tag.pages[0][0] = 0x44332211; + } else { + tag.uid = 0x55667788; + tag.pages[0][0] = 0x88776655; + } + */ + } + case 40: + //data received to be written + if (tag.tstate == WRITING_PAGE_DATA) { + tag.tstate = NO_OP; + tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] + << 0) + (rx[1] << 8) + (rx[2] << 16) + (rx[3] << 24); + //send ack + *txlen = 2; + tx[0] = 0x40; + page_to_be_written = 0; + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + } else if (tag.tstate == WRITING_BLOCK_DATA) { + tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] + << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; + //send ack + *txlen = 2; + tx[0] = 0x40; + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + page_to_be_written++; + block_data_left--; + if (block_data_left == 0) { + tag.tstate = NO_OP; + page_to_be_written = 0; + } + } + break; + case 20: { + //write page, write block, read page or read block command received + if ((rx[0] & 0xf0) == 0xc0) //read page + { + //send page data + page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + *txlen = 32; + tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; + tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; + tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; + tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + if (tag.LKP && page == 1) + tx[3] = 0xff; + + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + + if (tag.mode != STANDARD) { + //add crc8 + *txlen = 40; + crc = CRC_PRESET; + for (i = 0; i < 4; i++) + calc_crc(&crc, tx[i], 8); + tx[4] = crc; + } + + if (tag.LKP && (page == 2 || page == 3)) { + //if reader asks for key or password and the LKP-mark is set do not respond + sof_bits = 0; + *txlen = 0; + } + } else if ((rx[0] & 0xf0) == 0xd0) //read block + { + page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + *txlen = 32 * 4; + //send page,...,page+3 data + for (i = 0; i < 4; i++) { + tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; + tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; + tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; + tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + page++; + } + + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + + if (tag.mode != STANDARD) { + //add crc8 + *txlen = 32 * 4 + 8; + crc = CRC_PRESET; + for (i = 0; i < 16; i++) + calc_crc(&crc, tx[i], 8); + tx[16] = crc; + } + + if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) { + sof_bits = 0; + *txlen = 0; + } + } else if ((rx[0] & 0xf0) == 0x80) //write page + { + page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + if ((tag.LCON && page == 1) + || (tag.LKP && (page == 2 || page == 3))) { + //deny + *txlen = 0; + } else { + //allow + *txlen = 2; + tx[0] = 0x40; + page_to_be_written = page; + tag.tstate = WRITING_PAGE_DATA; + } + + } else if ((rx[0] & 0xf0) == 0x90) //write block + { + page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); + switch (tag.mode) { + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + if (page % 4 != 0 || page == 0) { + //deny + *txlen = 0; + } else { + //allow + *txlen = 2; + tx[0] = 0x40; + page_to_be_written = page; + block_data_left = 4; + tag.tstate = WRITING_BLOCK_DATA; + } + } + } + break; + default: + + break; + } +} + +/* + * to autenticate to a tag with the given key or challenge + */ +static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, const size_t rxlen, byte_t* tx, + size_t* txlen) { + byte_t rx_air[HITAG_FRAME_LEN]; + int response_bit[200]; + int i, j, z, k; + unsigned char mask = 1; + unsigned char uid[32]; + byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00; + unsigned char crc; + u64 state; + byte_t auth_ks[4]; + byte_t conf_pages[3]; + memcpy(rx_air, rx, nbytes(rxlen)); + *txlen = 0; + + if (tag.pstate == READY && rxlen >= 67) { + //received uid + if(end==true) { + Dbprintf("authentication failed!"); + return -1; + } + z = 0; + for (i = 0; i < 10; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + k = 0; + for (i = 5; i < z; i += 2) { + uid[k] = response_bit[i]; + k++; + if (k > 31) + break; + } + uid1 = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4) + | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7]; + uid2 = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | (uid[11] << 4) + | (uid[12] << 3) | (uid[13] << 2) | (uid[14] << 1) | uid[15]; + uid3 = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | (uid[19] << 4) + | (uid[20] << 3) | (uid[21] << 2) | (uid[22] << 1) | uid[23]; + uid4 = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) | (uid[27] << 4) + | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; + if (DEBUG) + Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); + tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); + + //select uid + *txlen = 45; + crc = CRC_PRESET; + calc_crc(&crc, 0x00, 5); + calc_crc(&crc, uid1, 8); + calc_crc(&crc, uid2, 8); + calc_crc(&crc, uid3, 8); + calc_crc(&crc, uid4, 8); + for (i = 0; i < 100; i++) { + response_bit[i] = 0; + } + for (i = 0; i < 5; i++) { + response_bit[i] = 0; + } + for (i = 5; i < 37; i++) { + response_bit[i] = uid[i - 5]; + } + for (j = 0; j < 8; j++) { + response_bit[i] = 0; + if ((crc & ((mask << 7) >> j)) != 0) + response_bit[i] = 1; + i++; + } + k = 0; + for (i = 0; i < 6; i++) { + tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) + | (response_bit[k + 2] << 5) | (response_bit[k + 3] << 4) + | (response_bit[k + 4] << 3) | (response_bit[k + 5] << 2) + | (response_bit[k + 6] << 1) | response_bit[k + 7]; + k += 8; + } + tag.pstate = INIT; + } else if (tag.pstate == INIT && rxlen == 44) { + // received configuration after select command + z = 0; + for (i = 0; i < 6; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6) + | (response_bit[6] << 5) | (response_bit[7] << 4) + | (response_bit[8] << 3) | (response_bit[9] << 2) + | (response_bit[10] << 1) | response_bit[11]); + //check wich memorysize this tag has + if (response_bit[10] == 0 && response_bit[11] == 0) + tag.max_page = 32 / 32; + if (response_bit[10] == 0 && response_bit[11] == 1) + tag.max_page = 256 / 32; + if (response_bit[10] == 1 && response_bit[11] == 0) + tag.max_page = 2048 / 32; + conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6) + | (response_bit[14] << 5) | (response_bit[15] << 4) + | (response_bit[16] << 3) | (response_bit[17] << 2) + | (response_bit[18] << 1) | response_bit[19]); + tag.auth = response_bit[12]; + tag.TTFC = response_bit[13]; + //tag.TTFDR in response_bit[14] and response_bit[15] + //tag.TTFM in response_bit[16] and response_bit[17] + tag.LCON = response_bit[18]; + tag.LKP = response_bit[19]; + conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6) + | (response_bit[22] << 5) | (response_bit[23] << 4) + | (response_bit[24] << 3) | (response_bit[25] << 2) + | (response_bit[26] << 1) | response_bit[27]); + tag.LCK7 = response_bit[20]; + tag.LCK6 = response_bit[21]; + tag.LCK5 = response_bit[22]; + tag.LCK4 = response_bit[23]; + tag.LCK3 = response_bit[24]; + tag.LCK2 = response_bit[25]; + tag.LCK1 = response_bit[26]; + tag.LCK0 = response_bit[27]; + + if (DEBUG) + Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], + conf_pages[1], conf_pages[2]); + if (tag.auth == 1) { + //if the tag is in authentication mode try the key or challenge + *txlen = 64; + if(end!=true){ + if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY + state = hitag2_init(rev64(key), rev32(tag.uid), + rev32(rnd)); + + for (i = 0; i < 4; i++) { + auth_ks[i] = hitag2_byte(&state) ^ 0xff; + } + *txlen = 64; + tx[0] = rnd & 0xff; + tx[1] = (rnd >> 8) & 0xff; + tx[2] = (rnd >> 16) & 0xff; + tx[3] = (rnd >> 24) & 0xff; + + tx[4] = auth_ks[0]; + tx[5] = auth_ks[1]; + tx[6] = auth_ks[2]; + tx[7] = auth_ks[3]; + if (DEBUG) + Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0], + tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]); + } else if(htf==01 || htf==03) { //RHTS_CHALLENGE //WHTS_CHALLENGE + for (i = 0; i < 8; i++) + tx[i]=((NrAr>>(56-(i*8)))&0xff); + } + end=true; + tag.pstate = AUTHENTICATE; + } else { + Dbprintf("authentication failed!"); + return -1; + } + } else if (tag.auth == 0) { + tag.pstate = SELECTED; + } + + } else if (tag.pstate == AUTHENTICATE && rxlen == 44) { + //encrypted con2,password received. + crc = CRC_PRESET; + calc_crc(&crc, 0x80, 1); + calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); + if (DEBUG) { + Dbprintf("UID:::%X", tag.uid); + Dbprintf("RND:::%X", rnd); + } + + //decrypt password + pwdh0=0; + pwdl0=0; + pwdl1=0; + if(htf==02 || htf==04){ //RHTS_KEY //WHTS_KEY + { + state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); + for (i = 0; i < 5; i++) + hitag2_byte(&state); + pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) + ^ hitag2_byte(&state); + pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) + ^ hitag2_byte(&state); + pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) + ^ hitag2_byte(&state); + } + + if (DEBUG) + Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); + + + //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); + //rnd += 1; + } + tag.pstate = SELECTED; //tag is now ready for read/write commands + } + return 0; + +} + +/* + * Emulates a Hitag S Tag with the given data from the .hts file + */ +void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { + int frame_count; + int response; + int overflow; + int i, j; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; +//bool bQuitTraceFull = false; + bQuiet = false; + byte_t txbuf[HITAG_FRAME_LEN]; + byte_t* tx = txbuf; + size_t txlen = 0; + BigBuf_free(); + +// Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + + DbpString("Starting HitagS simulation"); + LED_D_ON(); + + tag.pstate = READY; + tag.tstate = NO_OP; + for (i = 0; i < 16; i++) + for (j = 0; j < 4; j++) + tag.pages[i][j] = 0x0; + //read tag data into memory + if (tag_mem_supplied) { + DbpString("Loading hitagS memory..."); + memcpy((byte_t*)tag.pages,data,4*64); + } + tag.uid=(uint32_t)tag.pages[0]; + Dbprintf("Hitag S simulation started"); + tag.key=(intptr_t)tag.pages[3]; + tag.key<<=16; + tag.key+=((tag.pages[2][0])<<8)+tag.pages[2][1]; + tag.pwdl0=tag.pages[2][3]; + tag.pwdl1=tag.pages[2][2]; + tag.pwdh0=tag.pages[1][0]; + //con0 + tag.max_page=64; + if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==1) + tag.max_page=8; + if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==0) + tag.max_page=0; + //con1 + tag.auth=0; + if((tag.pages[1][2]&0x80)==1) + tag.auth=1; + tag.LCON=0; + if((tag.pages[1][2]&0x2)==1) + tag.LCON=1; + tag.LKP=0; + if((tag.pages[1][2]&0x1)==1) + tag.LKP=1; + //con2 + //0=read write 1=read only + tag.LCK7=0; + if((tag.pages[1][1]&0x80)==1) + tag.LCK7=1; + tag.LCK6=0; + if((tag.pages[1][1]&0x40)==1) + tag.LCK6=1; + tag.LCK5=0; + if((tag.pages[1][1]&0x20)==1) + tag.LCK5=1; + tag.LCK4=0; + if((tag.pages[1][1]&0x10)==1) + tag.LCK4=1; + tag.LCK3=0; + if((tag.pages[1][1]&0x8)==1) + tag.LCK3=1; + tag.LCK2=0; + if((tag.pages[1][1]&0x4)==1) + tag.LCK2=1; + tag.LCK1=0; + if((tag.pages[1][1]&0x2)==1) + tag.LCK1=1; + tag.LCK0=0; + if((tag.pages[1][1]&0x1)==1) + tag.LCK0=1; + +// Set up simulator mode, frequency divisor which will drive the FPGA +// and analog mux selection. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + 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, default 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; + +// Reset the received frame, frame count and timing info + memset(rx, 0x00, sizeof(rx)); + frame_count = 0; + response = 0; + overflow = 0; + +// Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + 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 > 0) { + frame_count++; + if (!bQuiet) { + if (!LogTraceHitag(rx, rxlen, response, 0, true)) { + DbpString("Trace full"); + clear_trace(); + } + } + + // 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) + hitagS_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 > 0) { + // Transmit the tag frame + hitag_send_frame(tx, txlen); + // Store the frame in the trace + if (!bQuiet) { + if (!LogTraceHitag(tx, txlen, 0, 0, false)) { + DbpString("Trace full"); + clear_trace(); + } + } + } + + // 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); +} + +/* + * Authenticates to the Tag with the given key or challenge. + * If the key was given the password will be decrypted. + * Reads every page of a hitag S transpoder. + */ +void ReadHitagS(hitag_function htf, hitag_data* htd) { + int i, j, z, k; + int frame_count; + int response_bit[200]; + 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; + int sendNum = 0; + unsigned char mask = 1; + unsigned char crc; + unsigned char pageData[32]; + page_to_be_written = 0; + + //read given key/challenge + byte_t NrAr_[8]; + uint64_t key=0; + uint64_t NrAr=0; + byte_t key_[6]; + switch(htf) { + case 01: { //RHTS_CHALLENGE + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr_,htd->auth.NrAr,8); + Dbhexdump(8,NrAr_,false); + NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | + ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; + } break; + case 02: { //RHTS_KEY + DbpString("Authenticating using key:"); + memcpy(key_,htd->crypto.key,6); + Dbhexdump(6,key_,false); + key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; + } break; + default: { + Dbprintf("Error , unknown function: %d",htf); + return; + } break; + } + + + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); +// Reset the return status + bSuccessful = false; + +// Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + + bQuiet = false; + bQuitTraceFull = true; + + LED_D_ON(); + +// 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; + + reset_sof = 1; + t_wait = 200; + + while (!bStop && !BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Check if frame was captured and store it + if (rxlen > 0) { + frame_count++; + if (!bQuiet) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + // By default reset the transmission buffer + tx = txbuf; + txlen = 0; + + if (rxlen == 0) { + //start authentication + txlen = 5; + memcpy(tx, "\xc0", nbytes(txlen)); + tag.pstate = READY; + tag.tstate = NO_OP; + } else if (tag.pstate != SELECTED) { + if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1) + bStop = !false; + } + if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) { + //send read request + tag.tstate = READING_PAGE; + txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + (sendNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); + tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE + && rxlen > 0) { + //save received data + z = 0; + for (i = 0; i < 5; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + k = 0; + for (i = 4; i < 36; i++) { + pageData[k] = response_bit[i]; + k++; + } + for (i = 0; i < 4; i++) + tag.pages[sendNum / 4][sendNum % 4] = 0x0; + for (i = 0; i < 4; i++) { + tag.pages[sendNum / 4][sendNum % 4] += ((pageData[i * 8] << 7) + | (pageData[1 + (i * 8)] << 6) + | (pageData[2 + (i * 8)] << 5) + | (pageData[3 + (i * 8)] << 4) + | (pageData[4 + (i * 8)] << 3) + | (pageData[5 + (i * 8)] << 2) + | (pageData[6 + (i * 8)] << 1) | pageData[7 + (i * 8)]) + << (i * 8); + } + if (tag.auth && tag.LKP && sendNum == 1) { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, + (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, + tag.pages[sendNum / 4][sendNum % 4] & 0xff); + } else { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, + (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, + tag.pages[sendNum / 4][sendNum % 4] & 0xff); + } + + sendNum++; + //display key and password if possible + if (sendNum == 2 && tag.auth == 1 && tag.LKP) { + if (htf == 02) { //RHTS_KEY + Dbprintf("Page[ 2]: %02X %02X %02X %02X", + (byte_t)(key >> 8) & 0xff, + (byte_t) key & 0xff, pwdl1, pwdl0); + Dbprintf("Page[ 3]: %02X %02X %02X %02X", + (byte_t)(key >> 40) & 0xff, + (byte_t)(key >> 32) & 0xff, + (byte_t)(key >> 24) & 0xff, + (byte_t)(key >> 16) & 0xff); + } else { + //if the authentication is done with a challenge the key and password are unknown + Dbprintf("Page[ 2]: __ __ __ __"); + Dbprintf("Page[ 3]: __ __ __ __"); + } + } + + txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + (sendNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); + tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + if (sendNum >= tag.max_page) { + bStop = !false; + } + } + + // 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 (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { + if (bQuitTraceFull) { + DbpString("Trace full"); + 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; + } + } + } + end=false; + 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); + cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); +} + +/* + * Authenticates to the Tag with the given Key or Challenge. + * Writes the given 32Bit data into page_ + */ +void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { + 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; + int page = page_; + unsigned char crc; + byte_t data[4]= {0,0,0,0}; + + //read given key/challenge, the page and the data + byte_t NrAr_[8]; + uint64_t key=0; + uint64_t NrAr=0; + byte_t key_[6]; + switch(htf) { + case 03: { //WHTS_CHALLENGE + memcpy(data,htd->auth.data,4); + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr_,htd->auth.NrAr,8); + Dbhexdump(8,NrAr_,false); + NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | + ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; + } break; + case 04: { //WHTS_KEY + memcpy(data,htd->crypto.data,4); + DbpString("Authenticating using key:"); + memcpy(key_,htd->crypto.key,6); + Dbhexdump(6,key_,false); + key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; + } break; + default: { + Dbprintf("Error , unknown function: %d",htf); + return; + } break; + } + + Dbprintf("Page: %d",page_); + Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); +// Reset the return status + bSuccessful = false; + + tag.pstate = READY; + tag.tstate = NO_OP; + +// Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + + bQuiet = false; + bQuitTraceFull = true; + + LED_D_ON(); + +// 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; + + reset_sof = 1; + t_wait = 200; + + while (!bStop && !BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Check if frame was captured and store it + if (rxlen > 0) { + frame_count++; + if (!bQuiet) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + //check for valid input + if (page == 0) { + Dbprintf( + "usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); + bStop = !false; + } + + // By default reset the transmission buffer + tx = txbuf; + txlen = 0; + + if (rxlen == 0 && tag.tstate == WRITING_PAGE_ACK) { + //no write access on this page + Dbprintf("no write access on page %d", page_); + bStop = !false; + } else if (rxlen == 0 && tag.tstate != WRITING_PAGE_DATA) { + //start the authetication + txlen = 5; + memcpy(tx, "\xc0", nbytes(txlen)); + tag.pstate = READY; + tag.tstate = NO_OP; + } else if (tag.pstate != SELECTED) { + //try to authenticate with the given key or challenge + if (hitagS_handle_tag_auth(htf,key,NrAr,rx, rxlen, tx, &txlen) == -1) + bStop = !false; + } + if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) { + //check if the given page exists + if (page > tag.max_page) { + Dbprintf("page number too big"); + bStop = !false; + } + //ask Tag for write permission + tag.tstate = WRITING_PAGE_ACK; + txlen = 20; + crc = CRC_PRESET; + tx[0] = 0x90 + (page / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((page % 16) * 16), 4); + tx[1] = 0x00 + ((page % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_ACK + && rxlen == 6 && rx[0] == 0xf4) { + //ACK recieved to write the page. send data + tag.tstate = WRITING_PAGE_DATA; + txlen = 40; + crc = CRC_PRESET; + calc_crc(&crc, data[3], 8); + calc_crc(&crc, data[2], 8); + calc_crc(&crc, data[1], 8); + calc_crc(&crc, data[0], 8); + tx[0] = data[3]; + tx[1] = data[2]; + tx[2] = data[1]; + tx[3] = data[0]; + tx[4] = crc; + } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_DATA + && rxlen == 6 && rx[0] == 0xf4) { + //received ACK + Dbprintf("Successful!"); + bStop = !false; + } + + // 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 (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { + if (bQuitTraceFull) { + DbpString("Trace full"); + 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; + } + } + } + end=false; + 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); + cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); +} + +/* + * Tries to authenticate to a Hitag S Transponder with the given challenges from a .cc file. + * Displays all Challenges that failed. + * When collecting Challenges to break the key it is possible that some data + * is not received correctly due to Antenna problems. This function + * detects these challenges. + */ +void check_challenges(bool file_given, byte_t* data) { + int i, j, z, k; + byte_t uid_byte[4]; + int frame_count; + int response; + byte_t rx[HITAG_FRAME_LEN]; + byte_t unlocker[60][8]; + int u1 = 0; + 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; + int STATE = 0; + bool bStop; + bool bQuitTraceFull = false; + int response_bit[200]; + unsigned char mask = 1; + unsigned char uid[32]; + unsigned char crc; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); +// Reset the return status + bSuccessful = false; + +// Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + + bQuiet = false; + bQuitTraceFull = true; + + LED_D_ON(); + +// 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; + + reset_sof = 1; + t_wait = 200; + + if (file_given) { + DbpString("Loading challenges..."); + memcpy((byte_t*)unlocker,data,60*8); + } + + while (file_given && !bStop && !BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); + + // Check if frame was captured and store it + if (rxlen > 0) { + frame_count++; + if (!bQuiet) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { + DbpString("Trace full"); + if (bQuitTraceFull) { + break; + } else { + bQuiet = true; + } + } + } + } + + tx = txbuf; + txlen = 0; + if (rxlen == 0) { + if (STATE == 2) + // challenge failed + Dbprintf("Challenge failed: %02X %02X %02X %02X %02X %02X %02X %02X", + unlocker[u1 - 1][0], unlocker[u1 - 1][1], + unlocker[u1 - 1][2], unlocker[u1 - 1][3], + unlocker[u1 - 1][4], unlocker[u1 - 1][5], + unlocker[u1 - 1][6], unlocker[u1 - 1][7]); + STATE = 0; + txlen = 5; + //start new authentication + memcpy(tx, "\xc0", nbytes(txlen)); + } else if (rxlen >= 67 && STATE == 0) { + //received uid + z = 0; + for (i = 0; i < 10; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + k = 0; + for (i = 5; i < z; i += 2) { + uid[k] = response_bit[i]; + k++; + if (k > 31) + break; + } + uid_byte[0] = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) + | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) + | (uid[6] << 1) | uid[7]; + uid_byte[1] = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) + | (uid[11] << 4) | (uid[12] << 3) | (uid[13] << 2) + | (uid[14] << 1) | uid[15]; + uid_byte[2] = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) + | (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2) + | (uid[22] << 1) | uid[23]; + uid_byte[3] = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) + | (uid[27] << 4) | (uid[28] << 3) | (uid[29] << 2) + | (uid[30] << 1) | uid[31]; + //Dbhexdump(10, rx, rxlen); + STATE = 1; + txlen = 45; + crc = CRC_PRESET; + calc_crc(&crc, 0x00, 5); + calc_crc(&crc, uid_byte[0], 8); + calc_crc(&crc, uid_byte[1], 8); + calc_crc(&crc, uid_byte[2], 8); + calc_crc(&crc, uid_byte[3], 8); + for (i = 0; i < 100; i++) { + response_bit[i] = 0; + } + for (i = 0; i < 5; i++) { + response_bit[i] = 0; + } + for (i = 5; i < 37; i++) { + response_bit[i] = uid[i - 5]; + } + for (j = 0; j < 8; j++) { + response_bit[i] = 0; + if ((crc & ((mask << 7) >> j)) != 0) + response_bit[i] = 1; + i++; + } + k = 0; + for (i = 0; i < 6; i++) { + tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) + | (response_bit[k + 2] << 5) + | (response_bit[k + 3] << 4) + | (response_bit[k + 4] << 3) + | (response_bit[k + 5] << 2) + | (response_bit[k + 6] << 1) | response_bit[k + 7]; + k += 8; + } + + } else if (STATE == 1 && rxlen == 44) { + //received configuration + STATE = 2; + z = 0; + for (i = 0; i < 6; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + txlen = 64; + + if (u1 >= (sizeof(unlocker) / sizeof(unlocker[0]))) + bStop = !false; + for (i = 0; i < 8; i++) + tx[i] = unlocker[u1][i]; + u1++; + + } else if (STATE == 2 && rxlen >= 44) { + STATE = 0; + } + + // 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 (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { + if (bQuitTraceFull) { + DbpString("Trace full"); + 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); + cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); +} + + + diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 27574dad..70dc54f1 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -15,12 +15,13 @@ #include "util.h" #include "string.h" #include "cmd.h" - #include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" #include "BigBuf.h" +#include "protocols.h" + static uint32_t iso14a_timeout; int rsamples = 0; uint8_t trigger = 0; @@ -2307,20 +2308,34 @@ void ReaderMifare(bool first_try) set_tracing(FALSE); } +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; +} nonces_t; + /** *MIFARE 1K simulate. * *@param flags : * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK - * 4B_FLAG_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that - * 7B_FLAG_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that + * FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that + * FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that + * FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later - *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite + *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... + * (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) */ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) { int cardSTATE = MFEMUL_NOFIELD; - int _7BUID = 0; + int _UID_LEN = 0; // 4, 7, 10 int vHf = 0; // in mV int res; uint32_t selTimer = 0; @@ -2344,20 +2359,32 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t response[MAX_MIFARE_FRAME_SIZE]; uint8_t response_par[MAX_MIFARE_PARITY_SIZE]; - uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID + uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! - uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; - uint8_t rSAK1[] = {0x04, 0xda, 0x17}; + uint8_t rUIDBCC3[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; + + uint8_t rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated + uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2 - // This can be used in a reader-only attack. - // (it can also be retrieved via 'hf 14a list', but hey... - uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0}; - uint8_t ar_nr_collected = 0; + //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 + // This will be used in the reader-only attack. + + //allow collecting up to 8 sets of nonces to allow recovery of up to 8 keys + #define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types (nml, moebius) + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; //*2 for 2nd attack type (moebius) + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); + uint8_t nonce1_count = 0; + uint8_t nonce2_count = 0; + uint8_t moebius_n_count = 0; + bool gettingMoebius = false; + uint8_t mM = 0; //moebius_modifier for collection storage // Authenticate response - nonce uint32_t nonce = bytes_to_num(rAUTH_NT, 4); @@ -2370,45 +2397,96 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 4B uid comes from data-portion of packet memcpy(rUIDBCC1,datain,4); rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - + _UID_LEN = 4; } else if (flags & FLAG_7B_UID_IN_DATA) { // 7B uid comes from data-portion of packet memcpy(&rUIDBCC1[1],datain,3); memcpy(rUIDBCC2, datain+3, 4); - _7BUID = true; + _UID_LEN = 7; + } else if (flags & FLAG_10B_UID_IN_DATA) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(&rUIDBCC2[1], datain+3, 3); + memcpy( rUIDBCC3, datain+6, 4); + _UID_LEN = 10; } else { - // get UID from emul memory + // get UID from emul memory - guess at length emlGetMemBt(receivedCmd, 7, 1); - _7BUID = !(receivedCmd[0] == 0x00); - if (!_7BUID) { // ---------- 4BUID + if (receivedCmd[0] == 0x00) { // ---------- 4BUID emlGetMemBt(rUIDBCC1, 0, 4); + _UID_LEN = 4; } else { // ---------- 7BUID emlGetMemBt(&rUIDBCC1[1], 0, 3); emlGetMemBt(rUIDBCC2, 3, 4); + _UID_LEN = 7; } } - /* - * Regardless of what method was used to set the UID, set fifth byte and modify - * the ATQA for 4 or 7-byte UID - */ - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (_7BUID) { - rATQA[0] = 0x44; - rUIDBCC1[0] = 0x88; - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - } - - if (MF_DBGLEVEL >= 1) { - if (!_7BUID) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); - } else { - Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], - rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]); - } + switch (_UID_LEN) { + case 4: + // save CUID + cuid = bytes_to_num(rUIDBCC1, 4); + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + if (MF_DBGLEVEL >= 2) { + Dbprintf("4B UID: %02x%02x%02x%02x", + rUIDBCC1[0], + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3] + ); + } + break; + case 7: + rATQA[0] |= 0x40; + // save CUID + cuid = bytes_to_num(rUIDBCC2, 4); + // CascadeTag, CT + rUIDBCC1[0] = 0x88; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (MF_DBGLEVEL >= 2) { + Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3], + rUIDBCC2[0], + rUIDBCC2[1], + rUIDBCC2[2], + rUIDBCC2[3] + ); + } + break; + case 10: + rATQA[0] |= 0x80; + //sak_10[0] &= 0xFB; + // save CUID + cuid = bytes_to_num(rUIDBCC3, 4); + // CascadeTag, CT + rUIDBCC1[0] = 0x88; + rUIDBCC2[0] = 0x88; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3]; + + if (MF_DBGLEVEL >= 2) { + Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3], + rUIDBCC2[1], + rUIDBCC2[2], + rUIDBCC2[3], + rUIDBCC3[0], + rUIDBCC3[1], + rUIDBCC3[2], + rUIDBCC3[3] + ); + } + break; + default: + break; } // We need to listen to the high-frequency, peak-detected path. @@ -2421,9 +2499,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * clear_trace(); set_tracing(TRUE); - bool finished = FALSE; - while (!BUTTON_PRESS() && !finished) { + bool button_pushed = BUTTON_PRESS(); + while (!button_pushed && !finished && !usb_poll_validate_length()) { WDT_HIT(); // find reader field @@ -2433,11 +2511,10 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE_TO_IDLE(); LED_A_ON(); } - } - if(cardSTATE == MFEMUL_NOFIELD) continue; + } + if (cardSTATE == MFEMUL_NOFIELD) continue; //Now, get data - res = EmGetCmd(receivedCmd, &len, receivedCmd_par); if (res == 2) { //Field is off! cardSTATE = MFEMUL_NOFIELD; @@ -2446,11 +2523,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } else if (res == 1) { break; //return value 1 means button press } - + // REQ or WUP request in ANY state and WUP in HALTED state - if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) { + if (len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { selTimer = GetTickCount(); - EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52)); + EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == ISO14443A_CMD_WUPA)); cardSTATE = MFEMUL_SELECT1; // init crypto block @@ -2469,59 +2546,137 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } case MFEMUL_SELECT1:{ - // select all - if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { + // select all - 0x93 0x20 + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received"); EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); break; } - if (MF_DBGLEVEL >= 4 && len == 9 && receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 ) - { - Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + // select card - 0x93 0x70 ... + if (len == 9 && + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { + if (MF_DBGLEVEL >= 4) + Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + + switch(_UID_LEN) { + case 4: + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); + break; + case 7: + cardSTATE = MFEMUL_SELECT2; + EmSendCmd(rSAK1, sizeof(rSAK1)); + break; + case 10: + cardSTATE = MFEMUL_SELECT2; + EmSendCmd(rSAK1, sizeof(rSAK1)); + break; + default:break; + } + } else { + cardSTATE_TO_IDLE(); + } + break; + } + case MFEMUL_SELECT3:{ + if (!len) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); + break; } - // select card + // select all cl3 - 0x97 0x20 + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x20)) { + EmSendCmd(rUIDBCC3, sizeof(rUIDBCC3)); + break; + } + // select card cl3 - 0x97 0x70 if (len == 9 && - (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { - EmSendCmd(_7BUID?rSAK1:rSAK, _7BUID?sizeof(rSAK1):sizeof(rSAK)); - cuid = bytes_to_num(rUIDBCC1, 4); - if (!_7BUID) { - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); - break; - } else { - cardSTATE = MFEMUL_SELECT2; - } + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && + receivedCmd[1] == 0x70 && + memcmp(&receivedCmd[2], rUIDBCC3, 4) == 0) ) { + + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol3 time: %d", GetTickCount() - selTimer); + break; } + cardSTATE_TO_IDLE(); break; } case MFEMUL_AUTH1:{ - if( len != 8) - { + if( len != 8) { cardSTATE_TO_IDLE(); LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } - uint32_t ar = bytes_to_num(receivedCmd, 4); - uint32_t nr = bytes_to_num(&receivedCmd[4], 4); - - //Collect AR/NR - if(ar_nr_collected < 2){ - if(ar_nr_responses[2] != ar) - {// Avoid duplicates... probably not necessary, ar should vary. - ar_nr_responses[ar_nr_collected*4] = cuid; - ar_nr_responses[ar_nr_collected*4+1] = nonce; - ar_nr_responses[ar_nr_collected*4+2] = ar; - ar_nr_responses[ar_nr_collected*4+3] = nr; - ar_nr_collected++; + uint32_t nr = bytes_to_num(receivedCmd, 4); + uint32_t ar = bytes_to_num(&receivedCmd[4], 4); + + // Collect AR/NR per keytype & sector + if(flags & FLAG_NR_AR_ATTACK) { + for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) { + // if first auth for sector, or matches sector and keytype of previous auth + if (ar_nr_collected[i+mM] < 2) { + // if we haven't already collected 2 nonces for this sector + if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { + // Avoid duplicates... probably not necessary, ar should vary. + if (ar_nr_collected[i+mM]==0) { + // first nonce collect + ar_nr_resp[i+mM].cuid = cuid; + ar_nr_resp[i+mM].sector = cardAUTHSC; + ar_nr_resp[i+mM].keytype = cardAUTHKEY; + ar_nr_resp[i+mM].nonce = nonce; + ar_nr_resp[i+mM].nr = nr; + ar_nr_resp[i+mM].ar = ar; + nonce1_count++; + // add this nonce to first moebius nonce + ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid; + ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC; + ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY; + ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce; + ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr; + ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar; + ar_nr_collected[i+ATTACK_KEY_COUNT]++; + } else { // second nonce collect (std and moebius) + ar_nr_resp[i+mM].nonce2 = nonce; + ar_nr_resp[i+mM].nr2 = nr; + ar_nr_resp[i+mM].ar2 = ar; + if (!gettingMoebius) { + nonce2_count++; + // check if this was the last second nonce we need for std attack + if ( nonce2_count == nonce1_count ) { + // done collecting std test switch to moebius + // first finish incrementing last sample + ar_nr_collected[i+mM]++; + // switch to moebius collection + gettingMoebius = true; + mM = ATTACK_KEY_COUNT; + nonce = nonce*7; + break; + } + } else { + moebius_n_count++; + // if we've collected all the nonces we need - finish. + if (nonce1_count == moebius_n_count) finished = true; + } + } + ar_nr_collected[i+mM]++; + } + } + // we found right spot for this nonce stop looking + break; + } } } // --- crypto - crypto1_word(pcs, ar , 1); - cardRr = nr ^ crypto1_word(pcs, 0, 0); + crypto1_word(pcs, nr , 1); + cardRr = ar ^ crypto1_word(pcs, 0, 0); // test if auth OK if (cardRr != prng_successor(nonce, 64)){ @@ -2537,6 +2692,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } + //auth successful ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); num_to_bytes(ans, 4, rAUTH_AT); @@ -2553,20 +2709,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (!len) { LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; - } - if (len == 2 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x20)) { + } + // select all cl2 - 0x95 0x20 + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); break; } - // select 2 card + // select cl2 card - 0x95 0x70 xxxxxxxxxxxx if (len == 9 && - (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { - EmSendCmd(rSAK, sizeof(rSAK)); - cuid = bytes_to_num(rUIDBCC2, 4); - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { + switch(_UID_LEN) { + case 7: + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + break; + case 10: + EmSendCmd(rSAK1, sizeof(rSAK1)); + cardSTATE = MFEMUL_SELECT3; + break; + default:break; + } break; } @@ -2594,11 +2759,22 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { + + // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack + if (receivedCmd[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) { + //is this the correct response to an auth on a out of range block? marshmellow + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + break; + } + authTimer = GetTickCount(); cardAUTHSC = receivedCmd[1] / 4; // received block num cardAUTHKEY = receivedCmd[0] - 0x60; crypto1_destroy(pcs);//Added by martin crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); + //uint64_t key=emlGetKey(cardAUTHSC, cardAUTHKEY); + //Dbprintf("key: %04x%08x",(uint32_t)(key>>32)&0xFFFF,(uint32_t)(key&0xFFFFFFFF)); if (!encrypted_data) { // first authentication if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY ); @@ -2775,45 +2951,48 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } } + button_pushed = BUTTON_PRESS(); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK - { - //May just aswell send the collected ar_nr in the response aswell - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4); - } - - if(flags & FLAG_NR_AR_ATTACK) - { - if(ar_nr_collected > 1) { - Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:"); - Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3], //NR1 - ar_nr_responses[6], //AR2 - ar_nr_responses[7] //NR2 - ); - } else { - Dbprintf("Failed to obtain two AR/NR pairs!"); - if(ar_nr_collected >0) { - Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3] //NR1 + if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) { + for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if (ar_nr_collected[i] == 2) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); - -} + if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK + //Send the collected ar_nr in the response + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); + } +} //----------------------------------------------------------------------------- diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 82e5dd6a..22227e74 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -547,15 +547,20 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } */ // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) + + //note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow #define CHECK_FOR_SUBCARRIER() { \ + v = MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2); \ + } + /* if(ci < 0) { \ - if(cq < 0) { /* ci < 0, cq < 0 */ \ + if(cq < 0) { \ // ci < 0, cq < 0 if (cq < ci) { \ v = -cq - (ci >> 1); \ } else { \ v = -ci - (cq >> 1); \ } \ - } else { /* ci < 0, cq >= 0 */ \ + } else { \ // ci < 0, cq >= 0 if (cq < -ci) { \ v = -ci + (cq >> 1); \ } else { \ @@ -563,13 +568,13 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } \ } \ } else { \ - if(cq < 0) { /* ci >= 0, cq < 0 */ \ + if(cq < 0) { \ // ci >= 0, cq < 0 if (-cq < ci) { \ v = ci - (cq >> 1); \ } else { \ v = -cq + (ci >> 1); \ } \ - } else { /* ci >= 0, cq >= 0 */ \ + } else { \ // ci >= 0, cq >= 0 if (cq < ci) { \ v = ci + (cq >> 1); \ } else { \ @@ -578,6 +583,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } \ } \ } + */ switch(Demod.state) { case DEMOD_UNSYNCD: diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e7145c5c..9a6ef9f0 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -319,18 +319,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * // 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; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -468,18 +457,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int // 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; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -648,18 +626,7 @@ void AcquireRawAdcSamplesIso15693(void) // 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; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -713,18 +680,7 @@ void RecordRawAdcSamplesIso15693(void) // 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; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 074a0f78..27dcc297 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -391,7 +391,7 @@ int legic_write_byte(int byte, int addr, int addr_sz) { uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd legic_prng_forward(2); /* we wait anyways */ - while(timer->TC_CV < 387) ; /* ~ 258us */ + while(timer->TC_CV < 387) {}; /* ~ 258us */ frame_send_rwd(cmd, cmd_sz); //== wait for ack ==================================== @@ -418,7 +418,7 @@ int legic_write_byte(int byte, int addr, int addr_sz) { } } timer->TC_CCR = AT91C_TC_SWTRG; - while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ + while(timer->TC_CV > 1) {}; /* Wait till the clock has reset */ return -1; } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 47fec7c2..2079f263 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -37,6 +37,8 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint sample_config sc = { 0,0,1, divisor_used, 0}; setSamplingConfig(&sc); + //clear read buffer + BigBuf_Clear_keep_EM(); /* Make sure the tag is reset */ FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -377,7 +379,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) AcquireTiType(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tiread to check"); + DbpString("Now use `lf ti read` to check"); } void SimulateTagLowFrequency(int period, int gap, int ledcontrol) @@ -640,6 +642,19 @@ static void biphaseSimBit(uint8_t c, int *n, uint8_t clock, uint8_t *phase) memset(dest+(*n), c ^ *phase, clock); *phase ^= 1; } + *n += clock; +} + +static void stAskSimBit(int *n, uint8_t clock) { + uint8_t *dest = BigBuf_get_addr(); + uint8_t halfClk = clock/2; + //ST = .5 high .5 low 1.5 high .5 low 1 high + memset(dest+(*n), 1, halfClk); + memset(dest+(*n) + halfClk, 0, halfClk); + memset(dest+(*n) + clock, 1, clock + halfClk); + memset(dest+(*n) + clock*2 + halfClk, 0, halfClk); + memset(dest+(*n) + clock*3, 1, clock); + *n += clock*4; } // args clock, ask/man or askraw, invert, transmission separator @@ -657,7 +672,7 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) for (i=0; i>32, id & 0xFFFFFFFF}; + uint32_t data[] = {0, (uint32_t)(id>>32), (uint32_t)(id & 0xFFFFFFFF)}; clock = (card & 0xFF00) >> 8; clock = (clock == 0) ? 64 : clock; diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index ab7c79dd..88df543f 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -124,7 +124,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag uint8_t *dest = BigBuf_get_addr(); int bufsize = BigBuf_max_traceLen(); - memset(dest, 0, bufsize); + //memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow) if(bits_per_sample < 1) bits_per_sample = 1; if(bits_per_sample > 8) bits_per_sample = 8; diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 7a09ce64..3d4dd400 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -42,14 +42,15 @@ extern int MF_DBGLEVEL; #define MFEMUL_IDLE 1 #define MFEMUL_SELECT1 2 #define MFEMUL_SELECT2 3 -#define MFEMUL_AUTH1 4 -#define MFEMUL_AUTH2 5 -#define MFEMUL_WORK 6 -#define MFEMUL_WRITEBL2 7 -#define MFEMUL_INTREG_INC 8 -#define MFEMUL_INTREG_DEC 9 -#define MFEMUL_INTREG_REST 10 -#define MFEMUL_HALTED 11 +#define MFEMUL_SELECT3 4 +#define MFEMUL_AUTH1 5 +#define MFEMUL_AUTH2 6 +#define MFEMUL_WORK 7 +#define MFEMUL_WRITEBL2 8 +#define MFEMUL_INTREG_INC 9 +#define MFEMUL_INTREG_DEC 10 +#define MFEMUL_INTREG_REST 11 +#define MFEMUL_HALTED 12 #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 3093a5e5..f9f33c53 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -7,9 +7,6 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -#define abs(x) ( ((x)<0) ? -(x) : (x) ) -#define max(x,y) ( x/dev/null) -Wall -O4 QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) LUALIB += -ldl + LDLIBS += -ltermcap -lncurses MOC = $(shell pkg-config --variable=moc_location QtCore) # Below is a variant you can use if you have problems compiling with QT5 on ubuntu. see http://www.proxmark.org/forum/viewtopic.php?id=1661 for more info. #MOC = /usr/lib/x86_64-linux-gnu/qt4/bin/moc @@ -99,6 +100,8 @@ CMDSRCS = nonce2key/crapto1.c\ cmdlft55xx.c \ cmdlfpcf7931.c\ cmdlfviking.c\ + cmdlfpresco.c\ + cmdlfpyramid.c\ pm3_binlib.c\ scripting.c\ cmdscript.c\ diff --git a/client/cmddata.c b/client/cmddata.c index 6dd96ab0..86dac423 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -8,23 +8,22 @@ // Data and Graph commands //----------------------------------------------------------------------------- -#include -#include -#include -#include -#include "proxmark3.h" -#include "data.h" -#include "ui.h" -#include "graph.h" -#include "cmdparser.h" +#include // also included in util.h +#include // also included in util.h +#include // for CmdNorm INT_MIN && INT_MAX +#include "data.h" // also included in util.h +#include "cmddata.h" #include "util.h" #include "cmdmain.h" -#include "cmddata.h" -#include "lfdemod.h" -#include "usb_cmd.h" -#include "crc.h" -#include "crc16.h" -#include "loclass/cipherutils.h" +#include "proxmark3.h" +#include "ui.h" // for show graph controls +#include "graph.h" // for graph data +#include "cmdparser.h"// already included in cmdmain.h +#include "usb_cmd.h" // already included in cmdmain.h and proxmark3.h +#include "lfdemod.h" // for demod code +#include "crc.h" // for pyramid checksum maxim +#include "crc16.h" // for FDXB demod checksum +#include "loclass/cipherutils.h" // for decimating samples in getsamples uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t g_debugMode=0; @@ -277,7 +276,8 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose) { - if (!ASKDemod(Cmd, FALSE, FALSE, 1)) return 0; + bool st = TRUE; + if (!ASKDemod_ext(Cmd, FALSE, FALSE, 1, &st)) return 0; return AskEm410xDecode(verbose, hi, lo); } @@ -312,8 +312,7 @@ int CmdAskEM410xDemod(const char *Cmd) //verbose will print results and demoding messages //emSearch will auto search for EM410x format in bitstream //askType switches decode: ask/raw = 0, ask/manchester = 1 -int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) -{ +int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, bool *stCheck) { int invert=0; int clk=0; int maxErr=100; @@ -334,15 +333,22 @@ int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) if (amp == 'a' || amp == 'A') askAmp=1; size_t BitLen = getFromGraphBuf(BitStream); if (g_debugMode) PrintAndLog("DEBUG: Bitlen from grphbuff: %d",BitLen); - if (BitLen<255) return 0; - if (maxLenmaxErr){ + if (errCnt > maxErr){ if (g_debugMode) PrintAndLog("DEBUG: Too many errors found, errors:%d, bits:%d, clock:%d",errCnt, BitLen, clk); return 0; } @@ -365,6 +371,10 @@ int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) } return 1; } +int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) { + bool st = false; + return ASKDemod_ext(Cmd, verbose, emSearch, askType, &st); +} //by marshmellow //takes 5 arguments - clock, invert, maxErr, maxLen as integers and amplify as char == 'a' @@ -374,7 +384,8 @@ int Cmdaskmandemod(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); + PrintAndLog("Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); + PrintAndLog(" ['s'] optional, check for Sequence Terminator"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); PrintAndLog(" , 1 to invert output"); PrintAndLog(" [set maximum allowed errors], default = 100"); @@ -388,7 +399,13 @@ int Cmdaskmandemod(const char *Cmd) PrintAndLog(" : data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); return 0; } - return ASKDemod(Cmd, TRUE, TRUE, 1); + bool st = TRUE; + if (Cmd[0]=='s') + return ASKDemod_ext(Cmd++, TRUE, TRUE, 1, &st); + else if (Cmd[1] == 's') + return ASKDemod_ext(Cmd+=2, TRUE, TRUE, 1, &st); + else + return ASKDemod(Cmd, TRUE, TRUE, 1); } //by marshmellow @@ -574,7 +591,7 @@ int Cmdaskbiphdemod(const char *Cmd) int CmdG_Prox_II_Demod(const char *Cmd) { if (!ASKbiphaseDemod(Cmd, FALSE)){ - if (g_debugMode) PrintAndLog("ASKbiphaseDemod failed 1st try"); + if (g_debugMode) PrintAndLog("Error gProxII: ASKbiphaseDemod failed 1st try"); return 0; } size_t size = DemodBufferLen; @@ -584,46 +601,32 @@ int CmdG_Prox_II_Demod(const char *Cmd) if (g_debugMode) PrintAndLog("Error gProxII_Demod"); return 0; } - //got a good demod - uint32_t ByteStream[65] = {0x00}; + //got a good demod of 96 bits + uint8_t ByteStream[8] = {0x00}; uint8_t xorKey=0; - uint8_t keyCnt=0; - uint8_t bitCnt=0; - uint8_t ByteCnt=0; - size_t startIdx = ans + 6; //start after preamble - for (size_t idx = 0; idx>2; uint32_t FC = 0; uint32_t Card = 0; + //get raw 96 bits to print uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans,32); uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer+ans+64, 32); @@ -631,13 +634,14 @@ int CmdG_Prox_II_Demod(const char *Cmd) if (fmtLen==36){ FC = ((ByteStream[3] & 0x7F)<<7) | (ByteStream[4]>>1); Card = ((ByteStream[4]&1)<<19) | (ByteStream[5]<<11) | (ByteStream[6]<<3) | (ByteStream[7]>>5); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d",fmtLen,FC,Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else if(fmtLen==26){ FC = ((ByteStream[3] & 0x7F)<<1) | (ByteStream[4]>>7); Card = ((ByteStream[4]&0x7F)<<9) | (ByteStream[5]<<1) | (ByteStream[6]>>7); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d",fmtLen,FC,Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else { - PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",fmtLen); + PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",(int)fmtLen); + PrintAndLog("Decoded Raw: %s", sprint_hex(ByteStream, 8)); } PrintAndLog("Raw: %08x%08x%08x", raw1,raw2,raw3); setDemodBuf(DemodBuffer+ans, 96, 0); @@ -664,7 +668,7 @@ int CmdVikingDemod(const char *Cmd) uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); uint32_t cardid = bytebits_to_byte(DemodBuffer+ans+24, 32); uint8_t checksum = bytebits_to_byte(DemodBuffer+ans+32+24, 8); - PrintAndLog("Viking Tag Found: Card ID %08X, Checksum: %02X", cardid, checksum); + PrintAndLog("Viking Tag Found: Card ID %08X, Checksum: %02X", cardid, (unsigned int) checksum); PrintAndLog("Raw: %08X%08X", raw1,raw2); setDemodBuf(DemodBuffer+ans, 64, 0); return 1; @@ -830,16 +834,18 @@ int CmdUndec(const char *Cmd) uint8_t factor = param_get8ex(Cmd, 0,2, 10); //We have memory, don't we? int swap[MAX_GRAPH_TRACE_LEN] = { 0 }; - uint32_t g_index = 0 ,s_index = 0; - while(g_index < GraphTraceLen && s_index < MAX_GRAPH_TRACE_LEN) + uint32_t g_index = 0, s_index = 0; + while(g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) { int count = 0; - for(count = 0; count < factor && s_index+count < MAX_GRAPH_TRACE_LEN; count ++) + for(count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) swap[s_index+count] = GraphBuffer[g_index]; - s_index+=count; + + s_index += count; + g_index++; } - memcpy(GraphBuffer,swap, s_index * sizeof(int)); + memcpy(GraphBuffer, swap, s_index * sizeof(int)); GraphTraceLen = s_index; RepaintGraphWindow(); return 0; @@ -873,13 +879,15 @@ int CmdGraphShiftZero(const char *Cmd) int CmdAskEdgeDetect(const char *Cmd) { int thresLen = 25; + int Last = 0; sscanf(Cmd, "%i", &thresLen); for(int i = 1; i=thresLen) //large jump up - GraphBuffer[i-1] = 127; + Last = 127; else if(GraphBuffer[i]-GraphBuffer[i-1]<=-1*thresLen) //large jump down - GraphBuffer[i-1] = -127; + Last = -127; + GraphBuffer[i-1] = Last; } RepaintGraphWindow(); return 0; @@ -919,19 +927,21 @@ int CmdDetectClockRate(const char *Cmd) char *GetFSKType(uint8_t fchigh, uint8_t fclow, uint8_t invert) { - char *fskType; + static char fType[8]; + memset(fType, 0x00, 8); + char *fskType = fType; if (fchigh==10 && fclow==8){ if (invert) //fsk2a - fskType = "FSK2a"; + memcpy(fskType, "FSK2a", 5); else //fsk2 - fskType = "FSK2"; + memcpy(fskType, "FSK2", 4); } else if (fchigh == 8 && fclow == 5) { if (invert) - fskType = "FSK1"; + memcpy(fskType, "FSK1", 4); else - fskType = "FSK1a"; + memcpy(fskType, "FSK1a", 5); } else { - fskType = "FSK??"; + memcpy(fskType, "FSK??", 5); } return fskType; } @@ -950,39 +960,40 @@ int FSKrawDemod(const char *Cmd, bool verbose) invert = param_get8(Cmd, 1); fchigh = param_get8(Cmd, 2); fclow = param_get8(Cmd, 3); + if (strlen(Cmd)>0 && strlen(Cmd)<=2) { - if (rfLen==1){ + if (rfLen==1) { invert = 1; //if invert option only is used rfLen = 0; - } + } } uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; size_t BitLen = getFromGraphBuf(BitStream); if (BitLen==0) return 0; //get field clock lengths - uint8_t fc1=0, fc2=0, rf1=0; + uint16_t fcs=0; if (!fchigh || !fclow) { - uint8_t ans = fskClocks(&fc1, &fc2, &rf1, false); - if (ans == 0) { - if (g_debugMode) PrintAndLog("\nError: cannot detect valid fsk field clocks"); - return 0; // can't detect field clock + fcs = countFC(BitStream, BitLen, 1); + if (!fcs) { + fchigh = 10; + fclow = 8; + } else { + fchigh = (fcs >> 8) & 0x00FF; + fclow = fcs & 0x00FF; } - fchigh = fc1; - fclow = fc2; - if (rfLen == 0) rfLen = rf1; } //get bit clock length - if (!rfLen){ + if (!rfLen) { rfLen = detectFSKClk(BitStream, BitLen, fchigh, fclow); if (!rfLen) rfLen = 50; } int size = fskdemod(BitStream, BitLen, rfLen, invert, fchigh, fclow); - if (size > 0){ + if (size > 0) { setDemodBuf(BitStream,size,0); // Now output the bitstream to the scrollback by line of 16 bits if (verbose || g_debugMode) { - PrintAndLog("\nUsing Clock:%hu, invert:%hu, fchigh:%hu, fclow:%hu", rfLen, invert, fchigh, fclow); + PrintAndLog("\nUsing Clock:%u, invert:%u, fchigh:%u, fclow:%u", (unsigned int)rfLen, (unsigned int)invert, (unsigned int)fchigh, (unsigned int)fclow); PrintAndLog("%s decoded bitstream:",GetFSKType(fchigh,fclow,invert)); printDemodBuff(); } @@ -1255,7 +1266,7 @@ int CmdFSKdemodAWID(const char *Cmd) //get binary from fsk wave int idx = AWIDdemodFSK(BitStream, &size); if (idx<=0){ - if (g_debugMode==1){ + if (g_debugMode){ if (idx == -1) PrintAndLog("DEBUG: Error - not enough samples"); else if (idx == -2) @@ -1293,7 +1304,7 @@ int CmdFSKdemodAWID(const char *Cmd) size = removeParity(BitStream, idx+8, 4, 1, 88); if (size != 66){ - if (g_debugMode==1) PrintAndLog("DEBUG: Error - at parity check-tag size does not match AWID format"); + if (g_debugMode) PrintAndLog("DEBUG: Error - at parity check-tag size does not match AWID format"); return 0; } // ok valid card found! @@ -1353,7 +1364,7 @@ int CmdFSKdemodPyramid(const char *Cmd) //get binary from fsk wave int idx = PyramiddemodFSK(BitStream, &size); if (idx < 0){ - if (g_debugMode==1){ + if (g_debugMode){ if (idx == -5) PrintAndLog("DEBUG: Error - not enough samples"); else if (idx == -1) @@ -1409,7 +1420,7 @@ int CmdFSKdemodPyramid(const char *Cmd) size = removeParity(BitStream, idx+8, 8, 1, 120); if (size != 105){ - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("DEBUG: Error at parity check - tag size does not match Pyramid format, SIZE: %d, IDX: %d, hi3: %x",size, idx, rawHi3); return 0; } @@ -1632,21 +1643,21 @@ int CmdIndalaDecode(const char *Cmd) } if (!ans){ - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("Error1: %d",ans); return 0; } uint8_t invert=0; size_t size = DemodBufferLen; - size_t startIdx = indala26decode(DemodBuffer, &size, &invert); - if (startIdx < 1 || size > 224) { - if (g_debugMode==1) + int startIdx = indala26decode(DemodBuffer, &size, &invert); + if (startIdx < 0 || size > 224) { + if (g_debugMode) PrintAndLog("Error2: %d",ans); return -1; } - setDemodBuf(DemodBuffer, size, startIdx); + setDemodBuf(DemodBuffer, size, (size_t)startIdx); if (invert) - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("Had to invert bits"); PrintAndLog("BitLen: %d",DemodBufferLen); @@ -2027,10 +2038,20 @@ int CmdSamples(const char *Cmd) int CmdTuneSamples(const char *Cmd) { - int timeout = 0; + int timeout = 0, arg = FLAG_TUNE_ALL; + + if(*Cmd == 'l') { + arg = FLAG_TUNE_LF; + } else if (*Cmd == 'h') { + arg = FLAG_TUNE_HF; + } else if (*Cmd != '\0') { + PrintAndLog("use 'tune' or 'tune l' or 'tune h'"); + return 0; + } + printf("\nMeasuring antenna characteristics, please wait..."); - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; + UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING, {arg, 0, 0}}; SendCommand(&c); UsbCommand resp; @@ -2313,9 +2334,8 @@ int Cmdbin2hex(const char *Cmd) return 0; } -int usage_data_hex2bin(){ - - PrintAndLog("Usage: data bin2hex "); +int usage_data_hex2bin() { + PrintAndLog("Usage: data hex2bin "); PrintAndLog(" This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); return 0; diff --git a/client/cmddata.h b/client/cmddata.h index c3303c54..9b9f2da9 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -11,6 +11,12 @@ #ifndef CMDDATA_H__ #define CMDDATA_H__ +#include //size_t +#include //uint_32+ +#include //bool + +#include "cmdparser.h" // for command_t + command_t * CmdDataCommands(); int CmdData(const char *Cmd); @@ -63,6 +69,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ); int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose); int ASKbiphaseDemod(const char *Cmd, bool verbose); int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType); +int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, bool *stCheck); int FSKrawDemod(const char *Cmd, bool verbose); int PSKDemod(const char *Cmd, bool verbose); int NRZrawDemod(const char *Cmd, bool verbose); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 81716db3..ecf3ba03 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -696,14 +696,17 @@ int CmdHF14ACmdRaw(const char *cmd) { c.arg[2] = 13560000 / 1000 / (8*16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) } - if(power) + if(power) { c.arg[0] |= ISO14A_NO_DISCONNECT; + } - if(datalen > 0) + if(datalen > 0) { c.arg[0] |= ISO14A_RAW; + } - if(topazmode) + if(topazmode) { c.arg[0] |= ISO14A_TOPAZMODE; + } // Max buffer is USB_CMD_DATA_SIZE c.arg[1] = (datalen & 0xFFFF) | (numbits << 16); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 48e78b1c..36c8e6c3 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" +#include "./nonce2key/nonce2key.h" static int CmdHelp(const char *Cmd); @@ -28,7 +29,7 @@ int CmdHF14AMifare(const char *Cmd) printf("-------------------------------------------------------------------------\n"); -start: + start: clearCommandBuffer(); SendCommand(&c); @@ -1015,72 +1016,273 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } -int CmdHF14AMf1kSim(const char *Cmd) -{ - uint8_t uid[7] = {0, 0, 0, 0, 0, 0, 0}; +void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { + #define ATTACK_KEY_COUNT 8 // keep same as define in iso14443a.c -> Mifare1ksim() + uint64_t key = 0; + typedef struct { + uint64_t keyA; + uint64_t keyB; + } st_t; + st_t sector_trailer[ATTACK_KEY_COUNT]; + memset(sector_trailer, 0x00, sizeof(sector_trailer)); + + uint8_t stSector[ATTACK_KEY_COUNT]; + memset(stSector, 0x00, sizeof(stSector)); + uint8_t key_cnt[ATTACK_KEY_COUNT]; + memset(key_cnt, 0x00, sizeof(key_cnt)); + + for (uint8_t i = 0; i 0) { + //PrintAndLog("DEBUG: Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (mfkey32(ar_resp[i], &key)) { + PrintAndLog(" Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + + for (uint8_t ii = 0; ii0) { + uint8_t memBlock[16]; + memset(memBlock, 0x00, sizeof(memBlock)); + char cmd1[36]; + memset(cmd1,0x00,sizeof(cmd1)); + snprintf(cmd1,sizeof(cmd1),"%04x%08xFF078069%04x%08x",(uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); + PrintAndLog("Setting Emulator Memory Block %02d: [%s]",stSector[i]*4+3, cmd1); + if (param_gethex(cmd1, 0, memBlock, 32)) { + PrintAndLog("block data must include 32 HEX symbols"); + return; + } + + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {(stSector[i]*4+3), 1, 0}}; + memcpy(c.d.asBytes, memBlock, 16); + clearCommandBuffer(); + SendCommand(&c); + } + } + } + /* + //un-comment to use as well moebius attack + for (uint8_t i = ATTACK_KEY_COUNT; i 0) { + if (tryMfk32_moebius(ar_resp[i], &key)) { + PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + } + } + }*/ +} + +int usage_hf14_mf1ksim(void) { + PrintAndLog("Usage: hf mf sim h u n i x"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" u (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used"); + PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); + PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); + PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); + PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory (implies x and i)"); + PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f ' (implies x and i)"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf sim u 0a0a0a0a"); + PrintAndLog(" hf mf sim u 11223344556677"); + PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim f uids.txt"); + PrintAndLog(" hf mf sim u 0a0a0a0a e"); + + return 0; +} + +int CmdHF14AMf1kSim(const char *Cmd) { + UsbCommand resp; + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; - - uint8_t cmdp = param_getchar(Cmd, 0); - - if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mf sim u n i x"); - PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID. If not specified, the UID from emulator memory will be used"); - PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); - PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); - PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); - PrintAndLog(""); - PrintAndLog(" sample: hf mf sim u 0a0a0a0a "); - return 0; - } + int uidlen = 0; uint8_t pnr = 0; - if (param_getchar(Cmd, pnr) == 'u') { - if(param_gethex(Cmd, pnr+1, uid, 8) == 0) - { - flags |= FLAG_4B_UID_IN_DATA; // UID from packet - } else if(param_gethex(Cmd,pnr+1,uid,14) == 0) { - flags |= FLAG_7B_UID_IN_DATA;// UID from packet - } else { - PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols"); - return 1; + bool setEmulatorMem = false; + bool attackFromFile = false; + FILE *f; + char filename[FILE_PATH_SIZE]; + memset(filename, 0x00, sizeof(filename)); + int len = 0; + char buf[64]; + + uint8_t cmdp = 0; + bool errors = false; + + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'e': + case 'E': + setEmulatorMem = true; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; + cmdp++; + break; + case 'f': + case 'F': + len = param_getstr(Cmd, cmdp+1, filename); + if (len < 1) { + PrintAndLog("error no filename found"); + return 0; + } + attackFromFile = true; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; + cmdp += 2; + break; + case 'h': + case 'H': + return usage_hf14_mf1ksim(); + case 'i': + case 'I': + flags |= FLAG_INTERACTIVE; + cmdp++; + break; + case 'n': + case 'N': + exitAfterNReads = param_get8(Cmd, pnr+1); + cmdp += 2; + break; + case 'u': + case 'U': + param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); + switch(uidlen) { + case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags = FLAG_7B_UID_IN_DATA; break; + case 8: flags = FLAG_4B_UID_IN_DATA; break; + default: return usage_hf14_mf1ksim(); + } + cmdp += 2; + break; + case 'x': + case 'X': + flags |= FLAG_NR_AR_ATTACK; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; } - pnr +=2; - } - if (param_getchar(Cmd, pnr) == 'n') { - exitAfterNReads = param_get8(Cmd,pnr+1); - pnr += 2; - } - if (param_getchar(Cmd, pnr) == 'i' ) { - //Using a flag to signal interactiveness, least significant bit - flags |= FLAG_INTERACTIVE; - pnr++; + if(errors) break; } + //Validations + if(errors) return usage_hf14_mf1ksim(); - if (param_getchar(Cmd, pnr) == 'x' ) { - //Using a flag to signal interactiveness, least significant bit - flags |= FLAG_NR_AR_ATTACK; - } - PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A" - , exitAfterNReads, flags,flags); + //get uid from file + if (attackFromFile) { + int count = 0; + // open file + f = fopen(filename, "r"); + if (f == NULL) { + PrintAndLog("File %s not found or locked", filename); + return 1; + } + PrintAndLog("Loading file and simulating. Press keyboard to abort"); + while(!feof(f) && !ukbhit()){ + memset(buf, 0, sizeof(buf)); + memset(uid, 0, sizeof(uid)); + if (fgets(buf, sizeof(buf), f) == NULL) { + if (count > 0) break; + + PrintAndLog("File reading error."); + fclose(f); + return 2; + } + if(!strlen(buf) && feof(f)) break; + + uidlen = strlen(buf)-1; + switch(uidlen) { + case 20: flags |= FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags |= FLAG_7B_UID_IN_DATA; break; + case 8: flags |= FLAG_4B_UID_IN_DATA; break; + default: + PrintAndLog("uid in file wrong length at %d (length: %d) [%s]",count, uidlen, buf); + fclose(f); + return 2; + } - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; - memcpy(c.d.asBytes, uid, sizeof(uid)); - SendCommand(&c); + for (uint8_t i = 0; i < uidlen; i += 2) { + sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]); + } + + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" + , exitAfterNReads, flags, flags); + + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + memcpy(c.d.asBytes, uid, sizeof(uid)); + clearCommandBuffer(); + SendCommand(&c); - if(flags & FLAG_INTERACTIVE) - { - UsbCommand resp; - PrintAndLog("Press pm3-button to abort simulation"); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - //We're waiting only 1.5 s at a time, otherwise we get the - // annoying message about "Waiting for a response... " + while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + //We're waiting only 1.5 s at a time, otherwise we get the + // annoying message about "Waiting for a response... " + } + //got a response + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; + memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); + readerAttack(ar_resp, setEmulatorMem); + if ((bool)resp.arg[1]) { + PrintAndLog("Device button pressed - quitting"); + fclose(f); + return 4; + } + count++; + } + fclose(f); + } else { //not from file + + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" + , exitAfterNReads, flags, flags); + + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + memcpy(c.d.asBytes, uid, sizeof(uid)); + clearCommandBuffer(); + SendCommand(&c); + + if(flags & FLAG_INTERACTIVE) { + PrintAndLog("Press pm3-button to abort simulation"); + while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + //We're waiting only 1.5 s at a time, otherwise we get the + // annoying message about "Waiting for a response... " + } + //got a response + if (flags & FLAG_NR_AR_ATTACK) { + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; + memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); + readerAttack(ar_resp, setEmulatorMem); + } } } - + return 0; } diff --git a/client/cmdhw.c b/client/cmdhw.c index 33dc78ae..74e476eb 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -467,7 +467,7 @@ static command_t CommandTable[] = {"reset", CmdReset, 0, "Reset the Proxmark3"}, {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"}, {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, - {"tune", CmdTune, 0, "Measure antenna tuning"}, + {"tune", CmdTune, 0, "['l'|'h'] -- Measure antenna tuning (option 'l' or 'h' to limit to LF or HF)"}, {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, {"status", CmdStatus, 0, "Show runtime status information about the connected Proxmark"}, {"ping", CmdPing, 0, "Test if the pm3 is responsive"}, diff --git a/client/cmdlf.c b/client/cmdlf.c index 41feec20..016f0fe2 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -13,24 +13,26 @@ #include #include #include "proxmark3.h" -#include "data.h" -#include "graph.h" -#include "ui.h" -#include "cmdparser.h" -#include "cmdmain.h" -#include "cmddata.h" -#include "util.h" #include "cmdlf.h" -#include "cmdlfhid.h" -#include "cmdlfawid.h" -#include "cmdlfti.h" -#include "cmdlfem4x.h" -#include "cmdlfhitag.h" -#include "cmdlft55xx.h" -#include "cmdlfpcf7931.h" -#include "cmdlfio.h" -#include "cmdlfviking.h" -#include "lfdemod.h" +#include "lfdemod.h" // for psk2TOpsk1 +#include "util.h" // for parsing cli command utils +#include "ui.h" // for show graph controls +#include "graph.h" // for graph data +#include "cmdparser.h" // for getting cli commands included in cmdmain.h +#include "cmdmain.h" // for sending cmds to device +#include "data.h" // for GetFromBigBuf +#include "cmddata.h" // for `lf search` +#include "cmdlfawid.h" // for awid menu +#include "cmdlfem4x.h" // for em4x menu +#include "cmdlfhid.h" // for hid menu +#include "cmdlfhitag.h" // for hitag menu +#include "cmdlfio.h" // for ioprox menu +#include "cmdlft55xx.h" // for t55xx menu +#include "cmdlfti.h" // for ti menu +#include "cmdlfpresco.h" // for presco menu +#include "cmdlfpcf7931.h"// for pcf7931 menu +#include "cmdlfpyramid.h"// for pyramid menu +#include "cmdlfviking.h" // for viking menu static int CmdHelp(const char *Cmd); @@ -62,7 +64,6 @@ int CmdLFCommandRead(const char *Cmd) bool errors = FALSE; //uint8_t divisor = 95; //125khz uint8_t cmdp = 0; - int strLength = 0; while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) @@ -78,7 +79,7 @@ int CmdLFCommandRead(const char *Cmd) cmdp++; break; case 'c': - strLength = param_getstr(Cmd, cmdp+1, (char *)&c.d.asBytes); + param_getstr(Cmd, cmdp+1, (char *)&c.d.asBytes); cmdp+=2; break; case 'd': @@ -539,7 +540,7 @@ int CmdLFSetConfig(const char *Cmd) return usage_lf_config(); } //Bps is limited to 8, so fits in lower half of arg1 - if(bps >> 8) bps = 8; + if(bps >> 4) bps = 8; sample_config config = { decimation,bps,averaging,divisor,trigger_threshold @@ -663,7 +664,7 @@ int usage_lf_simask(void) PrintAndLog(" b sim ask/biphase"); PrintAndLog(" m sim ask/manchester - Default"); PrintAndLog(" r sim ask/raw"); - PrintAndLog(" s TBD- -to enable a gap between playback repetitions - default: no gap"); + PrintAndLog(" s add t55xx Sequence Terminator gap - default: no gaps (only manchester)"); PrintAndLog(" d Data to sim as hex - omit to sim from DemodBuffer"); return 0; } @@ -1193,7 +1194,8 @@ int CmdLFfind(const char *Cmd) return 1; } } - ans=ASKDemod("0 0 0",TRUE,FALSE,1); + bool st = TRUE; + ans=ASKDemod_ext("0 0 0",TRUE,FALSE,1,&st); if (ans>0) { PrintAndLog("\nUnknown ASK Modulated and Manchester encoded Tag Found!"); PrintAndLog("\nif it does not look right it could instead be ASK/Biphase - try 'data rawdemod ab'"); @@ -1219,7 +1221,9 @@ static command_t CommandTable[] = {"hid", CmdLFHID, 1, "{ HID RFIDs... }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"}, {"io", CmdLFIO, 1, "{ ioProx tags... }"}, + {"presco", CmdLFPresco, 1, "{ Presco RFIDs... }"}, {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 RFIDs... }"}, + {"pyramid", CmdLFPyramid, 1, "{ Farpointe/Pyramid RFIDs... }"}, {"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"}, {"ti", CmdLFTI, 1, "{ TI RFIDs... }"}, {"viking", CmdLFViking, 1, "{ Viking tags... }"}, diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index fe5ba587..07247364 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -18,6 +18,7 @@ #include "common.h" #include "util.h" #include "hitag2.h" +#include "hitagS.h" #include "sleep.h" #include "cmdmain.h" @@ -190,14 +191,20 @@ int CmdLFHitagSim(const char *Cmd) { } int CmdLFHitagReader(const char *Cmd) { -// UsbCommand c = {CMD_READER_HITAG}; - -// param_get32ex(Cmd,1,0,16); UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}}; hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_function htf = param_get32ex(Cmd,0,0,10); switch (htf) { + case 01: { //RHTSF_CHALLENGE + c = (UsbCommand){ CMD_READ_HITAG_S }; + num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + } break; + case 02: { //RHTSF_KEY + c = (UsbCommand){ CMD_READ_HITAG_S }; + num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); + } break; case RHT2F_PASSWORD: { num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password); } break; @@ -216,6 +223,8 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog("Error: unkown reader function %d",htf); PrintAndLog("Hitag reader functions"); PrintAndLog(" HitagS (0*)"); + PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); + PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" 21 (password mode)"); @@ -257,14 +266,126 @@ int CmdLFHitagReader(const char *Cmd) { return 0; } + +int CmdLFHitagSimS(const char *Cmd) { + UsbCommand c = { CMD_SIMULATE_HITAG_S }; + char filename[FILE_PATH_SIZE] = { 0x00 }; + FILE* pf; + bool tag_mem_supplied; + int len = strlen(Cmd); + if (len > FILE_PATH_SIZE) + len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + if (strlen(filename) > 0) { + if ((pf = fopen(filename, "rb+")) == NULL) { + PrintAndLog("Error: Could not open file [%s]", filename); + return 1; + } + tag_mem_supplied = true; + if (fread(c.d.asBytes, 4*64, 1, pf) == 0) { + PrintAndLog("Error: File reading error"); + fclose(pf); + return 1; + } + fclose(pf); + } else { + tag_mem_supplied = false; + } + + // Does the tag comes with memory + c.arg[0] = (uint32_t) tag_mem_supplied; + + SendCommand(&c); + return 0; +} + +int CmdLFHitagCheckChallenges(const char *Cmd) { + UsbCommand c = { CMD_TEST_HITAGS_TRACES }; + char filename[FILE_PATH_SIZE] = { 0x00 }; + FILE* pf; + bool file_given; + int len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + if (strlen(filename) > 0) { + if ((pf = fopen(filename,"rb+")) == NULL) { + PrintAndLog("Error: Could not open file [%s]",filename); + return 1; + } + file_given = true; + if (fread(c.d.asBytes,8*60,1,pf) == 0) { + PrintAndLog("Error: File reading error"); + fclose(pf); + return 1; + } + fclose(pf); + } else { + file_given = false; + } + + //file with all the challenges to try + c.arg[0] = (uint32_t)file_given; + + SendCommand(&c); + return 0; +} + + +int CmdLFHitagWP(const char *Cmd) { + UsbCommand c = { CMD_WR_HITAG_S }; + hitag_data* htd = (hitag_data*)c.d.asBytes; + hitag_function htf = param_get32ex(Cmd,0,0,10); + switch (htf) { + case 03: { //WHTSF_CHALLENGE + num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr); + c.arg[2]= param_get32ex(Cmd, 2, 0, 10); + num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data); + } break; + case 04: { //WHTSF_KEY + num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); + c.arg[2]= param_get32ex(Cmd, 2, 0, 10); + num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data); + + } break; + default: { + PrintAndLog("Error: unkown writer function %d",htf); + PrintAndLog("Hitag writer functions"); + PrintAndLog(" HitagS (0*)"); + PrintAndLog(" 03 (Challenge) write page on a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" Hitag1 (1*)"); + PrintAndLog(" Hitag2 (2*)"); + return 1; + } break; + } + // Copy the hitag function into the first argument + c.arg[0] = htf; + + // Send the command to the proxmark + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + // Check the return status, stored in the first argument + if (resp.arg[0] == false) return 1; + return 0; +} + + static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdLFHitagList, 1, " List Hitag trace history"}, - {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, - {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, - {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"list", CmdLFHitagList, 1, " List Hitag trace history"}, + {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, + {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, + {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, + {"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, + {"simS", CmdLFHitagSimS, 1, " Simulate HitagS transponder" }, + {"checkChallenges", CmdLFHitagCheckChallenges, 1, " test all challenges" }, { + NULL,NULL, 0, NULL } }; int CmdLFHitag(const char *Cmd) diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c new file mode 100644 index 00000000..abae165d --- /dev/null +++ b/client/cmdlfpresco.c @@ -0,0 +1,263 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Presco tag commands +//----------------------------------------------------------------------------- +#include +#include +#include "cmdlfpresco.h" +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest + +static int CmdHelp(const char *Cmd); + +int usage_lf_presco_clone(void){ + PrintAndLog("clone a Presco tag to a T55x7 tag."); + PrintAndLog("Usage: lf presco clone d H "); + PrintAndLog("Options :"); + PrintAndLog(" d : 9 digit presco card ID"); + PrintAndLog(" H : 8 digit hex card number"); + PrintAndLog(" : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLog(""); + PrintAndLog("Sample : lf presco clone d 123456789"); + return 0; +} + +int usage_lf_presco_sim(void) { + PrintAndLog("Enables simulation of presco card with specified card number."); + PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLog("Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); + PrintAndLog(""); + PrintAndLog("Usage: lf presco sim d or H "); + PrintAndLog("Options :"); + PrintAndLog(" d : 9 digit presco card number"); + PrintAndLog(" H : 8 digit hex card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf presco sim d 123456789"); + return 0; +} + +// convert base 12 ID to sitecode & usercode & 8 bit other unknown code +int GetWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) { + + uint8_t val = 0; + bool hex = false, errors = false; + uint8_t cmdp = 0; + char id[11]; + int stringlen = 0; + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + return -1; + case 'H': + hex = true; + //get hex + *fullcode = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp+=2; + break; + case 'P': + case 'p': + //param get string int param_getstr(const char *line, int paramnum, char * str) + stringlen = param_getstr(Cmd, cmdp+1, id); + if (stringlen < 2) return -1; + cmdp+=2; + break; + case 'Q': + case 'q': + *Q5 = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = 1; + break; + } + if(errors) break; + } + // No args + if(cmdp == 0) errors = 1; + + //Validations + if(errors) return -1; + + if (!hex) { + for (int index =0; index < strlen(id); ++index) { + // Get value from number string. + if ( id[index] == '*' ) val = 10; + if ( id[index] == '#') val = 11; + if ( id[index] >= 0x30 && id[index] <= 0x39 ) + val = id[index] - 0x30; + + *fullcode += val; + + // last digit is only added, not multipled. + if ( index < strlen(id)-1 ) + *fullcode *= 12; + } + } + + *usercode = *fullcode & 0x0000FFFF; //% 65566 + *sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216; + return 0; +} + +// calc not certain - intended to get bitstream for programming / sim +int GetPrescoBits(uint32_t fullcode, uint8_t *prescoBits) { + num_to_bytebits(0x10D00000, 32, prescoBits); + num_to_bytebits(0x00000000, 32, prescoBits+32); + num_to_bytebits(0x00000000, 32, prescoBits+64); + num_to_bytebits(fullcode , 32, prescoBits+96); + return 1; +} + +//see ASKDemod for what args are accepted +int CmdPrescoDemod(const char *Cmd) { + if (!ASKDemod(Cmd, false, false, 1)) { + if (g_debugMode) PrintAndLog("ASKDemod failed"); + return 0; + } + size_t size = DemodBufferLen; + //call lfdemod.c demod for Viking + int ans = PrescoDemod(DemodBuffer, &size); + if (ans < 0) { + if (g_debugMode) PrintAndLog("Error Presco_Demod %d", ans); + return 0; + } + //got a good demod + uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans, 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); + uint32_t raw3 = bytebits_to_byte(DemodBuffer+ans+64, 32); + uint32_t raw4 = bytebits_to_byte(DemodBuffer+ans+96, 32); + uint32_t cardid = raw4; + PrintAndLog("Presco Tag Found: Card ID %08X", cardid); + PrintAndLog("Raw: %08X%08X%08X%08X", raw1,raw2,raw3,raw4); + setDemodBuf(DemodBuffer+ans, 128, 0); + + uint32_t sitecode = 0, usercode = 0, fullcode = 0; + bool Q5=false; + char cmd[12] = {0}; + sprintf(cmd, "H %08X", cardid); + GetWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); + PrintAndLog("SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode); + + return 1; +} + +//see ASKDemod for what args are accepted +int CmdPrescoRead(const char *Cmd) { + // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 + + // read lf silently + CmdLFRead("s"); + // get samples silently + getSamples("30000",false); + // demod and output Presco ID + return CmdPrescoDemod(Cmd); +} + +// takes base 12 ID converts to hex +// Or takes 8 digit hex ID +int CmdPrescoClone(const char *Cmd) { + + bool Q5 = false; + uint32_t sitecode=0, usercode=0, fullcode=0; + uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4<=0; i--) { + c.arg[0] = blocks[i]; + c.arg[1] = i; + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ + PrintAndLog("Error occurred, device did not respond during write operation."); + return -1; + } + } + return 0; +} + +// takes base 12 ID converts to hex +// Or takes 8 digit hex ID +int CmdPrescoSim(const char *Cmd) { + uint32_t sitecode=0, usercode=0, fullcode=0; + bool Q5=false; + // get wiegand from printed number. + if (GetWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == -1) return usage_lf_presco_sim(); + + uint8_t clk = 32, encoding = 1, separator = 1, invert = 0; + uint16_t arg1, arg2; + size_t size = 128; + arg1 = clk << 8 | encoding; + arg2 = invert << 8 | separator; + + PrintAndLog("Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode); + + UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; + GetPrescoBits(fullcode, c.d.asBytes); + clearCommandBuffer(); + SendCommand(&c); + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"read", CmdPrescoRead, 0, "Attempt to read and Extract tag data"}, + {"clone", CmdPrescoClone, 0, "d <9 digit ID> or h [Q5] clone presco tag"}, + {"sim", CmdPrescoSim, 0, "d <9 digit ID> or h simulate presco tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFPresco(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfpresco.h b/client/cmdlfpresco.h new file mode 100644 index 00000000..801df8a9 --- /dev/null +++ b/client/cmdlfpresco.h @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency T55xx commands +//----------------------------------------------------------------------------- +#ifndef CMDLFPRESCO_H__ +#define CMDLFPRESCO_H__ + +#include //uint_32+ +#include //bool + +int CmdLFPresco(const char *Cmd); +int CmdPrescoClone(const char *Cmd); +int CmdPrescoSim(const char *Cmd); + +int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5); + +int usage_lf_presco_clone(void); +int usage_lf_presco_sim(void); +#endif + diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c new file mode 100644 index 00000000..7c19fbdb --- /dev/null +++ b/client/cmdlfpyramid.c @@ -0,0 +1,199 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Farpoint / Pyramid tag commands +//----------------------------------------------------------------------------- +#include +#include +#include "cmdlfpyramid.h" +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "crc.h" + +static int CmdHelp(const char *Cmd); + +int usage_lf_pyramid_clone(void){ + PrintAndLog("clone a Farpointe/Pyramid tag to a T55x7 tag."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf pyramid clone "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(" Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); + PrintAndLog(""); + PrintAndLog("Sample : lf pyramid clone 123 11223"); + return 0; +} + +int usage_lf_pyramid_sim(void) { + PrintAndLog("Enables simulation of Farpointe/Pyramid card with specified card number."); + PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf pyramid sim "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf pyramid sim 123 11223"); + return 0; +} + +// Works for 26bits. +int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { + + uint8_t pre[128]; + memset(pre, 0x00, sizeof(pre)); + + // format start bit + pre[79] = 1; + + // Get 26 wiegand from FacilityCode, CardNumber + uint8_t wiegand[24]; + memset(wiegand, 0x00, sizeof(wiegand)); + num_to_bytebits(fc, 8, wiegand); + num_to_bytebits(cn, 16, wiegand+8); + + // add wiegand parity bits (dest, source, len) + wiegand_add_parity(pre+80, wiegand, 24); + + // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) + addParity(pre+8, pyramidBits+8, 102, 8, 1); + + // add checksum + uint8_t csBuff[13]; + for (uint8_t i = 0; i < 13; i++) + csBuff[i] = bytebits_to_byte(pyramidBits + 16 + (i*8), 8); + + uint32_t crc = CRC8Maxim(csBuff, 13); + num_to_bytebits(crc, 8, pyramidBits+120); + return 1; +} + +int CmdPyramidRead(const char *Cmd) { + CmdLFRead("s"); + getSamples("30000",false); + return CmdFSKdemodPyramid(""); +} + +int CmdPyramidClone(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); + + uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; + uint32_t blocks[5]; + uint8_t i; + uint8_t bs[128]; + memset(bs, 0x00, sizeof(bs)); + + if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_pyramid_clone(); + + facilitycode = (fc & 0x000000FF); + cardnumber = (cn & 0x0000FFFF); + + if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { + PrintAndLog("Error with tag bitstream generation."); + return 1; + } + + //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks + blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4< clone pyramid tag"}, + {"sim", CmdPyramidSim, 0, " simulate pyramid tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFPyramid(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfpyramid.h b/client/cmdlfpyramid.h new file mode 100644 index 00000000..73e8338a --- /dev/null +++ b/client/cmdlfpyramid.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency T55xx commands +//----------------------------------------------------------------------------- +#ifndef CMDLFPYRAMID_H__ +#define CMDLFPYRAMID_H__ + +int CmdLFPyramid(const char *Cmd); +int CmdPyramidClone(const char *Cmd); +int CmdPyramidSim(const char *Cmd); + +int usage_lf_pyramid_clone(void); +int usage_lf_pyramid_sim(void); +#endif + diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index dfee9aa6..9e4883c7 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -48,6 +48,7 @@ int usage_t55xx_config(){ PrintAndLog(" i [1] Invert data signal, defaults to normal"); PrintAndLog(" o [offset] Set offset, where data should start decode in bitstream"); PrintAndLog(" Q5 Set as Q5(T5555) chip instead of T55x7"); + PrintAndLog(" ST Set Sequence Terminator on"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx config d FSK - FSK demodulation"); @@ -75,7 +76,7 @@ int usage_t55xx_read(){ return 0; } int usage_t55xx_write(){ - PrintAndLog("Usage: lf t55xx wr [b ] [d ] [p ] [1]"); + PrintAndLog("Usage: lf t55xx write [b ] [d ] [p ] [1]"); PrintAndLog("Options:"); PrintAndLog(" b - block number to write. Between 0-7"); PrintAndLog(" d - 4 bytes of data to write (8 hex characters)"); @@ -83,8 +84,8 @@ int usage_t55xx_write(){ PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wr b 3 d 11223344 - write 11223344 to block 3"); - PrintAndLog(" lf t55xx wr b 3 d 11223344 p feedbeef - write 11223344 to block 3 password feedbeef"); + PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); + PrintAndLog(" lf t55xx write b 3 d 11223344 p feedbeef - write 11223344 to block 3 password feedbeef"); PrintAndLog(""); return 0; } @@ -270,6 +271,11 @@ int CmdT55xxSetConfig(const char *Cmd) { config.Q5 = TRUE; cmdp++; break; + case 'S': + case 's': + config.ST = TRUE; + cmdp++; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = TRUE; @@ -370,6 +376,7 @@ bool DecodeT55xxBlock(){ char buf[30] = {0x00}; char *cmdStr = buf; int ans = 0; + bool ST = config.ST; uint8_t bitRate[8] = {8,16,32,40,50,64,100,128}; DemodBufferLen = 0x00; @@ -390,7 +397,7 @@ bool DecodeT55xxBlock(){ break; case DEMOD_ASK: snprintf(cmdStr, sizeof(buf),"%d %d 1", bitRate[config.bitrate], config.inverted ); - ans = ASKDemod(cmdStr, FALSE, FALSE, 1); + ans = ASKDemod_ext(cmdStr, FALSE, FALSE, 1, &ST); break; case DEMOD_PSK1: // skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise) @@ -482,7 +489,6 @@ bool tryDetectModulation(){ t55xx_conf_block_t tests[15]; int bitRate=0; uint8_t fc1 = 0, fc2 = 0, clk=0; - if (GetFskClock("", FALSE, FALSE)){ fskClocks(&fc1, &fc2, &clk, FALSE); if ( FSKrawDemod("0 0", FALSE) && test(DEMOD_FSK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { @@ -494,6 +500,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } if ( FSKrawDemod("0 1", FALSE) && test(DEMOD_FSK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { @@ -505,19 +512,22 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = TRUE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } } else { clk = GetAskClock("", FALSE, FALSE); if (clk>0) { - if ( ASKDemod("0 0 1", FALSE, FALSE, 1) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { + tests[hits].ST = TRUE; + if ( ASKDemod_ext("0 0 1", FALSE, FALSE, 1, &tests[hits].ST) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { tests[hits].modulation = DEMOD_ASK; tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); ++hits; } - if ( ASKDemod("0 1 1", FALSE, FALSE, 1) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { + tests[hits].ST = TRUE; + if ( ASKDemod_ext("0 1 1", FALSE, FALSE, 1, &tests[hits].ST) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { tests[hits].modulation = DEMOD_ASK; tests[hits].bitrate = bitRate; tests[hits].inverted = TRUE; @@ -529,6 +539,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } if ( ASKbiphaseDemod("0 0 1 2", FALSE) && test(DEMOD_BIa, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5) ) { @@ -536,6 +547,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = TRUE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } } @@ -548,6 +560,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } @@ -556,6 +569,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = TRUE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } } @@ -571,6 +585,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } if ( PSKDemod("0 1 6", FALSE) && test(DEMOD_PSK1, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) { @@ -578,6 +593,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = TRUE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } // PSK2 - needs a call to psk1TOpsk2. @@ -588,6 +604,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } } // inverse waves does not affect this demod @@ -599,6 +616,7 @@ bool tryDetectModulation(){ tests[hits].bitrate = bitRate; tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); + tests[hits].ST = FALSE; ++hits; } } // inverse waves does not affect this demod @@ -613,6 +631,7 @@ bool tryDetectModulation(){ config.offset = tests[0].offset; config.block0 = tests[0].block0; config.Q5 = tests[0].Q5; + config.ST = tests[0].ST; printConfiguration( config ); return TRUE; } @@ -765,14 +784,14 @@ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5) uint8_t extend = PackBits(si, 1, DemodBuffer); si += 1; //bit 15 extended mode uint8_t modread = PackBits(si, 5, DemodBuffer); si += 5+2+1; //uint8_t pskcr = PackBits(si, 2, DemodBuffer); si += 2+1; //could check psk cr - uint8_t nml01 = PackBits(si, 1, DemodBuffer); si += 1+5; //bit 24, 30, 31 could be tested for 0 if not extended mode - uint8_t nml02 = PackBits(si, 2, DemodBuffer); si += 2; + //uint8_t nml01 = PackBits(si, 1, DemodBuffer); si += 1+5; //bit 24, 30, 31 could be tested for 0 if not extended mode + //uint8_t nml02 = PackBits(si, 2, DemodBuffer); si += 2; //if extended mode bool extMode =( (safer == 0x6 || safer == 0x9) && extend) ? TRUE : FALSE; if (!extMode){ - if (nml01 || nml02 || xtRate) continue; + if (xtRate) continue; //nml01 || nml02 || caused issues on noralys tags } //test modulation if (!testModulation(mode, modread)) continue; @@ -836,6 +855,7 @@ int printConfiguration( t55xx_conf_block_t b){ PrintAndLog("Bit Rate : %s", GetBitRateStr(b.bitrate) ); PrintAndLog("Inverted : %s", (b.inverted) ? "Yes" : "No" ); PrintAndLog("Offset : %d", b.offset); + PrintAndLog("Seq. Term. : %s", (b.ST) ? "Yes" : "No" ); PrintAndLog("Block0 : 0x%08X", b.block0); PrintAndLog(""); return 0; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 8ad98597..5c2ec79d 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -63,6 +63,7 @@ typedef struct { RF_128 = 0x07, } bitrate; bool Q5; + bool ST; } t55xx_conf_block_t; t55xx_conf_block_t Get_t55xx_Config(); void Set_t55xx_Config(t55xx_conf_block_t conf); diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 45e4b1d5..fa073df1 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -47,8 +47,8 @@ int usage_lf_viking_sim(void) { uint64_t getVikingBits(uint32_t id) { //calc checksum - uint8_t checksum = (id>>24) ^ ((id>>16) & 0xFF) ^ ((id>>8) & 0xFF) ^ (id & 0xFF) ^ 0xF2 ^ 0xA8; - return ((uint64_t)0xF2 << 56) | (id << 8) | checksum; + uint8_t checksum = ((id>>24) & 0xFF) ^ ((id>>16) & 0xFF) ^ ((id>>8) & 0xFF) ^ (id & 0xFF) ^ 0xF2 ^ 0xA8; + return ((uint64_t)0xF2 << 56) | ((uint64_t)id << 8) | checksum; } //by marshmellow //see ASKDemod for what args are accepted diff --git a/client/fpga_compress.c b/client/fpga_compress.c index 0c40f22f..28154243 100644 --- a/client/fpga_compress.c +++ b/client/fpga_compress.c @@ -19,25 +19,26 @@ #define MAX(a,b) ((a)>(b)?(a):(b)) // zlib configuration -#define COMPRESS_LEVEL 9 // use best possible compression -#define COMPRESS_WINDOW_BITS 15 // default = max = 15 for a window of 2^15 = 32KBytes -#define COMPRESS_MEM_LEVEL 9 // determines the amount of memory allocated during compression. Default = 8. +#define COMPRESS_LEVEL 9 // use best possible compression +#define COMPRESS_WINDOW_BITS 15 // default = max = 15 for a window of 2^15 = 32KBytes +#define COMPRESS_MEM_LEVEL 9 // determines the amount of memory allocated during compression. Default = 8. /* COMPRESS_STRATEGY can be Z_DEFAULT_STRATEGY (the default), Z_FILTERED (more huffmann, less string matching), Z_HUFFMAN_ONLY (huffman only, no string matching) Z_RLE (distances limited to one) Z_FIXED (prevents the use of dynamic Huffman codes) -*/ -#define COMPRESS_STRATEGY Z_DEFAULT_STRATEGY +*/ + +#define COMPRESS_STRATEGY Z_DEFAULT_STRATEGY // zlib tuning parameters: -#define COMPRESS_GOOD_LENGTH 258 -#define COMPRESS_MAX_LAZY 258 -#define COMPRESS_MAX_NICE_LENGTH 258 -#define COMPRESS_MAX_CHAIN 8192 +#define COMPRESS_GOOD_LENGTH 258 +#define COMPRESS_MAX_LAZY 258 +#define COMPRESS_MAX_NICE_LENGTH 258 +#define COMPRESS_MAX_CHAIN 8192 -#define FPGA_INTERLEAVE_SIZE 288 // (the FPGA's internal config frame size is 288 bits. Interleaving with 288 bytes should give best compression) -#define FPGA_CONFIG_SIZE 42336 // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#define FPGA_INTERLEAVE_SIZE 288 // (the FPGA's internal config frame size is 288 bits. Interleaving with 288 bytes should give best compression) +#define FPGA_CONFIG_SIZE 42336 // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE static void usage(void) { @@ -76,8 +77,8 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) { uint8_t *fpga_config; uint32_t i; - int ret; - uint8_t c; + int32_t ret; + uint8_t c; z_stream compressed_fpga_stream; fpga_config = malloc(num_infiles * FPGA_CONFIG_SIZE); @@ -87,7 +88,7 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) do { if (i >= num_infiles * FPGA_CONFIG_SIZE) { - fprintf(stderr, "Input files too big (total > %lu bytes). These are probably not PM3 FPGA config files.\n", num_infiles*FPGA_CONFIG_SIZE); + fprintf(stderr, "Input files too big (total > %u bytes). These are probably not PM3 FPGA config files.\n", num_infiles*FPGA_CONFIG_SIZE); for(uint16_t j = 0; j < num_infiles; j++) { fclose(infile[j]); } @@ -122,11 +123,11 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) COMPRESS_STRATEGY); // estimate the size of the compressed output - unsigned int outsize_max = deflateBound(&compressed_fpga_stream, compressed_fpga_stream.avail_in); + uint32_t outsize_max = deflateBound(&compressed_fpga_stream, compressed_fpga_stream.avail_in); uint8_t *outbuf = malloc(outsize_max); compressed_fpga_stream.next_out = outbuf; compressed_fpga_stream.avail_out = outsize_max; - + if (ret == Z_OK) { ret = deflateTune(&compressed_fpga_stream, COMPRESS_GOOD_LENGTH, @@ -139,10 +140,10 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) ret = deflate(&compressed_fpga_stream, Z_FINISH); } - fprintf(stderr, "compressed %lu input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out); + fprintf(stderr, "compressed %u input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out); if (ret != Z_STREAM_END) { - fprintf(stderr, "Error in deflate(): %d %s\n", ret, compressed_fpga_stream.msg); + fprintf(stderr, "Error in deflate(): %i %s\n", ret, compressed_fpga_stream.msg); free(outbuf); deflateEnd(&compressed_fpga_stream); for(uint16_t j = 0; j < num_infiles; j++) { @@ -177,7 +178,7 @@ int zlib_decompress(FILE *infile, FILE *outfile) #define DECOMPRESS_BUF_SIZE 1024 uint8_t outbuf[DECOMPRESS_BUF_SIZE]; uint8_t inbuf[DECOMPRESS_BUF_SIZE]; - int ret; + int32_t ret; z_stream compressed_fpga_stream; @@ -197,7 +198,7 @@ int zlib_decompress(FILE *infile, FILE *outfile) compressed_fpga_stream.next_in = inbuf; uint16_t i = 0; do { - int c = fgetc(infile); + int32_t c = fgetc(infile); if (!feof(infile)) { inbuf[i++] = c & 0xFF; compressed_fpga_stream.avail_in++; @@ -232,7 +233,7 @@ int zlib_decompress(FILE *infile, FILE *outfile) fclose(infile); return(EXIT_SUCCESS); } else { - fprintf(stderr, "Error. Inflate() returned error %d, %s", ret, compressed_fpga_stream.msg); + fprintf(stderr, "Error. Inflate() returned error %i, %s", ret, compressed_fpga_stream.msg); fclose(outfile); fclose(infile); return(EXIT_FAILURE); @@ -251,7 +252,7 @@ int main(int argc, char **argv) return(EXIT_FAILURE); } - if (!strcmp(argv[1], "-d")) { // Decompress + if (!strcmp(argv[1], "-d")) { // Decompress infiles = calloc(1, sizeof(FILE*)); if (argc != 4) { usage(); @@ -269,7 +270,7 @@ int main(int argc, char **argv) } return zlib_decompress(infiles[0], outfile); - } else { // Compress + } else { // Compress infiles = calloc(argc-2, sizeof(FILE*)); for (uint16_t i = 0; i < argc-2; i++) { diff --git a/client/graph.c b/client/graph.c index 06279848..319cde39 100644 --- a/client/graph.c +++ b/client/graph.c @@ -143,9 +143,13 @@ int GetAskClock(const char str[], bool printAns, bool verbose) PrintAndLog("Failed to copy from graphbuffer"); return -1; } - int start = DetectASKClock(grph, size, &clock, 20); + bool st = DetectST(grph, &size, &clock); + int start = 0; + if (st == false) { + start = DetectASKClock(grph, size, &clock, 20); + } // Only print this message if we're not looping something - if (printAns){ + if (printAns) { PrintAndLog("Auto-detected clock rate: %d, Best Starting Position: %d", clock, start); } return clock; diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index 46738181..bdf18912 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -107,6 +107,12 @@ typedef struct { #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 +#define CMD_SIMULATE_HITAG_S 0x0368 +#define CMD_TEST_HITAGS_TRACES 0x0367 +#define CMD_READ_HITAG_S 0x0373 +#define CMD_WR_HITAG_S 0x0375 +#define CMD_EMU_HITAG_S 0x0376 + #define CMD_SIMULATE_TAG_ISO_14443B 0x0381 #define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 diff --git a/client/lualibs/mf_default_keys.lua b/client/lualibs/mf_default_keys.lua index 804d4a84..4dee8b4d 100644 --- a/client/lualibs/mf_default_keys.lua +++ b/client/lualibs/mf_default_keys.lua @@ -106,7 +106,7 @@ local _keys = { '776974687573', -- RKF ÖstgötaTrafiken Key B --[[ - The keys below are taken from from https://code.google.com/p/mifare-key-cracker/downloads/list + The keys below are taken from https://code.google.com/p/mifare-key-cracker/downloads/list --]] 'bd493a3962b6', @@ -129,7 +129,7 @@ local _keys = { '123456789abc', --[[ - The keys below are taken from from https://github.com/4ZM/mfterm/blob/master/dictionary.txt + The keys below are taken from https://github.com/4ZM/mfterm/blob/master/dictionary.txt --]] 'abcdef123456', -- Key from ladyada.net @@ -199,7 +199,7 @@ local function uniq(list) table.insert(foobar, value); end end - --print("final list length length ", #foobar) + --print("final list length ", #foobar) return foobar end diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 70d874fe..5647c424 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -149,3 +149,140 @@ int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_ return 1; } + +// 32 bit recover key from 2 nonces +bool mfkey32(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s,*t; + uint64_t outkey = 0; + uint64_t key=0; // recovered key + uint32_t uid = data.cuid; + uint32_t nt = data.nonce; // first tag challenge (nonce) + uint32_t nr0_enc = data.nr; // first encrypted reader challenge + uint32_t ar0_enc = data.ar; // first encrypted reader response + uint32_t nr1_enc = data.nr2; // second encrypted reader challenge + uint32_t ar1_enc = data.ar2; // second encrypted reader response + clock_t t1 = clock(); + bool isSuccess = FALSE; + uint8_t counter=0; + + s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, nr0_enc, 1); + lfsr_rollback_word(t, uid ^ nt, 0); + crypto1_get_lfsr(t, &key); + crypto1_word(t, uid ^ nt, 0); + crypto1_word(t, nr1_enc, 1); + if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) { + //PrintAndLog("Found Key: [%012"llx"]",key); + outkey = key; + counter++; + if (counter==20) break; + } + } + isSuccess = (counter == 1); + t1 = clock() - t1; + //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.0f ticks \nFound %d possible keys", (float)t1, counter); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + /* //un-comment to save all keys to a stats.txt file + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + */ + return isSuccess; +} + +bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s, *t; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + uint32_t uid = data.cuid; + uint32_t nt0 = data.nonce; // first tag challenge (nonce) + uint32_t nr0_enc = data.nr; // first encrypted reader challenge + uint32_t ar0_enc = data.ar; // first encrypted reader response + uint32_t nt1 = data.nonce2; // second tag challenge (nonce) + uint32_t nr1_enc = data.nr2; // second encrypted reader challenge + uint32_t ar1_enc = data.ar2; // second encrypted reader response + bool isSuccess = FALSE; + int counter = 0; + + //PrintAndLog("Enter mfkey32_moebius"); + clock_t t1 = clock(); + + s = lfsr_recovery32(ar0_enc ^ prng_successor(nt0, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, nr0_enc, 1); + lfsr_rollback_word(t, uid ^ nt0, 0); + crypto1_get_lfsr(t, &key); + + crypto1_word(t, uid ^ nt1, 0); + crypto1_word(t, nr1_enc, 1); + if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt1, 64))) { + //PrintAndLog("Found Key: [%012"llx"]",key); + outkey=key; + ++counter; + if (counter==20) + break; + } + } + isSuccess = (counter == 1); + t1 = clock() - t1; + //if ( t1 > 0 ) PrintAndLog("Time in mfkey32_moebius: %.0f ticks \nFound %d possible keys", (float)t1,counter); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + /* // un-comment to output all keys to stats.txt + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + */ + return isSuccess; +} + +int tryMfk64_ex(uint8_t *data, uint64_t *outputkey){ + uint32_t uid = le32toh(data); + uint32_t nt = le32toh(data+4); // tag challenge + uint32_t nr_enc = le32toh(data+8); // encrypted reader challenge + uint32_t ar_enc = le32toh(data+12); // encrypted reader response + uint32_t at_enc = le32toh(data+16); // encrypted tag response + return tryMfk64(uid, nt, nr_enc, ar_enc, at_enc, outputkey); +} + +int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey){ + uint64_t key = 0; // recovered key + uint32_t ks2; // keystream used to encrypt reader response + uint32_t ks3; // keystream used to encrypt tag response + struct Crypto1State *revstate; + + PrintAndLog("Enter mfkey64"); + clock_t t1 = clock(); + + // Extract the keystream from the messages + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + crypto1_get_lfsr(revstate, &key); + PrintAndLog("Found Key: [%012"llx"]", key); + crypto1_destroy(revstate); + *outputkey = key; + + t1 = clock() - t1; + if ( t1 > 0 ) PrintAndLog("Time in mfkey64: %.0f ticks \n", (float)t1); + return 0; +} + diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key/nonce2key.h index e7d5f431..fac9c151 100644 --- a/client/nonce2key/nonce2key.h +++ b/client/nonce2key/nonce2key.h @@ -17,7 +17,26 @@ #include #include "crapto1.h" #include "common.h" +//#include //for bool + +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; + } nonces_t; int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key); +bool mfkey32(nonces_t data, uint64_t *outputkey); +bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey); +int tryMfk64_ex(uint8_t *data, uint64_t *outputkey); +int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey); + +//uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc); #endif diff --git a/client/proxgui.h b/client/proxgui.h index 6fcf4d0a..94b47acd 100644 --- a/client/proxgui.h +++ b/client/proxgui.h @@ -19,7 +19,7 @@ void MainGraphics(void); void InitGraphics(int argc, char **argv); void ExitGraphics(void); -#define MAX_GRAPH_TRACE_LEN (1024*128) +#define MAX_GRAPH_TRACE_LEN (40000*8) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; extern int GraphTraceLen; extern double CursorScaleFactor; diff --git a/client/util.c b/client/util.c index e5cbc4aa..e4add6c0 100644 --- a/client/util.c +++ b/client/util.c @@ -94,7 +94,7 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) memset(fileName, 0x00, 200); for (int j = 0; j < byteCount; j++, fnameptr += 2) - sprintf(fnameptr, "%02x", uid[j]); + sprintf(fnameptr, "%02x", (unsigned int) uid[j]); sprintf(fnameptr, "%s", ext); } @@ -119,7 +119,7 @@ char *sprint_hex(const uint8_t *data, const size_t len) { size_t i; for (i=0; i < maxLen; ++i, tmp += 3) - sprintf(tmp, "%02x ", data[i]); + sprintf(tmp, "%02x ", (unsigned int) data[i]); return buf; } @@ -142,7 +142,7 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea for (size_t out_index=0; out_index < max_len; out_index++) { // set character - (should be binary but verify it isn't more than 1 digit) if (data[in_index]<10) - sprintf(tmp++, "%u", data[in_index]); + sprintf(tmp++, "%u", (unsigned int) data[in_index]); // check if a line break is needed and we have room to print it in our array if ( (breaks > 0) && !((in_index+1) % breaks) && (out_index+1 != max_len) ) { // increment and print line break @@ -215,7 +215,7 @@ char * printBits(size_t const size, void const * const ptr) { byte = b[i] & (1<>= j; - sprintf(tmp, "%u", byte); + sprintf(tmp, "%u", (unsigned int)byte); tmp++; } } @@ -451,7 +451,7 @@ int binarraytohex(char *target,char *source, int length) { for(i= x= 0 ; i < 4 ; ++i) x += ( source[i] << (3 - i)); - sprintf(target,"%X", x); + sprintf(target,"%X", (unsigned int)x); ++target; source += 4; j -= 4; @@ -498,6 +498,9 @@ void xor(unsigned char *dst, unsigned char *src, size_t len) { int32_t le24toh (uint8_t data[3]) { return (data[2] << 16) | (data[1] << 8) | data[0]; } +uint32_t le32toh (uint8_t *data) { + return (uint32_t)( (data[3]<<24) | (data[2]<<16) | (data[1]<<8) | data[0]); +} // RotateLeft - Ultralight, Desfire, works on byte level // 00-01-02 >> 01-02-00 diff --git a/client/util.h b/client/util.h index 5674adcf..1b6b2fb1 100644 --- a/client/util.h +++ b/client/util.h @@ -9,13 +9,12 @@ //----------------------------------------------------------------------------- #include -#include -#include +#include //included in data.h #include #include #include #include -#include "data.h" +#include "data.h" //for FILE_PATH_SIZE #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) @@ -71,4 +70,5 @@ void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length); void xor(unsigned char *dst, unsigned char *src, size_t len); int32_t le24toh(uint8_t data[3]); +uint32_t le32toh (uint8_t *data); void rol(uint8_t *data, const size_t len); diff --git a/common/default_version.c b/common/default_version.c index 9f818bed..b564681c 100644 --- a/common/default_version.c +++ b/common/default_version.c @@ -2,7 +2,7 @@ /* This is the default version.c file that Makefile.common falls back to if perl is not available */ const struct version_information __attribute__((section(".version_information"))) version_information = { VERSION_INFORMATION_MAGIC, - 1, /* version version 1 */ + 1, /* version 1 */ 0, /* version information not present */ 2, /* cleanliness couldn't be determined */ /* Remaining fields: zero */ diff --git a/common/lfdemod.c b/common/lfdemod.c index 982a724a..7d40df3a 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -9,11 +9,10 @@ //----------------------------------------------------------------------------- #include -#include #include "lfdemod.h" -#include "common.h" +#include -//un_comment to allow debug print calls when used not on device +//to allow debug print calls when used not on device void dummy(char *fmt, ...){} #ifndef ON_DEVICE @@ -69,7 +68,7 @@ uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType) // by marshmellow // takes a array of binary values, start position, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 for Always 1's; 3 for Always 0's), and binary Length (length to run) size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen) { uint32_t parityWd = 0; @@ -81,10 +80,10 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p } j--; // overwrite parity with next data // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - if (!BitStream[j]) return 0; - } else { - if (parityTest(parityWd, pLen, pType) == 0) return 0; + switch (pType) { + case 3: if (BitStream[j]==1) {return 0;} break; //should be 0 spacer bit + case 2: if (BitStream[j]==0) {return 0;} break; //should be 1 spacer bit + default: if (parityTest(parityWd, pLen, pType) == 0) {return 0;} break; //test parity } bitCnt+=(pLen-1); parityWd = 0; @@ -96,7 +95,8 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p // by marshmellow // takes a array of binary values, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) +// Make sure *dest is long enough to store original sourceLen + #_of_parities_to_be_added size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType) { uint32_t parityWd = 0; @@ -107,10 +107,12 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p dest[j++] = (BitSource[word+bit]); } // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - dest[j++]=1; - } else { - dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + switch (pType) { + case 3: dest[j++]=0; break; // marker bit which should be a 0 + case 2: dest[j++]=1; break; // marker bit which should be a 1 + default: + dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + break; } bitCnt += pLen; parityWd = 0; @@ -218,6 +220,7 @@ int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int if (smplCnt > clk-(clk/4)-1) { //full clock if (smplCnt > clk + (clk/4)+1) { //too many samples errCnt++; + if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); BinStream[bitCnt++]=7; } else if (waveHigh) { BinStream[bitCnt++] = invert; @@ -256,11 +259,14 @@ int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int //by marshmellow void askAmp(uint8_t *BitStream, size_t size) { + uint8_t Last = 128; for(size_t i = 1; i=30) //large jump up - BitStream[i]=127; - else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down - BitStream[i]=-127; + Last = 255; + else if(BitStream[i-1]-BitStream[i]>=20) //large jump down + Last = 0; + + BitStream[i-1] = Last; } return; } @@ -274,7 +280,7 @@ int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr if (*clk==0 || start < 0) return -3; if (*invert != 1) *invert = 0; if (amp==1) askAmp(BinStream, *size); - if (g_debugMode==2) prnt("DEBUG: clk %d, beststart %d", *clk, start); + if (g_debugMode==2) prnt("DEBUG ASK: clk %d, beststart %d", *clk, start); uint8_t initLoopMax = 255; if (initLoopMax > *size) initLoopMax = *size; @@ -287,20 +293,21 @@ int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr size_t errCnt = 0; // if clean clipped waves detected run alternate demod if (DetectCleanAskWave(BinStream, *size, high, low)) { - if (g_debugMode==2) prnt("DEBUG: Clean Wave Detected"); + if (g_debugMode==2) prnt("DEBUG ASK: Clean Wave Detected - using clean wave demod"); errCnt = cleanAskRawDemod(BinStream, size, *clk, *invert, high, low); if (askType) //askman return manrawdecode(BinStream, size, 0); else //askraw return errCnt; } + if (g_debugMode==2) prnt("DEBUG ASK: Weak Wave Detected - using weak wave demod"); - int lastBit; //set first clock check - can go negative + int lastBit; //set first clock check - can go negative size_t i, bitnum = 0; //output counter uint8_t midBit = 0; uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - size_t MaxBits = 3072; + if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + size_t MaxBits = 3072; //max bits to collect lastBit = start - *clk; for (i = start; i < *size; ++i) { @@ -311,6 +318,7 @@ int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr BinStream[bitnum++] = *invert ^ 1; } else if (i-lastBit >= *clk+tol) { if (bitnum > 0) { + if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); BinStream[bitnum++]=7; errCnt++; } @@ -458,10 +466,10 @@ int gProxII_Demod(uint8_t BitStream[], size_t *size) //return start position return (int) startIdx; } - return -5; + return -5; //spacer bits not found - not a valid gproxII } -//translate wave to 11111100000 (1 for each short wave 0 for each long wave) +//translate wave to 11111100000 (1 for each short wave [higher freq] 0 for each long wave [lower freq]) size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow) { size_t last_transition = 0; @@ -483,8 +491,9 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow size_t numBits = 0; // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8) - // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere + // or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10 + // (could also be fc/5 && fc/7 for fsk1 = 4-9) for(idx = 161; idx < size-20; idx++) { // threshold current value @@ -492,23 +501,24 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow else dest[idx] = 1; // Check for 0->1 transition - if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition + if (dest[idx-1] < dest[idx]) { preLastSample = LastSample; LastSample = currSample; currSample = idx-last_transition; - if (currSample < (fclow-2)){ //0-5 = garbage noise (or 0-3) + if (currSample < (fclow-2)) { //0-5 = garbage noise (or 0-3) //do nothing with extra garbage - } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves or 3-6 = 5 + } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves (or 3-6 = 5) + //correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5) if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample == 0 )){ - dest[numBits-1]=1; //correct previous 9 wave surrounded by 8 waves + dest[numBits-1]=1; } dest[numBits++]=1; - } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = garbage + } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage //do nothing with beginning garbage - } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's + } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's) dest[numBits++]=1; - } else { //9+ = 10 sample waves + } else { //9+ = 10 sample waves (or 6+ = 7) dest[numBits++]=0; } last_transition = idx; @@ -518,6 +528,7 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow } //translate 11111100000 to 10 +//rfLen = clock, fchigh = larger field clock, fclow = smaller field clock size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) { @@ -527,8 +538,9 @@ size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint32_t n=1; for( idx=1; idx < size; idx++) { n++; - if (dest[idx]==lastval) continue; + if (dest[idx]==lastval) continue; //skip until we hit a transition + //find out how many bits (n) we collected //if lastval was 1, we have a 1->0 crossing if (dest[idx-1]==1) { n = (n * fclow + rfLen/2) / rfLen; @@ -537,6 +549,7 @@ size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, } if (n == 0) n = 1; + //add to our destination the bits we collected memset(dest+numBits, dest[idx-1]^invert , n); numBits += n; n=0; @@ -678,6 +691,19 @@ int VikingDemod_AM(uint8_t *dest, size_t *size) { return (int) startIdx; } +// find presco preamble 0x10D in already demoded data +int PrescoDemod(uint8_t *dest, size_t *size) { + //make sure buffer has data + if (*size < 64*2) return -2; + + size_t startIdx = 0; + uint8_t preamble[] = {1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -4; //preamble not found + //return start position + return (int) startIdx; +} + // Ask/Biphase Demod then try to locate an ISO 11784/85 ID // BitStream must contain previously askrawdemod and biphasedemoded data int FDXBdemodBI(uint8_t *dest, size_t *size) @@ -1199,7 +1225,7 @@ int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert) return (int) startidx; } -// by marshmellow - demodulate NRZ wave +// by marshmellow - demodulate NRZ wave - requires a read with strong signal // peaks invert bit (high=1 low=0) each clock cycle = 1 bit determined by last peak int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert){ if (justNoise(dest, *size)) return -1; @@ -1476,8 +1502,8 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert) numBits += (firstFullWave / *clock); //set start of wave as clock align lastClkBit = firstFullWave; - //PrintAndLog("DEBUG: firstFullWave: %d, waveLen: %d",firstFullWave,fullWaveLen); - //PrintAndLog("DEBUG: clk: %d, lastClkBit: %d", *clock, lastClkBit); + if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen); + if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc); waveStart = 0; dest[numBits++] = curPhase; //set first read bit for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){ @@ -1518,3 +1544,166 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert) *size = numBits; return errCnt; } + +//by marshmellow +//attempt to identify a Sequence Terminator in ASK modulated raw wave +bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { + size_t bufsize = *size; + //need to loop through all samples and identify our clock, look for the ST pattern + uint8_t fndClk[] = {8,16,32,40,50,64,128}; + int clk = 0; + int tol = 0; + int i, j, skip, start, end, low, high, minClk, waveStart; + bool complete = false; + int tmpbuff[bufsize / 64]; + int waveLen[bufsize / 64]; + size_t testsize = (bufsize < 512) ? bufsize : 512; + int phaseoff = 0; + high = low = 128; + memset(tmpbuff, 0, sizeof(tmpbuff)); + + if ( getHiLo(buffer, testsize, &high, &low, 80, 80) == -1 ) { + if (g_debugMode==2) prnt("DEBUG STT: just noise detected - quitting"); + return false; //just noise + } + i = 0; + j = 0; + minClk = 255; + // get to first full low to prime loop and skip incomplete first pulse + while ((buffer[i] < high) && (i < bufsize)) + ++i; + while ((buffer[i] > low) && (i < bufsize)) + ++i; + skip = i; + + // populate tmpbuff buffer with pulse lengths + while (i < bufsize) { + // measure from low to low + while ((buffer[i] > low) && (i < bufsize)) + ++i; + start= i; + while ((buffer[i] < high) && (i < bufsize)) + ++i; + //first high point for this wave + waveStart = i; + while ((buffer[i] > low) && (i < bufsize)) + ++i; + if (j >= (bufsize/64)) { + break; + } + waveLen[j] = i - waveStart; //first high to first low + tmpbuff[j++] = i - start; + if (i-start < minClk && i < bufsize) { + minClk = i - start; + } + } + // set clock - might be able to get this externally and remove this work... + if (!clk) { + for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) { + tol = fndClk[clkCnt]/8; + if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) { + clk=fndClk[clkCnt]; + break; + } + } + // clock not found - ERROR + if (!clk) { + if (g_debugMode==2) prnt("DEBUG STT: clock not found - quitting"); + return false; + } + } else tol = clk/8; + + *foundclock = clk; + + // look for Sequence Terminator - should be pulses of clk*(1 or 1.5), clk*2, clk*(1.5 or 2) + start = -1; + for (i = 0; i < j - 4; ++i) { + skip += tmpbuff[i]; + if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol && waveLen[i] < clk+tol) { //1 to 2 clocks depending on 2 bits prior + if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol && waveLen[i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2 + if (tmpbuff[i+2] >= (clk*3)/2-tol && tmpbuff[i+2] <= clk*2+tol && waveLen[i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave + if (tmpbuff[i+3] >= clk*1-tol && tmpbuff[i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit + start = i + 3; + break; + } + } + } + } + } + // first ST not found - ERROR + if (start < 0) { + if (g_debugMode==2) prnt("DEBUG STT: first STT not found - quitting"); + return false; + } + if (waveLen[i+2] > clk*1+tol) + phaseoff = 0; + else + phaseoff = clk/2; + + // skip over the remainder of ST + skip += clk*7/2; //3.5 clocks from tmpbuff[i] = end of st - also aligns for ending point + + // now do it again to find the end + end = skip; + for (i += 3; i < j - 4; ++i) { + end += tmpbuff[i]; + if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol) { //1 to 2 clocks depending on 2 bits prior + if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol && waveLen[i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2 + if (tmpbuff[i+2] >= (clk*3)/2-tol && tmpbuff[i+2] <= clk*2+tol && waveLen[i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave + if (tmpbuff[i+3] >= clk*1-tol && tmpbuff[i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit + complete = true; + break; + } + } + } + } + } + end -= phaseoff; + //didn't find second ST - ERROR + if (!complete) { + if (g_debugMode==2) prnt("DEBUG STT: second STT not found - quitting"); + return false; + } + if (g_debugMode==2) prnt("DEBUG STT: start of data: %d end of data: %d, datalen: %d, clk: %d, bits: %d, phaseoff: %d", skip, end, end-skip, clk, (end-skip)/clk, phaseoff); + //now begin to trim out ST so we can use normal demod cmds + start = skip; + size_t datalen = end - start; + // check validity of datalen (should be even clock increments) - use a tolerance of up to 1/8th a clock + if (datalen % clk > clk/8) { + if (g_debugMode==2) prnt("DEBUG STT: datalen not divisible by clk: %u %% %d = %d - quitting", datalen, clk, datalen % clk); + return false; + } else { + // padd the amount off - could be problematic... but shouldn't happen often + datalen += datalen % clk; + } + // if datalen is less than one t55xx block - ERROR + if (datalen/clk < 8*4) { + if (g_debugMode==2) prnt("DEBUG STT: datalen is less than 1 full t55xx block - quitting"); + return false; + } + size_t dataloc = start; + size_t newloc = 0; + i=0; + // warning - overwriting buffer given with raw wave data with ST removed... + while ( dataloc < bufsize-(clk/2) ) { + //compensate for long high at end of ST not being high due to signal loss... (and we cut out the start of wave high part) + if (buffer[dataloc]low && buffer[dataloc+3]low) { + for(i=0; i < clk/2-tol; ++i) { + buffer[dataloc+i] = high+5; + } + } + for (i=0; i +#include // for uint_32+ +#include // for bool //generic size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType); @@ -28,6 +29,7 @@ uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t f int DetectNRZClock(uint8_t dest[], size_t size, int clock); int DetectPSKClock(uint8_t dest[], size_t size, int clock); int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low); +bool DetectST(uint8_t buffer[], size_t *size, int *foundclock); int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow); int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo); uint32_t manchesterEncode2Bytes(uint16_t datain); @@ -52,5 +54,5 @@ int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert); int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); int PyramiddemodFSK(uint8_t *dest, size_t *size); int VikingDemod_AM(uint8_t *dest, size_t *size); - +int PrescoDemod(uint8_t *dest, size_t *size); #endif diff --git a/common/protocols.h b/common/protocols.h index cdcf720b..b57c414f 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -109,20 +109,25 @@ NXP/Philips CUSTOM COMMANDS #define ISO14443A_CMD_WUPA 0x52 #define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 +#define ISO14443A_CMD_ANTICOLL_OR_SELECT_3 0x97 #define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? #define ISO14443A_CMD_HALT 0x50 #define ISO14443A_CMD_RATS 0xE0 -#define MIFARE_AUTH_KEYA 0x60 -#define MIFARE_AUTH_KEYB 0x61 -#define MIFARE_MAGICWUPC1 0x40 -#define MIFARE_MAGICWUPC2 0x43 -#define MIFARE_MAGICWIPEC 0x41 +#define MIFARE_AUTH_KEYA 0x60 +#define MIFARE_AUTH_KEYB 0x61 +#define MIFARE_MAGICWUPC1 0x40 +#define MIFARE_MAGICWUPC2 0x43 +#define MIFARE_MAGICWIPEC 0x41 #define MIFARE_CMD_INC 0xC0 #define MIFARE_CMD_DEC 0xC1 #define MIFARE_CMD_RESTORE 0xC2 #define MIFARE_CMD_TRANSFER 0xB0 +#define MIFARE_EV1_PERSONAL_UID 0x40 +#define MIFARE_EV1_SETMODE 0x43 + + #define MIFARE_ULC_WRITE 0xA2 //#define MIFARE_ULC__COMP_WRITE 0xA0 #define MIFARE_ULC_AUTH_1 0x1A diff --git a/include/common.h b/include/common.h index feed109c..998db64d 100644 --- a/include/common.h +++ b/include/common.h @@ -24,6 +24,10 @@ typedef unsigned char byte_t; #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef ABS +# define ABS(a) ( ((a)<0) ? -(a) : (a) ) +#endif + #define RAMFUNC __attribute((long_call, section(".ramfunc"))) diff --git a/include/hitag2.h b/include/hitag2.h index ca15d81d..284b5ecb 100644 --- a/include/hitag2.h +++ b/include/hitag2.h @@ -7,11 +7,17 @@ //----------------------------------------------------------------------------- // Hitag2 type prototyping //----------------------------------------------------------------------------- +// HitagS added +//----------------------------------------------------------------------------- #ifndef _HITAG2_H_ #define _HITAG2_H_ typedef enum { + RHTSF_CHALLENGE = 01, + RHTSF_KEY = 02, + WHTSF_CHALLENGE = 03, + WHTSF_KEY = 04, RHT2F_PASSWORD = 21, RHT2F_AUTHENTICATE = 22, RHT2F_CRYPTO = 23, @@ -24,10 +30,12 @@ typedef struct { typedef struct { byte_t NrAr[8]; + byte_t data[4]; } PACKED rht2d_authenticate; typedef struct { - byte_t key[4]; + byte_t key[6]; + byte_t data[4]; } PACKED rht2d_crypto; typedef union { diff --git a/include/hitagS.h b/include/hitagS.h new file mode 100644 index 00000000..351ca86c --- /dev/null +++ b/include/hitagS.h @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// HitagS emulation (preliminary test version) +// +// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg +// +//----------------------------------------------------------------------------- + + +#include +#include +#include + +#ifndef _HITAGS_H_ +#define _HITAGS_H_ + +typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state +typedef enum TAG_STATE {NO_OP=0,READING_PAGE,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state +typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits + +struct hitagS_tag { + PSTATE pstate; //protocol-state + TSATE tstate; //tag-state + uint32_t uid; + uint32_t pages[16][4]; + uint64_t key; + byte_t pwdl0,pwdl1,pwdh0; + //con0 + int max_page; + stype mode; + //con1 + bool auth; //0=Plain 1=Auth + bool TTFC; //Transponder Talks first coding. 0=Manchester 1=Biphase + int TTFDR; //data rate in TTF Mode + int TTFM; //the number of pages that are sent to the RWD + bool LCON; //0=con1/2 read write 1=con1 read only and con2 OTP + bool LKP; //0=page2/3 read write 1=page2/3 read only in Plain mode and no access in authenticate mode + //con2 + //0=read write 1=read only + bool LCK7; //page4/5 + bool LCK6; //page6/7 + bool LCK5; //page8-11 + bool LCK4; //page12-15 + bool LCK3; //page16-23 + bool LCK2; //page24-31 + bool LCK1; //page32-47 + bool LCK0; //page48-63 +} ; + +#endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 38f8617a..66e6cf91 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -124,6 +124,13 @@ typedef struct{ #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 +#define CMD_SIMULATE_HITAG_S 0x0368 +#define CMD_TEST_HITAGS_TRACES 0x0367 +#define CMD_READ_HITAG_S 0x0373 +#define CMD_WR_HITAG_S 0x0375 +#define CMD_EMU_HITAG_S 0x0376 + + #define CMD_SIMULATE_TAG_ISO_14443B 0x0381 #define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 @@ -205,10 +212,11 @@ typedef struct{ //Mifare simulation flags -#define FLAG_INTERACTIVE 0x01 -#define FLAG_4B_UID_IN_DATA 0x02 -#define FLAG_7B_UID_IN_DATA 0x04 -#define FLAG_NR_AR_ATTACK 0x08 +#define FLAG_INTERACTIVE 0x01 +#define FLAG_4B_UID_IN_DATA 0x02 +#define FLAG_7B_UID_IN_DATA 0x04 +#define FLAG_10B_UID_IN_DATA 0x08 +#define FLAG_NR_AR_ATTACK 0x10 //Iclass reader flags @@ -221,6 +229,11 @@ typedef struct{ #define FLAG_ICLASS_READER_CEDITKEY 0x40 +//hw tune args +#define FLAG_TUNE_LF 1 +#define FLAG_TUNE_HF 2 +#define FLAG_TUNE_ALL 3 + // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ diff --git a/liblua/Makefile b/liblua/Makefile index fea895bc..55256066 100644 --- a/liblua/Makefile +++ b/liblua/Makefile @@ -103,7 +103,7 @@ freebsd: generic: $(ALL) linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -ltermcap -lncurses" macosx: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" diff --git a/tools/mfkey/example_trace.txt b/tools/mfkey/example_trace.txt index f2587fcd..73eb75ad 100644 --- a/tools/mfkey/example_trace.txt +++ b/tools/mfkey/example_trace.txt @@ -13,3 +13,67 @@ ./mfkey64 9c599b32 82a4166c a1e458ce 6eea41e0 5cadf439 + + +### Communication decryption + + +RDR 26 +TAG 04 00 +RDR 93 20 +TAG 14 57 9f 69 b5 +RDR 93 70 14 57 9f 69 b5 2e 51 +TAG 08 b6 dd +RDR 60 14 50 2d +TAG ce 84 42 61 +RDR f8 04 9c cb 05 25 c8 4f +TAG 94 31 cc 40 +RDR 70 93 df 99 +TAG 99 72 42 8c e2 e8 52 3f 45 6b 99 c8 31 e7 69 dc ed 09 +RDR 8c a6 82 7b +TAG ab 79 7f d3 69 e8 b9 3a 86 77 6b 40 da e3 ef 68 6e fd +RDR c3 c3 81 ba +TAG 49 e2 c9 de f4 86 8d 17 77 67 0e 58 4c 27 23 02 86 f4 +RDR fb dc d7 c1 +TAG 4a bd 96 4b 07 d3 56 3a a0 66 ed 0a 2e ac 7f 63 12 bf +RDR 9f 91 49 ea + + +./mfkey64 14579f69 ce844261 f8049ccb 0525c84f 9431cc40 7093df99 9972428ce2e8523f456b99c831e769dced09 8ca6827b ab797fd369e8b93a86776b40dae3ef686efd c3c381ba 49e2c9def4868d1777670e584c27230286f4 fbdcd7c1 4abd964b07d3563aa066ed0a2eac7f6312bf 9f9149ea + +Recovering key for: + uid: 14579f69 + nt: ce844261 + {nr}: f8049ccb + {ar}: 0525c84f + {at}: 9431cc40 +{enc0}: 7093df99 +{enc1}: 9972428ce2e8523f456b99c831e769dced09 +{enc2}: 8ca6827b +{enc3}: ab797fd369e8b93a86776b40dae3ef686efd +{enc4}: c3c381ba +{enc5}: 49e2c9def4868d1777670e584c27230286f4 +{enc6}: fbdcd7c1 +{enc7}: 4abd964b07d3563aa066ed0a2eac7f6312bf +{enc8}: 9f9149ea + +LFSR succesors of the tag challenge: + nt': 76d4468d + nt'': d5f3c476 + +Keystream used to generate {ar} and {at}: + ks2: 73f18ec2 + ks3: 41c20836 + +Decrypted communication: +{dec0}: 3014a7fe +{dec1}: c26935cfdb95c4b4a27a84b8217ae9e48217 +{dec2}: 30152eef +{dec3}: 493167c536c30f8e220b09675687067d4b31 +{dec4}: 3016b5dd +{dec5}: 493167c536c30f8e220b09675687067d4b31 +{dec6}: 30173ccc +{dec7}: 0000000000007e178869000000000000c4f2 +{dec8}: 61148834 + +Found Key: [091e639cb715] \ No newline at end of file diff --git a/tools/mfkey/mfkey64.c b/tools/mfkey/mfkey64.c index 448cb2ac..43e077e5 100755 --- a/tools/mfkey/mfkey64.c +++ b/tools/mfkey/mfkey64.c @@ -6,6 +6,7 @@ // Test-file: test2.c #include "crapto1.h" #include +#include int main (int argc, char *argv[]) { struct Crypto1State *revstate; @@ -21,32 +22,50 @@ int main (int argc, char *argv[]) { printf("MIFARE Classic key recovery - based 64 bits of keystream\n"); printf("Recover key from only one complete authentication!\n\n"); - if (argc < 6) { - printf(" syntax: %s <{nr}> <{ar}> <{at}>\n\n",argv[0]); + if (argc < 6 ) { + printf(" syntax: %s <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]); return 1; } - sscanf(argv[1],"%x",&uid); - sscanf(argv[2],"%x",&nt); - sscanf(argv[3],"%x",&nr_enc); - sscanf(argv[4],"%x",&ar_enc); - sscanf(argv[5],"%x",&at_enc); + int encc = argc - 6; + int enclen[encc]; + uint8_t enc[encc][120]; + sscanf(argv[1], "%x", &uid); + sscanf(argv[2], "%x", &nt); + sscanf(argv[3], "%x", &nr_enc); + sscanf(argv[4], "%x", &ar_enc); + sscanf(argv[5], "%x", &at_enc); + for (int i = 0; i < encc; i++) { + enclen[i] = strlen(argv[i + 6]) / 2; + for (int i2 = 0; i2 < enclen[i]; i2++) { + sscanf(argv[i+6] + i2*2,"%2x", (uint8_t*)&enc[i][i2]); + } + } printf("Recovering key for:\n"); - printf(" uid: %08x\n",uid); - printf(" nt: %08x\n",nt); - printf(" {nr}: %08x\n",nr_enc); - printf(" {ar}: %08x\n",ar_enc); - printf(" {at}: %08x\n",at_enc); -/* + printf(" uid: %08x\n", uid); + printf(" nt: %08x\n", nt); + printf(" {nr}: %08x\n", nr_enc); + printf(" {ar}: %08x\n", ar_enc); + printf(" {at}: %08x\n", at_enc); + for (int i = 0; i < encc; i++) { + printf("{enc%d}: ", i); + for (int i2 = 0; i2 < enclen[i]; i2++) { + printf("%02x", enc[i][i2]); + } + printf("\n"); + } + + + /* uint32_t uid = 0x9c599b32; uint32_t tag_challenge = 0x82a4166c; uint32_t nr_enc = 0xa1e458ce; uint32_t reader_response = 0x6eea41e0; uint32_t tag_response = 0x5cadf439; */ - // Generate lfsr succesors of the tag challenge + // Generate lfsr succesors of the tag challenge printf("\nLFSR succesors of the tag challenge:\n"); printf(" nt': %08x\n",prng_successor(nt, 64)); printf(" nt'': %08x\n",prng_successor(nt, 96)); @@ -59,6 +78,26 @@ int main (int argc, char *argv[]) { printf(" ks3: %08x\n",ks3); revstate = lfsr_recovery64(ks2, ks3); + + // Decrypting communication using keystream if presented + if (argc > 6 ) { + printf("\nDecrypted communication:\n"); + uint8_t ks4; + int rollb = 0; + for (int i = 0; i < encc; i++) { + printf("{dec%d}: ", i); + for (int i2 = 0; i2 < enclen[i]; i2++) { + ks4 = crypto1_byte(revstate, 0, 0); + printf("%02x", ks4 ^ enc[i][i2]); + rollb += 1; + } + printf("\n"); + } + for (int i = 0; i < rollb; i++) { + lfsr_rollback_byte(revstate, 0, 0); + } + } + lfsr_rollback_word(revstate, 0, 0); lfsr_rollback_word(revstate, 0, 0); lfsr_rollback_word(revstate, nr_enc, 1);