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.
This commit is contained in:
AntiCat 2018-09-05 22:23:25 +02:00
commit 61e4eac2b2
7 changed files with 176 additions and 24 deletions

View file

@ -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

View file

@ -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]);

View file

@ -1,7 +1,7 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 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
}

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 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 */

139
armsrc/legicrfsim.c Normal file
View file

@ -0,0 +1,139 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 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();
}

19
armsrc/legicrfsim.h Normal file
View file

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 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 */

View file

@ -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] <tagtype> <phase> <frame> <reqresp>");
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <tagtype> : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, " <phase> : phase drift");
PrintAndLogEx(NORMAL, " <frame> : frame drift");
PrintAndLogEx(NORMAL, " <reqresp> : 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;