diff --git a/armsrc/Makefile b/armsrc/Makefile index d70008e0c..aedcd79a1 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -54,7 +54,7 @@ SRC_FELICA = felica.c SRC_CRAPTO1 = crypto1.c des.c aes.c desfire_key.c desfire_crypto.c mifaredesfire.c SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipher.c -SRC_LEGIC = legicrf.c legic_prng.c +SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c SRC_BEE = bee.c # RDV40 related hardware support diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c6e6e0dee..a048418d0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -19,6 +19,7 @@ #include "printf.h" #include "string.h" #include "legicrf.h" +#include "legicrfsim.h" #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" @@ -796,10 +797,10 @@ void UsbPacketReceived(uint8_t *packet, int len) { #ifdef WITH_LEGICRF case CMD_SIMULATE_TAG_LEGIC_RF: - LegicRfSimulate(c->arg[0], c->arg[1], c->arg[2]); + LegicRfSimulate(c->arg[0]); break; case CMD_WRITER_LEGIC_RF: - LegicRfWriter( c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + LegicRfWriter(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_READER_LEGIC_RF: LegicRfReader(c->arg[0], c->arg[1], c->arg[2]); diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 3a45c4c67..59cda1221 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz // 2016 Iceman -// 2018 AntiCat (rwd rewritten) +// 2018 AntiCat // // 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 @@ -16,7 +16,7 @@ #include "legic_prng.h" /* legic PRNG impl */ #include "legic.h" /* legic_card_select_t struct */ -static uint8_t* legic_mem; /* card memory, used for read, write and sim */ +static uint8_t* legic_mem; /* card memory, used for read, write */ static legic_card_select_t card;/* metadata of currently selected card */ static crc_t legic_crc; @@ -179,7 +179,7 @@ static uint32_t rx_frame(uint8_t len) { uint32_t last_frame_start = last_frame_end; uint32_t frame = 0; - for(uint8_t i = 0; i < len; i++) { + for(uint8_t i = 0; i < len; ++i) { frame |= (rx_bit() ^ legic_prng_get_bit()) << i; legic_prng_forward(1); @@ -235,7 +235,7 @@ static bool rx_ack() { // Legic Reader //----------------------------------------------------------------------------- -int init_card(uint8_t cardtype, legic_card_select_t *p_card) { +static int init_card(uint8_t cardtype, legic_card_select_t *p_card) { p_card->tagtype = cardtype; switch(p_card->tagtype) { @@ -314,7 +314,7 @@ static uint32_t setup_phase_reader(uint8_t iv) { legic_prng_init(0); tx_frame(iv, 7); - // configure iv + // configure prng legic_prng_init(iv); legic_prng_forward(2); @@ -501,7 +501,3 @@ OUT: switch_off(); StopTicks(); } - -void LegicRfSimulate(int phase, int frame, int reqresp) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); //TODO Implement -} diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 4bcf04899..639687558 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz +// 2018 AntiCat // // 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 @@ -16,6 +17,5 @@ extern void LegicRfInfo(void); extern void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv); extern void LegicRfWriter(uint16_t offset, uint16_t byte, uint8_t iv, uint8_t *data); -extern void LegicRfSimulate(int phase, int frame, int reqresp); #endif /* __LEGICRF_H */ diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c new file mode 100644 index 000000000..791082d6b --- /dev/null +++ b/armsrc/legicrfsim.c @@ -0,0 +1,139 @@ +//----------------------------------------------------------------------------- +// (c) 2009 Henryk Plötz +// 2016 Iceman +// 2018 AntiCat +// +// 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. +//----------------------------------------------------------------------------- +// LEGIC RF simulation code +//----------------------------------------------------------------------------- +#include "legicrf.h" + +#include "ticks.h" /* timers */ +#include "crc.h" /* legic crc-4 */ +#include "legic_prng.h" /* legic PRNG impl */ +#include "legic.h" /* legic_card_select_t struct */ + +static uint8_t* legic_mem; /* card memory, used for sim */ +static legic_card_select_t card;/* metadata of currently selected card */ +static crc_t legic_crc; + +//----------------------------------------------------------------------------- +// Frame timing and pseudorandom number generator +// +// The Prng is forwarded every 99.1us (TAG_BIT_PERIOD), except when the reader is +// transmitting. In that case the prng has to be forwarded every bit transmitted: +// - 31.3us for a 0 (RWD_TIME_0) +// - 99.1us for a 1 (RWD_TIME_1) +// +// The data dependent timing makes writing comprehensible code significantly +// harder. The current aproach forwards the prng data based if there is data on +// air and time based, using GetCountSspClk(), during computational and wait +// periodes. SSP Clock is clocked by the FPGA at 212 kHz (subcarrier frequency). +// +// To not have the necessity to calculate/guess exection time dependend timeouts +// tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots. +//----------------------------------------------------------------------------- + +static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ + +#define TAG_FRAME_WAIT 70 /* 330us from READER frame end to TAG frame start */ +#define TAG_BIT_PERIOD 21 /* 99.1us */ + +#define RWD_TIME_PAUSE 4 /* 18.9us */ +#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */ +#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */ +#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */ + +//----------------------------------------------------------------------------- +// Legic Simulator +//----------------------------------------------------------------------------- + +static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) { + p_card->tagtype = cardtype; + + switch(p_card->tagtype) { + case 0: + p_card->cmdsize = 6; + p_card->addrsize = 5; + p_card->cardsize = 22; + break; + case 1: + p_card->cmdsize = 9; + p_card->addrsize = 8; + p_card->cardsize = 256; + break; + case 2: + p_card->cmdsize = 11; + p_card->addrsize = 10; + p_card->cardsize = 1024; + break; + default: + p_card->cmdsize = 0; + p_card->addrsize = 0; + p_card->cardsize = 0; + return 2; + } + return 0; +} + +static void init_tag() { + // configure FPGA + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR + | FPGA_HF_SIMULATOR_MODULATE_212K); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // configure SSC with defaults + FpgaSetupSsc(); + + // first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT + LOW(GPIO_SSC_DOUT); + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. + legic_mem = BigBuf_get_EM_addr(); + + // init crc calculator + crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); + + // start 212kHz timer (running from SSP Clock) + StartCountSspClk(); +} + +//----------------------------------------------------------------------------- +// Command Line Interface +// +// Only this function is public / called from appmain.c +//----------------------------------------------------------------------------- + +void LegicRfSimulate(uint8_t cardtype) { + // configure ARM and FPGA + init_tag(); + + // verify command line input + if(init_card(cardtype, &card) != 0) { + DbpString("Unknown tagtype."); + goto OUT; + } + + LED_A_ON(); + DbpString("Starting Legic emulator, press button to end"); + while(!BUTTON_PRESS()) { + WDT_HIT(); + + // init coordination timestamp + last_frame_end = GetCountSspClk(); + + // reset prng + legic_prng_init(0); + } + +OUT: + DbpString("Stopped"); + switch_off(); + StopTicks(); +} diff --git a/armsrc/legicrfsim.h b/armsrc/legicrfsim.h new file mode 100644 index 000000000..c1c8a86e2 --- /dev/null +++ b/armsrc/legicrfsim.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// (c) 2009 Henryk Plötz +// 2018 AntiCat +// +// 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. +//----------------------------------------------------------------------------- +// LEGIC RF emulation public interface +//----------------------------------------------------------------------------- + +#ifndef __LEGICRFSIM_H +#define __LEGICRFSIM_H + +#include "proxmark3.h" + +extern void LegicRfSimulate(uint8_t tagtype); + +#endif /* __LEGICRFSIM_H */ diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 559209afb..0b744c659 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -46,19 +46,15 @@ int usage_legic_rdmem(void){ int usage_legic_sim(void){ PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated"); PrintAndLogEx(NORMAL, "Use eload/esave to upload a dump into emulator memory"); - PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] "); + PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " : 0 = MIM22"); PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)"); - PrintAndLogEx(NORMAL, " : 2 = MIM1024"); - PrintAndLogEx(NORMAL, " : phase drift"); - PrintAndLogEx(NORMAL, " : frame drift"); - PrintAndLogEx(NORMAL, " : reqresp drift"); + PrintAndLogEx(NORMAL, " : 2 = MIM1024"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf legic sim"); - PrintAndLogEx(NORMAL, " hf legic sim "); return 0; } int usage_legic_write(void){ @@ -504,12 +500,13 @@ int CmdLegicRdmem(const char *Cmd) { return status; } -// should say which tagtype -// should load a tag to device mem. -// int phase, int frame, int reqresp int CmdLegicRfSim(const char *Cmd) { - UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}}; - sscanf(Cmd, " %" SCNi64 " %" SCNi64 " %" SCNi64 , &c.arg[0], &c.arg[1], &c.arg[2]); + + char cmdp = param_getchar(Cmd, 0); + if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_sim(); + + UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {1}}; + sscanf(Cmd, " %" SCNi64, &c.arg[0]); clearCommandBuffer(); SendCommand(&c); return 0;