2015-11-23 00:33:41 +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.
//-----------------------------------------------------------------------------
2017-07-14 22:20:34 +08:00
// Low frequency Viking tag commands (AKA FDI Matalec Transit)
// ASK/Manchester, RF/32, 64 bits (complete)
2015-11-23 00:33:41 +08:00
//-----------------------------------------------------------------------------
2015-10-05 00:01:33 +08:00
# include "cmdlfviking.h"
2017-07-30 15:17:48 +08:00
2019-08-08 22:57:33 +08:00
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
# include "cmdparser.h" // command_t
# include "comms.h"
# include "ui.h"
# include "cmddata.h"
# include "cmdlf.h"
# include "lfdemod.h"
2015-10-05 00:01:33 +08:00
static int CmdHelp ( const char * Cmd ) ;
2015-11-10 18:42:59 +08:00
2019-04-10 19:06:05 +08:00
static int usage_lf_viking_clone ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " clone a Viking AM tag to a T55x7 tag. " ) ;
PrintAndLogEx ( NORMAL , " Usage: lf viking clone <Card ID - 8 hex digits> <Q5> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " <Card Number> : 8 digit hex viking card number " ) ;
PrintAndLogEx ( NORMAL , " <Q5> : specify write to Q5 (t5555 instead of t55x7) " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " lf viking clone 1A337 Q5 " ) ;
2019-05-22 21:44:55 +08:00
return PM3_SUCCESS ;
2015-11-10 18:42:59 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_lf_viking_sim ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Enables simulation of viking card with specified card number. " ) ;
PrintAndLogEx ( NORMAL , " Simulation runs until the button is pressed or another USB command is issued. " ) ;
PrintAndLogEx ( NORMAL , " Per viking format, the card number is 8 digit hex number. Larger values are truncated. " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: lf viking sim <Card-Number> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " <Card Number> : 8 digit hex viking card number " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " lf viking sim 1A337 " ) ;
2019-05-22 21:44:55 +08:00
return PM3_SUCCESS ;
2015-11-23 00:33:41 +08:00
}
2017-07-30 15:17:48 +08:00
//by marshmellow
//see ASKDemod for what args are accepted
2019-04-12 08:07:11 +08:00
static int CmdVikingDemod ( const char * Cmd ) {
2019-05-24 21:48:31 +08:00
if ( ASKDemod ( Cmd , false , false , 1 ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - Viking ASKDemod failed " ) ;
2019-05-22 21:44:55 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
size_t size = DemodBufferLen ;
int ans = detectViking ( DemodBuffer , & size ) ;
if ( ans < 0 ) {
2019-05-26 01:27:43 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - Viking Demod %d %s " , ans , ( ans = = - 5 ) ? _RED_ ( " [chksum error] " ) : " " ) ;
2019-05-22 21:44:55 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
//got a good demod
2019-03-10 07:00:59 +08:00
uint32_t raw1 = bytebits_to_byte ( DemodBuffer + ans , 32 ) ;
uint32_t raw2 = bytebits_to_byte ( DemodBuffer + ans + 32 , 32 ) ;
uint32_t cardid = bytebits_to_byte ( DemodBuffer + ans + 24 , 32 ) ;
uint8_t checksum = bytebits_to_byte ( DemodBuffer + ans + 32 + 24 , 8 ) ;
2019-05-26 01:27:43 +08:00
PrintAndLogEx ( SUCCESS , " Viking Tag Found: Card ID " _YELLOW_ ( " %08X " ) " checksum " _YELLOW_ ( " %02X " ) , cardid , checksum ) ;
PrintAndLogEx ( SUCCESS , " Raw hex: %08X%08X " , raw1 , raw2 ) ;
2019-04-07 03:46:00 +08:00
setDemodBuff ( DemodBuffer , 64 , ans ) ;
2019-03-10 07:00:59 +08:00
setClockGrid ( g_DemodClock , g_DemodStartIdx + ( ans * g_DemodClock ) ) ;
2019-05-22 21:44:55 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
2016-02-10 03:42:59 +08:00
2015-11-10 18:42:59 +08:00
//by marshmellow
//see ASKDemod for what args are accepted
2019-04-12 08:07:11 +08:00
static int CmdVikingRead ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
lf_read ( true , 10000 ) ;
return CmdVikingDemod ( Cmd ) ;
2015-10-05 00:01:33 +08:00
}
2015-11-10 18:42:59 +08:00
2019-04-12 08:07:11 +08:00
static int CmdVikingClone ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint32_t id = 0 ;
uint64_t rawID = 0 ;
bool Q5 = false ;
2019-05-24 19:06:08 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) = = 0 | | cmdp = = ' h ' ) return usage_lf_viking_clone ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
id = param_get32ex ( Cmd , 0 , 0 , 16 ) ;
if ( id = = 0 ) return usage_lf_viking_clone ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
cmdp = param_getchar ( Cmd , 1 ) ;
2019-03-10 07:00:59 +08:00
if ( cmdp = = ' Q ' | | cmdp = = ' q ' )
2019-03-10 06:35:06 +08:00
Q5 = true ;
2015-11-23 00:33:41 +08:00
2019-03-10 06:35:06 +08:00
rawID = getVikingBits ( id ) ;
2019-03-09 15:59:13 +08:00
2019-05-26 01:27:43 +08:00
PrintAndLogEx ( INFO , " Preparing to clone Viking tag - ID " _YELLOW_ ( " %08X " ) " raw " _YELLOW_ ( " %08X%08X " ) , id , ( uint32_t ) ( rawID > > 32 ) , ( uint32_t ) ( rawID & 0xFFFFFFFF ) ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandMIX ( CMD_LF_VIKING_CLONE , rawID > > 32 , rawID & 0xFFFFFFFF , Q5 , NULL , 0 ) ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 07:00:59 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & resp , T55XX_WRITE_TIMEOUT ) ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Error occurred, device did not respond during write operation. " ) ;
2019-05-22 21:44:55 +08:00
return PM3_ETIMEOUT ;
2019-03-10 06:35:06 +08:00
}
2019-05-22 21:44:55 +08:00
return PM3_SUCCESS ;
2015-10-05 00:01:33 +08:00
}
2019-04-12 08:07:11 +08:00
static int CmdVikingSim ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint32_t id = 0 ;
uint64_t rawID = 0 ;
2019-05-24 19:06:08 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) = = 0 | | cmdp = = ' h ' ) return usage_lf_viking_sim ( ) ;
2015-11-23 00:33:41 +08:00
2019-03-10 06:35:06 +08:00
id = param_get32ex ( Cmd , 0 , 0 , 16 ) ;
if ( id = = 0 ) return usage_lf_viking_sim ( ) ;
2015-11-23 00:33:41 +08:00
2019-03-10 06:35:06 +08:00
rawID = getVikingBits ( id ) ;
2015-11-23 00:33:41 +08:00
2019-05-26 01:27:43 +08:00
PrintAndLogEx ( SUCCESS , " Simulating Viking - ID " _YELLOW_ ( " %08X " ) " raw " _YELLOW_ ( " %08X%08X " ) , id , ( uint32_t ) ( rawID > > 32 ) , ( uint32_t ) ( rawID & 0xFFFFFFFF ) ) ;
2019-03-09 15:59:13 +08:00
2019-05-24 19:06:08 +08:00
uint8_t bs [ 64 ] ;
num_to_bytebits ( rawID , sizeof ( bs ) , bs ) ;
lf_asksim_t * payload = calloc ( 1 , sizeof ( lf_asksim_t ) + sizeof ( bs ) ) ;
payload - > encoding = 1 ;
payload - > invert = 0 ;
payload - > separator = 0 ;
payload - > clock = 32 ;
memcpy ( payload - > data , bs , sizeof ( bs ) ) ;
2019-03-10 06:35:06 +08:00
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 ;
2015-11-23 00:33:41 +08:00
}
static command_t CommandTable [ ] = {
2019-05-02 02:48:15 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
{ " demod " , CmdVikingDemod , AlwaysAvailable , " Demodulate a Viking tag from the GraphBuffer " } ,
2019-05-02 06:02:38 +08:00
{ " read " , CmdVikingRead , IfPm3Lf , " Attempt to read and Extract tag data from the antenna " } ,
{ " clone " , CmdVikingClone , IfPm3Lf , " <8 digit ID number> clone viking tag " } ,
{ " sim " , CmdVikingSim , IfPm3Lf , " <8 digit ID number> simulate viking tag " } ,
2019-05-02 02:48:15 +08:00
{ NULL , NULL , NULL , NULL }
2015-10-05 00:01:33 +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 21:44:55 +08:00
return PM3_SUCCESS ;
2015-10-05 00:01:33 +08:00
}
2019-04-12 08:07:11 +08:00
int CmdLFViking ( const char * Cmd ) {
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2015-10-05 00:01:33 +08:00
}
2019-04-12 06:38:54 +08:00
// calc checksum
uint64_t getVikingBits ( uint32_t id ) {
uint8_t checksum = ( ( id > > 24 ) & 0xFF ) ^ ( ( id > > 16 ) & 0xFF ) ^ ( ( id > > 8 ) & 0xFF ) ^ ( id & 0xFF ) ^ 0xF2 ^ 0xA8 ;
uint64_t ret = ( uint64_t ) 0xF2 < < 56 ;
ret | = ( uint64_t ) id < < 8 ;
ret | = checksum ;
return ret ;
}
// by marshmellow
// find viking preamble 0xF200 in already demoded data
2019-05-26 01:27:43 +08:00
int detectViking ( uint8_t * src , size_t * size ) {
2019-04-12 06:38:54 +08:00
//make sure buffer has data
2019-05-26 01:27:43 +08:00
if ( * size < 64 ) return - 2 ;
2019-04-12 06:38:54 +08:00
size_t startIdx = 0 ;
uint8_t preamble [ ] = { 1 , 1 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2019-05-26 01:27:43 +08:00
if ( ! preambleSearch ( src , preamble , sizeof ( preamble ) , size , & startIdx ) )
2019-04-12 06:38:54 +08:00
return - 4 ; //preamble not found
2019-05-26 01:27:43 +08:00
uint32_t checkCalc = bytebits_to_byte ( src + startIdx , 8 ) ^
bytebits_to_byte ( src + startIdx + 8 , 8 ) ^
bytebits_to_byte ( src + startIdx + 16 , 8 ) ^
bytebits_to_byte ( src + startIdx + 24 , 8 ) ^
bytebits_to_byte ( src + startIdx + 32 , 8 ) ^
bytebits_to_byte ( src + startIdx + 40 , 8 ) ^
bytebits_to_byte ( src + startIdx + 48 , 8 ) ^
bytebits_to_byte ( src + startIdx + 56 , 8 ) ;
2019-04-12 06:38:54 +08:00
if ( checkCalc ! = 0xA8 ) return - 5 ;
if ( * size ! = 64 ) return - 6 ;
//return start position
return ( int ) startIdx ;
}
int demodViking ( void ) {
return CmdVikingDemod ( " " ) ;
}