From 61e4eac2b249e8a4d4b86fe6ea2089c22e87b49f Mon Sep 17 00:00:00 2001 From: AntiCat Date: Wed, 5 Sep 2018 22:23:25 +0200 Subject: [PATCH] Legic: Moved card simulator into separate file & cleaned interface. Reader and card simulation have almost no common code. Moreover the sim uses an SSP Clock at 212kHz for all timings to prevent any drifting from the PRNG. This clock speed is not available in reader simulation mode (SSP runs at up to 3.4MHz, and changes speed between TX and RX). For these reasons having the code in separate files makes it significantly cleaner. --- armsrc/Makefile | 2 +- armsrc/appmain.c | 5 +- armsrc/legicrf.c | 14 ++--- armsrc/legicrf.h | 2 +- armsrc/legicrfsim.c | 139 ++++++++++++++++++++++++++++++++++++++++++++ armsrc/legicrfsim.h | 19 ++++++ client/cmdhflegic.c | 19 +++--- 7 files changed, 176 insertions(+), 24 deletions(-) create mode 100644 armsrc/legicrfsim.c create mode 100644 armsrc/legicrfsim.h 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;