2016-02-14 03:53:06 +08:00
//-----------------------------------------------------------------------------
//
// 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
//-----------------------------------------------------------------------------
2017-07-30 15:17:48 +08:00
2016-02-14 03:53:06 +08:00
# include "cmdlfpresco.h"
2019-09-27 02:36:13 +08:00
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
2020-11-27 02:42:24 +08:00
# include "commonutil.h" // ARRAYLEN
2019-09-27 02:36:13 +08:00
# include "cmdparser.h" // command_t
# include "comms.h"
# include "ui.h"
# include "cmddata.h"
# include "cmdlf.h"
2020-11-27 02:42:24 +08:00
# include "protocols.h" // for T55xx config register definitions
# include "lfdemod.h" // parityTest
# include "cmdlft55xx.h" // verifywrite
# include "cmdlfem4x05.h" //
# include "cliparser.h"
2019-09-27 02:36:13 +08:00
2016-02-14 03:53:06 +08:00
static int CmdHelp ( const char * Cmd ) ;
2020-11-27 02:42:24 +08:00
// find presco preamble 0x10D in already demoded data
static int detectPresco ( uint8_t * dest , size_t * size ) {
if ( * size < 128 * 2 ) return - 1 ; //make sure buffer has data
size_t startIdx = 0 ;
uint8_t preamble [ ] = { 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
if ( ! preambleSearch ( dest , preamble , sizeof ( preamble ) , size , & startIdx ) )
return - 2 ; //preamble not found
if ( * size ! = 128 ) return - 3 ; //wrong demoded size
//return start position
return ( int ) startIdx ;
}
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
static int getWiegandFromPrintedPresco ( void * arr , uint32_t * fullcode ) {
char * s = ( char * ) arr ;
uint8_t val = 0 ;
for ( int i = 0 ; i < strlen ( s ) ; + + i ) {
// Get value from number string.
if ( s [ i ] = = ' * ' )
val = 10 ;
if ( s [ i ] = = ' # ' )
val = 11 ;
if ( s [ i ] > = 0x30 & & s [ i ] < = 0x39 )
val = s [ i ] - 0x30 ;
* fullcode + = val ;
// last digit is only added, not multipled.
if ( i < strlen ( s ) - 1 )
* fullcode * = 12 ;
}
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2016-02-14 03:53:06 +08:00
}
2020-11-27 02:42:24 +08:00
// calc not certain - intended to get bitstream for programming / sim
static 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 ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2016-02-14 03:53:06 +08:00
}
2016-02-14 18:58:25 +08:00
//see ASKDemod for what args are accepted
2020-09-28 17:50:20 +08:00
int demodPresco ( bool verbose ) {
( void ) verbose ; // unused so far
2019-03-10 06:35:06 +08:00
bool st = true ;
2020-09-29 06:36:35 +08:00
if ( ASKDemod_ext ( 32 , 0 , 0 , 0 , false , false , false , 1 , & st ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error Presco ASKDemod failed " ) ;
2019-05-22 20:32:30 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
size_t size = DemodBufferLen ;
int ans = detectPresco ( DemodBuffer , & size ) ;
if ( ans < 0 ) {
if ( ans = = - 1 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Presco: too few bits found " ) ;
else if ( ans = = - 2 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Presco: preamble not found " ) ;
else if ( ans = = - 3 )
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - Presco: Size not correct: %zu " , size ) ;
2019-03-10 06:35:06 +08:00
else
PrintAndLogEx ( DEBUG , " DEBUG: Error - Presco: ans: %d " , ans ) ;
2019-05-22 20:32:30 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-04-07 03:46:00 +08:00
setDemodBuff ( DemodBuffer , 128 , ans ) ;
2019-03-10 07:00:59 +08:00
setClockGrid ( g_DemodClock , g_DemodStartIdx + ( ans * g_DemodClock ) ) ;
2019-03-10 06:35:06 +08:00
//got a good demod
uint32_t raw1 = bytebits_to_byte ( DemodBuffer , 32 ) ;
2019-03-10 07:00:59 +08:00
uint32_t raw2 = bytebits_to_byte ( DemodBuffer + 32 , 32 ) ;
uint32_t raw3 = bytebits_to_byte ( DemodBuffer + 64 , 32 ) ;
uint32_t raw4 = bytebits_to_byte ( DemodBuffer + 96 , 32 ) ;
2020-11-27 02:42:24 +08:00
uint32_t fullcode = raw4 ;
uint32_t usercode = fullcode & 0x0000FFFF ;
uint32_t sitecode = ( fullcode > > 24 ) & 0x000000FF ;
PrintAndLogEx ( SUCCESS , " Presco Site code: " _GREEN_ ( " %u " ) " User code: " _GREEN_ ( " %u " ) " Full code: " _GREEN_ ( " %08X " ) " Raw: " _YELLOW_ ( " %08X%08X%08X%08X " )
, sitecode
, usercode
, fullcode
, raw1 , raw2 , raw3 , raw4
) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2016-02-14 18:58:25 +08:00
}
2016-02-14 03:53:06 +08:00
2020-09-28 17:50:20 +08:00
static int CmdPrescoDemod ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
return demodPresco ( true ) ;
}
2016-02-14 03:53:06 +08:00
//see ASKDemod for what args are accepted
2020-11-27 02:42:24 +08:00
static int CmdPrescoReader ( const char * Cmd ) {
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " lf presco reader " ,
" read a presco tag " ,
" lf presco reader -@ -> continuous reader mode "
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_lit0 ( " @ " , NULL , " optional - continuous reader mode " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
bool cm = arg_get_lit ( ctx , 1 ) ;
CLIParserFree ( ctx ) ;
do {
lf_read ( false , 12000 ) ;
demodPresco ( ! cm ) ;
} while ( cm & & ! kbd_enter_pressed ( ) ) ;
return PM3_SUCCESS ;
2016-02-14 03:53:06 +08:00
}
2016-03-08 01:53:02 +08:00
// takes base 12 ID converts to hex
// Or takes 8 digit hex ID
2019-04-12 08:07:11 +08:00
static int CmdPrescoClone ( const char * Cmd ) {
2020-11-27 02:42:24 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " lf presco clone " ,
" clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag. " ,
" lf presco clone -d 018363467 \n "
" lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag \n "
" lf presco clone -d 018363467 --em -> encode for EM4305/4469 "
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str0 ( " c " , NULL , " <hex> " , " 8 digit hex card number " ) ,
arg_str0 ( " d " , NULL , " <digits> " , " 9 digit presco card ID " ) ,
arg_lit0 ( NULL , " q5 " , " optional - specify writing to Q5/T5555 tag " ) ,
arg_lit0 ( NULL , " em " , " optional - specify writing to EM4305/4469 tag " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , false ) ;
int hex_len = 0 ;
uint8_t hex [ 4 ] = { 0 , 0 , 0 , 0 } ;
CLIGetHexWithReturn ( ctx , 1 , hex , & hex_len ) ;
uint8_t idstr [ 11 ] ;
int slen = 9 ;
memset ( idstr , 0x00 , sizeof ( idstr ) ) ;
CLIGetStrWithReturn ( ctx , 2 , idstr , & slen ) ;
bool q5 = arg_get_lit ( ctx , 3 ) ;
bool em = arg_get_lit ( ctx , 4 ) ;
CLIParserFree ( ctx ) ;
if ( q5 & & em ) {
PrintAndLogEx ( FAILED , " Can't specify both Q5 and EM4305 at the same time " ) ;
return PM3_EINVARG ;
}
2016-02-14 03:53:06 +08:00
2020-11-27 02:42:24 +08:00
uint32_t fullcode = 0 ;
if ( hex_len ) {
fullcode = bytes_to_num ( hex , hex_len ) ;
} else {
//param get string int param_getstr(const char *line, int paramnum, char * str)
if ( slen < 2 ) {
PrintAndLogEx ( ERR , " Must contain atleast 2 digits " ) ;
return PM3_EINVARG ;
}
getWiegandFromPrintedPresco ( idstr , & fullcode ) ;
}
uint32_t usercode = fullcode & 0x0000FFFF ; //% 65566
uint32_t sitecode = ( fullcode > > 24 ) & 0x000000FF ; // /= 16777216;
2019-03-10 06:35:06 +08:00
2020-11-27 02:42:24 +08:00
uint32_t blocks [ 5 ] = { T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 < < T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR , 0 , 0 , 0 , 0 } ;
2019-03-10 06:35:06 +08:00
2020-11-27 02:42:24 +08:00
char cardtype [ 16 ] = { " T55x7 " } ;
// Q5
if ( q5 ) {
2020-08-28 16:03:33 +08:00
blocks [ 0 ] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE ( 32 ) | 4 < < T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR ;
2020-11-27 02:42:24 +08:00
snprintf ( cardtype , sizeof ( cardtype ) , " Q5/T5555 " ) ;
}
// EM4305
if ( em ) {
blocks [ 0 ] = EM4305_PRESCO_CONFIG_BLOCK ;
snprintf ( cardtype , sizeof ( cardtype ) , " EM4305/4469 " ) ;
}
2019-03-10 06:35:06 +08:00
if ( ( sitecode & 0xFF ) ! = sitecode ) {
sitecode & = 0xFF ;
2020-11-27 02:42:24 +08:00
PrintAndLogEx ( INFO , " Site code truncated to 8-bits (Presco): %u " , sitecode ) ;
2019-03-10 06:35:06 +08:00
}
if ( ( usercode & 0xFFFF ) ! = usercode ) {
usercode & = 0xFFFF ;
2020-11-27 02:42:24 +08:00
PrintAndLogEx ( INFO , " User code truncated to 16-bits (Presco): %u " , usercode ) ;
2019-03-10 06:35:06 +08:00
}
blocks [ 1 ] = 0x10D00000 ; //preamble
blocks [ 2 ] = 0x00000000 ;
blocks [ 3 ] = 0x00000000 ;
blocks [ 4 ] = fullcode ;
2020-11-27 02:42:24 +08:00
PrintAndLogEx ( INFO , " Preparing to clone Presco to " _GREEN_ ( " %s " ) " with Site code: " _GREEN_ ( " %u " ) " User code: " _GREEN_ ( " %u " ) " Full code: " _GREEN_ ( " %08x " )
, cardtype
, sitecode
, usercode
, fullcode
) ;
2019-09-27 02:36:13 +08:00
print_blocks ( blocks , ARRAYLEN ( blocks ) ) ;
2019-09-16 02:27:50 +08:00
2020-11-27 02:42:24 +08:00
int res ;
if ( em ) {
res = em4x05_clone_tag ( blocks , ARRAYLEN ( blocks ) , 0 , false ) ;
} else {
res = clone_t55xx_tag ( blocks , ARRAYLEN ( blocks ) ) ;
}
2020-03-02 21:15:51 +08:00
PrintAndLogEx ( SUCCESS , " Done " ) ;
2020-11-27 02:42:24 +08:00
PrintAndLogEx ( HINT , " Hint: try " _YELLOW_ ( " `lf presco reader` " ) " to verify " ) ;
2020-03-02 21:15:51 +08:00
return res ;
2016-02-14 03:53:06 +08:00
}
2016-03-08 01:53:02 +08:00
// takes base 12 ID converts to hex
// Or takes 8 digit hex ID
2019-04-12 08:07:11 +08:00
static int CmdPrescoSim ( const char * Cmd ) {
2020-11-27 02:42:24 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " lf presco sim " ,
" Enables simulation of presco card with specified card number. \n "
" Simulation runs until the button is pressed or another USB command is issued. \n "
" Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated. " ,
" lf presco sim -d 018363467 "
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str0 ( " c " , NULL , " <hex> " , " 8 digit hex card number " ) ,
arg_str0 ( " d " , NULL , " <digits> " , " 9 digit presco card ID " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , false ) ;
int hex_len = 0 ;
uint8_t hex [ 4 ] = { 0 , 0 , 0 , 0 } ;
CLIGetHexWithReturn ( ctx , 1 , hex , & hex_len ) ;
uint8_t idstr [ 11 ] ;
int slen = 9 ;
memset ( idstr , 0x00 , sizeof ( idstr ) ) ;
CLIGetStrWithReturn ( ctx , 2 , idstr , & slen ) ;
CLIParserFree ( ctx ) ;
uint32_t fullcode = 0 ;
if ( hex_len ) {
fullcode = bytes_to_num ( hex , hex_len ) ;
} else {
if ( slen < 2 ) {
PrintAndLogEx ( ERR , " Must contain atleast 2 digits " ) ;
return PM3_EINVARG ;
}
getWiegandFromPrintedPresco ( idstr , & fullcode ) ;
}
2019-03-10 06:35:06 +08:00
2020-11-27 02:42:24 +08:00
uint32_t usercode = fullcode & 0x0000FFFF ;
uint32_t sitecode = ( fullcode > > 24 ) & 0x000000FF ;
if ( ( sitecode & 0xFF ) ! = sitecode ) {
sitecode & = 0xFF ;
PrintAndLogEx ( INFO , " Site code truncated to 8-bits (Presco): %u " , sitecode ) ;
}
if ( ( usercode & 0xFFFF ) ! = usercode ) {
usercode & = 0xFFFF ;
PrintAndLogEx ( INFO , " User code truncated to 16-bits (Presco): %u " , usercode ) ;
}
PrintAndLogEx ( SUCCESS , " Simulating Presco - Site Code: " _GREEN_ ( " %u " ) " User Code: " _GREEN_ ( " %u " ) " Full Code: " _GREEN_ ( " %08X " )
, sitecode
, usercode
, fullcode )
;
2019-03-10 06:35:06 +08:00
2019-05-24 19:06:08 +08:00
uint8_t bs [ 128 ] ;
getPrescoBits ( fullcode , bs ) ;
lf_asksim_t * payload = calloc ( 1 , sizeof ( lf_asksim_t ) + sizeof ( bs ) ) ;
payload - > encoding = 1 ;
payload - > invert = 0 ;
payload - > separator = 1 ;
payload - > clock = 32 ;
memcpy ( payload - > data , bs , sizeof ( bs ) ) ;
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_LF_ASK_SIMULATE , ( uint8_t * ) payload , sizeof ( lf_asksim_t ) + sizeof ( bs ) ) ;
2019-05-24 19:06:08 +08:00
free ( payload ) ;
2019-05-09 06:08:59 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
WaitForResponse ( CMD_LF_ASK_SIMULATE , & resp ) ;
2019-05-24 19:06:08 +08:00
PrintAndLogEx ( INFO , " Done " ) ;
2019-05-10 02:20:54 +08:00
if ( resp . status ! = PM3_EOPABORTED )
2019-05-09 06:08:59 +08:00
return resp . status ;
return PM3_SUCCESS ;
2016-02-14 03:53:06 +08:00
}
static command_t CommandTable [ ] = {
2019-05-02 02:48:15 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2020-09-28 17:50:20 +08:00
{ " demod " , CmdPrescoDemod , AlwaysAvailable , " demodulate Presco tag from the GraphBuffer " } ,
2020-11-27 02:42:24 +08:00
{ " reader " , CmdPrescoReader , IfPm3Lf , " Attempt to read and Extract tag data " } ,
{ " clone " , CmdPrescoClone , IfPm3Lf , " clone presco tag to T55x7 or Q5/T5555 " } ,
{ " sim " , CmdPrescoSim , IfPm3Lf , " simulate presco tag " } ,
2019-05-02 02:48:15 +08:00
{ NULL , NULL , NULL , NULL }
2016-02-14 03:53:06 +08:00
} ;
2019-04-12 08:07:11 +08:00
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2016-02-14 03:53:06 +08:00
}
2019-04-12 08:07:11 +08:00
int CmdLFPresco ( const char * Cmd ) {
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2016-02-14 03:53:06 +08:00
}