2017-07-30 15:17:48 +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 Indala commands
// PSK1, rf/32, 64 or 224 bits (known)
//-----------------------------------------------------------------------------
# include "cmdlfindala.h"
2019-08-08 22:57:33 +08:00
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <inttypes.h>
# include "cmdparser.h" // command_t
# include "comms.h"
# include "graph.h"
# include "cliparser/cliparser.h"
# include "commonutil.h"
# include "ui.h" // PrintAndLog
# include "lfdemod.h" // parityTest, bitbytes_to_byte
# include "cmddata.h"
# include "cmdlf.h" // lf_read
2017-07-30 15:17:48 +08:00
static int CmdHelp ( const char * Cmd ) ;
2019-03-26 16:09:43 +08:00
//large 224 bit indala formats (different preamble too...)
static uint8_t preamble224 [ ] = { 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ;
// standard 64 bit indala formats including 26 bit 40134 format
static uint8_t preamble64 [ ] = { 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ;
2019-04-10 19:06:05 +08:00
static int usage_lf_indala_demod ( void ) {
2019-04-10 19:46:51 +08:00
PrintAndLogEx ( NORMAL , " Tries to psk demodulate the graphbuffer as Indala " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-04-10 19:46:51 +08:00
PrintAndLogEx ( NORMAL , " Usage: lf indala demod [h] <clock> <0|1> <maxerror> " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
2019-04-10 19:46:51 +08:00
PrintAndLogEx ( NORMAL , " h : This help " ) ;
PrintAndLogEx ( NORMAL , " clock : Set clock (as integer) optional, if not set, autodetect. " ) ;
PrintAndLogEx ( NORMAL , " invert : 1 for invert output " ) ;
2019-04-14 19:37:53 +08:00
PrintAndLogEx ( NORMAL , " maxerror : Set maximum allowed errors, default = 100. " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " lf indala demod " ) ;
2019-04-10 19:46:51 +08:00
PrintAndLogEx ( NORMAL , " lf indala demod 32 = demod a Indala tag from GraphBuffer using a clock of RF/32 " ) ;
2019-04-14 19:37:53 +08:00
PrintAndLogEx ( NORMAL , " lf indala demod 32 1 = demod a Indala tag from GraphBuffer using a clock of RF/32 and inverting data " ) ;
PrintAndLogEx ( NORMAL , " lf indala demod 64 1 0 = demod a Indala tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors " ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_lf_indala_sim ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Enables simulation of Indala card with specified uid. " ) ;
PrintAndLogEx ( NORMAL , " Simulation runs until the button is pressed or another USB command is issued. " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: lf indala sim [h] <uid> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h : This help " ) ;
PrintAndLogEx ( NORMAL , " <uid> : 64/224 UID " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " lf indala sim deadc0de " ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
// Indala 26 bit decode
// by marshmellow
// optional arguments - same as PSKDemod (clock & invert & maxerr)
2019-04-12 07:55:25 +08:00
static int CmdIndalaDemod ( const char * Cmd ) {
2019-04-10 19:31:09 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-04-10 19:46:51 +08:00
if ( cmdp = = ' h ' ) return usage_lf_indala_demod ( ) ;
2019-04-14 19:37:53 +08:00
2019-03-10 06:35:06 +08:00
int ans ;
if ( strlen ( Cmd ) > 0 )
2019-03-26 16:09:43 +08:00
ans = PSKDemod ( Cmd , true ) ;
else
ans = PSKDemod ( " 32 " , true ) ;
2019-03-10 06:35:06 +08:00
2019-05-22 20:32:30 +08:00
if ( ans ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala can't demod signal: %d " , ans ) ;
2019-05-22 20:32:30 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
uint8_t invert = 0 ;
size_t size = DemodBufferLen ;
2019-03-26 16:09:43 +08:00
int idx = detectIndala ( DemodBuffer , & size , & invert ) ;
if ( idx < 0 ) {
if ( idx = = - 1 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala: not enough samples " ) ;
else if ( idx = = - 2 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala: only noise found " ) ;
else if ( idx = = - 4 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala: preamble not found " ) ;
else if ( idx = = - 5 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala: size not correct: %d " , size ) ;
else
PrintAndLogEx ( DEBUG , " DEBUG: Error - Indala: error demoding psk idx: %d " , idx ) ;
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 , size , idx ) ;
2019-03-10 06:35:06 +08:00
setClockGrid ( g_DemodClock , g_DemodStartIdx + ( idx * g_DemodClock ) ) ;
2019-03-28 21:19:41 +08:00
2019-03-10 06:35:06 +08:00
//convert UID to HEX
2019-06-08 00:41:39 +08:00
uint32_t uid1 = bytebits_to_byte ( DemodBuffer , 32 ) ;
uint32_t uid2 = bytebits_to_byte ( DemodBuffer + 32 , 32 ) ;
2019-03-28 21:19:41 +08:00
uint64_t foo = ( ( ( uint64_t ) uid1 < < 32 ) & 0x1FFFFFFF ) | ( uid2 & 0x7FFFFFFF ) ;
2019-03-26 16:09:43 +08:00
2019-03-10 07:00:59 +08:00
if ( DemodBufferLen = = 64 ) {
2019-03-26 16:09:43 +08:00
PrintAndLogEx (
SUCCESS
, " Indala Found - bitlength %d, Raw %x%08x "
, DemodBufferLen
, uid1
, uid2
) ;
2019-03-28 21:19:41 +08:00
2019-03-26 16:09:43 +08:00
uint16_t p1 = 0 ;
2019-03-28 21:19:41 +08:00
p1 | = DemodBuffer [ 32 + 3 ] < < 8 ;
p1 | = DemodBuffer [ 32 + 6 ] < < 5 ;
p1 | = DemodBuffer [ 32 + 8 ] < < 4 ;
p1 | = DemodBuffer [ 32 + 9 ] < < 3 ;
p1 | = DemodBuffer [ 32 + 11 ] < < 1 ;
p1 | = DemodBuffer [ 32 + 16 ] < < 6 ;
p1 | = DemodBuffer [ 32 + 19 ] < < 7 ;
p1 | = DemodBuffer [ 32 + 20 ] < < 10 ;
p1 | = DemodBuffer [ 32 + 21 ] < < 2 ;
p1 | = DemodBuffer [ 32 + 22 ] < < 0 ;
p1 | = DemodBuffer [ 32 + 24 ] < < 9 ;
/*
uint16_t fc = 0 ;
fc | = DemodBuffer [ 32 + 1 ] < < 0 ;
fc | = DemodBuffer [ 32 + 2 ] < < 1 ;
fc | = DemodBuffer [ 32 + 4 ] < < 2 ;
fc | = DemodBuffer [ 32 + 5 ] < < 3 ;
fc | = DemodBuffer [ 32 + 7 ] < < 4 ;
fc | = DemodBuffer [ 32 + 10 ] < < 5 ;
fc | = DemodBuffer [ 32 + 14 ] < < 6 ;
fc | = DemodBuffer [ 32 + 15 ] < < 7 ;
fc | = DemodBuffer [ 32 + 17 ] < < 8 ;
*/
2019-03-26 16:09:43 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( SUCCESS , " Possible de-scramble patterns " ) ;
PrintAndLogEx ( SUCCESS , " \t Printed | __%04d__ [0x%X] " , p1 , p1 ) ;
2019-03-27 04:13:57 +08:00
//PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", fc, fc);
2019-03-28 21:19:41 +08:00
PrintAndLogEx ( SUCCESS , " \t Internal ID | % " PRIu64 , foo ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-06-08 00:41:39 +08:00
uint32_t uid3 = bytebits_to_byte ( DemodBuffer + 64 , 32 ) ;
uint32_t uid4 = bytebits_to_byte ( DemodBuffer + 96 , 32 ) ;
uint32_t uid5 = bytebits_to_byte ( DemodBuffer + 128 , 32 ) ;
uint32_t uid6 = bytebits_to_byte ( DemodBuffer + 160 , 32 ) ;
uint32_t uid7 = bytebits_to_byte ( DemodBuffer + 192 , 32 ) ;
2019-04-07 14:52:10 +08:00
PrintAndLogEx (
SUCCESS
, " Indala Found - bitlength %d, Raw 0x%x%08x%08x%08x%08x%08x%08x "
2019-04-07 18:10:51 +08:00
, DemodBufferLen
, uid1
, uid2
, uid3
, uid4
, uid5
, uid6
, uid7
) ;
2019-03-10 06:35:06 +08:00
}
2019-03-28 21:19:41 +08:00
2019-03-10 07:00:59 +08:00
if ( g_debugMode ) {
2019-03-26 16:09:43 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Indala - printing demodbuffer " ) ;
2019-03-10 06:35:06 +08:00
printDemodBuff ( ) ;
}
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
// older alternative indala demodulate (has some positives and negatives)
// returns false positives more often - but runs against more sets of samples
// poor psk signal can be difficult to demod this approach might succeed when the other fails
// but the other appears to currently be more accurate than this approach most of the time.
2019-04-12 07:55:25 +08:00
static int CmdIndalaDemodAlt ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
// Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
int state = - 1 ;
int count = 0 ;
int i , j ;
// worst case with GraphTraceLen=40000 is < 4096
// under normal conditions it's < 2048
uint8_t data [ MAX_GRAPH_TRACE_LEN ] = { 0 } ;
size_t datasize = getFromGraphBuf ( data ) ;
uint8_t rawbits [ 4096 ] ;
int rawbit = 0 ;
int worst = 0 , worstPos = 0 ;
//clear clock grid and demod plot
setClockGrid ( 0 , 0 ) ;
DemodBufferLen = 0 ;
// PrintAndLogEx(NORMAL, "Expecting a bit less than %d raw bits", GraphTraceLen / 32);
// loop through raw signal - since we know it is psk1 rf/32 fc/2 skip every other value (+=2)
2019-03-10 07:00:59 +08:00
for ( i = 0 ; i < datasize - 1 ; i + = 2 ) {
2019-03-10 06:35:06 +08:00
count + = 1 ;
if ( ( data [ i ] > data [ i + 1 ] ) & & ( state ! = 1 ) ) {
// appears redundant - marshmellow
if ( state = = 0 ) {
for ( j = 0 ; j < count - 8 ; j + = 16 ) {
rawbits [ rawbit + + ] = 0 ;
}
if ( ( abs ( count - j ) ) > worst ) {
worst = abs ( count - j ) ;
worstPos = i ;
}
}
state = 1 ;
count = 0 ;
} else if ( ( data [ i ] < data [ i + 1 ] ) & & ( state ! = 0 ) ) {
//appears redundant
if ( state = = 1 ) {
for ( j = 0 ; j < count - 8 ; j + = 16 ) {
rawbits [ rawbit + + ] = 1 ;
}
if ( ( abs ( count - j ) ) > worst ) {
worst = abs ( count - j ) ;
worstPos = i ;
}
}
state = 0 ;
count = 0 ;
}
}
2019-03-10 07:00:59 +08:00
if ( rawbit > 0 ) {
PrintAndLogEx ( INFO , " Recovered %d raw bits, expected: %d " , rawbit , GraphTraceLen / 32 ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " worst metric (0=best..7=worst): %d at pos %d " , worst , worstPos ) ;
} else {
2019-05-22 20:32:30 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
// Finding the start of a UID
int uidlen , long_wait ;
if ( strcmp ( Cmd , " 224 " ) = = 0 ) {
uidlen = 224 ;
long_wait = 30 ;
} else {
uidlen = 64 ;
long_wait = 29 ;
}
int start ;
int first = 0 ;
for ( start = 0 ; start < = rawbit - uidlen ; start + + ) {
first = rawbits [ start ] ;
for ( i = start ; i < start + long_wait ; i + + ) {
if ( rawbits [ i ] ! = first ) {
break ;
}
}
if ( i = = ( start + long_wait ) ) {
break ;
}
}
if ( start = = rawbit - uidlen + 1 ) {
PrintAndLogEx ( FAILED , " nothing to wait for " ) ;
2019-05-22 20:32:30 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
// Inverting signal if needed
if ( first = = 1 ) {
for ( i = start ; i < rawbit ; i + + ) {
rawbits [ i ] = ! rawbits [ i ] ;
}
}
// Dumping UID
uint8_t bits [ 224 ] = { 0x00 } ;
char showbits [ 225 ] = { 0x00 } ;
int bit ;
i = start ;
int times = 0 ;
if ( uidlen > rawbit ) {
PrintAndLogEx ( WARNING , " Warning: not enough raw bits to get a full UID " ) ;
for ( bit = 0 ; bit < rawbit ; bit + + ) {
bits [ bit ] = rawbits [ i + + ] ;
// As we cannot know the parity, let's use "." and "/"
showbits [ bit ] = ' . ' + bits [ bit ] ;
}
2019-03-10 07:00:59 +08:00
showbits [ bit + 1 ] = ' \0 ' ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " Partial UID | %s " , showbits ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
} else {
for ( bit = 0 ; bit < uidlen ; bit + + ) {
bits [ bit ] = rawbits [ i + + ] ;
showbits [ bit ] = ' 0 ' + bits [ bit ] ;
}
times = 1 ;
}
//convert UID to HEX
int idx ;
2019-06-08 00:41:39 +08:00
uint32_t uid1 = 0 ;
uint32_t uid2 = 0 ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( uidlen = = 64 ) {
for ( idx = 0 ; idx < 64 ; idx + + ) {
if ( showbits [ idx ] = = ' 0 ' ) {
uid1 = ( uid1 < < 1 ) | ( uid2 > > 31 ) ;
uid2 = ( uid2 < < 1 ) | 0 ;
} else {
uid1 = ( uid1 < < 1 ) | ( uid2 > > 31 ) ;
uid2 = ( uid2 < < 1 ) | 1 ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " UID | %s (%x%08x) " , showbits , uid1 , uid2 ) ;
2019-03-10 07:00:59 +08:00
} else {
2019-06-08 00:41:39 +08:00
uint32_t uid3 = 0 ;
uint32_t uid4 = 0 ;
uint32_t uid5 = 0 ;
uint32_t uid6 = 0 ;
uint32_t uid7 = 0 ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
for ( idx = 0 ; idx < 224 ; idx + + ) {
uid1 = ( uid1 < < 1 ) | ( uid2 > > 31 ) ;
uid2 = ( uid2 < < 1 ) | ( uid3 > > 31 ) ;
uid3 = ( uid3 < < 1 ) | ( uid4 > > 31 ) ;
uid4 = ( uid4 < < 1 ) | ( uid5 > > 31 ) ;
uid5 = ( uid5 < < 1 ) | ( uid6 > > 31 ) ;
uid6 = ( uid6 < < 1 ) | ( uid7 > > 31 ) ;
2019-03-10 06:35:06 +08:00
if ( showbits [ idx ] = = ' 0 ' )
2019-03-10 07:00:59 +08:00
uid7 = ( uid7 < < 1 ) | 0 ;
2019-03-10 06:35:06 +08:00
else
2019-03-10 07:00:59 +08:00
uid7 = ( uid7 < < 1 ) | 1 ;
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " UID | %s (%x%08x%08x%08x%08x%08x%08x) " , showbits , uid1 , uid2 , uid3 , uid4 , uid5 , uid6 , uid7 ) ;
}
// Checking UID against next occurrences
for ( ; i + uidlen < = rawbit ; ) {
2019-04-08 02:21:14 +08:00
int failed = 0 ;
2019-03-10 06:35:06 +08:00
for ( bit = 0 ; bit < uidlen ; bit + + ) {
if ( bits [ bit ] ! = rawbits [ i + + ] ) {
failed = 1 ;
break ;
}
}
if ( failed = = 1 ) {
break ;
}
times + = 1 ;
}
PrintAndLogEx ( DEBUG , " Occurrences: %d (expected %d) " , times , ( rawbit - start ) / uidlen ) ;
// Remodulating for tag cloning
// HACK: 2015-01-04 this will have an impact on our new way of seening lf commands (demod)
// since this changes graphbuffer data.
GraphTraceLen = 32 * uidlen ;
i = 0 ;
2019-04-08 02:21:14 +08:00
int phase ;
2019-03-10 06:35:06 +08:00
for ( bit = 0 ; bit < uidlen ; bit + + ) {
if ( bits [ bit ] = = 0 ) {
phase = 0 ;
} else {
phase = 1 ;
}
for ( j = 0 ; j < 32 ; j + + ) {
GraphBuffer [ i + + ] = phase ;
phase = ! phase ;
}
}
RepaintGraphWindow ( ) ;
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
2019-04-12 07:55:25 +08:00
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdIndalaRead ( const char * Cmd ) {
lf_read ( true , 30000 ) ;
return CmdIndalaDemod ( Cmd ) ;
}
static int CmdIndalaSim ( const char * Cmd ) {
2017-07-30 15:17:48 +08:00
2019-03-10 06:35:06 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) = = 0 | | cmdp = = ' h ' ) return usage_lf_indala_sim ( ) ;
2019-05-24 21:11:30 +08:00
uint8_t bs [ 224 ] ;
memset ( bs , 0x00 , sizeof ( bs ) ) ;
2019-03-10 06:35:06 +08:00
// uid
uint8_t hexuid [ 100 ] ;
int len = 0 ;
param_gethex_ex ( Cmd , 0 , hexuid , & len ) ;
2019-03-10 07:00:59 +08:00
if ( len > 28 )
2019-03-10 06:35:06 +08:00
return usage_lf_indala_sim ( ) ;
// convert to binarray
uint8_t counter = 223 ;
for ( uint8_t i = 0 ; i < len ; i + + ) {
2019-03-10 07:00:59 +08:00
for ( uint8_t j = 0 ; j < 8 ; j + + ) {
2019-05-24 21:11:30 +08:00
bs [ counter - - ] = hexuid [ i ] & 1 ;
2019-03-10 06:35:06 +08:00
hexuid [ i ] > > = 1 ;
}
}
// indala PSK
// It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
// lf simpsk 1 c 32 r 2 d 0102030405060708
PrintAndLogEx ( SUCCESS , " Simulating Indala UID: %s " , sprint_hex ( hexuid , len ) ) ;
PrintAndLogEx ( SUCCESS , " Press pm3-button to abort simulation or run another command " ) ;
2019-05-24 21:11:30 +08:00
// indala PSK, clock 32, carrier 0
lf_psksim_t * payload = calloc ( 1 , sizeof ( lf_psksim_t ) + sizeof ( bs ) ) ;
payload - > carrier = 2 ;
payload - > invert = 0 ;
payload - > clock = 32 ;
memcpy ( payload - > data , bs , sizeof ( bs ) ) ;
PrintAndLogEx ( INFO , " Simulating " ) ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_LF_PSK_SIMULATE , ( uint8_t * ) payload , sizeof ( lf_psksim_t ) + sizeof ( bs ) ) ;
2019-05-24 21:11:30 +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_PSK_SIMULATE , & resp ) ;
2019-05-24 21:11:30 +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 ;
2017-07-30 15:17:48 +08:00
}
2019-03-09 15:59:13 +08:00
// iceman - needs refactoring
2019-04-12 07:55:25 +08:00
static int CmdIndalaClone ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
2019-03-26 16:09:43 +08:00
bool isLongUid = false ;
2019-03-28 21:19:41 +08:00
uint8_t data [ 7 * 4 ] ;
2019-03-26 16:09:43 +08:00
int datalen = 0 ;
2019-03-28 21:19:41 +08:00
2019-03-26 16:09:43 +08:00
CLIParserInit ( " lf indala clone " ,
" Enables cloning of Indala card with specified uid onto T55x7 \n "
" defaults to 64. \n " ,
" \n "
" Samples: \n "
" \t lf indala clone a0000000a0002021 \n "
" \t lf indala clone -l 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5 " ) ;
void * argtable [ ] = {
arg_param_begin ,
arg_lit0 ( " lL " , " long " , " long UID 224 bits " ) ,
arg_strx1 ( NULL , NULL , " <uid (hex)> " , NULL ) ,
arg_param_end
} ;
CLIExecWithReturn ( Cmd , argtable , false ) ;
isLongUid = arg_get_lit ( 1 ) ;
CLIGetHexWithReturn ( 2 , data , & datalen ) ;
CLIParserFree ( ) ;
if ( isLongUid ) {
2019-04-07 14:52:10 +08:00
PrintAndLogEx ( INFO , " Preparing to clone Indala 224bit tag with RawID %s " , sprint_hex ( data , datalen ) ) ;
2019-04-19 23:03:39 +08:00
uint32_t datawords [ 7 ] = { 0 } ;
datawords [ 0 ] = bytes_to_num ( data , 4 ) ;
datawords [ 1 ] = bytes_to_num ( data + 4 , 4 ) ;
datawords [ 2 ] = bytes_to_num ( data + 8 , 4 ) ;
datawords [ 3 ] = bytes_to_num ( data + 12 , 4 ) ;
datawords [ 4 ] = bytes_to_num ( data + 16 , 4 ) ;
datawords [ 5 ] = bytes_to_num ( data + 20 , 4 ) ;
datawords [ 6 ] = bytes_to_num ( data + 24 , 4 ) ;
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandOLD ( CMD_LF_INDALA224_CLONE , 0 , 0 , 0 , datawords , sizeof ( datawords ) ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-04-07 14:52:10 +08:00
PrintAndLogEx ( INFO , " Preparing to clone Indala 64bit tag with RawID %s " , sprint_hex ( data , datalen ) ) ;
2019-04-19 23:03:39 +08:00
uint32_t datawords [ 2 ] = { 0 } ;
datawords [ 0 ] = bytes_to_num ( data , 4 ) ;
datawords [ 1 ] = bytes_to_num ( data + 4 , 4 ) ;
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandOLD ( CMD_LF_INDALA_CLONE , 0 , 0 , 0 , datawords , sizeof ( datawords ) ) ;
2019-03-10 06:35:06 +08:00
}
2019-03-28 21:19:41 +08:00
2019-05-22 20:32:30 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
static command_t CommandTable [ ] = {
2019-05-02 02:48:15 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " this help " } ,
{ " demod " , CmdIndalaDemod , AlwaysAvailable , " demodulate an indala tag (PSK1) from GraphBuffer " } ,
{ " altdemod " , CmdIndalaDemodAlt , AlwaysAvailable , " alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit) " } ,
2019-05-02 06:02:38 +08:00
{ " read " , CmdIndalaRead , IfPm3Lf , " read an Indala Prox tag from the antenna " } ,
{ " clone " , CmdIndalaClone , IfPm3Lf , " clone Indala to T55x7 " } ,
{ " sim " , CmdIndalaSim , IfPm3Lf , " simulate Indala tag " } ,
2019-05-02 02:48:15 +08:00
{ NULL , NULL , NULL , NULL }
2017-07-30 15:17:48 +08:00
} ;
2019-04-12 07:55:25 +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 ;
2019-04-12 07:55:25 +08:00
}
2019-03-10 18:20:22 +08:00
int CmdLFINDALA ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2017-07-30 15:17:48 +08:00
}
2019-04-12 07:55:25 +08:00
// redesigned by marshmellow adjusted from existing decode functions
// indala id decoding
int detectIndala ( uint8_t * dest , size_t * size , uint8_t * invert ) {
uint8_t preamble64_i [ ] = { 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 } ;
uint8_t preamble224_i [ ] = { 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 } ;
size_t idx = 0 ;
size_t found_size = * size ;
// PSK1
bool res = preambleSearch ( dest , preamble64 , sizeof ( preamble64 ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK1 found 64 " ) ;
goto out ;
}
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble64_i , sizeof ( preamble64_i ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK1 found 64 inverted preamble " ) ;
goto inv ;
}
/*
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble224 , sizeof ( preamble224 ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK1 found 224 " ) ;
goto out ;
}
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble224_i , sizeof ( preamble224_i ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK1 found 224 inverted preamble " ) ;
goto inv ;
}
*/
// PSK2
psk1TOpsk2 ( dest , * size ) ;
PrintAndLogEx ( DEBUG , " DEBUG: detectindala Converting PSK1 -> PSK2 " ) ;
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble64 , sizeof ( preamble64 ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK2 found 64 preamble " ) ;
goto out ;
}
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble224 , sizeof ( preamble224 ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK2 found 224 preamble " ) ;
goto out ;
}
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble64_i , sizeof ( preamble64_i ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK2 found 64 inverted preamble " ) ;
goto inv ;
}
idx = 0 ;
found_size = * size ;
res = preambleSearch ( dest , preamble224_i , sizeof ( preamble224_i ) , & found_size , & idx ) ;
if ( res ) {
PrintAndLogEx ( DEBUG , " DEBUG: detectindala PSK2 found 224 inverted preamble " ) ;
goto inv ;
}
inv :
if ( res = = 0 ) {
return - 4 ;
}
* invert ^ = 1 ;
if ( * invert & & idx > 0 ) {
for ( size_t i = idx - 1 ; i < found_size + idx + 2 ; i + + ) {
dest [ i ] ^ = 1 ;
}
}
PrintAndLogEx ( DEBUG , " DEBUG: Warning - Indala had to invert bits " ) ;
out :
* size = found_size ;
//PrintAndLogEx(INFO, "DEBUG: detectindala RES = %d | %d | %d", res, found_size, idx);
if ( found_size ! = 224 & & found_size ! = 64 ) {
PrintAndLogEx ( INFO , " DEBUG: detectindala | %d " , found_size ) ;
return - 5 ;
}
// 224 formats are typically PSK2 (afaik 2017 Marshmellow)
// note loses 1 bit at beginning of transformation...
return ( int ) idx ;
}
int demodIndala ( void ) {
return CmdIndalaDemod ( " " ) ;
2017-07-30 15:17:48 +08:00
}