2022-02-11 00:39:25 +08:00
//-----------------------------------------------------------------------------
// Copyright by Łukasz Jurczyk, 2021-2022
//
// This code is licensed to you under the terms of the GNU GPL, version 3.
// See the LICENSE.txt file for the text of the license.
//-----------------------------------------------------------------------------
// LF rsww - This mode can read EM4100 tag, save it to flash (RDV4 only), emulate it, clone it to T55xx tag, validate the write and wipe T55xx tag.
//
// To recall stored ID from flash execute:
// mem spiffs dump -s lf
// then from shell:
// hexdump lf.bin -e '5/1 "%02X" /0 "\n"'
//
// To recall only LAST stored ID from flash use lf-last instead of lf file.
//
//-----------------------------------------------------------------------------
// Modes of operation:
2022-02-13 00:46:34 +08:00
//
2022-02-11 00:39:25 +08:00
// --- Read ---
// Proxmark reads an EM4100 tag. LED A is turned on. When the tag is detected, it is saved to flash (RDV4 only) and proxmark enters the emulation mode.
// It's the default mode for non-RDV4 devices, and if no previous read is present in the flash it's the default mode for RDV4 devices.
// Pressing the button exists reading mode and enters emulation mode (only if any read is present in the memory).
// Double pressing the button enters wiping mode.
//
// --- Emulate ---
// Proxmark emulates last read tag. LED B is turned on.
// It's the default mode for RDV4 if lf-last file is present on the flash.
// Pressing the button enters writing mode and clones the emulated tag.
// Double pressing the button enters the validation mode.
// Holding the button enters the reading mode.
2022-02-13 00:46:34 +08:00
//
2022-02-11 00:39:25 +08:00
// --- Write ---
// Proxmarks writes the last read tag. LEDs A and B are turned on.
// When writing is complete LEDs A and B blink three times and proxmark enters the emulation mode.
2022-02-13 00:46:34 +08:00
//
2022-02-11 00:39:25 +08:00
// --- Validate ---
// Proxmark reads an EM4100 tag. LED C is turned on.
// If tag matches the last saved tag, LED C blinks three times. If it doesn't all LEDs blink three times. Proxmark enters the emulation mode afterwards.
// The result of the read is DISCARDED.
// Pressing the button enters the emulation mode.
2022-02-13 00:46:34 +08:00
//
2022-02-11 00:39:25 +08:00
// --- Wipe ---
// Proxmark continously wipes all approached T55xx tags. LED D is turned on, LEDs A-C are blinking.
// Pressing the button enters the default mode (reading or emulation).
//-----------------------------------------------------------------------------
# include "standalone.h"
# include "proxmark3_arm.h"
# include "appmain.h"
# include "fpgaloader.h"
# include "util.h"
# include "dbprint.h"
# include "ticks.h"
# include "string.h"
# include "BigBuf.h"
# include "spiffs.h"
# include "inttypes.h"
# include "parity.h"
# include "lfops.h"
# ifdef WITH_FLASH
# include "flashmem.h"
char * filename = " lf " ;
char * filenameLast = " lf-last " ;
# endif
# define LF_CLOCK 64 // for 125kHz
# define LF_RWSB_T55XX_TYPE 1 // Tag type: 0 - T5555, 1-T55x7
static uint64_t low = 0 ;
static uint64_t low2 = 0 ;
static uint32_t high = 0 ;
static uint32_t high2 = 0 ;
static unsigned char mode = 0 ;
static int buflen ;
void ModInfo ( void ) {
DbpString ( " === LF EM4100 read/sim/write/wipe/validate === " ) ;
}
static uint64_t rev_quads ( uint64_t bits ) {
uint64_t result = 0 ;
for ( int i = 0 ; i < 16 ; i + + ) {
result + = ( ( bits > > ( 60 - 4 * i ) ) & 0xf ) < < ( 4 * i ) ;
}
return result > > 24 ;
}
static void fill_buff ( uint8_t bit ) {
uint8_t * bba = BigBuf_get_addr ( ) ;
memset ( bba + buflen , bit , LF_CLOCK / 2 ) ;
buflen + = ( LF_CLOCK / 2 ) ;
memset ( bba + buflen , bit ^ 1 , LF_CLOCK / 2 ) ;
buflen + = ( LF_CLOCK / 2 ) ;
}
static void construct_EM410x_emul ( uint64_t id ) {
int i , j ;
int binary [ 4 ] = { 0 , 0 , 0 , 0 } ;
int parity [ 4 ] = { 0 , 0 , 0 , 0 } ;
buflen = 0 ;
for ( i = 0 ; i < 9 ; i + + )
fill_buff ( 1 ) ;
for ( i = 0 ; i < 10 ; i + + ) {
for ( j = 3 ; j > = 0 ; j - - , id / = 2 )
binary [ j ] = id % 2 ;
for ( j = 0 ; j < 4 ; j + + )
fill_buff ( binary [ j ] ) ;
fill_buff ( binary [ 0 ] ^ binary [ 1 ] ^ binary [ 2 ] ^ binary [ 3 ] ) ;
for ( j = 0 ; j < 4 ; j + + )
parity [ j ] ^ = binary [ j ] ;
}
for ( j = 0 ; j < 4 ; j + + )
fill_buff ( parity [ j ] ) ;
fill_buff ( 0 ) ;
}
# ifdef WITH_FLASH
static void SaveIDtoFlash ( uint64_t id ) {
uint8_t bt [ 5 ] ;
rdv40_spiffs_mount ( ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
bt [ 4 - i ] = ( uint8_t ) ( id > > 8 * i & 0xff ) ;
}
if ( exists_in_spiffs ( filename ) )
2022-02-13 00:46:34 +08:00
rdv40_spiffs_append ( filename , & bt [ 0 ] , 5 , RDV40_SPIFFS_SAFETY_NORMAL ) ;
else
2022-02-11 00:39:25 +08:00
rdv40_spiffs_write ( filename , & bt [ 0 ] , 5 , RDV40_SPIFFS_SAFETY_NORMAL ) ;
2022-02-13 00:46:34 +08:00
if ( exists_in_spiffs ( filenameLast ) )
rdv40_spiffs_remove ( filenameLast , RDV40_SPIFFS_SAFETY_NORMAL ) ;
rdv40_spiffs_write ( filenameLast , & bt [ 0 ] , 5 , RDV40_SPIFFS_SAFETY_NORMAL ) ;
2022-02-11 00:39:25 +08:00
}
static bool ReadFlash ( void ) {
2022-02-13 00:46:34 +08:00
if ( exists_in_spiffs ( filenameLast ) = = false )
return false ;
uint8_t bt [ 5 ] ;
if ( rdv40_spiffs_read ( filenameLast , ( uint8_t * ) & bt , 5 , RDV40_SPIFFS_SAFETY_NORMAL ) < 0 )
return false ;
low = bt [ 0 ] ;
low < < = 32 ;
low | = ( bt [ 1 ] < < 24 ) | ( bt [ 2 ] < < 16 ) | ( bt [ 3 ] < < 8 ) | bt [ 4 ] ;
low2 = low ;
high = 0 ;
high2 = 0 ;
return true ;
2022-02-11 00:39:25 +08:00
}
# endif
static void Wipe ( void ) {
2022-02-13 00:46:34 +08:00
DbpString ( " Wipe mode " ) ;
LEDsoff ( ) ;
for ( ; ; ) {
LED_A_ON ( ) ;
LED_B_ON ( ) ;
LED_C_ON ( ) ;
LED_D_ON ( ) ;
copy_em410x_to_t55xx ( LF_RWSB_T55XX_TYPE , LF_CLOCK , ( uint32_t ) 0 , ( uint32_t ) 0 , false ) ;
SpinDelay ( 60 ) ;
LEDsoff ( ) ;
LED_D_ON ( ) ;
int b = BUTTON_HELD ( 100 ) ;
if ( b ! = BUTTON_NO_CLICK | | data_available ( ) )
return ;
SpinDelay ( 100 ) ;
b = BUTTON_HELD ( 100 ) ;
if ( b ! = BUTTON_NO_CLICK | | data_available ( ) )
return ;
}
2022-02-11 00:39:25 +08:00
}
static void Read ( void ) {
2022-02-13 00:46:34 +08:00
mode = 0 ;
while ( low2 = = 0 | | mode = = 0 ) {
DbpString ( " Read " ) ;
LEDsoff ( ) ;
LED_A_ON ( ) ;
low2 = 0 ;
high2 = 0 ;
lf_em410x_watch ( 1 , & high2 , & low2 , false ) ;
if ( low2 ! = 0 ) {
LED_B_ON ( ) ;
low = low2 ;
high = high2 ;
mode = 1 ;
# ifdef WITH_FLASH
SaveIDtoFlash ( low2 ) ;
# endif
SpinDelay ( 50 ) ;
LED_C_ON ( ) ;
SpinDelay ( 50 ) ;
LED_D_ON ( ) ;
SpinDelay ( 50 ) ;
LEDsoff ( ) ;
return ;
}
if ( data_available ( ) )
return ;
int b = BUTTON_CLICKED ( 1000 ) ;
if ( ( b = = BUTTON_SINGLE_CLICK | | b = = BUTTON_HOLD ) & & low ! = 0 ) {
mode = 1 ;
return ;
}
if ( b = = BUTTON_DOUBLE_CLICK ) {
Wipe ( ) ;
if ( low ! = 0 ) {
mode = 1 ;
return ;
}
}
}
2022-02-11 00:39:25 +08:00
}
static void Validate ( void ) {
2022-02-13 00:46:34 +08:00
DbpString ( " Validate " ) ;
LEDsoff ( ) ;
LED_C_ON ( ) ;
for ( ; ; ) {
low2 = 0 ;
high2 = 0 ;
lf_em410x_watch ( 1 , & high2 , & low2 , false ) ;
if ( low = = low2 & & high = = high2 ) {
LED_C_OFF ( ) ;
SpinDelay ( 150 ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
LED_C_ON ( ) ;
SpinDelay ( 150 ) ;
LED_C_OFF ( ) ;
SpinDelay ( 150 ) ;
}
return ;
} else if ( low2 ! = 0 | | high2 ! = 0 ) {
LEDsoff ( ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
LED_A_ON ( ) ;
LED_B_ON ( ) ;
LED_C_ON ( ) ;
LED_D_ON ( ) ;
SpinDelay ( 250 ) ;
LEDsoff ( ) ;
SpinDelay ( 150 ) ;
}
return ;
} else
SpinDelay ( 200 ) ;
int b = BUTTON_HELD ( 200 ) ;
if ( b ! = BUTTON_NO_CLICK | | data_available ( ) )
return ;
}
2022-02-11 00:39:25 +08:00
}
static void Write ( void ) {
2022-02-13 00:46:34 +08:00
DbpString ( " Write " ) ;
LED_A_ON ( ) ;
LED_B_ON ( ) ;
copy_em410x_to_t55xx ( LF_RWSB_T55XX_TYPE , LF_CLOCK , ( uint32_t ) ( low > > 32 ) , ( uint32_t ) ( low & 0xffffffff ) , false ) ;
SpinDelay ( 75 ) ;
LEDsoff ( ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
LED_A_ON ( ) ;
LED_B_ON ( ) ;
SpinDelay ( 75 ) ;
LED_A_OFF ( ) ;
LED_B_OFF ( ) ;
SpinDelay ( 75 ) ;
}
2022-02-11 00:39:25 +08:00
}
static void Emulate ( void ) {
2022-02-13 00:46:34 +08:00
DbpString ( " Emulate " ) ;
LEDsoff ( ) ;
for ( ; ; ) {
int bx = BUTTON_HELD ( 50 ) ;
if ( bx = = BUTTON_NO_CLICK )
break ;
SpinDelay ( 50 ) ;
}
LED_B_ON ( ) ;
construct_EM410x_emul ( rev_quads ( low ) ) ;
2022-02-11 00:39:25 +08:00
SimulateTagLowFrequencyEx ( buflen , 0 , false , - 1 ) ;
2022-02-13 00:46:34 +08:00
int b = BUTTON_CLICKED ( 800 ) ;
2022-02-11 00:39:25 +08:00
2022-02-13 00:46:34 +08:00
if ( b = = BUTTON_NO_CLICK )
return ;
2022-02-11 00:39:25 +08:00
2022-02-13 00:46:34 +08:00
for ( ; ; ) {
int bx = BUTTON_HELD ( 50 ) ;
if ( bx = = BUTTON_NO_CLICK )
break ;
SpinDelay ( 50 ) ;
}
2022-02-11 00:39:25 +08:00
2022-02-13 00:46:34 +08:00
if ( b = = BUTTON_SINGLE_CLICK )
Write ( ) ;
else if ( b = = BUTTON_HOLD )
mode = 0 ;
else if ( b = = BUTTON_DOUBLE_CLICK )
Validate ( ) ;
2022-02-11 00:39:25 +08:00
}
void RunMod ( ) {
StandAloneMode ( ) ;
2022-02-13 00:46:34 +08:00
LEDsoff ( ) ;
LED_D_ON ( ) ;
2022-02-11 00:39:25 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_LF ) ;
2022-02-13 00:46:34 +08:00
WDT_HIT ( ) ;
# ifdef WITH_FLASH
if ( ReadFlash ( ) )
mode = 1 ;
else Read ( ) ;
2022-02-11 00:39:25 +08:00
# else
2022-02-13 00:46:34 +08:00
Read ( ) ;
2022-02-11 00:39:25 +08:00
# endif
for ( ; ; ) {
2022-02-13 00:46:34 +08:00
WDT_HIT ( ) ;
LEDsoff ( ) ;
2022-02-11 00:39:25 +08:00
if ( data_available ( ) ) return ;
2022-02-13 00:46:34 +08:00
if ( mode = = 0 )
Read ( ) ;
else Emulate ( ) ;
2022-02-11 00:39:25 +08:00
}
}