2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
2012-07-07 00:19:05 +08:00
// Merlok - June 2011, 2012
2011-06-18 02:39:54 +08:00
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
2015-01-05 22:51:27 +08:00
// Midnitesnake - Dec 2013
// Andy Davies - Apr 2014
2016-04-12 17:30:49 +08:00
// Iceman - May 2014,2015,2016
2011-06-18 02:39:54 +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.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
# include "mifarecmd.h"
2017-07-27 15:28:43 +08:00
# include <inttypes.h>
2017-10-12 21:17:10 +08:00
2018-01-15 21:22:46 +08:00
# ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation)
2017-10-12 21:17:10 +08:00
# endif
2018-01-15 21:22:46 +08:00
# ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME
# define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
2017-10-12 21:17:10 +08:00
# endif
2018-01-15 21:22:46 +08:00
// send an incomplete dummy response in order to trigger the card's authentication failure timeout
2017-10-12 21:17:10 +08:00
# ifndef CHK_TIMEOUT
2017-10-30 22:02:44 +08:00
# define CHK_TIMEOUT() { \
2018-01-15 21:22:46 +08:00
ReaderTransmit ( & dummy_answer , 1 , NULL ) ; \
uint32_t timeout = GetCountSspClk ( ) + HARDNESTED_AUTHENTICATION_TIMEOUT ; \
while ( GetCountSspClk ( ) < timeout ) { } ; \
}
2017-10-12 21:17:10 +08:00
# endif
2018-01-15 21:22:46 +08:00
2017-10-30 22:12:03 +08:00
static uint8_t dummy_answer = 0 ;
2017-10-12 21:17:10 +08:00
2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
2014-09-11 01:04:50 +08:00
// Select, Authenticate, Read a MIFARE tag.
2011-06-18 02:39:54 +08:00
// read block
//-----------------------------------------------------------------------------
void MifareReadBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t arg2 , uint8_t * datain )
{
// params
uint8_t blockNo = arg0 ;
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( datain , 6 ) ;
// variables
byte_t isOK = 0 ;
2016-01-21 00:44:51 +08:00
byte_t dataoutbuf [ 16 ] = { 0x00 } ;
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
2011-06-18 02:39:54 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2014-02-20 04:35:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2011-06-18 02:39:54 +08:00
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-06-30 04:36:55 +08:00
2011-06-18 02:39:54 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
while ( true ) {
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2014-09-11 01:04:50 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
2011-06-18 02:39:54 +08:00
break ;
} ;
if ( mifare_classic_auth ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST ) ) {
2014-09-11 01:04:50 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Auth error " ) ;
2011-06-18 02:39:54 +08:00
break ;
} ;
if ( mifare_classic_readblock ( pcs , cuid , blockNo , dataoutbuf ) ) {
2014-09-11 01:04:50 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Read block error " ) ;
2011-06-18 02:39:54 +08:00
break ;
} ;
if ( mifare_classic_halt ( pcs , cuid ) ) {
2014-09-11 01:04:50 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
2011-06-18 02:39:54 +08:00
break ;
} ;
isOK = 1 ;
break ;
}
crypto1_destroy ( pcs ) ;
if ( MF_DBGLEVEL > = 2 ) DbpString ( " READ BLOCK FINISHED " ) ;
LED_B_ON ( ) ;
2014-09-11 01:04:50 +08:00
cmd_send ( CMD_ACK , isOK , 0 , 0 , dataoutbuf , 16 ) ;
2011-06-18 02:39:54 +08:00
LED_B_OFF ( ) ;
2015-01-14 06:18:04 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
}
2015-05-16 21:34:01 +08:00
void MifareUC_Auth ( uint8_t arg0 , uint8_t * keybytes ) {
2015-01-14 06:18:04 +08:00
2015-05-16 21:34:01 +08:00
bool turnOffField = ( arg0 = = 1 ) ;
2015-01-14 06:18:04 +08:00
2015-03-30 22:24:03 +08:00
LED_A_ON ( ) ; LED_B_OFF ( ) ; LED_C_OFF ( ) ;
2015-06-30 04:36:55 +08:00
2015-01-14 06:18:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-06-30 04:36:55 +08:00
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 0 ) ;
2015-01-14 06:18:04 +08:00
return ;
} ;
2015-05-19 02:58:33 +08:00
if ( ! mifare_ultra_auth ( keybytes ) ) {
2015-05-16 21:34:01 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Authentication failed " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 1 ) ;
2015-01-14 06:18:04 +08:00
return ;
}
2015-05-16 21:34:01 +08:00
if ( turnOffField ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2015-05-16 13:00:31 +08:00
}
2015-05-19 01:11:00 +08:00
cmd_send ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2014-06-20 07:02:59 +08:00
}
2015-05-05 06:33:07 +08:00
// Arg0 = BlockNo,
// Arg1 = UsePwd bool
2015-05-06 12:55:29 +08:00
// datain = PWD bytes,
2015-03-24 18:45:31 +08:00
void MifareUReadBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain )
2014-06-20 07:02:59 +08:00
{
uint8_t blockNo = arg0 ;
2015-01-08 07:08:33 +08:00
byte_t dataout [ 16 ] = { 0x00 } ;
2015-05-16 21:34:01 +08:00
bool useKey = ( arg1 = = 1 ) ; //UL_C
bool usePwd = ( arg1 = = 2 ) ; //UL_EV1/NTAG
2015-05-05 06:33:07 +08:00
2015-05-06 12:55:29 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
2015-01-08 07:08:33 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-04-30 06:27:31 +08:00
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-06-30 04:36:55 +08:00
2017-10-02 04:06:06 +08:00
int len = iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ;
2015-01-08 07:08:33 +08:00
if ( ! len ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Can't select card (RC:%02X) " , len ) ;
2015-03-24 18:45:31 +08:00
OnError ( 1 ) ;
2015-01-08 07:08:33 +08:00
return ;
2015-03-30 22:24:03 +08:00
}
2015-04-30 06:27:31 +08:00
2015-05-16 21:34:01 +08:00
// UL-C authentication
if ( useKey ) {
2015-05-18 08:49:25 +08:00
uint8_t key [ 16 ] = { 0x00 } ;
2015-05-16 21:34:01 +08:00
memcpy ( key , datain , sizeof ( key ) ) ;
2015-05-19 02:58:33 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2015-03-30 22:24:03 +08:00
OnError ( 1 ) ;
2015-04-30 06:27:31 +08:00
return ;
2015-03-24 18:45:31 +08:00
}
2015-05-16 21:34:01 +08:00
}
2015-04-30 06:27:31 +08:00
2015-05-16 21:34:01 +08:00
// UL-EV1 / NTAG authentication
2015-05-18 08:49:25 +08:00
if ( usePwd ) {
2015-05-16 21:34:01 +08:00
uint8_t pwd [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain , 4 ) ;
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2015-05-19 02:58:33 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
2015-03-24 18:45:31 +08:00
OnError ( 1 ) ;
2015-04-30 06:27:31 +08:00
return ;
2015-05-01 21:29:19 +08:00
}
2015-05-18 08:49:25 +08:00
}
2015-04-30 06:27:31 +08:00
2015-03-30 22:24:03 +08:00
if ( mifare_ultra_readblock ( blockNo , dataout ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Read block error " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 2 ) ;
2015-01-08 07:08:33 +08:00
return ;
2015-03-30 22:24:03 +08:00
}
2015-05-18 08:49:25 +08:00
2015-03-30 22:24:03 +08:00
if ( mifare_ultra_halt ( ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 3 ) ;
2015-01-08 07:08:33 +08:00
return ;
2015-03-30 22:24:03 +08:00
}
2015-05-18 08:49:25 +08:00
2015-01-08 07:08:33 +08:00
cmd_send ( CMD_ACK , 1 , 0 , 0 , dataout , 16 ) ;
2014-06-20 07:02:59 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
}
2015-05-19 02:58:33 +08:00
2014-06-20 07:02:59 +08:00
//-----------------------------------------------------------------------------
2014-09-11 01:04:50 +08:00
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
void MifareReadSector ( uint8_t arg0 , uint8_t arg1 , uint8_t arg2 , uint8_t * datain )
{
// params
uint8_t sectorNo = arg0 ;
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( datain , 6 ) ;
// variables
2015-01-05 22:51:27 +08:00
byte_t isOK = 0 ;
2014-09-11 01:04:50 +08:00
byte_t dataoutbuf [ 16 * 16 ] ;
2016-01-21 00:44:51 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
2011-06-18 02:39:54 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2014-02-20 04:35:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2011-06-18 02:39:54 +08:00
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2011-06-18 02:39:54 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
2014-09-11 01:04:50 +08:00
isOK = 1 ;
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2014-09-11 01:04:50 +08:00
isOK = 0 ;
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
2014-09-11 01:04:50 +08:00
}
2015-05-19 02:58:33 +08:00
2014-09-11 01:04:50 +08:00
if ( isOK & & mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keyType , ui64Key , AUTH_FIRST ) ) {
isOK = 0 ;
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Auth error " ) ;
2014-09-11 01:04:50 +08:00
}
for ( uint8_t blockNo = 0 ; isOK & & blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
if ( mifare_classic_readblock ( pcs , cuid , FirstBlockOfSector ( sectorNo ) + blockNo , dataoutbuf + 16 * blockNo ) ) {
isOK = 0 ;
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Read sector %2d block %2d error " , sectorNo , blockNo ) ;
2011-06-18 02:39:54 +08:00
break ;
2014-09-11 01:04:50 +08:00
}
}
2011-06-18 02:39:54 +08:00
2014-09-11 01:04:50 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
}
2014-09-11 01:04:50 +08:00
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 2 ) DbpString ( " READ SECTOR FINISHED " ) ;
2016-04-12 17:30:49 +08:00
crypto1_destroy ( pcs ) ;
2011-06-18 02:39:54 +08:00
LED_B_ON ( ) ;
2014-09-11 01:04:50 +08:00
cmd_send ( CMD_ACK , isOK , 0 , 0 , dataoutbuf , 16 * NumBlocksPerSector ( sectorNo ) ) ;
2012-12-06 00:14:10 +08:00
LED_B_OFF ( ) ;
2011-06-18 02:39:54 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2014-06-20 07:02:59 +08:00
}
2015-05-05 06:33:07 +08:00
// arg0 = blockNo (start)
// arg1 = Pages (number of blocks)
// arg2 = useKey
// datain = KEY bytes
void MifareUReadCard ( uint8_t arg0 , uint16_t arg1 , uint8_t arg2 , uint8_t * datain )
2014-06-20 07:02:59 +08:00
{
2015-06-30 04:36:55 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-05-20 00:46:38 +08:00
// free eventually allocated BigBuf memory
2016-03-12 16:03:28 +08:00
BigBuf_free ( ) ; BigBuf_Clear_ext ( false ) ;
2015-05-20 00:46:38 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-03-24 18:45:31 +08:00
// params
2015-05-05 06:33:07 +08:00
uint8_t blockNo = arg0 ;
uint16_t blocks = arg1 ;
2015-05-16 21:34:01 +08:00
bool useKey = ( arg2 = = 1 ) ; //UL_C
bool usePwd = ( arg2 = = 2 ) ; //UL_EV1/NTAG
2015-05-19 02:58:33 +08:00
uint32_t countblocks = 0 ;
2015-05-20 00:46:38 +08:00
uint8_t * dataout = BigBuf_malloc ( CARD_MEMORY_SIZE ) ;
if ( dataout = = NULL ) {
Dbprintf ( " out of memory " ) ;
OnError ( 1 ) ;
return ;
}
2014-06-20 07:02:59 +08:00
2017-10-02 04:06:06 +08:00
int len = iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ;
2015-01-08 07:08:33 +08:00
if ( ! len ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Can't select card (RC:%d) " , len ) ;
2015-03-24 18:45:31 +08:00
OnError ( 1 ) ;
2015-01-08 07:08:33 +08:00
return ;
}
2015-05-06 12:55:29 +08:00
2015-05-18 08:49:25 +08:00
// UL-C authentication
2015-05-06 12:55:29 +08:00
if ( useKey ) {
uint8_t key [ 16 ] = { 0x00 } ;
2015-05-18 08:49:25 +08:00
memcpy ( key , datain , sizeof ( key ) ) ;
2015-05-06 12:55:29 +08:00
2015-05-19 01:11:00 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2015-05-06 12:55:29 +08:00
OnError ( 1 ) ;
return ;
}
}
2015-05-18 08:49:25 +08:00
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain , sizeof ( pwd ) ) ;
2015-05-16 13:00:31 +08:00
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2015-05-19 01:11:00 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
2015-05-16 13:00:31 +08:00
OnError ( 1 ) ;
return ;
}
}
2015-05-06 12:55:29 +08:00
for ( int i = 0 ; i < blocks ; i + + ) {
2015-05-28 05:23:46 +08:00
if ( ( i * 4 ) + 4 > = CARD_MEMORY_SIZE ) {
2015-05-19 01:11:00 +08:00
Dbprintf ( " Data exceeds buffer!! " ) ;
break ;
}
2015-05-05 06:33:07 +08:00
2015-05-19 02:58:33 +08:00
len = mifare_ultra_readblock ( blockNo + i , dataout + 4 * i ) ;
2015-01-08 07:08:33 +08:00
if ( len ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Read block %d error " , i ) ;
2015-05-19 02:58:33 +08:00
// if no blocks read - error out
2018-03-16 03:06:12 +08:00
if ( i = = 0 ) {
2015-05-19 01:11:00 +08:00
OnError ( 2 ) ;
2018-03-16 03:06:12 +08:00
return ;
2015-05-19 02:58:33 +08:00
} else {
//stop at last successful read block and return what we got
break ;
}
2015-01-08 07:08:33 +08:00
} else {
2015-05-16 21:34:01 +08:00
countblocks + + ;
2015-01-08 07:08:33 +08:00
}
}
2015-05-06 12:55:29 +08:00
2015-05-16 21:34:01 +08:00
len = mifare_ultra_halt ( ) ;
if ( len ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 3 ) ;
2015-01-08 07:08:33 +08:00
return ;
}
2014-06-20 07:02:59 +08:00
2015-05-16 21:34:01 +08:00
if ( MF_DBGLEVEL > = MF_DBG_EXTENDED ) Dbprintf ( " Blocks read %d " , countblocks ) ;
2014-06-20 07:02:59 +08:00
2015-05-19 02:58:33 +08:00
countblocks * = 4 ;
2015-05-28 05:23:46 +08:00
2015-05-24 10:35:50 +08:00
cmd_send ( CMD_ACK , 1 , countblocks , BigBuf_max_traceLen ( ) , 0 , 0 ) ;
2015-01-09 00:51:52 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2015-05-25 19:10:55 +08:00
BigBuf_free ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2014-06-20 07:02:59 +08:00
}
//-----------------------------------------------------------------------------
2014-09-11 01:04:50 +08:00
// Select, Authenticate, Write a MIFARE tag.
2014-06-20 07:02:59 +08:00
// read block
2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
void MifareWriteBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t arg2 , uint8_t * datain )
{
// params
uint8_t blockNo = arg0 ;
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
2016-01-21 00:44:51 +08:00
byte_t blockdata [ 16 ] = { 0x00 } ;
2011-06-18 02:39:54 +08:00
ui64Key = bytes_to_num ( datain , 6 ) ;
memcpy ( blockdata , datain + 10 , 16 ) ;
// variables
byte_t isOK = 0 ;
2016-01-21 00:44:51 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
2011-06-18 02:39:54 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2014-02-20 04:35:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2011-06-18 02:39:54 +08:00
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2011-06-18 02:39:54 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
while ( true ) {
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
break ;
} ;
if ( mifare_classic_auth ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Auth error " ) ;
break ;
} ;
if ( mifare_classic_writeblock ( pcs , cuid , blockNo , blockdata ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
break ;
} ;
if ( mifare_classic_halt ( pcs , cuid ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
break ;
} ;
isOK = 1 ;
break ;
}
crypto1_destroy ( pcs ) ;
if ( MF_DBGLEVEL > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
2013-09-15 17:33:17 +08:00
cmd_send ( CMD_ACK , isOK , 0 , 0 , 0 , 0 ) ;
2011-06-18 02:39:54 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2014-06-20 07:02:59 +08:00
}
2015-05-28 05:23:46 +08:00
/* // Command not needed but left for future testing
void MifareUWriteBlockCompat ( uint8_t arg0 , uint8_t * datain )
2014-06-20 07:02:59 +08:00
{
2015-04-30 06:27:31 +08:00
uint8_t blockNo = arg0 ;
2015-01-08 07:08:33 +08:00
byte_t blockdata [ 16 ] = { 0x00 } ;
2014-06-20 07:02:59 +08:00
2015-04-30 06:27:31 +08:00
memcpy ( blockdata , datain , 16 ) ;
2015-01-08 07:08:33 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
LED_A_ON ( ) ; LED_B_OFF ( ) ; LED_C_OFF ( ) ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-03-30 22:24:03 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2014-06-20 07:02:59 +08:00
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , NULL , true , 0 , true ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
OnError ( 0 ) ;
return ;
} ;
2015-05-28 05:23:46 +08:00
if ( mifare_ultra_writeblock_compat ( blockNo , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 0 ) ;
return ; } ;
if ( mifare_ultra_halt ( ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
OnError ( 0 ) ;
return ;
} ;
2015-04-30 06:27:31 +08:00
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
cmd_send ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2014-06-20 07:02:59 +08:00
}
2015-05-28 05:23:46 +08:00
*/
2014-06-20 07:02:59 +08:00
2015-05-21 05:44:11 +08:00
// Arg0 : Block to write to.
// Arg1 : 0 = use no authentication.
// 1 = use 0x1A authentication.
// 2 = use 0x1B authentication.
// datain : 4 first bytes is data to be written.
// : 4/16 next bytes is authentication key.
2015-05-28 05:23:46 +08:00
void MifareUWriteBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain )
2014-06-20 07:02:59 +08:00
{
2014-09-11 01:04:50 +08:00
uint8_t blockNo = arg0 ;
2015-05-21 05:44:11 +08:00
bool useKey = ( arg1 = = 1 ) ; //UL_C
bool usePwd = ( arg1 = = 2 ) ; //UL_EV1/NTAG
2015-01-08 07:08:33 +08:00
byte_t blockdata [ 4 ] = { 0x00 } ;
2014-06-20 07:02:59 +08:00
2018-03-31 16:36:39 +08:00
memcpy ( blockdata , datain , 4 ) ;
2015-03-30 22:24:03 +08:00
2015-05-05 06:33:07 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
2015-03-30 22:24:03 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2018-03-31 16:36:39 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
OnError ( 0 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-05-21 05:44:11 +08:00
// UL-C authentication
if ( useKey ) {
uint8_t key [ 16 ] = { 0x00 } ;
memcpy ( key , datain + 4 , sizeof ( key ) ) ;
if ( ! mifare_ultra_auth ( key ) ) {
OnError ( 1 ) ;
return ;
}
}
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain + 4 , 4 ) ;
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
OnError ( 1 ) ;
return ;
}
}
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_writeblock ( blockNo , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 0 ) ;
return ;
} ;
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_halt ( ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
OnError ( 0 ) ;
return ;
} ;
if ( MF_DBGLEVEL > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
cmd_send ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2015-03-30 22:24:03 +08:00
}
void MifareUSetPwd ( uint8_t arg0 , uint8_t * datain ) {
uint8_t pwd [ 16 ] = { 0x00 } ;
byte_t blockdata [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain , 16 ) ;
LED_A_ON ( ) ; LED_B_OFF ( ) ; LED_C_OFF ( ) ;
2014-09-11 01:04:50 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2014-06-20 07:02:59 +08:00
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2018-03-31 16:36:39 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
OnError ( 0 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
blockdata [ 0 ] = pwd [ 7 ] ;
blockdata [ 1 ] = pwd [ 6 ] ;
blockdata [ 2 ] = pwd [ 5 ] ;
blockdata [ 3 ] = pwd [ 4 ] ;
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_writeblock ( 44 , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 44 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
blockdata [ 0 ] = pwd [ 3 ] ;
blockdata [ 1 ] = pwd [ 2 ] ;
blockdata [ 2 ] = pwd [ 1 ] ;
blockdata [ 3 ] = pwd [ 0 ] ;
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_writeblock ( 45 , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 45 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
blockdata [ 0 ] = pwd [ 15 ] ;
blockdata [ 1 ] = pwd [ 14 ] ;
blockdata [ 2 ] = pwd [ 13 ] ;
blockdata [ 3 ] = pwd [ 12 ] ;
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_writeblock ( 46 , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 46 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
blockdata [ 0 ] = pwd [ 11 ] ;
blockdata [ 1 ] = pwd [ 10 ] ;
blockdata [ 2 ] = pwd [ 9 ] ;
blockdata [ 3 ] = pwd [ 8 ] ;
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_writeblock ( 47 , blockdata ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Write block error " ) ;
OnError ( 47 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2018-03-31 16:36:39 +08:00
if ( mifare_ultra_halt ( ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
OnError ( 0 ) ;
return ;
} ;
2014-06-20 07:02:59 +08:00
2015-03-30 22:24:03 +08:00
cmd_send ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2014-09-11 01:04:50 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2014-06-20 07:02:59 +08:00
}
// Return 1 if the nonce is invalid else return 0
2014-12-16 14:41:07 +08:00
int valid_nonce ( uint32_t Nt , uint32_t NtEnc , uint32_t Ks1 , uint8_t * parity ) {
2015-12-15 15:51:29 +08:00
return ( ( oddparity8 ( ( Nt > > 24 ) & 0xFF ) = = ( ( parity [ 0 ] ) ^ oddparity8 ( ( NtEnc > > 24 ) & 0xFF ) ^ BIT ( Ks1 , 16 ) ) ) & \
( oddparity8 ( ( Nt > > 16 ) & 0xFF ) = = ( ( parity [ 1 ] ) ^ oddparity8 ( ( NtEnc > > 16 ) & 0xFF ) ^ BIT ( Ks1 , 8 ) ) ) & \
( oddparity8 ( ( Nt > > 8 ) & 0xFF ) = = ( ( parity [ 2 ] ) ^ oddparity8 ( ( NtEnc > > 8 ) & 0xFF ) ^ BIT ( Ks1 , 0 ) ) ) ) ? 1 : 0 ;
2011-06-18 02:39:54 +08:00
}
2017-08-26 18:57:18 +08:00
void MifareAcquireNonces ( uint32_t arg0 , uint32_t arg1 , uint32_t flags , uint8_t * datain ) {
uint8_t uid [ 10 ] = { 0x00 } ;
uint8_t answer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t par [ 1 ] = { 0x00 } ;
uint8_t buf [ USB_CMD_DATA_SIZE ] = { 0x00 } ;
2018-01-15 21:22:46 +08:00
uint32_t cuid = 0 ;
int16_t isOK = 0 ;
uint16_t num_nonces = 0 ;
uint8_t cascade_levels = 0 ;
2017-08-26 18:57:18 +08:00
uint8_t blockNo = arg0 & 0xff ;
uint8_t keyType = ( arg0 > > 8 ) & 0xff ;
bool initialize = flags & 0x0001 ;
bool field_off = flags & 0x0004 ;
2017-10-12 21:17:10 +08:00
bool have_uid = false ;
2017-08-26 18:57:18 +08:00
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
BigBuf_free ( ) ; BigBuf_Clear_ext ( false ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
2017-12-11 03:02:51 +08:00
if ( initialize )
2017-08-26 18:57:18 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
LED_C_ON ( ) ;
for ( uint16_t i = 0 ; i < = USB_CMD_DATA_SIZE - 4 ; i + = 4 ) {
// Test if the action was cancelled
2017-12-11 03:02:51 +08:00
if ( BUTTON_PRESS ( ) ) {
2017-08-26 18:57:18 +08:00
isOK = 2 ;
field_off = true ;
break ;
}
if ( ! have_uid ) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info ;
2017-12-11 03:02:51 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2017-08-26 18:57:18 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Can't select card (ALL) " ) ;
continue ;
}
switch ( card_info . uidlen ) {
case 4 : cascade_levels = 1 ; break ;
case 7 : cascade_levels = 2 ; break ;
case 10 : cascade_levels = 3 ; break ;
default : break ;
}
have_uid = true ;
} else { // no need for anticollision. We can directly select the card
2017-12-11 03:02:51 +08:00
if ( ! iso14443a_fast_select_card ( uid , cascade_levels ) ) {
2017-08-26 18:57:18 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Can't select card (UID) " ) ;
continue ;
}
}
// Transmit MIFARE_CLASSIC_AUTH
uint8_t dcmd [ 4 ] = { 0x60 + ( keyType & 0x01 ) , blockNo , 0x00 , 0x00 } ;
2018-02-01 22:19:47 +08:00
AddCrc14A ( dcmd , 2 ) ;
2017-08-26 18:57:18 +08:00
ReaderTransmit ( dcmd , sizeof ( dcmd ) , NULL ) ;
int len = ReaderReceive ( answer , par ) ;
2017-10-12 21:17:10 +08:00
// wait for the card to become ready again
CHK_TIMEOUT ( ) ;
2017-08-26 18:57:18 +08:00
if ( len ! = 4 ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " AcquireNonces: Auth1 error " ) ;
2017-08-26 18:57:18 +08:00
continue ;
}
num_nonces + + ;
// Save the tag nonce (nt)
buf [ i ] = answer [ 0 ] ;
buf [ i + 1 ] = answer [ 1 ] ;
buf [ i + 2 ] = answer [ 2 ] ;
buf [ i + 3 ] = answer [ 3 ] ;
}
LED_C_OFF ( ) ;
LED_B_ON ( ) ;
cmd_send ( CMD_ACK , isOK , cuid , num_nonces - 1 , buf , sizeof ( buf ) ) ;
LED_B_OFF ( ) ;
if ( MF_DBGLEVEL > = 3 ) DbpString ( " AcquireNonces finished " ) ;
if ( field_off ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
}
}
2013-09-15 17:33:17 +08:00
2015-11-27 23:24:00 +08:00
//-----------------------------------------------------------------------------
// acquire encrypted nonces in order to perform the attack described in
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
// Computer and Communications Security, 2015
//-----------------------------------------------------------------------------
2017-12-11 06:09:53 +08:00
void MifareAcquireEncryptedNonces ( uint32_t arg0 , uint32_t arg1 , uint32_t flags , uint8_t * datain ) {
2018-01-15 21:22:46 +08:00
2015-11-27 23:24:00 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2018-01-15 21:22:46 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2016-01-21 00:44:51 +08:00
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t par_enc [ 1 ] = { 0x00 } ;
uint8_t buf [ USB_CMD_DATA_SIZE ] = { 0x00 } ;
2017-10-12 21:17:10 +08:00
2018-01-15 21:22:46 +08:00
uint64_t ui64Key = bytes_to_num ( datain , 6 ) ;
uint32_t cuid = 0 ;
int16_t isOK = 0 ;
uint16_t num_nonces = 0 ;
uint8_t nt_par_enc = 0 ;
uint8_t cascade_levels = 0 ;
2015-11-27 23:24:00 +08:00
uint8_t blockNo = arg0 & 0xff ;
uint8_t keyType = ( arg0 > > 8 ) & 0xff ;
uint8_t targetBlockNo = arg1 & 0xff ;
2018-01-15 21:22:46 +08:00
uint8_t targetKeyType = ( arg1 > > 8 ) & 0xff ;
2015-11-27 23:24:00 +08:00
bool initialize = flags & 0x0001 ;
bool slow = flags & 0x0002 ;
bool field_off = flags & 0x0004 ;
2017-10-12 21:17:10 +08:00
bool have_uid = false ;
2015-11-27 23:24:00 +08:00
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
2016-11-17 00:44:08 +08:00
BigBuf_free ( ) ; BigBuf_Clear_ext ( false ) ;
clear_trace ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2016-11-17 00:44:08 +08:00
2017-12-11 06:09:53 +08:00
if ( initialize )
2015-11-27 23:24:00 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2016-11-17 00:44:08 +08:00
2015-11-27 23:24:00 +08:00
LED_C_ON ( ) ;
for ( uint16_t i = 0 ; i < = USB_CMD_DATA_SIZE - 9 ; ) {
// Test if the action was cancelled
if ( BUTTON_PRESS ( ) ) {
isOK = 2 ;
field_off = true ;
break ;
}
if ( ! have_uid ) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info ;
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2015-11-27 23:24:00 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Can't select card (ALL) " ) ;
continue ;
}
switch ( card_info . uidlen ) {
case 4 : cascade_levels = 1 ; break ;
case 7 : cascade_levels = 2 ; break ;
case 10 : cascade_levels = 3 ; break ;
default : break ;
}
have_uid = true ;
} else { // no need for anticollision. We can directly select the card
2017-10-05 22:00:56 +08:00
if ( ! iso14443a_fast_select_card ( uid , cascade_levels ) ) {
2015-11-27 23:24:00 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Can't select card (UID) " ) ;
continue ;
}
}
2017-10-12 21:17:10 +08:00
if ( slow )
2018-01-15 21:22:46 +08:00
SpinDelayUs ( HARDNESTED_PRE_AUTHENTICATION_LEADTIME ) ;
2015-11-27 23:24:00 +08:00
uint32_t nt1 ;
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , NULL ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Auth1 error " ) ;
continue ;
}
// nested authentication
uint16_t len = mifare_sendcmd_short ( pcs , AUTH_NESTED , 0x60 + ( targetKeyType & 0x01 ) , targetBlockNo , receivedAnswer , par_enc , NULL ) ;
2017-08-26 18:57:18 +08:00
2017-10-12 21:17:10 +08:00
// wait for the card to become ready again
CHK_TIMEOUT ( ) ;
2017-08-26 18:57:18 +08:00
2015-11-27 23:24:00 +08:00
if ( len ! = 4 ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " AcquireNonces: Auth2 error len=%d " , len ) ;
continue ;
}
num_nonces + + ;
if ( num_nonces % 2 ) {
memcpy ( buf + i , receivedAnswer , 4 ) ;
nt_par_enc = par_enc [ 0 ] & 0xf0 ;
} else {
2016-11-08 05:42:57 +08:00
nt_par_enc | = par_enc [ 0 ] > > 4 ;
2015-11-27 23:24:00 +08:00
memcpy ( buf + i + 4 , receivedAnswer , 4 ) ;
memcpy ( buf + i + 8 , & nt_par_enc , 1 ) ;
i + = 9 ;
}
}
LED_C_OFF ( ) ;
2016-11-08 05:42:57 +08:00
crypto1_destroy ( pcs ) ;
2015-11-27 23:24:00 +08:00
LED_B_ON ( ) ;
cmd_send ( CMD_ACK , isOK , cuid , num_nonces , buf , sizeof ( buf ) ) ;
LED_B_OFF ( ) ;
if ( MF_DBGLEVEL > = 3 ) DbpString ( " AcquireEncryptedNonces finished " ) ;
if ( field_off ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2015-11-27 23:24:00 +08:00
}
}
2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
// MIFARE nested authentication.
//
//-----------------------------------------------------------------------------
2013-09-15 17:33:17 +08:00
void MifareNested ( uint32_t arg0 , uint32_t arg1 , uint32_t calibrate , uint8_t * datain )
2011-06-18 02:39:54 +08:00
{
// params
2013-09-15 17:33:17 +08:00
uint8_t blockNo = arg0 & 0xff ;
uint8_t keyType = ( arg0 > > 8 ) & 0xff ;
uint8_t targetBlockNo = arg1 & 0xff ;
uint8_t targetKeyType = ( arg1 > > 8 ) & 0xff ;
2011-06-18 02:39:54 +08:00
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( datain , 6 ) ;
// variables
2013-09-15 17:33:17 +08:00
uint16_t rtr , i , j , len ;
2016-01-21 00:44:51 +08:00
uint16_t davg = 0 ;
2013-09-15 17:33:17 +08:00
static uint16_t dmin , dmax ;
2016-01-21 00:44:51 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2016-01-21 02:53:58 +08:00
uint32_t cuid = 0 , nt1 , nt2 , nttmp , nttest , ks1 ;
2016-01-21 00:44:51 +08:00
uint8_t par [ 1 ] = { 0x00 } ;
uint32_t target_nt [ 2 ] = { 0x00 } , target_ks [ 2 ] = { 0x00 } ;
2013-09-15 17:33:17 +08:00
2016-01-21 00:44:51 +08:00
uint8_t par_array [ 4 ] = { 0x00 } ;
2013-09-15 17:33:17 +08:00
uint16_t ncount = 0 ;
2011-06-18 02:39:54 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2016-01-21 02:53:58 +08:00
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
uint32_t auth1_time , auth2_time ;
2016-02-17 04:43:45 +08:00
static uint16_t delta_time = 0 ;
2013-09-15 17:33:17 +08:00
2015-06-30 04:36:55 +08:00
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-01-27 15:34:48 +08:00
// free eventually allocated BigBuf memory
2016-03-12 16:03:28 +08:00
BigBuf_free ( ) ; BigBuf_Clear_ext ( false ) ;
2015-07-13 04:58:16 +08:00
if ( calibrate ) clear_trace ( ) ;
set_tracing ( true ) ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
// statistics on nonce distance
2015-06-25 18:41:39 +08:00
int16_t isOK = 0 ;
# define NESTED_MAX_TRIES 12
uint16_t unsuccessfull_tries = 0 ;
2013-09-15 17:33:17 +08:00
if ( calibrate ) { // for first call only. Otherwise reuse previous calibration
LED_B_ON ( ) ;
2015-01-05 22:51:27 +08:00
WDT_HIT ( ) ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
davg = dmax = 0 ;
dmin = 2000 ;
delta_time = 0 ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
for ( rtr = 0 ; rtr < 17 ; rtr + + ) {
2011-06-18 02:39:54 +08:00
2015-06-25 18:41:39 +08:00
// Test if the action was cancelled
if ( BUTTON_PRESS ( ) ) {
isOK = - 2 ;
break ;
}
2013-09-15 17:33:17 +08:00
// prepare next select. No need to power down the card.
if ( mifare_classic_halt ( pcs , cuid ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Halt error " ) ;
2013-09-15 17:33:17 +08:00
rtr - - ;
continue ;
}
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Can't select card " ) ;
2013-09-15 17:33:17 +08:00
rtr - - ;
continue ;
} ;
auth1_time = 0 ;
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , & auth1_time ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Auth1 error " ) ;
2013-09-15 17:33:17 +08:00
rtr - - ;
continue ;
} ;
2016-02-17 04:43:45 +08:00
auth2_time = ( delta_time ) ? auth1_time + delta_time : 0 ;
2013-09-15 17:33:17 +08:00
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_NESTED , & nt2 , & auth2_time ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Auth2 error " ) ;
2013-09-15 17:33:17 +08:00
rtr - - ;
continue ;
} ;
2013-09-29 19:44:07 +08:00
nttmp = prng_successor ( nt1 , 100 ) ; //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
for ( i = 101 ; i < 1200 ; i + + ) {
2016-04-10 18:56:59 +08:00
nttmp = prng_successor ( nttmp , 1 ) ;
2013-09-15 17:33:17 +08:00
if ( nttmp = = nt2 ) break ;
}
if ( i ! = 1200 ) {
if ( rtr ! = 0 ) {
davg + = i ;
dmin = MIN ( dmin , i ) ;
dmax = MAX ( dmax , i ) ;
}
else {
delta_time = auth2_time - auth1_time + 32 ; // allow some slack for proper timing
}
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Nested: calibrating... ntdist=%d " , i ) ;
2015-06-25 18:41:39 +08:00
} else {
unsuccessfull_tries + + ;
if ( unsuccessfull_tries > NESTED_MAX_TRIES ) { // card isn't vulnerable to nested attack (random numbers are not predictable)
isOK = - 3 ;
}
2013-09-15 17:33:17 +08:00
}
2011-06-18 02:39:54 +08:00
}
2013-09-15 17:33:17 +08:00
davg = ( davg + ( rtr - 1 ) / 2 ) / ( rtr - 1 ) ;
2015-06-25 18:41:39 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d " , rtr , isOK , dmin , dmax , davg , delta_time ) ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
dmin = davg - 2 ;
dmax = davg + 2 ;
LED_B_OFF ( ) ;
}
2011-06-18 02:39:54 +08:00
// -------------------------------------------------------------------------------------------------
LED_C_ON ( ) ;
// get crypted nonces for target sector
2015-06-25 18:41:39 +08:00
for ( i = 0 ; i < 2 & & ! isOK ; i + + ) { // look for exactly two different nonces
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
target_nt [ i ] = 0 ;
while ( target_nt [ i ] = = 0 ) { // continue until we have an unambiguous nonce
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
// prepare next select. No need to power down the card.
if ( mifare_classic_halt ( pcs , cuid ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Halt error " ) ;
2013-09-15 17:33:17 +08:00
continue ;
}
2011-06-18 02:39:54 +08:00
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Can't select card " ) ;
2013-09-15 17:33:17 +08:00
continue ;
} ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
auth1_time = 0 ;
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , & auth1_time ) ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Auth1 error " ) ;
2013-09-15 17:33:17 +08:00
continue ;
} ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
// nested authentication
auth2_time = auth1_time + delta_time ;
2016-02-17 04:43:45 +08:00
2015-06-01 03:47:33 +08:00
len = mifare_sendcmd_short ( pcs , AUTH_NESTED , 0x60 + ( targetKeyType & 0x01 ) , targetBlockNo , receivedAnswer , par , & auth2_time ) ;
2013-09-15 17:33:17 +08:00
if ( len ! = 4 ) {
2017-12-11 03:02:51 +08:00
if ( MF_DBGLEVEL > = 2 ) Dbprintf ( " Nested: Auth2 error len=%d " , len ) ;
2013-09-15 17:33:17 +08:00
continue ;
} ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
nt2 = bytes_to_num ( receivedAnswer , 4 ) ;
2014-12-16 14:41:07 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x " , i + 1 , nt1 , nt2 , par [ 0 ] ) ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
// Parity validity check
2017-07-07 18:34:20 +08:00
for ( j = 0 ; j < 4 ; j + + ) {
par_array [ j ] = ( oddparity8 ( receivedAnswer [ j ] ) ! = ( ( par [ 0 ] > > ( 7 - j ) ) & 0x01 ) ) ;
}
2013-09-15 17:33:17 +08:00
ncount = 0 ;
nttest = prng_successor ( nt1 , dmin - 1 ) ;
for ( j = dmin ; j < dmax + 1 ; j + + ) {
2016-04-10 18:56:59 +08:00
nttest = prng_successor ( nttest , 1 ) ;
2013-09-15 17:33:17 +08:00
ks1 = nt2 ^ nttest ;
if ( valid_nonce ( nttest , nt2 , ks1 , par_array ) ) {
if ( ncount > 0 ) { // we are only interested in disambiguous nonces, try again
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Nonce#%d: dismissed (ambigous), ntdist=%d " , i + 1 , j ) ;
target_nt [ i ] = 0 ;
break ;
}
target_nt [ i ] = nttest ;
target_ks [ i ] = ks1 ;
ncount + + ;
if ( i = = 1 & & target_nt [ 1 ] = = target_nt [ 0 ] ) { // we need two different nonces
target_nt [ i ] = 0 ;
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Nonce#2: dismissed (= nonce#1), ntdist=%d " , j ) ;
2011-06-18 02:39:54 +08:00
break ;
}
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Nonce#%d: valid, ntdist=%d " , i + 1 , j ) ;
2011-06-18 02:39:54 +08:00
}
}
2013-09-15 17:33:17 +08:00
if ( target_nt [ i ] = = 0 & & j = = dmax + 1 & & MF_DBGLEVEL > = 3 ) Dbprintf ( " Nonce#%d: dismissed (all invalid) " , i + 1 ) ;
2011-06-18 02:39:54 +08:00
}
}
LED_C_OFF ( ) ;
crypto1_destroy ( pcs ) ;
2017-07-07 18:34:20 +08:00
uint8_t buf [ 4 + 4 * 4 ] = { 0 } ;
2016-02-17 06:51:52 +08:00
memcpy ( buf , & cuid , 4 ) ;
2013-09-15 17:33:17 +08:00
memcpy ( buf + 4 , & target_nt [ 0 ] , 4 ) ;
memcpy ( buf + 8 , & target_ks [ 0 ] , 4 ) ;
memcpy ( buf + 12 , & target_nt [ 1 ] , 4 ) ;
memcpy ( buf + 16 , & target_ks [ 1 ] , 4 ) ;
2011-06-18 02:39:54 +08:00
LED_B_ON ( ) ;
2015-06-25 18:41:39 +08:00
cmd_send ( CMD_ACK , isOK , 0 , targetBlockNo + ( targetKeyType * 0x100 ) , buf , sizeof ( buf ) ) ;
2012-12-06 00:14:10 +08:00
LED_B_OFF ( ) ;
2011-06-18 02:39:54 +08:00
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 3 ) DbpString ( " NESTED FINISHED " ) ;
2011-06-18 02:39:54 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2011-06-18 02:39:54 +08:00
}
//-----------------------------------------------------------------------------
2013-09-15 17:33:17 +08:00
// MIFARE check keys. key count up to 85.
2011-06-18 02:39:54 +08:00
//
2017-12-11 06:09:53 +08:00
//-----------------------------------------------------------------------------
2017-10-05 22:00:56 +08:00
typedef struct sector_t {
uint8_t keyA [ 6 ] ;
uint8_t keyB [ 6 ] ;
} sector_t ;
typedef struct chk_t {
uint64_t key ;
uint32_t cuid ;
uint8_t cl ;
uint8_t block ;
uint8_t keyType ;
uint8_t * uid ;
struct Crypto1State * pcs ;
} chk_t ;
// checks one key.
2017-10-12 21:17:10 +08:00
// fast select, tries 5 times to select
2017-10-05 22:00:56 +08:00
//
// return:
// 2 = failed to select.
// 1 = wrong key
// 0 = correct key
uint8_t chkKey ( struct chk_t * c ) {
uint8_t i = 0 , res = 2 ;
2017-10-12 21:17:10 +08:00
while ( i < 5 ) {
2017-10-05 22:00:56 +08:00
// this part is from Piwi's faster nonce collecting part in Hardnested.
// assume: fast select
2017-12-11 06:09:53 +08:00
if ( ! iso14443a_fast_select_card ( c - > uid , c - > cl ) ) {
2017-10-05 22:00:56 +08:00
+ + i ;
continue ;
}
res = mifare_classic_authex ( c - > pcs , c - > cuid , c - > block , c - > keyType , c - > key , AUTH_FIRST , NULL , NULL ) ;
2017-12-11 03:02:51 +08:00
2017-12-10 18:18:44 +08:00
CHK_TIMEOUT ( ) ;
2017-10-12 21:17:10 +08:00
// if successfull auth, send HALT
2017-12-11 03:02:51 +08:00
// if ( !res )
// mifare_classic_halt_ex(c->pcs);
2017-10-05 22:00:56 +08:00
break ;
}
return res ;
}
uint8_t chkKey_readb ( struct chk_t * c , uint8_t * keyb ) {
2017-12-11 06:09:53 +08:00
if ( ! iso14443a_fast_select_card ( c - > uid , c - > cl ) )
2017-10-05 22:00:56 +08:00
return 2 ;
if ( mifare_classic_authex ( c - > pcs , c - > cuid , c - > block , 0 , c - > key , AUTH_FIRST , NULL , NULL ) )
return 1 ;
uint8_t data [ 16 ] = { 0x00 } ;
uint8_t res = mifare_classic_readblock ( c - > pcs , c - > cuid , c - > block , data ) ;
// successful read
if ( ! res ) {
// data was something else than zeros.
if ( memcmp ( data + 10 , " \x00 \x00 \x00 \x00 \x00 \x00 " , 6 ) ! = 0 ) {
memcpy ( keyb , data + 10 , 6 ) ;
res = 0 ;
} else {
res = 3 ;
}
2017-10-12 21:17:10 +08:00
mifare_classic_halt_ex ( c - > pcs ) ;
2017-10-05 22:00:56 +08:00
}
return res ;
}
void chkKey_scanA ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , uint8_t * sectorcnt , uint8_t * foundkeys ) {
2017-12-11 08:44:55 +08:00
uint8_t status ;
for ( uint8_t s = 0 ; s < * sectorcnt ; s + + ) {
2017-10-05 22:00:56 +08:00
// skip already found A keys
2017-12-11 08:44:55 +08:00
if ( found [ ( s * 2 ) ] )
continue ;
c - > block = FirstBlockOfSector ( s ) ;
status = chkKey ( c ) ;
if ( status = = 0 ) {
num_to_bytes ( c - > key , 6 , k_sector [ s ] . keyA ) ;
found [ ( s * 2 ) ] = 1 ;
+ + * foundkeys ;
2017-10-12 21:17:10 +08:00
2017-12-12 04:43:29 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " ChkKeys_fast: Scan A found (%d) " , c - > block ) ;
2017-10-05 22:00:56 +08:00
}
}
}
2017-12-12 04:43:29 +08:00
void chkKey_scanB ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , uint8_t * sectorcnt , uint8_t * foundkeys ) {
2017-12-11 08:44:55 +08:00
uint8_t status ;
for ( uint8_t s = 0 ; s < * sectorcnt ; s + + ) {
2017-10-05 22:00:56 +08:00
// skip already found B keys
2017-12-11 08:44:55 +08:00
if ( found [ ( s * 2 ) + 1 ] )
continue ;
c - > block = FirstBlockOfSector ( s ) ;
status = chkKey ( c ) ;
if ( status = = 0 ) {
num_to_bytes ( c - > key , 6 , k_sector [ s ] . keyB ) ;
found [ ( s * 2 ) + 1 ] = 1 ;
+ + * foundkeys ;
2017-12-12 04:43:29 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " ChkKeys_fast: Scan B found (%d) " , c - > block ) ;
2017-10-05 22:00:56 +08:00
}
}
}
// loop all A keys,
// when A is found but not B, try to read B.
void chkKey_loopBonly ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , uint8_t * sectorcnt , uint8_t * foundkeys ) {
// read Block B, if A is found.
for ( uint8_t s = 0 ; s < * sectorcnt ; + + s ) {
c - > block = ( FirstBlockOfSector ( s ) + NumBlocksPerSector ( s ) - 1 ) ;
// A but not B
if ( found [ ( s * 2 ) ] & & ! found [ ( s * 2 ) + 1 ] ) {
c - > key = bytes_to_num ( k_sector [ s ] . keyA , 6 ) ;
uint8_t status = chkKey_readb ( c , k_sector [ s ] . keyB ) ;
if ( status = = 0 ) {
found [ ( s * 2 ) + 1 ] = 1 ;
+ + * foundkeys ;
2017-12-11 08:44:55 +08:00
2017-12-12 04:43:29 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " ChkKeys_fast: Reading B found (%d) " , c - > block ) ;
2017-12-11 08:44:55 +08:00
2017-10-05 22:00:56 +08:00
// try quick find all B?
// assume: keys comes in groups. Find one B, test against all B.
c - > key = bytes_to_num ( k_sector [ s ] . keyB , 6 ) ;
2017-12-11 08:44:55 +08:00
c - > keyType = 1 ;
2017-10-05 22:00:56 +08:00
chkKey_scanB ( c , k_sector , found , sectorcnt , foundkeys ) ;
}
}
}
}
// get Chunks of keys, to test authentication against card.
// arg0 = antal sectorer
// arg0 = first time
// arg1 = clear trace
// arg2 = antal nycklar i keychunk
// datain = keys as array
void MifareChkKeys_fast ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
// first call or
uint8_t sectorcnt = arg0 & 0xFF ; // 16;
uint8_t firstchunk = ( arg0 > > 8 ) & 0xF ;
uint8_t lastchunk = ( arg0 > > 12 ) & 0xF ;
2017-12-11 08:44:55 +08:00
uint8_t strategy = arg1 & 0xFF ;
2017-10-05 22:00:56 +08:00
uint8_t keyCount = arg2 & 0xFF ;
uint8_t status = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
struct chk_t chk_data ;
uint8_t allkeys = sectorcnt < < 1 ;
static uint32_t cuid = 0 ;
static uint8_t cascade_levels = 0 ;
static uint8_t foundkeys = 0 ;
static sector_t k_sector [ 80 ] ;
static uint8_t found [ 80 ] ;
static uint8_t * uid ;
2018-02-06 05:59:49 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2017-10-05 22:00:56 +08:00
if ( uid = = NULL | | firstchunk ) {
uid = BigBuf_malloc ( 10 ) ;
if ( uid = = NULL ) {
2017-12-09 15:27:56 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " ChkKeys: uid malloc failed " ) ;
2017-10-05 22:00:56 +08:00
goto OUT ;
}
}
LEDsoff ( ) ;
LED_A_ON ( ) ;
if ( firstchunk ) {
clear_trace ( ) ;
set_tracing ( false ) ;
memset ( k_sector , 0x00 , 480 + 10 ) ;
2017-12-11 08:44:55 +08:00
memset ( found , 0x00 , sizeof ( found ) ) ;
2017-10-05 22:00:56 +08:00
foundkeys = 0 ;
iso14a_card_select_t card_info ;
2017-12-10 18:11:23 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2017-12-09 15:27:56 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " ChkKeys: Can't select card (ALL) " ) ;
2017-10-05 22:00:56 +08:00
goto OUT ;
}
switch ( card_info . uidlen ) {
case 4 : cascade_levels = 1 ; break ;
case 7 : cascade_levels = 2 ; break ;
case 10 : cascade_levels = 3 ; break ;
default : break ;
}
CHK_TIMEOUT ( ) ;
}
// set check struct.
chk_data . uid = uid ;
chk_data . cuid = cuid ;
chk_data . cl = cascade_levels ;
chk_data . pcs = pcs ;
2017-12-12 05:33:50 +08:00
chk_data . block = 0 ;
2017-12-12 04:43:29 +08:00
// keychunk loop - depth first one sector.
2017-12-11 08:44:55 +08:00
if ( strategy = = 1 ) {
2017-12-12 05:33:50 +08:00
uint8_t newfound = foundkeys ;
2017-12-12 04:43:29 +08:00
// Sector main loop
// keep track of how many sectors on card.
for ( uint8_t s = 0 ; s < sectorcnt ; + + s ) {
if ( found [ ( s * 2 ) ] & & found [ ( s * 2 ) + 1 ] )
continue ;
2017-12-11 06:59:19 +08:00
2017-12-12 04:43:29 +08:00
for ( uint8_t i = 0 ; i < keyCount ; + + i ) {
2017-12-12 05:33:50 +08:00
2017-12-12 04:43:29 +08:00
// Allow button press / usb cmd to interrupt device
if ( BUTTON_PRESS ( ) & & ! usb_poll_validate_length ( ) ) {
goto OUT ;
2017-10-05 22:00:56 +08:00
}
2017-12-12 04:43:29 +08:00
2017-12-12 05:33:50 +08:00
// found all keys?
if ( foundkeys = = allkeys )
goto OUT ;
2017-12-12 04:43:29 +08:00
WDT_HIT ( ) ;
2017-10-05 22:00:56 +08:00
2017-12-12 05:54:14 +08:00
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
chk_data . block = FirstBlockOfSector ( s ) ;
2017-12-12 04:43:29 +08:00
// new key
chk_data . key = bytes_to_num ( datain + i * 6 , 6 ) ;
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
// skip already found A keys
if ( ! found [ ( s * 2 ) ] ) {
chk_data . keyType = 0 ;
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
memcpy ( k_sector [ s ] . keyA , datain + i * 6 , 6 ) ;
found [ ( s * 2 ) ] = 1 ;
+ + foundkeys ;
chkKey_scanA ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
// read Block B, if A is found.
chkKey_loopBonly ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
chk_data . block = FirstBlockOfSector ( s ) ;
}
2017-10-05 22:00:56 +08:00
}
2017-12-12 04:43:29 +08:00
// skip already found B keys
if ( ! found [ ( s * 2 ) + 1 ] ) {
chk_data . keyType = 1 ;
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
memcpy ( k_sector [ s ] . keyB , datain + i * 6 , 6 ) ;
found [ ( s * 2 ) + 1 ] = 1 ;
+ + foundkeys ;
chkKey_scanB ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
}
}
2017-12-12 05:33:50 +08:00
2017-12-12 05:49:44 +08:00
} // end keys test loop - depth first
// assume1. if no keys found in first sector, get next keychunk from client
if ( newfound - foundkeys = = 0 )
2017-12-12 05:33:50 +08:00
goto OUT ;
2017-12-12 04:43:29 +08:00
} // end loop - sector
} // end strategy 1
2017-12-11 08:44:55 +08:00
if ( strategy = = 2 ) {
// Keychunk loop
for ( uint8_t i = 0 ; i < keyCount ; i + + ) {
// Allow button press / usb cmd to interrupt device
if ( BUTTON_PRESS ( ) & & ! usb_poll_validate_length ( ) ) break ;
WDT_HIT ( ) ;
2017-10-05 22:00:56 +08:00
2017-12-11 08:44:55 +08:00
// new key
chk_data . key = bytes_to_num ( datain + i * 6 , 6 ) ;
// Sector main loop
// keep track of how many sectors on card.
for ( uint8_t s = 0 ; s < sectorcnt ; + + s ) {
2017-12-12 05:33:50 +08:00
// found all keys?
if ( foundkeys = = allkeys )
goto OUT ;
2017-12-11 08:44:55 +08:00
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
chk_data . block = FirstBlockOfSector ( s ) ;
// skip already found A keys
if ( ! found [ ( s * 2 ) ] ) {
chk_data . keyType = 0 ;
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
memcpy ( k_sector [ s ] . keyA , datain + i * 6 , 6 ) ;
found [ ( s * 2 ) ] = 1 ;
+ + foundkeys ;
chkKey_scanA ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
// read Block B, if A is found.
chkKey_loopBonly ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
chk_data . block = FirstBlockOfSector ( s ) ;
}
}
// skip already found B keys
if ( ! found [ ( s * 2 ) + 1 ] ) {
chk_data . keyType = 1 ;
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
memcpy ( k_sector [ s ] . keyB , datain + i * 6 , 6 ) ;
found [ ( s * 2 ) + 1 ] = 1 ;
+ + foundkeys ;
chkKey_scanB ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
}
}
2017-12-12 05:33:50 +08:00
2017-12-11 08:44:55 +08:00
} // end loop sectors
} // end loop keys
} // end loop strategy 2
2017-10-05 22:00:56 +08:00
OUT :
LEDsoff ( ) ;
2017-12-12 05:33:50 +08:00
crypto1_destroy ( pcs ) ;
2017-10-05 22:00:56 +08:00
// All keys found, send to client, or last keychunk from client
2017-12-12 05:33:50 +08:00
if ( foundkeys = = allkeys | | lastchunk ) {
2017-10-05 22:00:56 +08:00
uint64_t foo = 0 ;
uint16_t bar = 0 ;
for ( uint8_t m = 0 ; m < 64 ; + + m )
foo | = ( found [ m ] < < m ) ;
for ( uint8_t m = 64 ; m < sizeof ( found ) ; + + m )
bar | = ( found [ m ] < < ( m - 64 ) ) ;
uint8_t * tmp = BigBuf_malloc ( 480 + 10 ) ;
memcpy ( tmp , k_sector , sectorcnt * sizeof ( sector_t ) ) ;
num_to_bytes ( foo , 8 , tmp + 480 ) ;
tmp [ 488 ] = bar & 0xFF ;
tmp [ 489 ] = bar > > 8 & 0xFF ;
cmd_send ( CMD_ACK , foundkeys , 0 , 0 , tmp , 480 + 10 ) ;
set_tracing ( false ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
2018-02-06 05:59:49 +08:00
BigBuf_free ( ) ; BigBuf_Clear_ext ( false ) ;
2017-10-05 22:00:56 +08:00
} else {
// partial/none keys found
cmd_send ( CMD_ACK , foundkeys , 0 , 0 , 0 , 0 ) ;
}
}
2016-04-11 21:25:00 +08:00
void MifareChkKeys ( uint16_t arg0 , uint8_t arg1 , uint8_t arg2 , uint8_t * datain ) {
2017-03-07 02:11:08 +08:00
2018-01-15 21:22:46 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
uint8_t uid [ 10 ] = { 0x00 } ;
uint64_t key = 0 ;
uint32_t cuid = 0 ;
int i , res ;
2017-03-07 02:11:08 +08:00
uint8_t blockNo = arg0 & 0xFF ;
uint8_t keyType = ( arg0 > > 8 ) & 0xFF ;
2011-06-18 02:39:54 +08:00
uint8_t keyCount = arg2 ;
2017-12-11 06:09:53 +08:00
uint8_t cascade_levels = 0 ;
uint8_t isOK = 0 ;
2018-01-15 21:22:46 +08:00
bool have_uid = false ;
bool clearTrace = arg1 & 0xFF ;
2011-06-18 02:39:54 +08:00
2016-02-17 04:43:45 +08:00
LEDsoff ( ) ;
2011-06-18 02:39:54 +08:00
LED_A_ON ( ) ;
2016-02-17 04:43:45 +08:00
2015-06-30 04:36:55 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2016-01-21 05:26:01 +08:00
if ( clearTrace )
clear_trace ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( true ) ;
2016-04-10 18:56:59 +08:00
2017-07-11 23:40:29 +08:00
for ( i = 0 ; i < keyCount ; i + + ) {
2011-06-18 02:39:54 +08:00
2017-07-07 18:34:20 +08:00
// Iceman: use piwi's faster nonce collecting part in hardnested.
2016-04-11 21:25:00 +08:00
if ( ! have_uid ) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info ;
2017-12-11 06:09:53 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2017-12-09 15:27:56 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " ChkKeys: Can't select card (ALL) " ) ;
2017-07-07 18:34:20 +08:00
- - i ; // try same key once again
continue ;
2016-04-11 21:25:00 +08:00
}
switch ( card_info . uidlen ) {
case 4 : cascade_levels = 1 ; break ;
case 7 : cascade_levels = 2 ; break ;
case 10 : cascade_levels = 3 ; break ;
default : break ;
}
2017-07-07 18:34:20 +08:00
have_uid = true ;
2016-04-11 21:25:00 +08:00
} else { // no need for anticollision. We can directly select the card
2017-12-11 06:09:53 +08:00
if ( ! iso14443a_select_card ( uid , NULL , NULL , false , cascade_levels , true ) ) {
2017-12-09 15:27:56 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " ChkKeys: Can't select card (UID) " ) ;
2017-07-07 18:34:20 +08:00
- - i ; // try same key once again
2016-04-11 21:25:00 +08:00
continue ;
}
}
2017-07-27 15:28:43 +08:00
key = bytes_to_num ( datain + i * 6 , 6 ) ;
2017-12-11 03:02:51 +08:00
res = mifare_classic_auth ( pcs , cuid , blockNo , keyType , key , AUTH_FIRST ) ;
2017-12-11 06:09:53 +08:00
2017-12-11 03:02:51 +08:00
CHK_TIMEOUT ( ) ;
2016-04-11 21:25:00 +08:00
2017-12-11 03:02:51 +08:00
if ( res )
2011-06-18 02:39:54 +08:00
continue ;
2017-12-11 03:02:51 +08:00
2017-07-07 18:34:20 +08:00
isOK = 1 ;
break ;
2011-06-18 02:39:54 +08:00
}
LED_B_ON ( ) ;
2016-04-10 18:56:59 +08:00
cmd_send ( CMD_ACK , isOK , 0 , 0 , datain + i * 6 , 6 ) ;
2016-02-18 00:30:37 +08:00
2017-07-07 18:34:20 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2016-02-18 00:30:37 +08:00
crypto1_destroy ( pcs ) ;
2011-06-18 02:39:54 +08:00
}
//-----------------------------------------------------------------------------
// MIFARE commands set debug level
//
//-----------------------------------------------------------------------------
2018-01-29 22:58:00 +08:00
void MifareSetDbgLvl ( uint16_t arg0 ) {
2011-06-18 02:39:54 +08:00
MF_DBGLEVEL = arg0 ;
Dbprintf ( " Debug level: %d " , MF_DBGLEVEL ) ;
}
//-----------------------------------------------------------------------------
// Work with emulator memory
//
2015-06-30 04:36:55 +08:00
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) here although FPGA is not
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
2011-06-18 02:39:54 +08:00
//-----------------------------------------------------------------------------
2015-06-30 04:36:55 +08:00
2011-06-18 02:39:54 +08:00
void MifareEMemClr ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
2015-06-30 04:36:55 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2011-06-18 02:39:54 +08:00
emlClearMem ( ) ;
}
void MifareEMemSet ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
2015-06-30 04:36:55 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2015-12-16 18:01:46 +08:00
if ( arg2 = = 0 ) arg2 = 16 ; // backwards compat... default bytewidth
2015-10-05 00:01:33 +08:00
emlSetMem_xt ( datain , arg0 , arg1 , arg2 ) ; // data, block num, blocks count, block byte width
2011-06-18 02:39:54 +08:00
}
void MifareEMemGet ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
2015-06-30 04:36:55 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2016-01-21 00:44:51 +08:00
byte_t buf [ USB_CMD_DATA_SIZE ] = { 0x00 } ;
2014-09-11 01:04:50 +08:00
emlGetMem ( buf , arg0 , arg1 ) ; // data, block num, blocks count (max 4)
2011-06-18 02:39:54 +08:00
LED_B_ON ( ) ;
2015-01-05 22:51:27 +08:00
cmd_send ( CMD_ACK , arg0 , arg1 , 0 , buf , USB_CMD_DATA_SIZE ) ;
2011-06-18 02:39:54 +08:00
LED_B_OFF ( ) ;
}
//-----------------------------------------------------------------------------
// Load a card into the emulator memory
//
//-----------------------------------------------------------------------------
void MifareECardLoad ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
2014-09-11 01:04:50 +08:00
uint8_t numSectors = arg0 ;
2011-06-18 02:39:54 +08:00
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
2016-01-21 00:44:51 +08:00
uint32_t cuid = 0 ;
2011-06-18 02:39:54 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
// variables
2016-01-21 00:44:51 +08:00
byte_t dataoutbuf [ 16 ] = { 0x00 } ;
byte_t dataoutbuf2 [ 16 ] = { 0x00 } ;
uint8_t uid [ 10 ] = { 0x00 } ;
2011-06-18 02:39:54 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
2015-06-30 04:36:55 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( true ) ;
2011-06-18 02:39:54 +08:00
2014-09-11 01:04:50 +08:00
bool isOK = true ;
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2014-09-11 01:04:50 +08:00
isOK = false ;
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
}
2011-06-18 02:39:54 +08:00
2014-09-11 01:04:50 +08:00
for ( uint8_t sectorNo = 0 ; isOK & & sectorNo < numSectors ; sectorNo + + ) {
ui64Key = emlGetKey ( sectorNo , keyType ) ;
if ( sectorNo = = 0 ) {
if ( isOK & & mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keyType , ui64Key , AUTH_FIRST ) ) {
isOK = false ;
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Sector[%2d]. Auth error " , sectorNo ) ;
2011-06-18 02:39:54 +08:00
break ;
2014-09-11 01:04:50 +08:00
}
} else {
if ( isOK & & mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keyType , ui64Key , AUTH_NESTED ) ) {
isOK = false ;
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Sector[%2d]. Auth nested error " , sectorNo ) ;
2011-06-18 02:39:54 +08:00
break ;
2014-09-11 01:04:50 +08:00
}
}
for ( uint8_t blockNo = 0 ; isOK & & blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
if ( isOK & & mifare_classic_readblock ( pcs , cuid , FirstBlockOfSector ( sectorNo ) + blockNo , dataoutbuf ) ) {
isOK = false ;
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Error reading sector %2d block %2d " , sectorNo , blockNo ) ;
2011-06-22 09:25:16 +08:00
break ;
2016-01-21 00:44:51 +08:00
}
2014-09-11 01:04:50 +08:00
if ( isOK ) {
if ( blockNo < NumBlocksPerSector ( sectorNo ) - 1 ) {
emlSetMem ( dataoutbuf , FirstBlockOfSector ( sectorNo ) + blockNo , 1 ) ;
} else { // sector trailer, keep the keys, set only the AC
emlGetMem ( dataoutbuf2 , FirstBlockOfSector ( sectorNo ) + blockNo , 1 ) ;
memcpy ( & dataoutbuf2 [ 6 ] , & dataoutbuf [ 6 ] , 4 ) ;
emlSetMem ( dataoutbuf2 , FirstBlockOfSector ( sectorNo ) + blockNo , 1 ) ;
}
}
2011-06-18 02:39:54 +08:00
}
2014-09-11 01:04:50 +08:00
}
2016-01-21 00:44:51 +08:00
if ( mifare_classic_halt ( pcs , cuid ) )
if ( MF_DBGLEVEL > = 1 )
Dbprintf ( " Halt error " ) ;
2011-06-18 02:39:54 +08:00
// ----------------------------- crypto1 destroy
crypto1_destroy ( pcs ) ;
2011-06-22 09:25:16 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2011-06-18 02:39:54 +08:00
if ( MF_DBGLEVEL > = 2 ) DbpString ( " EMUL FILL SECTORS FINISHED " ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2011-06-18 02:39:54 +08:00
}
2012-07-05 15:31:56 +08:00
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
//
2015-11-10 04:46:15 +08:00
// PARAMS - workFlags
// bit 0 - need get UID
// bit 1 - need wupC
// bit 2 - need HALT after sequence
// bit 3 - need turn on FPGA before sequence
// bit 4 - need turn off FPGA
// bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a)
// bit 6 - wipe tag.
2012-07-05 15:31:56 +08:00
//-----------------------------------------------------------------------------
2015-11-10 04:46:15 +08:00
// magic uid card generation 1 commands
uint8_t wupC1 [ ] = { MIFARE_MAGICWUPC1 } ;
uint8_t wupC2 [ ] = { MIFARE_MAGICWUPC2 } ;
uint8_t wipeC [ ] = { MIFARE_MAGICWIPEC } ;
void MifareCSetBlock ( uint32_t arg0 , uint32_t arg1 , uint8_t * datain ) {
2012-07-05 15:31:56 +08:00
2015-11-10 04:46:15 +08:00
// params
uint8_t workFlags = arg0 ;
uint8_t blockNo = arg1 ;
2017-07-07 18:34:20 +08:00
// detect 1a/1b
bool is1b = false ;
2012-07-05 15:31:56 +08:00
// variables
2016-02-16 05:04:24 +08:00
bool isOK = false ; //assume we will get an error
uint8_t errormsg = 0x00 ;
2015-01-05 22:51:27 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2015-11-10 04:46:15 +08:00
uint8_t data [ 18 ] = { 0x00 } ;
2016-01-21 00:44:51 +08:00
uint32_t cuid = 0 ;
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] = { 0x00 } ;
2014-12-16 14:41:07 +08:00
2015-11-10 04:46:15 +08:00
if ( workFlags & MAGIC_INIT ) {
2012-07-05 18:59:15 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
2015-06-30 04:36:55 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-02-08 03:49:40 +08:00
clear_trace ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( true ) ;
2012-07-05 18:59:15 +08:00
}
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
//loop doesn't loop just breaks out if error
while ( true ) {
// read UID and return to client with write
if ( workFlags & MAGIC_UID ) {
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2016-02-16 05:04:24 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
errormsg = MAGIC_UID ;
}
2016-10-29 02:43:07 +08:00
mifare_classic_halt_ex ( NULL ) ;
break ;
2015-12-16 18:01:46 +08:00
}
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
// wipe tag, fill it with zeros
if ( workFlags & MAGIC_WIPE ) {
2016-04-10 18:56:59 +08:00
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2016-02-16 05:04:24 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
errormsg = MAGIC_WIPE ;
break ;
}
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
ReaderTransmit ( wipeC , sizeof ( wipeC ) , NULL ) ;
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " wipeC error " ) ;
errormsg = MAGIC_WIPE ;
break ;
}
2012-07-05 15:31:56 +08:00
2016-10-29 02:43:07 +08:00
mifare_classic_halt_ex ( NULL ) ;
2016-02-16 05:04:24 +08:00
}
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
// write block
if ( workFlags & MAGIC_WUPC ) {
2016-04-10 18:56:59 +08:00
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2016-02-16 05:04:24 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
errormsg = MAGIC_WUPC ;
break ;
}
2017-07-07 18:34:20 +08:00
if ( ! is1b ) {
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ALL ) Dbprintf ( " Assuming Magic Gen 1B tag. [wupC2 failed] " ) ;
is1b = true ;
continue ;
}
2016-02-16 05:04:24 +08:00
}
2015-12-16 18:01:46 +08:00
}
2015-11-10 04:46:15 +08:00
2016-02-16 05:04:24 +08:00
if ( ( mifare_sendcmd_short ( NULL , 0 , ISO14443A_CMD_WRITEBLOCK , blockNo , receivedAnswer , receivedAnswerPar , NULL ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " write block send command error " ) ;
errormsg = 4 ;
break ;
}
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
memcpy ( data , datain , 16 ) ;
2018-02-01 22:19:47 +08:00
AddCrc14A ( data , 16 ) ;
2012-07-05 15:31:56 +08:00
2016-02-16 05:04:24 +08:00
ReaderTransmit ( data , sizeof ( data ) , NULL ) ;
if ( ( ReaderReceive ( receivedAnswer , receivedAnswerPar ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " write block send data error " ) ;
errormsg = 0 ;
break ;
}
2012-07-05 15:31:56 +08:00
2017-07-07 18:34:20 +08:00
if ( workFlags & MAGIC_HALT )
2016-10-29 02:43:07 +08:00
mifare_classic_halt_ex ( NULL ) ;
2016-02-16 05:04:24 +08:00
isOK = true ;
break ;
} // end while
if ( isOK )
cmd_send ( CMD_ACK , 1 , 0 , 0 , uid , sizeof ( uid ) ) ;
else
OnErrorMagic ( errormsg ) ;
2012-07-05 15:31:56 +08:00
2015-11-10 04:46:15 +08:00
if ( workFlags & MAGIC_OFF )
OnSuccessMagic ( ) ;
2012-07-05 15:31:56 +08:00
}
2012-07-05 22:05:01 +08:00
2015-11-10 04:46:15 +08:00
void MifareCGetBlock ( uint32_t arg0 , uint32_t arg1 , uint8_t * datain ) {
2012-07-05 22:05:01 +08:00
uint8_t workFlags = arg0 ;
2015-11-10 04:46:15 +08:00
uint8_t blockNo = arg1 ;
2016-02-16 05:04:24 +08:00
uint8_t errormsg = 0x00 ;
bool isOK = false ; //assume we will get an error
2017-07-07 18:34:20 +08:00
// detect 1a/1b
bool is1b = false ;
2012-07-05 22:05:01 +08:00
// variables
2015-11-10 04:46:15 +08:00
uint8_t data [ MAX_MIFARE_FRAME_SIZE ] ;
2016-02-16 05:04:24 +08:00
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] = { 0x00 } ;
2012-07-05 22:05:01 +08:00
2015-11-10 04:46:15 +08:00
memset ( data , 0x00 , sizeof ( data ) ) ;
if ( workFlags & MAGIC_INIT ) {
2012-07-05 22:05:01 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
2015-11-10 04:46:15 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-02-08 03:49:40 +08:00
clear_trace ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( true ) ;
2012-07-05 22:05:01 +08:00
}
2016-02-16 05:04:24 +08:00
//loop doesn't loop just breaks out if error or done
while ( true ) {
if ( workFlags & MAGIC_WUPC ) {
2016-04-10 18:56:59 +08:00
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2016-02-16 05:04:24 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
errormsg = MAGIC_WUPC ;
break ;
}
2012-07-05 22:05:01 +08:00
2017-07-07 18:34:20 +08:00
if ( ! is1b ) {
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ALL ) Dbprintf ( " Assuming Magic Gen 1B tag. [wupC2 failed] " ) ;
is1b = true ;
continue ;
}
2016-02-16 05:04:24 +08:00
}
2015-12-16 18:01:46 +08:00
}
2015-11-10 04:46:15 +08:00
2016-02-16 05:04:24 +08:00
// read block
if ( ( mifare_sendcmd_short ( NULL , 0 , ISO14443A_CMD_READBLOCK , blockNo , receivedAnswer , receivedAnswerPar , NULL ) ! = 18 ) ) {
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " read block send command error " ) ;
errormsg = 0 ;
break ;
}
memcpy ( data , receivedAnswer , sizeof ( data ) ) ;
// send HALT
2016-02-20 07:29:35 +08:00
if ( workFlags & MAGIC_HALT )
2016-02-16 05:04:24 +08:00
mifare_classic_halt_ex ( NULL ) ;
2016-02-20 07:29:35 +08:00
2016-02-16 05:04:24 +08:00
isOK = true ;
break ;
2015-12-16 18:01:46 +08:00
}
2015-11-10 04:46:15 +08:00
// if MAGIC_DATAIN, the data stays on device side.
2016-02-16 05:04:24 +08:00
if ( workFlags & MAGIC_DATAIN ) {
if ( isOK )
memcpy ( datain , data , sizeof ( data ) ) ;
} else {
if ( isOK )
cmd_send ( CMD_ACK , 1 , 0 , 0 , data , sizeof ( data ) ) ;
else
OnErrorMagic ( errormsg ) ;
}
2015-11-10 04:46:15 +08:00
if ( workFlags & MAGIC_OFF )
OnSuccessMagic ( ) ;
2012-07-05 22:05:01 +08:00
}
2015-01-05 22:51:27 +08:00
void MifareCIdent ( ) {
2017-02-28 02:18:38 +08:00
# define GEN_1A 1
# define GEN_1B 2
2017-02-28 15:16:02 +08:00
# define GEN_2 4
2015-01-05 22:51:27 +08:00
// variables
2017-02-28 02:18:38 +08:00
uint8_t isGen = 0 ;
2017-02-28 15:16:02 +08:00
uint8_t rec [ 1 ] = { 0x00 } ;
uint8_t recpar [ 1 ] = { 0x00 } ;
2017-10-30 19:05:14 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2017-02-28 15:16:02 +08:00
// Generation 1 test
2016-04-10 18:56:59 +08:00
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2017-02-28 15:16:02 +08:00
if ( ! ReaderReceive ( rec , recpar ) | | ( rec [ 0 ] ! = 0x0a ) ) {
goto TEST2 ;
} ;
isGen = GEN_1B ;
2017-02-28 02:18:38 +08:00
2015-01-05 22:51:27 +08:00
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
2017-02-28 15:16:02 +08:00
if ( ! ReaderReceive ( rec , recpar ) | | ( rec [ 0 ] ! = 0x0a ) ) {
2017-02-28 02:18:38 +08:00
goto OUT ;
2017-02-28 15:16:02 +08:00
} ;
2017-02-28 02:18:38 +08:00
isGen = GEN_1A ;
2017-02-28 15:16:02 +08:00
goto OUT ;
2015-01-05 22:51:27 +08:00
2017-02-28 15:16:02 +08:00
TEST2 : ;
/*
// Generation 2 test
// halt previous.
mifare_classic_halt ( NULL , 0 ) ;
//select
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2017-02-28 15:16:02 +08:00
goto OUT ;
} ;
// MIFARE_CLASSIC_WRITEBLOCK 0xA0
// ACK 0x0a
2017-10-02 04:06:06 +08:00
uint16_t len = mifare_sendcmd_short ( null , 1 , 0xA0 , 0 , rec , recpar , NULL ) ;
2017-02-28 15:16:02 +08:00
if ( ( len ! = 1 ) | | ( rec [ 0 ] ! = 0x0A ) ) {
isGen = GEN_2 ;
} ;
*/
OUT : ;
2015-11-02 05:16:16 +08:00
// removed the if, since some magic tags misbehavies and send an answer to it.
2017-07-07 18:34:20 +08:00
mifare_classic_halt_ex ( NULL ) ;
2017-10-30 19:05:14 +08:00
cmd_send ( CMD_ACK , isGen , 0 , 0 , 0 , 0 ) ;
// turns off
OnSuccessMagic ( ) ;
2015-01-05 22:51:27 +08:00
}
2015-11-10 04:46:15 +08:00
void OnSuccessMagic ( ) {
2015-04-25 00:41:49 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2015-11-10 04:46:15 +08:00
}
void OnErrorMagic ( uint8_t reason ) {
// ACK, ISOK, reason,0,0,0
cmd_send ( CMD_ACK , 0 , reason , 0 , 0 , 0 ) ;
OnSuccessMagic ( ) ;
}
2017-03-09 21:36:19 +08:00
void MifareSetMod ( uint8_t mod , uint8_t * key ) {
uint64_t ui64Key = bytes_to_num ( key , 6 ) ;
// variables
uint8_t isOK = 0 ;
uint8_t uid [ 10 ] = { 0 } ;
uint32_t cuid = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs = & mpcs ;
int respLen = 0 ;
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0 } ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] = { 0 } ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
while ( true ) {
2017-10-02 04:06:06 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2017-03-09 21:36:19 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Can't select card " ) ;
break ;
}
if ( mifare_classic_auth ( pcs , cuid , 0 , 0 , ui64Key , AUTH_FIRST ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Auth error " ) ;
break ;
}
if ( ( ( respLen = mifare_sendcmd_short ( pcs , 1 , 0x43 , mod , receivedAnswer , receivedAnswerPar , NULL ) ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " SetMod error; response[0]: %hhX, len: %d " , receivedAnswer [ 0 ] , respLen ) ;
break ;
}
if ( mifare_classic_halt ( pcs , cuid ) ) {
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Halt error " ) ;
break ;
}
isOK = 1 ;
break ;
}
crypto1_destroy ( pcs ) ;
LED_B_ON ( ) ;
cmd_send ( CMD_ACK , isOK , 0 , 0 , 0 , 0 ) ;
LED_B_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
}
2015-04-25 00:41:49 +08:00
//
2015-01-05 22:51:27 +08:00
// DESFIRE
//
2015-01-14 06:18:04 +08:00
void Mifare_DES_Auth1 ( uint8_t arg0 , uint8_t * datain ) {
2016-01-21 00:13:25 +08:00
byte_t dataout [ 12 ] = { 0x00 } ;
2015-01-14 06:18:04 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2016-01-21 00:44:51 +08:00
uint32_t cuid = 0 ;
2015-01-14 06:18:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2015-06-30 04:36:55 +08:00
clear_trace ( ) ;
2016-01-21 05:26:01 +08:00
set_tracing ( true ) ;
2015-01-14 06:18:04 +08:00
2017-10-02 04:06:06 +08:00
int len = iso14443a_select_card ( uid , NULL , & cuid , true , 0 , false ) ;
2015-01-14 06:18:04 +08:00
if ( ! len ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 1 ) ;
2015-01-14 06:18:04 +08:00
return ;
} ;
if ( mifare_desfire_des_auth1 ( cuid , dataout ) ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_ERROR ) Dbprintf ( " Authentication part1: Fail. " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 4 ) ;
2015-01-14 06:18:04 +08:00
return ;
}
if ( MF_DBGLEVEL > = MF_DBG_EXTENDED ) DbpString ( " AUTH 1 FINISHED " ) ;
2016-04-12 17:30:49 +08:00
cmd_send ( CMD_ACK , 1 , cuid , 0 , dataout , sizeof ( dataout ) ) ;
2015-01-14 06:18:04 +08:00
}
void Mifare_DES_Auth2 ( uint32_t arg0 , uint8_t * datain ) {
uint32_t cuid = arg0 ;
uint8_t key [ 16 ] = { 0x00 } ;
byte_t dataout [ 12 ] = { 0x00 } ;
2015-03-30 22:24:03 +08:00
byte_t isOK = 0 ;
2015-01-14 06:18:04 +08:00
memcpy ( key , datain , 16 ) ;
isOK = mifare_desfire_des_auth2 ( cuid , key , dataout ) ;
if ( isOK ) {
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_EXTENDED ) Dbprintf ( " Authentication part2: Failed " ) ;
2015-03-24 18:45:31 +08:00
OnError ( 4 ) ;
2015-01-14 06:18:04 +08:00
return ;
}
2015-03-30 22:24:03 +08:00
if ( MF_DBGLEVEL > = MF_DBG_EXTENDED ) DbpString ( " AUTH 2 FINISHED " ) ;
2015-01-14 06:18:04 +08:00
cmd_send ( CMD_ACK , isOK , 0 , 0 , dataout , sizeof ( dataout ) ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2017-07-07 18:34:20 +08:00
set_tracing ( false ) ;
2015-05-23 14:38:46 +08:00
}