2019-08-01 21:39:33 +08:00
//-----------------------------------------------------------------------------
2022-01-07 08:58:03 +08:00
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
2019-08-01 21:39:33 +08:00
//
2022-01-07 08:58:03 +08:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
2019-08-01 21:39:33 +08:00
//-----------------------------------------------------------------------------
// Thinfilm commands
//-----------------------------------------------------------------------------
# include "cmdhfthinfilm.h"
2019-08-08 22:57:33 +08:00
# include <stdio.h>
# include <string.h>
# include <ctype.h>
2020-12-06 08:35:52 +08:00
# include "cliparser.h"
2019-08-08 22:57:33 +08:00
# include "cmdparser.h" // command_t
# include "comms.h"
# include "cmdtrace.h"
# include "crc16.h"
# include "ui.h"
# include "cmdhf14a.h" // manufacture
2019-08-01 21:39:33 +08:00
static int CmdHelp ( const char * Cmd ) ;
// Printing function based upon the code in libnfc
// ref
// https://github.com/nfc-tools/libnfc/blob/master/utils/nfc-barcode.c
2019-08-01 23:33:00 +08:00
static int print_barcode ( uint8_t * barcode , const size_t barcode_len , bool verbose ) {
2019-08-01 21:39:33 +08:00
2019-09-24 00:59:45 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-08-02 00:16:33 +08:00
// remove start bit
uint8_t mb = barcode [ 0 ] & ~ 0x80 ;
PrintAndLogEx ( SUCCESS , " Manufacturer : " _YELLOW_ ( " %s " ) " [0x%02X] " , getTagInfo ( mb ) , mb ) ;
2019-08-01 23:09:51 +08:00
2019-08-01 23:33:00 +08:00
if ( verbose ) {
PrintAndLogEx ( SUCCESS , " Data format : " _YELLOW_ ( " %02X " ) , barcode [ 1 ] ) ;
2019-08-01 23:49:35 +08:00
if ( barcode_len > 2 ) {
uint8_t b1 , b2 ;
compute_crc ( CRC_14443_A , barcode , barcode_len - 2 , & b1 , & b2 ) ;
bool isok = ( barcode [ barcode_len - 1 ] = = b1 & & barcode [ barcode_len - 2 ] = = b2 ) ;
2022-02-25 01:03:19 +08:00
PrintAndLogEx ( SUCCESS , " Checksum : " _YELLOW_ ( " %02X %02X " ) " ( %s ) " , b2 , b1 , ( isok ) ? _GREEN_ ( " ok " ) : _RED_ ( " fail " ) ) ;
2019-08-01 23:49:35 +08:00
} else {
2020-04-22 08:22:55 +08:00
PrintAndLogEx ( SUCCESS , " Checksum : " _YELLOW_ ( " too few data for checksum " ) " - " _RED_ ( " fail " ) ) ;
2019-08-01 23:49:35 +08:00
}
2022-02-25 01:03:19 +08:00
PrintAndLogEx ( SUCCESS , " Data len (bits) : " _YELLOW_ ( " %zu " ) " ( %s ) " , barcode_len * 8 , ( barcode_len = = 16 | | barcode_len = = 32 ) ? _GREEN_ ( " ok " ) : _YELLOW_ ( " warning " ) ) ;
2019-08-01 23:33:00 +08:00
PrintAndLogEx ( SUCCESS , " Raw data : " _YELLOW_ ( " %s " ) , sprint_hex ( barcode , barcode_len ) ) ;
2019-08-01 23:49:35 +08:00
if ( barcode_len < 4 ) // too few to go to next decoding stages
return PM3_ESOFT ;
2019-08-01 23:33:00 +08:00
}
2019-08-01 23:09:51 +08:00
2019-08-01 21:39:33 +08:00
char s [ 45 ] ;
memset ( s , 0x00 , sizeof ( s ) ) ;
2019-08-01 23:15:39 +08:00
2019-08-01 21:39:33 +08:00
switch ( barcode [ 1 ] ) {
case 0 :
2019-08-02 00:22:51 +08:00
PrintAndLogEx ( SUCCESS , " Data format : Reserved for allocation by tag manufacturer " ) ;
2019-08-01 21:39:33 +08:00
return PM3_SUCCESS ;
case 1 :
2019-08-01 23:15:39 +08:00
snprintf ( s , sizeof ( s ) , " http://www. " ) ;
2019-08-01 21:39:33 +08:00
break ;
case 2 :
snprintf ( s , sizeof ( s ) , " https://www. " ) ;
break ;
case 3 :
snprintf ( s , sizeof ( s ) , " http:// " ) ;
break ;
case 4 :
snprintf ( s , sizeof ( s ) , " https:// " ) ;
break ;
case 5 :
2019-08-01 23:49:35 +08:00
if ( barcode_len < 16 ) {
PrintAndLogEx ( WARNING , " EPC: (partial data) %s " , sprint_hex ( barcode + 2 , barcode_len - 2 ) ) ;
return PM3_ESOFT ;
}
2019-08-01 23:15:39 +08:00
PrintAndLogEx ( SUCCESS , " EPC: %s " , sprint_hex ( barcode + 2 , 12 ) ) ;
2019-08-01 21:39:33 +08:00
return PM3_SUCCESS ;
default :
2019-08-02 00:22:51 +08:00
PrintAndLogEx ( SUCCESS , " Data format : RFU Reserved for future use (%02X) " , barcode [ 1 ] ) ;
2019-08-02 00:03:41 +08:00
if ( ! verbose )
PrintAndLogEx ( SUCCESS , " Raw data with CRC: " _YELLOW_ ( " %s " ) , sprint_hex ( barcode , barcode_len ) ) ;
2019-08-01 21:39:33 +08:00
return PM3_SUCCESS ;
}
2019-08-01 23:15:39 +08:00
snprintf ( s + strlen ( s ) , barcode_len - 3 , ( const char * ) & barcode [ 2 ] , barcode_len - 4 ) ;
2019-08-01 21:39:33 +08:00
2022-02-17 05:23:16 +08:00
for ( size_t i = 0 ; i < strlen ( s ) ; i + + ) {
2019-08-01 21:39:33 +08:00
// terminate string
2019-08-01 23:07:07 +08:00
if ( ( uint8_t ) s [ i ] = = 0xFE ) {
2019-08-01 21:39:33 +08:00
s [ i ] = 0 ;
break ;
}
}
PrintAndLogEx ( SUCCESS , " Decoded NFC URL : " _YELLOW_ ( " %s " ) , s ) ;
return PM3_SUCCESS ;
}
2021-05-29 04:35:42 +08:00
int CmdHfThinFilmInfo ( const char * Cmd ) {
2020-12-06 08:35:52 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " hf thinfilm info " ,
" Get info from Thinfilm tags " ,
" hf thinfilm info " ) ;
2019-08-01 21:39:33 +08:00
2020-12-06 08:35:52 +08:00
void * argtable [ ] = {
arg_param_begin ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
CLIParserFree ( ctx ) ;
2019-08-01 23:33:00 +08:00
return infoThinFilm ( true ) ;
2019-08-01 21:39:33 +08:00
}
2019-08-01 23:33:00 +08:00
int infoThinFilm ( bool verbose ) {
2019-08-01 23:15:39 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_THINFILM_READ , NULL , 0 ) ;
2019-08-01 21:39:33 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_THINFILM_READ , & resp , 1500 ) ) {
2019-08-01 21:39:33 +08:00
PrintAndLogEx ( WARNING , " timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
}
2019-08-01 23:15:39 +08:00
if ( resp . status = = PM3_SUCCESS ) {
2019-11-19 19:14:58 +08:00
if ( resp . length = = 16 | | resp . length = = 32 ) {
2021-03-29 16:48:46 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Tag Information " ) " --------------------------- " ) ;
2019-08-01 23:33:00 +08:00
print_barcode ( resp . data . asBytes , resp . length , verbose ) ;
} else {
2019-11-19 19:14:58 +08:00
if ( verbose )
PrintAndLogEx ( WARNING , " Response is wrong length. (%d) " , resp . length ) ;
2019-08-01 23:33:00 +08:00
return PM3_ESOFT ;
}
2019-08-01 21:39:33 +08:00
}
return resp . status ;
}
2021-05-29 04:35:42 +08:00
int CmdHfThinFilmSim ( const char * Cmd ) {
2020-12-06 08:35:52 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " hf thinfilm sim " ,
" Simulate Thinfilm tag " ,
" hf thinfilm sim -d B70470726f786d61726b2e636f6d " ) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str1 ( " d " , " data " , " <hex> " , " bytes to send " ) ,
arg_lit0 ( NULL , " raw " , " raw, provided bytes should include CRC " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , false ) ;
int data_len = 0 ;
uint8_t data [ 512 ] = { 0 } ;
CLIGetHexWithReturn ( ctx , 1 , data , & data_len ) ;
2019-08-02 06:00:37 +08:00
bool addcrc = true ;
2020-12-06 08:35:52 +08:00
if ( arg_get_lit ( ctx , 2 ) ) {
addcrc = false ;
2019-08-02 06:00:37 +08:00
}
2020-12-06 08:35:52 +08:00
CLIParserFree ( ctx ) ;
if ( addcrc & & data_len < = 510 ) {
2019-08-02 06:00:37 +08:00
uint8_t b1 , b2 ;
2020-12-06 08:35:52 +08:00
compute_crc ( CRC_14443_A , data , data_len , & b1 , & b2 ) ;
data [ data_len + + ] = b2 ;
data [ data_len + + ] = b1 ;
2019-08-02 06:00:37 +08:00
}
clearCommandBuffer ( ) ;
2020-12-06 08:35:52 +08:00
SendCommandNG ( CMD_HF_THINFILM_SIMULATE , ( uint8_t * ) & data , data_len ) ;
2019-08-02 06:00:37 +08:00
PacketResponseNG resp ;
PrintAndLogEx ( SUCCESS , " press pm3-button to abort simulation " ) ;
2019-08-04 04:37:01 +08:00
int ret ;
while ( ! ( ret = kbd_enter_pressed ( ) ) ) {
if ( WaitForResponseTimeout ( CMD_HF_THINFILM_SIMULATE , & resp , 500 ) = = 0 ) continue ;
2019-08-02 06:00:37 +08:00
if ( resp . status ! = PM3_SUCCESS ) break ;
}
2019-08-04 04:37:01 +08:00
if ( ret ) {
PrintAndLogEx ( INFO , " Client side interrupted " ) ;
PrintAndLogEx ( WARNING , " Simulation still running on Proxmark3 till next command or button press " ) ;
} else {
PrintAndLogEx ( INFO , " Done " ) ;
}
2019-08-02 06:00:37 +08:00
return PM3_SUCCESS ;
2019-08-01 21:39:33 +08:00
}
static int CmdHfThinFilmList ( const char * Cmd ) {
2021-04-20 03:43:32 +08:00
return CmdTraceListAlias ( Cmd , " hf thinfilm " , " thinfilm " ) ;
2019-08-01 21:39:33 +08:00
}
static command_t CommandTable [ ] = {
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2019-08-04 03:17:52 +08:00
{ " info " , CmdHfThinFilmInfo , IfPm3NfcBarcode , " Tag information " } ,
{ " list " , CmdHfThinFilmList , AlwaysAvailable , " List NFC Barcode / Thinfilm history - not correct " } ,
{ " sim " , CmdHfThinFilmSim , IfPm3NfcBarcode , " Fake Thinfilm tag " } ,
2019-08-01 21:39:33 +08:00
{ NULL , NULL , NULL , NULL }
} ;
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
return PM3_SUCCESS ;
}
int CmdHFThinfilm ( const char * Cmd ) {
clearCommandBuffer ( ) ;
return CmdsParse ( CommandTable , Cmd ) ;
}