2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
2022-01-06 18:24:04 +08:00
// Copyright (C) Gerhard de Koning Gans - May 2008
2022-01-06 09:19:46 +08:00
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
2019-03-09 15:49:41 +08:00
//
2022-01-06 09:19:46 +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-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
# include "mifarecmd.h"
2019-07-16 19:50:38 +08:00
# include "pmflash.h"
2019-08-08 22:57:33 +08:00
# include "proxmark3_arm.h"
# include "string.h"
# include "mifareutil.h"
# include "protocols.h"
# include "parity.h"
# include "BigBuf.h"
# include "cmd.h"
# include "flashmem.h"
# include "fpgaloader.h"
# include "iso14443a.h"
# include "mifaredesfire.h"
# include "util.h"
# include "commonutil.h"
# include "crc16.h"
# include "dbprint.h"
# include "ticks.h"
2019-12-14 19:45:07 +08:00
# include "usb_cdc.h" // usb_poll_validate_length
2020-01-22 20:11:20 +08:00
# include "spiffs.h" // spiffs
2020-08-31 09:04:32 +08:00
# include "appmain.h" // print_stack_usage
2019-07-16 19:50:38 +08:00
2019-03-09 15:49:41 +08:00
# ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
2019-03-10 03:34:41 +08:00
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
2019-03-09 15:49:41 +08:00
# endif
# ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME
2019-03-10 03:34:41 +08:00
# define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
2019-03-09 15:59:13 +08:00
# endif
2019-03-09 15:49:41 +08:00
// send an incomplete dummy response in order to trigger the card's authentication failure timeout
# ifndef CHK_TIMEOUT
2020-05-10 22:59:38 +08:00
# define CHK_TIMEOUT(void) { \
2019-03-10 07:00:59 +08:00
ReaderTransmit ( & dummy_answer , 1 , NULL ) ; \
uint32_t timeout = GetCountSspClk ( ) + HARDNESTED_AUTHENTICATION_TIMEOUT ; \
while ( GetCountSspClk ( ) < timeout ) { } ; \
}
2019-03-09 15:49:41 +08:00
# endif
static uint8_t dummy_answer = 0 ;
//-----------------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// Select, Authenticate, Read a MIFARE tag.
2019-03-09 15:49:41 +08:00
// read block
//-----------------------------------------------------------------------------
2019-05-29 01:20:56 +08:00
void MifareReadBlock ( uint8_t blockNo , uint8_t keyType , uint8_t * datain ) {
2019-03-10 07:00:59 +08:00
// params
2019-03-10 03:34:41 +08:00
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( datain , 6 ) ;
// variables
2019-03-21 22:19:18 +08:00
uint8_t dataoutbuf [ 16 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2019-05-29 01:20:56 +08:00
uint32_t cuid = 0 , status = PM3_EOPABORTED ;
2019-06-08 03:40:33 +08:00
2019-03-10 03:34:41 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
while ( true ) {
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_auth ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Auth error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_readblock ( pcs , cuid , blockNo , dataoutbuf ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Read block error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-05-29 01:20:56 +08:00
status = PM3_SUCCESS ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) DbpString ( " READ BLOCK FINISHED " ) ;
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_READBL , status , dataoutbuf , 16 ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2019-03-09 15:49:41 +08:00
}
2019-04-07 18:30:49 +08:00
void MifareUC_Auth ( uint8_t arg0 , uint8_t * keybytes ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
bool turnOffField = ( arg0 = = 1 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2019-03-09 15:59:13 +08:00
2019-04-07 18:30:49 +08:00
if ( ! mifare_ultra_auth ( keybytes ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Authentication failed " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
if ( turnOffField ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
}
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2019-03-09 15:49:41 +08:00
}
// Arg0 = BlockNo,
// Arg1 = UsePwd bool
// datain = PWD bytes,
2019-03-10 18:20:22 +08:00
void MifareUReadBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
uint8_t blockNo = arg0 ;
2019-03-21 22:19:18 +08:00
uint8_t dataout [ 16 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
bool useKey = ( arg1 = = 1 ) ; //UL_C
bool usePwd = ( arg1 = = 2 ) ; //UL_EV1/NTAG
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
int len = iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ;
2019-03-10 07:00:59 +08:00
if ( ! len ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card (RC:%02X) " , len ) ;
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
// UL-C authentication
2019-03-10 07:00:59 +08:00
if ( useKey ) {
2019-03-10 03:34:41 +08:00
uint8_t key [ 16 ] = { 0x00 } ;
2019-03-10 07:00:59 +08:00
memcpy ( key , datain , sizeof ( key ) ) ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
}
// UL-EV1 / NTAG authentication
2019-03-10 07:00:59 +08:00
if ( usePwd ) {
2019-03-10 03:34:41 +08:00
uint8_t pwd [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain , 4 ) ;
2019-03-10 07:00:59 +08:00
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2019-03-10 03:34:41 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
OnError ( 1 ) ;
return ;
}
}
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_readblock ( blockNo , dataout ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Read block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 2 ) ;
return ;
}
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_halt ( ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 3 ) ;
return ;
}
2019-03-09 15:49:41 +08:00
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , 0 , 0 , dataout , 16 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// Select, Authenticate, Read a MIFARE tag.
2019-03-09 15:49:41 +08:00
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
//-----------------------------------------------------------------------------
2019-05-13 18:49:41 +08:00
void MifareReadSector ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain ) {
2019-03-10 07:00:59 +08:00
// params
2019-03-10 03:34:41 +08:00
uint8_t sectorNo = arg0 ;
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( datain , 6 ) ;
// variables
2019-03-21 22:19:18 +08:00
uint8_t isOK = 0 ;
uint8_t dataoutbuf [ 16 * 16 ] ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
isOK = 1 ;
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2019-03-10 03:34:41 +08:00
isOK = 0 ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
}
2019-03-10 07:00:59 +08:00
if ( isOK & & mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keyType , ui64Key , AUTH_FIRST ) ) {
2019-03-10 03:34:41 +08:00
isOK = 0 ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Auth error " ) ;
2019-03-10 03:34:41 +08:00
}
for ( uint8_t blockNo = 0 ; isOK & & blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
2019-03-10 07:00:59 +08:00
if ( mifare_classic_readblock ( pcs , cuid , FirstBlockOfSector ( sectorNo ) + blockNo , dataoutbuf + 16 * blockNo ) ) {
2019-03-10 03:34:41 +08:00
isOK = 0 ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Read sector %2d block %2d error " , sectorNo , blockNo ) ;
2019-03-10 03:34:41 +08:00
break ;
}
}
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) DbpString ( " READ SECTOR FINISHED " ) ;
2019-03-10 03:34:41 +08:00
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
2019-04-18 18:43:35 +08:00
reply_old ( CMD_ACK , isOK , 0 , 0 , dataoutbuf , 16 * NumBlocksPerSector ( sectorNo ) ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
// arg0 = blockNo (start)
// arg1 = Pages (number of blocks)
// arg2 = useKey
// datain = KEY bytes
2019-03-10 18:20:22 +08:00
void MifareUReadCard ( uint8_t arg0 , uint16_t arg1 , uint8_t arg2 , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
// free eventually allocated BigBuf memory
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
// params
uint8_t blockNo = arg0 ;
uint16_t blocks = arg1 ;
bool useKey = ( arg2 = = 1 ) ; //UL_C
bool usePwd = ( arg2 = = 2 ) ; //UL_EV1/NTAG
uint32_t countblocks = 0 ;
uint8_t * dataout = BigBuf_malloc ( CARD_MEMORY_SIZE ) ;
2019-03-10 07:00:59 +08:00
if ( dataout = = NULL ) {
2019-03-10 03:34:41 +08:00
Dbprintf ( " out of memory " ) ;
OnError ( 1 ) ;
return ;
}
int len = iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ;
if ( ! len ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card (RC:%d) " , len ) ;
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
// UL-C authentication
2019-03-10 07:00:59 +08:00
if ( useKey ) {
2019-03-10 03:34:41 +08:00
uint8_t key [ 16 ] = { 0x00 } ;
2019-03-10 07:00:59 +08:00
memcpy ( key , datain , sizeof ( key ) ) ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
}
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd [ 4 ] = { 0x00 } ;
memcpy ( pwd , datain , sizeof ( pwd ) ) ;
2019-03-10 07:00:59 +08:00
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
}
2019-03-10 07:00:59 +08:00
for ( int i = 0 ; i < blocks ; i + + ) {
if ( ( i * 4 ) + 4 > = CARD_MEMORY_SIZE ) {
2019-03-10 03:34:41 +08:00
Dbprintf ( " Data exceeds buffer!! " ) ;
break ;
}
len = mifare_ultra_readblock ( blockNo + i , dataout + 4 * i ) ;
if ( len ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Read block %d error " , i ) ;
2019-03-10 03:34:41 +08:00
// if no blocks read - error out
if ( i = = 0 ) {
OnError ( 2 ) ;
return ;
} else {
//stop at last successful read block and return what we got
break ;
}
} else {
countblocks + + ;
}
}
len = mifare_ultra_halt ( ) ;
if ( len ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 3 ) ;
return ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) Dbprintf ( " Blocks read %d " , countblocks ) ;
2019-03-10 03:34:41 +08:00
countblocks * = 4 ;
2020-09-06 22:15:12 +08:00
reply_mix ( CMD_ACK , 1 , countblocks , dataout - BigBuf_get_addr ( ) , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
BigBuf_free ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// Select, Authenticate, Write a MIFARE tag.
2019-03-09 15:49:41 +08:00
// read block
//-----------------------------------------------------------------------------
2019-05-13 18:49:41 +08:00
void MifareWriteBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
// params
uint8_t blockNo = arg0 ;
uint8_t keyType = arg1 ;
uint64_t ui64Key = 0 ;
2019-03-21 22:19:18 +08:00
uint8_t blockdata [ 16 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
ui64Key = bytes_to_num ( datain , 6 ) ;
memcpy ( blockdata , datain + 10 , 16 ) ;
// variables
2019-03-21 22:19:18 +08:00
uint8_t isOK = 0 ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
while ( true ) {
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_auth ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Auth error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_writeblock ( pcs , cuid , blockNo , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
break ;
} ;
isOK = 1 ;
break ;
}
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
2019-03-10 03:34:41 +08:00
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , isOK , 0 , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +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.
2020-11-05 19:06:12 +08:00
static void MifareUWriteBlockEx ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain , bool reply ) {
2019-03-10 03:34:41 +08:00
uint8_t blockNo = arg0 ;
bool useKey = ( arg1 = = 1 ) ; //UL_C
bool usePwd = ( arg1 = = 2 ) ; //UL_EV1/NTAG
2019-03-21 22:19:18 +08:00
uint8_t blockdata [ 4 ] = { 0x00 } ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
memcpy ( blockdata , datain , 4 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// UL-C authentication
2019-03-10 07:00:59 +08:00
if ( useKey ) {
2019-03-10 03:34:41 +08:00
uint8_t key [ 16 ] = { 0x00 } ;
2019-03-10 07:00:59 +08:00
memcpy ( key , datain + 4 , sizeof ( key ) ) ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
}
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd [ 4 ] = { 0x00 } ;
2019-03-10 07:00:59 +08:00
memcpy ( pwd , datain + 4 , 4 ) ;
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2019-03-10 03:34:41 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
OnError ( 1 ) ;
return ;
}
}
if ( mifare_ultra_writeblock ( blockNo , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
if ( mifare_ultra_halt ( ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2019-03-09 15:49:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
2019-03-09 15:49:41 +08:00
2020-11-05 19:06:12 +08:00
if ( reply )
reply_mix ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2020-09-08 03:34:44 +08:00
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
2020-11-05 19:06:12 +08:00
void MifareUWriteBlock ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain ) {
MifareUWriteBlockEx ( arg0 , arg1 , datain , true ) ;
}
2019-03-09 15:49:41 +08:00
// Arg0 : Block to write to.
// Arg1 : 0 = use no authentication.
// 1 = use 0x1A authentication.
// 2 = use 0x1B authentication.
2020-09-08 03:34:44 +08:00
// datain : 16 first bytes is data to be written.
2019-03-09 15:49:41 +08:00
// : 4/16 next bytes is authentication key.
2020-09-08 03:34:44 +08:00
void MifareUWriteBlockCompat ( uint8_t arg0 , uint8_t arg1 , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
uint8_t blockNo = arg0 ;
bool useKey = ( arg1 = = 1 ) ; //UL_C
bool usePwd = ( arg1 = = 2 ) ; //UL_EV1/NTAG
2020-09-08 03:34:44 +08:00
uint8_t blockdata [ 16 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
2020-09-08 03:34:44 +08:00
memcpy ( blockdata , datain , 16 ) ;
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
// UL-C authentication
2019-03-10 07:00:59 +08:00
if ( useKey ) {
2019-03-10 03:34:41 +08:00
uint8_t key [ 16 ] = { 0x00 } ;
2020-09-08 03:34:44 +08:00
memcpy ( key , datain + 16 , sizeof ( key ) ) ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! mifare_ultra_auth ( key ) ) {
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
}
}
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd [ 4 ] = { 0x00 } ;
2020-09-08 03:34:44 +08:00
memcpy ( pwd , datain + 16 , 4 ) ;
2019-03-10 07:00:59 +08:00
uint8_t pack [ 4 ] = { 0 , 0 , 0 , 0 } ;
2019-03-10 03:34:41 +08:00
if ( ! mifare_ul_ev1_auth ( pwd , pack ) ) {
OnError ( 1 ) ;
return ;
}
}
2020-09-08 03:34:44 +08:00
if ( mifare_ultra_writeblock_compat ( blockNo , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
if ( mifare_ultra_halt ( ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) DbpString ( " WRITE BLOCK FINISHED " ) ;
2019-03-10 03:34:41 +08:00
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void MifareUSetPwd ( uint8_t arg0 , uint8_t * datain ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
uint8_t pwd [ 16 ] = { 0x00 } ;
2019-03-21 22:19:18 +08:00
uint8_t blockdata [ 4 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
memcpy ( pwd , datain , 16 ) ;
2019-03-10 07:00:59 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
2019-03-10 03:34:41 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
blockdata [ 0 ] = pwd [ 7 ] ;
blockdata [ 1 ] = pwd [ 6 ] ;
blockdata [ 2 ] = pwd [ 5 ] ;
blockdata [ 3 ] = pwd [ 4 ] ;
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_writeblock ( 44 , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 44 ) ;
return ;
} ;
blockdata [ 0 ] = pwd [ 3 ] ;
blockdata [ 1 ] = pwd [ 2 ] ;
blockdata [ 2 ] = pwd [ 1 ] ;
blockdata [ 3 ] = pwd [ 0 ] ;
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_writeblock ( 45 , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 45 ) ;
return ;
} ;
blockdata [ 0 ] = pwd [ 15 ] ;
blockdata [ 1 ] = pwd [ 14 ] ;
blockdata [ 2 ] = pwd [ 13 ] ;
blockdata [ 3 ] = pwd [ 12 ] ;
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_writeblock ( 46 , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 46 ) ;
return ;
} ;
blockdata [ 0 ] = pwd [ 11 ] ;
blockdata [ 1 ] = pwd [ 10 ] ;
blockdata [ 2 ] = pwd [ 9 ] ;
blockdata [ 3 ] = pwd [ 8 ] ;
2019-03-10 07:00:59 +08:00
if ( mifare_ultra_writeblock ( 47 , blockdata ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Write block error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 47 ) ;
return ;
} ;
if ( mifare_ultra_halt ( ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 0 ) ;
return ;
} ;
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , 0 , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
// Return 1 if the nonce is invalid else return 0
2022-01-06 22:40:11 +08:00
static int valid_nonce ( uint32_t Nt , uint32_t NtEnc , uint32_t Ks1 , const uint8_t * parity ) {
2021-02-24 06:53:08 +08:00
return (
2021-04-08 16:44:31 +08:00
( 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 ;
2019-03-09 15:49:41 +08:00
}
2019-05-13 19:31:11 +08:00
void MifareAcquireNonces ( uint32_t arg0 , uint32_t flags ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint8_t answer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t par [ 1 ] = { 0x00 } ;
2019-05-01 03:10:11 +08:00
uint8_t buf [ PM3_CMD_DATA_SIZE ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
uint32_t cuid = 0 ;
int16_t isOK = 0 ;
uint16_t num_nonces = 0 ;
uint8_t cascade_levels = 0 ;
uint8_t blockNo = arg0 & 0xff ;
uint8_t keyType = ( arg0 > > 8 ) & 0xff ;
bool initialize = flags & 0x0001 ;
bool field_off = flags & 0x0004 ;
bool have_uid = false ;
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
if ( initialize )
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
LED_C_ON ( ) ;
2021-01-22 23:05:45 +08:00
while ( num_nonces < PM3_CMD_DATA_SIZE / 4 ) {
2019-03-10 03:34:41 +08:00
// 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 ;
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireNonces: Can't select card (ALL) " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
switch ( card_info . uidlen ) {
2019-03-10 07:00:59 +08:00
case 4 :
cascade_levels = 1 ;
break ;
case 7 :
cascade_levels = 2 ;
break ;
case 10 :
cascade_levels = 3 ;
break ;
default :
break ;
2019-03-10 03:34:41 +08:00
}
have_uid = true ;
} else { // no need for anticollision. We can directly select the card
if ( ! iso14443a_fast_select_card ( uid , cascade_levels ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireNonces: Can't select card (UID) " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
}
// Transmit MIFARE_CLASSIC_AUTH
uint8_t dcmd [ 4 ] = { 0x60 + ( keyType & 0x01 ) , blockNo , 0x00 , 0x00 } ;
AddCrc14A ( dcmd , 2 ) ;
ReaderTransmit ( dcmd , sizeof ( dcmd ) , NULL ) ;
int len = ReaderReceive ( answer , par ) ;
// wait for the card to become ready again
CHK_TIMEOUT ( ) ;
if ( len ! = 4 ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 2 ) Dbprintf ( " AcquireNonces: Auth1 error " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
// Save the tag nonce (nt)
2021-01-22 23:05:45 +08:00
memcpy ( buf + num_nonces * 4 , answer , 4 ) ;
num_nonces + + ;
2019-03-10 03:34:41 +08:00
}
LED_C_OFF ( ) ;
LED_B_ON ( ) ;
2021-01-22 23:05:45 +08:00
reply_old ( CMD_ACK , isOK , cuid , num_nonces , buf , sizeof ( buf ) ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 3 ) DbpString ( " AcquireNonces finished " ) ;
2019-03-10 03:34:41 +08:00
if ( field_off ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
}
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
// acquire encrypted nonces in order to perform the attack described in
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
2019-03-09 15:59:13 +08:00
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
2019-03-09 15:49:41 +08:00
// Computer and Communications Security, 2015
//-----------------------------------------------------------------------------
2019-03-10 18:20:22 +08:00
void MifareAcquireEncryptedNonces ( uint32_t arg0 , uint32_t arg1 , uint32_t flags , uint8_t * datain ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
uint8_t uid [ 10 ] = { 0x00 } ;
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t par_enc [ 1 ] = { 0x00 } ;
2019-05-01 03:10:11 +08:00
uint8_t buf [ PM3_CMD_DATA_SIZE ] = { 0x00 } ;
2019-03-10 03:34:41 +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 ;
uint8_t blockNo = arg0 & 0xff ;
uint8_t keyType = ( arg0 > > 8 ) & 0xff ;
uint8_t targetBlockNo = arg1 & 0xff ;
uint8_t targetKeyType = ( arg1 > > 8 ) & 0xff ;
bool initialize = flags & 0x0001 ;
bool slow = flags & 0x0002 ;
bool field_off = flags & 0x0004 ;
bool have_uid = false ;
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( false ) ;
if ( initialize )
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
LED_C_ON ( ) ;
2019-05-01 03:10:11 +08:00
for ( uint16_t i = 0 ; i < = PM3_CMD_DATA_SIZE - 9 ; ) {
2019-03-10 03:34:41 +08:00
// Test if the action was cancelled
2019-03-10 07:00:59 +08:00
if ( BUTTON_PRESS ( ) ) {
2019-03-10 03:34:41 +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 ;
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireEncryptedNonces: Can't select card (ALL) " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
switch ( card_info . uidlen ) {
2019-03-10 07:00:59 +08:00
case 4 :
cascade_levels = 1 ;
break ;
case 7 :
cascade_levels = 2 ;
break ;
case 10 :
cascade_levels = 3 ;
break ;
default :
break ;
2019-03-10 03:34:41 +08:00
}
have_uid = true ;
} else { // no need for anticollision. We can directly select the card
if ( ! iso14443a_fast_select_card ( uid , cascade_levels ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireEncryptedNonces: Can't select card (UID) " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
}
if ( slow )
SpinDelayUs ( HARDNESTED_PRE_AUTHENTICATION_LEADTIME ) ;
uint32_t nt1 ;
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , NULL ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireEncryptedNonces: Auth1 error " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
// nested authentication
uint16_t len = mifare_sendcmd_short ( pcs , AUTH_NESTED , 0x60 + ( targetKeyType & 0x01 ) , targetBlockNo , receivedAnswer , par_enc , NULL ) ;
// wait for the card to become ready again
CHK_TIMEOUT ( ) ;
if ( len ! = 4 ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " AcquireEncryptedNonces: Auth2 error len=%d " , len ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
num_nonces + + ;
if ( num_nonces % 2 ) {
2019-03-10 07:00:59 +08:00
memcpy ( buf + i , receivedAnswer , 4 ) ;
2019-03-10 03:34:41 +08:00
nt_par_enc = par_enc [ 0 ] & 0xf0 ;
} else {
nt_par_enc | = par_enc [ 0 ] > > 4 ;
2019-03-10 07:00:59 +08:00
memcpy ( buf + i + 4 , receivedAnswer , 4 ) ;
memcpy ( buf + i + 8 , & nt_par_enc , 1 ) ;
2019-03-10 03:34:41 +08:00
i + = 9 ;
}
}
LED_C_OFF ( ) ;
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
2019-04-18 18:43:35 +08:00
reply_old ( CMD_ACK , isOK , cuid , num_nonces , buf , sizeof ( buf ) ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 3 ) DbpString ( " AcquireEncryptedNonces finished " ) ;
2019-03-10 03:34:41 +08:00
if ( field_off ) {
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
}
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// MIFARE nested authentication.
//
2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
2019-10-03 22:15:47 +08:00
void MifareNested ( uint8_t blockNo , uint8_t keyType , uint8_t targetBlockNo , uint8_t targetKeyType , bool calibrate , uint8_t * key ) {
2019-03-10 03:34:41 +08:00
uint64_t ui64Key = 0 ;
2019-10-03 22:15:47 +08:00
ui64Key = bytes_to_num ( key , 6 ) ;
2019-03-10 03:34:41 +08:00
// variables
2019-06-08 00:41:39 +08:00
uint16_t i , j , len ;
2019-03-10 03:34:41 +08:00
static uint16_t dmin , dmax ;
2019-10-03 22:15:47 +08:00
uint8_t par [ 1 ] = { 0x00 } ;
uint8_t par_array [ 4 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
2019-06-08 00:41:39 +08:00
uint32_t cuid = 0 , nt1 , nt2 , nttest , ks1 ;
2019-03-10 03:34:41 +08:00
uint32_t target_nt [ 2 ] = { 0x00 } , target_ks [ 2 ] = { 0x00 } ;
uint16_t ncount = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint32_t auth1_time , auth2_time ;
static uint16_t delta_time = 0 ;
LED_A_ON ( ) ;
LED_C_OFF ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
// free eventually allocated BigBuf memory
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2019-03-10 03:34:41 +08:00
2019-10-03 22:15:47 +08:00
if ( calibrate )
clear_trace ( ) ;
2019-03-10 03:34:41 +08:00
set_tracing ( true ) ;
// statistics on nonce distance
2020-09-02 18:16:11 +08:00
int16_t isOK = PM3_SUCCESS ;
2019-03-10 07:00:59 +08:00
# define NESTED_MAX_TRIES 12
2019-10-03 22:15:47 +08:00
if ( calibrate ) { // calibrate: for first call only. Otherwise reuse previous calibration
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
WDT_HIT ( ) ;
2019-09-14 23:44:58 +08:00
uint16_t unsuccessful_tries = 0 ;
2019-06-08 00:41:39 +08:00
uint16_t davg = 0 ;
dmax = 0 ;
2019-03-10 03:34:41 +08:00
dmin = 2000 ;
delta_time = 0 ;
2019-06-08 00:41:39 +08:00
uint16_t rtr ;
2019-03-10 03:34:41 +08:00
for ( rtr = 0 ; rtr < 17 ; rtr + + ) {
// Test if the action was cancelled
2019-12-30 20:25:15 +08:00
if ( BUTTON_PRESS ( ) | | data_available ( ) ) {
2020-09-02 18:16:11 +08:00
isOK = PM3_EOPABORTED ;
2019-03-10 03:34:41 +08:00
break ;
}
// prepare next select. No need to power down the card.
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Halt error " ) ;
2019-03-10 03:34:41 +08:00
rtr - - ;
continue ;
}
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Can't select card " ) ;
2019-03-10 03:34:41 +08:00
rtr - - ;
continue ;
} ;
auth1_time = 0 ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , & auth1_time ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth1 error " ) ;
2019-03-10 03:34:41 +08:00
rtr - - ;
continue ;
} ;
auth2_time = ( delta_time ) ? auth1_time + delta_time : 0 ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_NESTED , & nt2 , & auth2_time ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth2 error " ) ;
2019-03-10 03:34:41 +08:00
rtr - - ;
continue ;
} ;
2019-10-04 20:21:04 +08:00
// cards with fixed nonce
if ( nt1 = = nt2 ) {
2019-10-13 06:48:26 +08:00
Dbprintf ( " Nested: %08x vs %08x " , nt1 , nt2 ) ;
break ;
2019-10-04 20:21:04 +08:00
}
2019-06-08 00:41:39 +08:00
uint32_t nttmp = prng_successor ( nt1 , 100 ) ; //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
2019-03-10 03:34:41 +08:00
for ( i = 101 ; i < 1200 ; i + + ) {
nttmp = prng_successor ( nttmp , 1 ) ;
if ( nttmp = = nt2 ) break ;
}
if ( i ! = 1200 ) {
if ( rtr ! = 0 ) {
davg + = i ;
dmin = MIN ( dmin , i ) ;
dmax = MAX ( dmax , i ) ;
2019-03-10 07:00:59 +08:00
} else {
2019-03-10 03:34:41 +08:00
delta_time = auth2_time - auth1_time + 32 ; // allow some slack for proper timing
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Nested: calibrating... ntdist=%d " , i ) ;
2019-03-10 03:34:41 +08:00
} else {
2019-09-14 23:44:58 +08:00
unsuccessful_tries + + ;
if ( unsuccessful_tries > NESTED_MAX_TRIES ) { // card isn't vulnerable to nested attack (random numbers are not predictable)
2020-09-02 18:16:11 +08:00
isOK = PM3_EFAILED ;
2019-03-10 03:34:41 +08:00
}
}
}
2021-02-24 06:53:08 +08:00
if ( rtr > 1 )
davg = ( davg + ( rtr - 1 ) / 2 ) / ( rtr - 1 ) ;
2019-03-10 03:34:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d " , rtr , isOK , dmin , dmax , davg , delta_time ) ;
2019-03-10 03:34:41 +08:00
dmin = davg - 2 ;
dmax = davg + 2 ;
LED_B_OFF ( ) ;
}
2019-03-09 15:59:13 +08:00
// -------------------------------------------------------------------------------------------------
2019-03-10 03:34:41 +08:00
LED_C_ON ( ) ;
// get crypted nonces for target sector
2019-03-10 07:00:59 +08:00
for ( i = 0 ; i < 2 & & ! isOK ; i + + ) { // look for exactly two different nonces
2019-03-10 03:34:41 +08:00
target_nt [ i ] = 0 ;
2019-03-10 07:00:59 +08:00
while ( target_nt [ i ] = = 0 ) { // continue until we have an unambiguous nonce
2019-03-10 03:34:41 +08:00
2019-12-14 19:45:07 +08:00
// Test if the action was cancelled
2019-12-30 20:25:15 +08:00
if ( BUTTON_PRESS ( ) | | data_available ( ) ) {
2020-09-02 18:16:11 +08:00
isOK = PM3_EOPABORTED ;
2019-12-14 19:45:07 +08:00
break ;
}
2019-03-10 03:34:41 +08:00
// prepare next select. No need to power down the card.
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Halt error " ) ;
2019-03-10 03:34:41 +08:00
continue ;
}
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Can't select card " ) ;
2019-03-10 03:34:41 +08:00
continue ;
} ;
auth1_time = 0 ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , & auth1_time ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth1 error " ) ;
2019-03-10 03:34:41 +08:00
continue ;
} ;
// nested authentication
auth2_time = auth1_time + delta_time ;
len = mifare_sendcmd_short ( pcs , AUTH_NESTED , 0x60 + ( targetKeyType & 0x01 ) , targetBlockNo , receivedAnswer , par , & auth2_time ) ;
if ( len ! = 4 ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth2 error len=%d " , len ) ;
2019-03-10 03:34:41 +08:00
continue ;
} ;
nt2 = bytes_to_num ( receivedAnswer , 4 ) ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x " , i + 1 , nt1 , nt2 , par [ 0 ] ) ;
2019-03-10 03:34:41 +08:00
// Parity validity check
for ( j = 0 ; j < 4 ; j + + ) {
2019-03-10 07:00:59 +08:00
par_array [ j ] = ( oddparity8 ( receivedAnswer [ j ] ) ! = ( ( par [ 0 ] > > ( 7 - j ) ) & 0x01 ) ) ;
2019-03-10 03:34:41 +08:00
}
ncount = 0 ;
nttest = prng_successor ( nt1 , dmin - 1 ) ;
for ( j = dmin ; j < dmax + 1 ; j + + ) {
nttest = prng_successor ( nttest , 1 ) ;
ks1 = nt2 ^ nttest ;
2019-03-10 07:00:59 +08:00
if ( valid_nonce ( nttest , nt2 , ks1 , par_array ) ) {
2019-03-10 03:34:41 +08:00
if ( ncount > 0 ) { // we are only interested in disambiguous nonces, try again
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Nonce#%d: dismissed (ambiguous), ntdist=%d " , i + 1 , j ) ;
2019-03-10 03:34:41 +08:00
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 ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Nonce#2: dismissed (= nonce#1), ntdist=%d " , j ) ;
2019-03-10 03:34:41 +08:00
break ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Nonce#%d: valid, ntdist=%d " , i + 1 , j ) ;
2019-03-10 03:34:41 +08:00
}
}
2021-08-22 05:02:27 +08:00
if ( target_nt [ i ] = = 0 & & j = = dmax + 1 & & g_dbglevel > = 3 ) Dbprintf ( " Nonce#%d: dismissed (all invalid) " , i + 1 ) ;
2019-03-10 03:34:41 +08:00
}
}
LED_C_OFF ( ) ;
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
2019-10-03 22:15:47 +08:00
struct p {
2019-10-13 06:48:26 +08:00
int16_t isOK ;
uint8_t block ;
uint8_t keytype ;
uint8_t cuid [ 4 ] ;
uint8_t nt_a [ 4 ] ;
uint8_t ks_a [ 4 ] ;
uint8_t nt_b [ 4 ] ;
uint8_t ks_b [ 4 ] ;
2019-10-03 22:15:47 +08:00
} PACKED payload ;
payload . isOK = isOK ;
payload . block = targetBlockNo ;
payload . keytype = targetKeyType ;
memcpy ( payload . cuid , & cuid , 4 ) ;
memcpy ( payload . nt_a , & target_nt [ 0 ] , 4 ) ;
memcpy ( payload . ks_a , & target_ks [ 0 ] , 4 ) ;
memcpy ( payload . nt_b , & target_nt [ 1 ] , 4 ) ;
memcpy ( payload . ks_b , & target_ks [ 1 ] , 4 ) ;
2019-03-10 03:34:41 +08:00
2019-10-13 06:48:26 +08:00
reply_ng ( CMD_HF_MIFARE_NESTED , PM3_SUCCESS , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
2020-01-14 23:00:31 +08:00
void MifareStaticNested ( uint8_t blockNo , uint8_t keyType , uint8_t targetBlockNo , uint8_t targetKeyType , uint8_t * key ) {
LEDsoff ( ) ;
uint64_t ui64Key = 0 ;
ui64Key = bytes_to_num ( key , 6 ) ;
uint16_t len ;
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 , nt1 , nt2 ;
2020-08-31 09:04:32 +08:00
uint32_t target_nt = 0 , target_ks = 0 ;
2020-01-14 23:00:31 +08:00
uint8_t par [ 1 ] = { 0x00 } ;
uint8_t receivedAnswer [ 10 ] = { 0x00 } ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
// free eventually allocated BigBuf memory
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
int16_t isOK = 0 ;
LED_C_ON ( ) ;
for ( uint8_t retry = 0 ; retry < 3 & & ( isOK = = 0 ) ; retry + + ) {
WDT_HIT ( ) ;
// prepare next select. No need to power down the card.
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Halt error " ) ;
2020-01-14 23:00:31 +08:00
retry - - ;
continue ;
}
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Can't select card " ) ;
2020-01-14 23:00:31 +08:00
retry - - ;
continue ;
} ;
2020-08-31 09:04:32 +08:00
// First authentication. Normal auth.
2020-01-14 23:00:31 +08:00
if ( mifare_classic_authex ( pcs , cuid , blockNo , keyType , ui64Key , AUTH_FIRST , & nt1 , NULL ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth1 error " ) ;
2020-01-14 23:00:31 +08:00
retry - - ;
continue ;
} ;
2020-01-16 02:25:29 +08:00
2020-01-14 23:00:31 +08:00
// second authentication. Nested auth
len = mifare_sendcmd_short ( pcs , AUTH_NESTED , 0x60 + ( targetKeyType & 0x01 ) , targetBlockNo , receivedAnswer , par , NULL ) ;
if ( len ! = 4 ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Nested: Auth2 error len=%d " , len ) ;
2020-01-14 23:00:31 +08:00
continue ;
} ;
nt2 = bytes_to_num ( receivedAnswer , 4 ) ;
2020-08-31 09:04:32 +08:00
target_nt = prng_successor ( nt1 , 160 ) ;
target_ks = nt2 ^ target_nt ;
2020-01-14 23:00:31 +08:00
isOK = 1 ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x " , nt1 , nt2 , par [ 0 ] , target_ks ) ;
2020-01-14 23:00:31 +08:00
}
LED_C_OFF ( ) ;
crypto1_deinit ( pcs ) ;
struct p {
int16_t isOK ;
uint8_t block ;
uint8_t keytype ;
uint8_t cuid [ 4 ] ;
uint8_t nt [ 4 ] ;
uint8_t ks [ 4 ] ;
} PACKED payload ;
payload . isOK = isOK ;
payload . block = targetBlockNo ;
payload . keytype = targetKeyType ;
memcpy ( payload . cuid , & cuid , 4 ) ;
memcpy ( payload . nt , & target_nt , 4 ) ;
memcpy ( payload . ks , & target_ks , 4 ) ;
LED_B_ON ( ) ;
reply_ng ( CMD_HF_MIFARE_STATIC_NESTED , PM3_SUCCESS , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
LED_B_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2020-01-16 02:25:29 +08:00
set_tracing ( false ) ;
2020-01-14 23:00:31 +08:00
}
2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// MIFARE check keys. key count up to 85.
//
//-----------------------------------------------------------------------------
2019-03-09 15:49:41 +08:00
typedef struct sector_t {
2019-03-10 03:34:41 +08:00
uint8_t keyA [ 6 ] ;
uint8_t keyB [ 6 ] ;
2019-03-09 15:49:41 +08:00
} sector_t ;
typedef struct chk_t {
2019-03-10 03:34:41 +08:00
uint64_t key ;
uint32_t cuid ;
uint8_t cl ;
uint8_t block ;
uint8_t keyType ;
uint8_t * uid ;
struct Crypto1State * pcs ;
2019-03-09 15:49:41 +08:00
} chk_t ;
// checks one key.
// fast select, tries 5 times to select
2019-03-09 15:59:13 +08:00
//
2019-03-09 15:49:41 +08:00
// return:
// 2 = failed to select.
// 1 = wrong key
// 0 = correct key
2020-05-10 22:59:38 +08:00
static uint8_t chkKey ( struct chk_t * c ) {
2019-03-10 03:34:41 +08:00
uint8_t i = 0 , res = 2 ;
2019-03-10 07:00:59 +08:00
while ( i < 5 ) {
2019-03-10 03:34:41 +08:00
// this part is from Piwi's faster nonce collecting part in Hardnested.
// assume: fast select
if ( ! iso14443a_fast_select_card ( c - > uid , c - > cl ) ) {
+ + i ;
continue ;
}
res = mifare_classic_authex ( c - > pcs , c - > cuid , c - > block , c - > keyType , c - > key , AUTH_FIRST , NULL , NULL ) ;
2020-01-25 03:12:34 +08:00
// CHK_TIMEOUT();
2019-03-10 03:34:41 +08:00
2019-09-14 23:44:58 +08:00
// if successful auth, send HALT
2019-03-10 03:34:41 +08:00
// if ( !res )
2019-03-10 07:00:59 +08:00
// mifare_classic_halt_ex(c->pcs);
2019-03-10 03:34:41 +08:00
break ;
}
return res ;
2019-03-09 15:49:41 +08:00
}
2020-05-10 22:59:38 +08:00
static uint8_t chkKey_readb ( struct chk_t * c , uint8_t * keyb ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
if ( ! iso14443a_fast_select_card ( c - > uid , c - > cl ) )
return 2 ;
2019-03-10 07:00:59 +08:00
if ( mifare_classic_authex ( c - > pcs , c - > cuid , c - > block , 0 , c - > key , AUTH_FIRST , NULL , NULL ) )
2019-03-10 03:34:41 +08:00
return 1 ;
uint8_t data [ 16 ] = { 0x00 } ;
uint8_t res = mifare_classic_readblock ( c - > pcs , c - > cuid , c - > block , data ) ;
// successful read
2019-03-10 07:00:59 +08:00
if ( ! res ) {
2019-03-10 03:34:41 +08:00
// data was something else than zeros.
2019-03-10 07:00:59 +08:00
if ( memcmp ( data + 10 , " \x00 \x00 \x00 \x00 \x00 \x00 " , 6 ) ! = 0 ) {
memcpy ( keyb , data + 10 , 6 ) ;
2019-03-10 03:34:41 +08:00
res = 0 ;
} else {
res = 3 ;
}
mifare_classic_halt_ex ( c - > pcs ) ;
}
return res ;
2019-03-09 15:49:41 +08:00
}
2022-01-06 22:40:11 +08:00
static void chkKey_scanA ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , const uint8_t * sectorcnt , uint8_t * foundkeys ) {
2019-03-10 03:34:41 +08:00
for ( uint8_t s = 0 ; s < * sectorcnt ; s + + ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// skip already found A keys
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] )
2019-03-10 03:34:41 +08:00
continue ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
c - > block = FirstBlockOfSector ( s ) ;
if ( chkKey ( c ) = = 0 ) {
2019-03-10 03:34:41 +08:00
num_to_bytes ( c - > key , 6 , k_sector [ s ] . keyA ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + * foundkeys ;
2019-03-09 15:59:13 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 3 ) Dbprintf ( " ChkKeys_fast: Scan A found (%d) " , c - > block ) ;
2019-03-10 03:34:41 +08:00
}
}
2019-03-09 15:49:41 +08:00
}
2022-01-06 22:40:11 +08:00
static void chkKey_scanB ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , const uint8_t * sectorcnt , uint8_t * foundkeys ) {
2019-03-10 03:34:41 +08:00
for ( uint8_t s = 0 ; s < * sectorcnt ; s + + ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// skip already found B keys
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) + 1 ] )
2019-03-10 03:34:41 +08:00
continue ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
c - > block = FirstBlockOfSector ( s ) ;
if ( chkKey ( c ) = = 0 ) {
2019-03-10 03:34:41 +08:00
num_to_bytes ( c - > key , 6 , k_sector [ s ] . keyB ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) + 1 ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + * foundkeys ;
2019-03-09 15:59:13 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 3 ) Dbprintf ( " ChkKeys_fast: Scan B found (%d) " , c - > block ) ;
2019-03-10 03:34:41 +08:00
}
}
2019-03-09 15:49:41 +08:00
}
// loop all A keys,
// when A is found but not B, try to read B.
2020-05-10 22:59:38 +08:00
static void chkKey_loopBonly ( struct chk_t * c , struct sector_t * k_sector , uint8_t * found , uint8_t * sectorcnt , uint8_t * foundkeys ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// read Block B, if A is found.
for ( uint8_t s = 0 ; s < * sectorcnt ; + + s ) {
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] & & found [ ( s * 2 ) + 1 ] )
2019-03-10 03:34:41 +08:00
continue ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
c - > block = ( FirstBlockOfSector ( s ) + NumBlocksPerSector ( s ) - 1 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// A but not B
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] & & ! found [ ( s * 2 ) + 1 ] ) {
2019-03-10 03:34:41 +08:00
c - > key = bytes_to_num ( k_sector [ s ] . keyA , 6 ) ;
uint8_t status = chkKey_readb ( c , k_sector [ s ] . keyB ) ;
2019-03-10 07:00:59 +08:00
if ( status = = 0 ) {
found [ ( s * 2 ) + 1 ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + * foundkeys ;
2019-03-09 15:49:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = 3 ) Dbprintf ( " ChkKeys_fast: Reading B found (%d) " , c - > block ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// try quick find all B?
// assume: keys comes in groups. Find one B, test against all B.
2019-03-10 07:00:59 +08:00
c - > key = bytes_to_num ( k_sector [ s ] . keyB , 6 ) ;
2019-03-10 03:34:41 +08:00
c - > keyType = 1 ;
chkKey_scanB ( c , k_sector , found , sectorcnt , foundkeys ) ;
}
}
}
2019-03-09 15:49:41 +08:00
}
// 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
2019-03-10 18:20:22 +08:00
void MifareChkKeys_fast ( uint32_t arg0 , uint32_t arg1 , uint32_t arg2 , uint8_t * datain ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// first call or
uint8_t sectorcnt = arg0 & 0xFF ; // 16;
uint8_t firstchunk = ( arg0 > > 8 ) & 0xF ;
uint8_t lastchunk = ( arg0 > > 12 ) & 0xF ;
uint8_t strategy = arg1 & 0xFF ;
uint8_t use_flashmem = ( arg1 > > 8 ) & 0xFF ;
uint16_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 ;
2019-03-09 15:49:41 +08:00
2021-08-22 05:02:27 +08:00
int oldbg = g_dbglevel ;
2019-12-30 23:27:51 +08:00
2019-03-09 15:59:13 +08:00
# ifdef WITH_FLASH
2019-03-10 07:00:59 +08:00
if ( use_flashmem ) {
2019-03-10 03:34:41 +08:00
BigBuf_free ( ) ;
uint16_t isok = 0 ;
uint8_t size [ 2 ] = { 0x00 , 0x00 } ;
isok = Flash_ReadData ( DEFAULT_MF_KEYS_OFFSET , size , 2 ) ;
2019-03-10 07:00:59 +08:00
if ( isok ! = 2 )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
keyCount = size [ 1 ] < < 8 | size [ 0 ] ;
2019-03-09 15:59:13 +08:00
2020-05-13 19:40:52 +08:00
if ( keyCount = = 0 )
2019-03-10 03:34:41 +08:00
goto OUT ;
2020-05-14 07:04:26 +08:00
2021-10-10 07:35:38 +08:00
// limit size of available for keys in bigbuff
2020-05-13 19:40:52 +08:00
// a key is 6bytes
2020-06-11 01:06:40 +08:00
uint16_t key_mem_available = MIN ( BigBuf_get_size ( ) , keyCount * 6 ) ;
2020-05-14 07:04:26 +08:00
2020-05-13 19:40:52 +08:00
keyCount = key_mem_available / 6 ;
datain = BigBuf_malloc ( key_mem_available ) ;
2019-03-10 07:00:59 +08:00
if ( datain = = NULL )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-09 15:49:41 +08:00
2020-05-13 19:40:52 +08:00
isok = Flash_ReadData ( DEFAULT_MF_KEYS_OFFSET + 2 , datain , key_mem_available ) ;
if ( isok ! = key_mem_available )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
}
2019-03-09 15:49:41 +08:00
# endif
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
if ( uid = = NULL | | firstchunk ) {
uid = BigBuf_malloc ( 10 ) ;
2019-03-10 07:00:59 +08:00
if ( uid = = NULL )
2019-03-10 03:34:41 +08:00
goto OUT ;
}
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
LEDsoff ( ) ;
LED_A_ON ( ) ;
2019-03-10 07:00:59 +08:00
if ( firstchunk ) {
2019-03-10 03:34:41 +08:00
clear_trace ( ) ;
set_tracing ( false ) ;
2019-03-10 07:00:59 +08:00
memset ( k_sector , 0x00 , 480 + 10 ) ;
2019-03-10 03:34:41 +08:00
memset ( found , 0x00 , sizeof ( found ) ) ;
foundkeys = 0 ;
iso14a_card_select_t card_info ;
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " ChkKeys_fast: Can't select card (ALL) " ) ;
2019-03-10 03:34:41 +08:00
goto OUT ;
}
switch ( card_info . uidlen ) {
2019-03-10 07:00:59 +08:00
case 4 :
cascade_levels = 1 ;
break ;
case 7 :
cascade_levels = 2 ;
break ;
case 10 :
cascade_levels = 3 ;
break ;
default :
break ;
2019-03-10 03:34:41 +08:00
}
CHK_TIMEOUT ( ) ;
}
2019-12-30 20:25:15 +08:00
// clear debug level. We are expecting lots of authentication failures...
2021-08-22 05:02:27 +08:00
g_dbglevel = DBG_NONE ;
2019-12-30 23:27:51 +08:00
2019-03-10 03:34:41 +08:00
// set check struct.
chk_data . uid = uid ;
chk_data . cuid = cuid ;
chk_data . cl = cascade_levels ;
chk_data . pcs = pcs ;
chk_data . block = 0 ;
// keychunk loop - depth first one sector.
2019-03-10 07:00:59 +08:00
if ( strategy = = 1 | | use_flashmem ) {
2019-03-10 03:34:41 +08:00
uint8_t newfound = foundkeys ;
uint16_t lastpos = 0 ;
uint16_t s_point = 0 ;
// Sector main loop
// keep track of how many sectors on card.
for ( uint8_t s = 0 ; s < sectorcnt ; + + s ) {
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] & & found [ ( s * 2 ) + 1 ] )
2019-03-10 03:34:41 +08:00
continue ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
for ( uint16_t i = s_point ; i < keyCount ; + + i ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Allow button press / usb cmd to interrupt device
2020-03-26 16:30:59 +08:00
if ( BUTTON_PRESS ( ) | | data_available ( ) ) {
2019-03-10 03:34:41 +08:00
goto OUT ;
}
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// found all keys?
2019-03-10 07:00:59 +08:00
if ( foundkeys = = allkeys )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
2019-03-10 07:00:59 +08:00
chk_data . block = FirstBlockOfSector ( s ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// new key
chk_data . key = bytes_to_num ( datain + i * 6 , 6 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
// skip already found A keys
2019-03-10 07:00:59 +08:00
if ( ! found [ ( s * 2 ) ] ) {
2019-03-10 03:34:41 +08:00
chk_data . keyType = 0 ;
2019-03-10 07:00:59 +08:00
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
2019-03-10 03:34:41 +08:00
memcpy ( k_sector [ s ] . keyA , datain + i * 6 , 6 ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + foundkeys ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
chkKey_scanA ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// read Block B, if A is found.
2019-03-10 07:00:59 +08:00
chkKey_loopBonly ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
chk_data . keyType = 1 ;
chkKey_scanB ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
chk_data . keyType = 0 ;
2019-03-10 07:00:59 +08:00
chk_data . block = FirstBlockOfSector ( s ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( use_flashmem ) {
if ( lastpos ! = i & & lastpos ! = 0 ) {
if ( i - lastpos < 0xF ) {
2019-03-10 03:34:41 +08:00
s_point = i & 0xFFF0 ;
}
} else {
lastpos = i ;
}
}
}
}
// skip already found B keys
2019-03-10 07:00:59 +08:00
if ( ! found [ ( s * 2 ) + 1 ] ) {
2019-03-10 03:34:41 +08:00
chk_data . keyType = 1 ;
2019-03-10 07:00:59 +08:00
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
2019-03-10 03:34:41 +08:00
memcpy ( k_sector [ s ] . keyB , datain + i * 6 , 6 ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) + 1 ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + foundkeys ;
chkKey_scanB ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-10 07:00:59 +08:00
if ( use_flashmem ) {
if ( lastpos ! = i & & lastpos ! = 0 ) {
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( i - lastpos < 0xF )
2019-03-10 03:34:41 +08:00
s_point = i & 0xFFF0 ;
} else {
lastpos = i ;
}
}
}
}
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] & & found [ ( s * 2 ) + 1 ] )
2019-03-10 03:34:41 +08:00
break ;
} // end keys test loop - depth first
// assume1. if no keys found in first sector, get next keychunk from client
2019-03-10 07:00:59 +08:00
if ( ! use_flashmem & & ( newfound - foundkeys = = 0 ) )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
} // end loop - sector
} // end strategy 1
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( foundkeys = = allkeys )
2019-03-10 03:34:41 +08:00
goto OUT ;
2019-03-10 07:00:59 +08:00
if ( strategy = = 2 | | use_flashmem ) {
2019-03-10 03:34:41 +08:00
// Keychunk loop
for ( uint16_t i = 0 ; i < keyCount ; i + + ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Allow button press / usb cmd to interrupt device
2020-03-26 16:30:59 +08:00
if ( BUTTON_PRESS ( ) | | data_available ( ) ) break ;
2019-03-10 03:34:41 +08:00
// found all keys?
2019-03-10 07:00:59 +08:00
if ( foundkeys = = allkeys )
2019-03-10 03:34:41 +08:00
goto OUT ;
WDT_HIT ( ) ;
// 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 ) {
2019-03-10 07:00:59 +08:00
if ( found [ ( s * 2 ) ] & & found [ ( s * 2 ) + 1 ] ) continue ;
2019-03-10 03:34:41 +08:00
// found all keys?
2019-03-10 07:00:59 +08:00
if ( foundkeys = = allkeys )
2019-03-10 03:34:41 +08:00
goto OUT ;
// assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector
2019-03-10 07:00:59 +08:00
chk_data . block = FirstBlockOfSector ( s ) ;
2019-03-10 03:34:41 +08:00
// skip already found A keys
2019-03-10 07:00:59 +08:00
if ( ! found [ ( s * 2 ) ] ) {
2019-03-10 03:34:41 +08:00
chk_data . keyType = 0 ;
2019-03-10 07:00:59 +08:00
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
2019-03-10 03:34:41 +08:00
memcpy ( k_sector [ s ] . keyA , datain + i * 6 , 6 ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + foundkeys ;
2019-03-10 07:00:59 +08:00
chkKey_scanA ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-10 03:34:41 +08:00
// read Block B, if A is found.
2019-03-10 07:00:59 +08:00
chkKey_loopBonly ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
chk_data . block = FirstBlockOfSector ( s ) ;
2019-03-10 03:34:41 +08:00
}
}
// skip already found B keys
2019-03-10 07:00:59 +08:00
if ( ! found [ ( s * 2 ) + 1 ] ) {
2019-03-10 03:34:41 +08:00
chk_data . keyType = 1 ;
2019-03-10 07:00:59 +08:00
status = chkKey ( & chk_data ) ;
if ( status = = 0 ) {
2019-03-10 03:34:41 +08:00
memcpy ( k_sector [ s ] . keyB , datain + i * 6 , 6 ) ;
2019-03-10 07:00:59 +08:00
found [ ( s * 2 ) + 1 ] = 1 ;
2019-03-10 03:34:41 +08:00
+ + foundkeys ;
chkKey_scanB ( & chk_data , k_sector , found , & sectorcnt , & foundkeys ) ;
}
}
} // end loop sectors
} // end loop keys
} // end loop strategy 2
2019-03-09 15:49:41 +08:00
OUT :
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
// All keys found, send to client, or last keychunk from client
2019-03-10 07:00:59 +08:00
if ( foundkeys = = allkeys | | lastchunk ) {
2019-03-10 03:34:41 +08:00
uint64_t foo = 0 ;
for ( uint8_t m = 0 ; m < 64 ; m + + ) {
foo | = ( ( uint64_t ) ( found [ m ] & 1 ) < < m ) ;
}
uint16_t bar = 0 ;
uint8_t j = 0 ;
2019-08-01 06:14:09 +08:00
for ( uint8_t m = 64 ; m < ARRAYLEN ( found ) ; m + + ) {
2019-03-10 03:34:41 +08:00
bar | = ( ( uint16_t ) ( found [ m ] & 1 ) < < j + + ) ;
}
2020-08-19 22:41:28 +08:00
uint8_t * tmp = BigBuf_malloc ( 480 + 10 ) ;
2019-03-10 07:00:59 +08:00
memcpy ( tmp , k_sector , sectorcnt * sizeof ( sector_t ) ) ;
num_to_bytes ( foo , 8 , tmp + 480 ) ;
2019-03-10 03:34:41 +08:00
tmp [ 488 ] = bar & 0xFF ;
tmp [ 489 ] = bar > > 8 & 0xFF ;
2019-04-18 18:43:35 +08:00
reply_old ( CMD_ACK , foundkeys , 0 , 0 , tmp , 480 + 10 ) ;
2019-03-10 03:34:41 +08:00
set_tracing ( false ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2019-08-30 16:45:52 +08:00
// special trick ecfill
if ( use_flashmem & & foundkeys = = allkeys ) {
uint8_t block [ 16 ] = { 0 } ;
for ( int i = 0 ; i < sectorcnt ; i + + ) {
uint8_t blockno ;
if ( i < 32 ) {
blockno = ( i * 4 ) ^ 0x3 ;
} else {
blockno = ( 32 * 4 + ( i - 32 ) * 16 ) ^ 0xF ;
}
// get ST
emlGetMem ( block , blockno , 1 ) ;
memcpy ( block , k_sector [ i ] . keyA , 6 ) ;
memcpy ( block + 10 , k_sector [ i ] . keyB , 6 ) ;
emlSetMem_xt ( block , blockno , 1 , sizeof ( block ) ) ;
}
2019-12-30 20:25:15 +08:00
2019-08-30 16:45:52 +08:00
MifareECardLoad ( sectorcnt , 0 ) ;
MifareECardLoad ( sectorcnt , 1 ) ;
}
2019-03-10 03:34:41 +08:00
} else {
// partial/none keys found
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , foundkeys , 0 , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
}
2019-12-30 20:25:15 +08:00
2021-08-22 05:02:27 +08:00
g_dbglevel = oldbg ;
2019-03-09 15:49:41 +08:00
}
2020-08-31 09:04:32 +08:00
void MifareChkKeys ( uint8_t * datain , uint8_t reserved_mem ) {
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
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 ;
2019-05-01 18:19:51 +08:00
uint8_t cascade_levels = 0 ;
struct {
uint8_t key [ 6 ] ;
bool found ;
} PACKED keyresult ;
keyresult . found = false ;
2020-05-13 19:40:52 +08:00
bool have_uid = false ;
uint8_t keyType = datain [ 0 ] ;
uint8_t blockNo = datain [ 1 ] ;
bool clearTrace = datain [ 2 ] ;
uint16_t key_count = ( datain [ 3 ] < < 8 ) | datain [ 4 ] ;
2020-08-31 09:04:32 +08:00
uint16_t key_mem_available ;
if ( reserved_mem )
2020-09-07 16:35:09 +08:00
key_mem_available = key_count * 6 ;
2020-08-31 09:04:32 +08:00
else
2020-09-07 16:35:09 +08:00
key_mem_available = MIN ( ( PM3_CMD_DATA_SIZE - 5 ) , key_count * 6 ) ;
2020-05-13 19:40:52 +08:00
key_count = key_mem_available / 6 ;
2020-05-14 07:04:26 +08:00
2020-01-22 20:11:20 +08:00
datain + = 5 ;
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
if ( clearTrace )
clear_trace ( ) ;
2021-08-22 05:02:27 +08:00
int oldbg = g_dbglevel ;
g_dbglevel = DBG_NONE ;
2019-12-30 20:25:15 +08:00
set_tracing ( false ) ;
2019-03-10 03:34:41 +08:00
2020-05-13 19:40:52 +08:00
for ( i = 0 ; i < key_count ; i + + ) {
2019-03-10 03:34:41 +08:00
// Iceman: use piwi's faster nonce collecting part in hardnested.
if ( ! have_uid ) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info ;
if ( ! iso14443a_select_card ( uid , & card_info , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " ChkKeys: Can't select card (ALL) " ) ;
2019-03-10 03:34:41 +08:00
- - i ; // try same key once again
continue ;
}
switch ( card_info . uidlen ) {
2019-03-10 07:00:59 +08:00
case 4 :
cascade_levels = 1 ;
break ;
case 7 :
cascade_levels = 2 ;
break ;
case 10 :
cascade_levels = 3 ;
break ;
default :
break ;
2019-03-10 03:34:41 +08:00
}
have_uid = true ;
} else { // no need for anticollision. We can directly select the card
if ( ! iso14443a_select_card ( uid , NULL , NULL , false , cascade_levels , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " ChkKeys: Can't select card (UID) " ) ;
2019-03-10 03:34:41 +08:00
- - i ; // try same key once again
continue ;
}
}
key = bytes_to_num ( datain + i * 6 , 6 ) ;
res = mifare_classic_auth ( pcs , cuid , blockNo , keyType , key , AUTH_FIRST ) ;
2020-01-25 03:12:34 +08:00
// CHK_TIMEOUT();
2019-03-10 03:34:41 +08:00
if ( res )
continue ;
2019-12-30 20:25:15 +08:00
2019-05-01 18:19:51 +08:00
memcpy ( keyresult . key , datain + i * 6 , 6 ) ;
keyresult . found = true ;
2019-03-10 03:34:41 +08:00
break ;
}
LED_B_ON ( ) ;
2019-03-09 15:49:41 +08:00
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_CHKKEYS , PM3_SUCCESS , ( uint8_t * ) & keyresult , sizeof ( keyresult ) ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
set_tracing ( false ) ;
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-12-30 20:25:15 +08:00
2021-08-22 05:02:27 +08:00
g_dbglevel = oldbg ;
2019-03-09 15:49:41 +08:00
}
2020-01-22 20:11:20 +08:00
void MifareChkKeys_file ( uint8_t * fn ) {
2020-01-23 04:14:05 +08:00
2020-01-25 03:12:34 +08:00
# ifdef WITH_FLASH
2020-08-31 09:04:32 +08:00
BigBuf_free ( ) ;
2020-01-22 20:11:20 +08:00
SpinOff ( 0 ) ;
int changed = rdv40_spiffs_lazy_mount ( ) ;
uint32_t size = size_in_spiffs ( ( char * ) fn ) ;
uint8_t * mem = BigBuf_malloc ( size ) ;
2020-01-25 03:12:34 +08:00
2020-01-22 20:11:20 +08:00
rdv40_spiffs_read_as_filetype ( ( char * ) fn , mem , size , RDV40_SPIFFS_SAFETY_SAFE ) ;
if ( changed ) {
rdv40_spiffs_lazy_unmount ( ) ;
}
SpinOff ( 0 ) ;
2020-08-31 09:04:32 +08:00
MifareChkKeys ( mem , true ) ;
2020-01-22 20:11:20 +08:00
BigBuf_free ( ) ;
2020-01-23 04:14:05 +08:00
# endif
2020-01-22 20:11:20 +08:00
}
2020-03-09 18:02:26 +08:00
//-----------------------------------------------------------------------------
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
//-----------------------------------------------------------------------------
void MifarePersonalizeUID ( uint8_t keyType , uint8_t perso_option , uint64_t key ) {
uint16_t isOK = PM3_EUNDEF ;
2020-03-10 00:11:11 +08:00
uint8_t uid [ 10 ] ;
uint32_t cuid ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2020-03-09 18:02:26 +08:00
2020-03-10 00:11:11 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2020-03-09 18:02:26 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
2020-03-10 00:11:11 +08:00
LED_A_ON ( ) ;
while ( true ) {
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2020-03-10 00:11:11 +08:00
break ;
}
uint8_t block_number = 0 ;
if ( mifare_classic_auth ( pcs , cuid , block_number , keyType , key , AUTH_FIRST ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Auth error " ) ;
2020-03-10 00:11:11 +08:00
break ;
}
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] ;
int len = mifare_sendcmd_short ( pcs , true , MIFARE_EV1_PERSONAL_UID , perso_option , receivedAnswer , receivedAnswerPar , NULL ) ;
if ( len ! = 1 | | receivedAnswer [ 0 ] ! = CARD_ACK ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Cmd Error: %02x " , receivedAnswer [ 0 ] ) ;
2020-05-12 16:27:54 +08:00
break ;
2020-03-10 00:11:11 +08:00
}
2020-03-09 18:02:26 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2020-03-09 18:02:26 +08:00
break ;
}
2020-03-10 00:11:11 +08:00
isOK = PM3_SUCCESS ;
break ;
}
2020-03-09 18:02:26 +08:00
2020-03-10 00:11:11 +08:00
crypto1_deinit ( pcs ) ;
2020-03-09 18:02:26 +08:00
LED_B_ON ( ) ;
reply_ng ( CMD_HF_MIFARE_PERSONALIZE_UID , isOK , NULL , 0 ) ;
LED_B_OFF ( ) ;
2020-03-10 00:11:11 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2020-03-09 18:02:26 +08:00
}
2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
// Work with emulator memory
2019-03-09 15:59:13 +08:00
//
2019-03-09 15:49:41 +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.
//-----------------------------------------------------------------------------
2019-05-13 18:30:27 +08:00
void MifareEMemClr ( void ) {
2019-03-10 03:34:41 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2019-06-08 03:40:33 +08:00
emlClearMem ( ) ;
2019-03-09 15:49:41 +08:00
}
2019-05-27 19:46:27 +08:00
void MifareEMemSet ( uint8_t blockno , uint8_t blockcnt , uint8_t blockwidth , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2019-05-27 19:46:27 +08:00
if ( blockwidth = = 0 )
blockwidth = 16 ; // backwards compat... default bytewidth
2019-06-08 03:40:33 +08:00
2019-05-27 19:46:27 +08:00
emlSetMem_xt ( datain , blockno , blockcnt , blockwidth ) ; // data, block num, blocks count, block byte width
2019-03-09 15:49:41 +08:00
}
2019-05-27 19:46:27 +08:00
void MifareEMemGet ( uint8_t blockno , uint8_t blockcnt ) {
2019-03-10 03:34:41 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2019-06-08 03:40:33 +08:00
//
2019-05-27 19:46:27 +08:00
size_t size = blockcnt * 16 ;
2019-06-08 03:40:33 +08:00
if ( size > PM3_CMD_DATA_SIZE ) {
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_EML_MEMGET , PM3_EMALLOC , NULL , 0 ) ;
2019-05-27 19:46:27 +08:00
return ;
}
2019-06-08 03:40:33 +08:00
2019-05-27 19:46:27 +08:00
uint8_t * buf = BigBuf_malloc ( size ) ;
2019-06-08 03:40:33 +08:00
2019-05-27 19:46:27 +08:00
emlGetMem ( buf , blockno , blockcnt ) ; // data, block num, blocks count (max 4)
2019-03-09 15:49:41 +08:00
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_EML_MEMGET , PM3_SUCCESS , buf , size ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
2019-05-27 19:46:27 +08:00
BigBuf_free_keep_EM ( ) ;
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
// Load a card into the emulator memory
2019-03-09 15:59:13 +08:00
//
2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
2019-12-31 04:31:56 +08:00
int MifareECardLoadExt ( uint8_t sectorcnt , uint8_t keytype ) {
int retval = MifareECardLoad ( sectorcnt , keytype ) ;
2019-08-30 16:45:52 +08:00
reply_ng ( CMD_HF_MIFARE_EML_LOAD , retval , NULL , 0 ) ;
return retval ;
2019-08-29 03:23:31 +08:00
}
2019-12-31 04:31:56 +08:00
int MifareECardLoad ( uint8_t sectorcnt , uint8_t keytype ) {
2019-08-29 03:23:31 +08:00
2019-04-10 02:39:38 +08:00
uint32_t cuid = 0 ;
2019-03-10 03:34:41 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
// variables
2019-03-21 22:19:18 +08:00
uint8_t dataoutbuf [ 16 ] = { 0x00 } ;
uint8_t dataoutbuf2 [ 16 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
LED_A_ON ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
2020-05-21 00:30:41 +08:00
int retval = PM3_SUCCESS ;
2019-03-10 03:34:41 +08:00
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2019-08-29 03:23:31 +08:00
retval = PM3_ESOFT ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-08-30 16:45:52 +08:00
goto out ;
2019-03-10 03:34:41 +08:00
}
2019-12-31 04:19:51 +08:00
for ( uint8_t sectorNo = 0 ; sectorNo < sectorcnt ; sectorNo + + ) {
2019-12-31 04:31:56 +08:00
uint64_t ui64Key = emlGetKey ( sectorNo , keytype ) ;
2019-03-10 07:00:59 +08:00
if ( sectorNo = = 0 ) {
2019-12-31 04:31:56 +08:00
if ( mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keytype , ui64Key , AUTH_FIRST ) ) {
2020-09-18 18:07:34 +08:00
retval = PM3_EPARTIAL ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " Sector[%2d]. Auth error " , sectorNo ) ;
2020-09-18 18:07:34 +08:00
continue ;
2019-03-10 03:34:41 +08:00
}
} else {
2019-12-31 04:31:56 +08:00
if ( mifare_classic_auth ( pcs , cuid , FirstBlockOfSector ( sectorNo ) , keytype , ui64Key , AUTH_NESTED ) ) {
2020-09-18 18:07:34 +08:00
retval = PM3_EPARTIAL ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " Sector[%2d]. Auth nested error " , sectorNo ) ;
2020-09-18 18:07:34 +08:00
continue ;
2019-03-10 03:34:41 +08:00
}
}
2019-08-29 03:23:31 +08:00
for ( uint8_t blockNo = 0 ; blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
if ( mifare_classic_readblock ( pcs , cuid , FirstBlockOfSector ( sectorNo ) + blockNo , dataoutbuf ) ) {
2020-09-03 16:31:50 +08:00
retval = PM3_EPARTIAL ;
2020-09-07 16:35:09 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " Error reading sector %2d block %2d " , sectorNo , blockNo ) ;
2020-09-03 16:31:50 +08:00
continue ;
2019-03-10 03:34:41 +08:00
}
2020-09-03 16:31:50 +08:00
2020-09-05 14:32:26 +08:00
if ( memcmp ( dataoutbuf , " \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 " , 16 ) = = 0 ) {
continue ;
}
2019-08-30 16:45:52 +08:00
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 ) ;
2020-08-19 22:41:28 +08:00
memcpy ( dataoutbuf2 + 6 , dataoutbuf + 6 , 4 ) ;
2019-08-30 16:45:52 +08:00
emlSetMem ( dataoutbuf2 , FirstBlockOfSector ( sectorNo ) + blockNo , 1 ) ;
2019-03-10 03:34:41 +08:00
}
}
2019-08-30 16:45:52 +08:00
}
2019-03-10 03:34:41 +08:00
2020-05-21 00:30:41 +08:00
int res = mifare_classic_halt ( pcs , cuid ) ;
( void ) res ;
2019-03-10 03:34:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) DbpString ( " Emulator fill sectors finished " ) ;
2019-03-10 03:34:41 +08:00
2019-08-29 03:23:31 +08:00
out :
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-08-29 03:23:31 +08:00
return retval ;
2019-03-09 15:49:41 +08:00
}
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
2019-03-09 15:59:13 +08:00
//
2019-03-09 15:49:41 +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.
//-----------------------------------------------------------------------------
// magic uid card generation 1 commands
2020-05-19 23:25:50 +08:00
static uint8_t wupC1 [ ] = { MIFARE_MAGICWUPC1 } ;
static uint8_t wupC2 [ ] = { MIFARE_MAGICWUPC2 } ;
static uint8_t wipeC [ ] = { MIFARE_MAGICWIPEC } ;
2019-03-09 15:59:13 +08:00
2019-03-10 18:20:22 +08:00
void MifareCSetBlock ( uint32_t arg0 , uint32_t arg1 , uint8_t * datain ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// params
uint8_t workFlags = arg0 ;
uint8_t blockNo = arg1 ;
// detect 1a/1b
bool is1b = false ;
// variables
bool isOK = false ; //assume we will get an error
uint8_t errormsg = 0x00 ;
uint8_t uid [ 10 ] = { 0x00 } ;
uint8_t data [ 18 ] = { 0x00 } ;
uint32_t cuid = 0 ;
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] = { 0x00 } ;
if ( workFlags & MAGIC_INIT ) {
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
}
//loop doesn't loop just breaks out if error
while ( true ) {
// read UID and return to client with write
if ( workFlags & MAGIC_UID ) {
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
errormsg = MAGIC_UID ;
2020-11-16 01:14:08 +08:00
mifare_classic_halt_ex ( NULL ) ;
break ;
2019-03-10 03:34:41 +08:00
}
mifare_classic_halt_ex ( NULL ) ;
}
// wipe tag, fill it with zeros
2019-03-10 07:00:59 +08:00
if ( workFlags & MAGIC_WIPE ) {
2019-03-10 03:34:41 +08:00
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = MAGIC_WIPE ;
break ;
}
2020-09-07 16:35:09 +08:00
uint32_t old_timeout = iso14a_get_timeout ( ) ;
// 2000 ms timeout
// 13560000 / 1000 / (8 * 16) * timeout
iso14a_set_timeout ( 21190 ) ;
2019-03-10 03:34:41 +08:00
ReaderTransmit ( wipeC , sizeof ( wipeC ) , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " wipeC error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = MAGIC_WIPE ;
break ;
}
2020-09-07 16:35:09 +08:00
iso14a_set_timeout ( old_timeout ) ;
2019-03-10 03:34:41 +08:00
mifare_classic_halt_ex ( NULL ) ;
}
// write block
if ( workFlags & MAGIC_WUPC ) {
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = MAGIC_WUPC ;
break ;
}
2019-03-10 07:00:59 +08:00
if ( ! is1b ) {
2019-03-10 03:34:41 +08:00
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Assuming Magic Gen 1B tag. [wupC2 failed] " ) ;
2019-03-10 03:34:41 +08:00
is1b = true ;
continue ;
}
}
}
2019-12-27 06:41:30 +08:00
if ( ( mifare_sendcmd_short ( NULL , CRYPT_NONE , ISO14443A_CMD_WRITEBLOCK , blockNo , receivedAnswer , receivedAnswerPar , NULL ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " write block send command error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = 4 ;
break ;
}
memcpy ( data , datain , 16 ) ;
AddCrc14A ( data , 16 ) ;
ReaderTransmit ( data , sizeof ( data ) , NULL ) ;
if ( ( ReaderReceive ( receivedAnswer , receivedAnswerPar ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " write block send data error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = 0 ;
break ;
}
if ( workFlags & MAGIC_HALT )
mifare_classic_halt_ex ( NULL ) ;
isOK = true ;
break ;
} // end while
2019-03-10 07:00:59 +08:00
if ( isOK )
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , 0 , 0 , uid , sizeof ( uid ) ) ;
2019-03-10 03:34:41 +08:00
else
OnErrorMagic ( errormsg ) ;
if ( workFlags & MAGIC_OFF )
OnSuccessMagic ( ) ;
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void MifareCGetBlock ( uint32_t arg0 , uint32_t arg1 , uint8_t * datain ) {
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
uint8_t workFlags = arg0 ;
uint8_t blockNo = arg1 ;
uint8_t errormsg = 0x00 ;
bool isOK = false ; //assume we will get an error
// detect 1a/1b
bool is1b = false ;
// variables
uint8_t data [ MAX_MIFARE_FRAME_SIZE ] ;
uint8_t receivedAnswer [ MAX_MIFARE_FRAME_SIZE ] = { 0x00 } ;
uint8_t receivedAnswerPar [ MAX_MIFARE_PARITY_SIZE ] = { 0x00 } ;
memset ( data , 0x00 , sizeof ( data ) ) ;
if ( workFlags & MAGIC_INIT ) {
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
}
//loop doesn't loop just breaks out if error or done
while ( true ) {
if ( workFlags & MAGIC_WUPC ) {
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " wupC1 error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = MAGIC_WUPC ;
break ;
}
2019-03-10 07:00:59 +08:00
if ( ! is1b ) {
2019-03-10 03:34:41 +08:00
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
2019-03-10 07:00:59 +08:00
if ( ! ReaderReceive ( receivedAnswer , receivedAnswerPar ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_INFO ) Dbprintf ( " Assuming Magic Gen 1B tag. [wupC2 failed] " ) ;
2019-03-10 03:34:41 +08:00
is1b = true ;
continue ;
}
}
}
// read block
2019-12-27 06:41:30 +08:00
if ( ( mifare_sendcmd_short ( NULL , CRYPT_NONE , ISO14443A_CMD_READBLOCK , blockNo , receivedAnswer , receivedAnswerPar , NULL ) ! = 18 ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " read block send command error " ) ;
2019-03-10 03:34:41 +08:00
errormsg = 0 ;
break ;
}
memcpy ( data , receivedAnswer , sizeof ( data ) ) ;
// send HALT
if ( workFlags & MAGIC_HALT )
mifare_classic_halt_ex ( NULL ) ;
isOK = true ;
break ;
}
// if MAGIC_DATAIN, the data stays on device side.
if ( workFlags & MAGIC_DATAIN ) {
if ( isOK )
memcpy ( datain , data , sizeof ( data ) ) ;
} else {
if ( isOK )
2019-04-18 18:43:35 +08:00
reply_old ( CMD_ACK , 1 , 0 , 0 , data , sizeof ( data ) ) ;
2019-03-10 03:34:41 +08:00
else
OnErrorMagic ( errormsg ) ;
}
if ( workFlags & MAGIC_OFF )
OnSuccessMagic ( ) ;
2019-03-09 15:49:41 +08:00
}
2020-09-23 18:25:30 +08:00
void MifareCIdent ( bool is_mfc ) {
2019-03-10 03:34:41 +08:00
// variables
uint8_t isGen = 0 ;
uint8_t rec [ 1 ] = { 0x00 } ;
uint8_t recpar [ 1 ] = { 0x00 } ;
2019-03-21 19:53:05 +08:00
uint8_t rats [ 4 ] = { ISO14443A_CMD_RATS , 0x80 , 0x31 , 0x73 } ;
2020-09-23 18:25:30 +08:00
uint8_t rdblf0 [ 4 ] = { ISO14443A_CMD_READBLOCK , 0xF0 , 0x8D , 0x5f } ;
uint8_t rdbl00 [ 4 ] = { ISO14443A_CMD_READBLOCK , 0x00 , 0x02 , 0xa8 } ;
2019-03-21 19:53:05 +08:00
uint8_t * par = BigBuf_malloc ( MAX_PARITY_SIZE ) ;
2019-05-01 03:10:11 +08:00
uint8_t * buf = BigBuf_malloc ( PM3_CMD_DATA_SIZE ) ;
2019-03-21 19:53:05 +08:00
uint8_t * uid = BigBuf_malloc ( 10 ) ;
2020-10-29 19:26:43 +08:00
memset ( par , 0x00 , MAX_PARITY_SIZE ) ;
memset ( buf , 0x00 , PM3_CMD_DATA_SIZE ) ;
memset ( uid , 0x00 , 10 ) ;
2019-03-21 19:53:05 +08:00
uint32_t cuid = 0 ;
2019-05-15 19:03:19 +08:00
uint8_t data [ 1 ] = { 0x00 } ;
2019-03-28 21:19:41 +08:00
2019-03-10 03:34:41 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
// Generation 1 test
ReaderTransmitBitsPar ( wupC1 , 7 , NULL , NULL ) ;
2019-09-22 05:25:21 +08:00
if ( ReaderReceive ( rec , recpar ) & & ( rec [ 0 ] = = 0x0a ) ) {
2019-09-13 22:25:33 +08:00
ReaderTransmit ( wupC2 , sizeof ( wupC2 ) , NULL ) ;
if ( ! ReaderReceive ( rec , recpar ) | | ( rec [ 0 ] ! = 0x0a ) ) {
2019-09-22 05:50:32 +08:00
isGen = MAGIC_GEN_1B ;
2019-09-13 22:25:33 +08:00
goto OUT ;
} ;
2019-09-22 05:50:32 +08:00
isGen = MAGIC_GEN_1A ;
2019-09-13 22:25:33 +08:00
goto OUT ;
}
2019-03-09 15:49:41 +08:00
2019-03-21 19:53:05 +08:00
// reset card
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
2019-10-04 20:21:04 +08:00
SpinDelay ( 40 ) ;
2019-03-21 19:53:05 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2019-03-28 21:19:41 +08:00
2019-03-21 19:53:05 +08:00
int res = iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ;
2019-03-28 21:19:41 +08:00
if ( res = = 2 ) {
2019-08-27 04:28:39 +08:00
if ( cuid = = 0xAA55C396 ) {
2019-09-22 05:50:32 +08:00
isGen = MAGIC_GEN_UNFUSED ;
2019-08-27 04:28:39 +08:00
goto OUT ;
2019-08-20 20:53:52 +08:00
}
2019-03-28 21:19:41 +08:00
ReaderTransmit ( rats , sizeof ( rats ) , NULL ) ;
2019-03-21 19:53:05 +08:00
res = ReaderReceive ( buf , par ) ;
2020-11-02 08:46:47 +08:00
if ( res ) {
2020-10-29 19:26:43 +08:00
// test for some MFC gen2
if ( memcmp ( buf , " \x09 \x78 \x00 \x91 \x02 \xDA \xBC \x19 \x10 \xF0 \x05 " , 11 ) = = 0 ) {
// super card ident
uint8_t super [ ] = { 0x0A , 0x00 , 0x00 , 0xA6 , 0xB0 , 0x00 , 0x10 , 0x14 , 0x1D } ;
ReaderTransmit ( super , sizeof ( super ) , NULL ) ;
res = ReaderReceive ( buf , par ) ;
if ( res = = 22 ) {
isGen = MAGIC_SUPER ;
goto OUT ;
}
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for some MFC 7b gen2
if ( memcmp ( buf , " \x0D \x78 \x00 \x71 \x02 \x88 \x49 \xA1 \x30 \x20 \x15 \x06 \x08 \x56 \x3D " , 15 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for Ultralight magic gen2
if ( memcmp ( buf , " \x0A \x78 \x00 \x81 \x02 \xDB \xA0 \xC1 \x19 \x40 \x2A \xB5 " , 12 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for Ultralight EV1 magic gen2
if ( memcmp ( buf , " \x85 \x00 \x00 \xA0 \x00 \x00 \x0A \xC3 \x00 \x04 \x03 \x01 \x01 \x00 \x0B \x03 \x41 \xDF " , 18 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for some other Ultralight EV1 magic gen2
if ( memcmp ( buf , " \x85 \x00 \x00 \xA0 \x0A \x00 \x0A \xC3 \x00 \x04 \x03 \x01 \x01 \x00 \x0B \x03 \x16 \xD7 " , 18 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for some other Ultralight magic gen2
if ( memcmp ( buf , " \x85 \x00 \x00 \xA0 \x0A \x00 \x0A \xB0 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x18 \x4D " , 18 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
goto OUT ;
}
// test for NTAG213 magic gen2
if ( memcmp ( buf , " \x85 \x00 \x00 \xA0 \x00 \x00 \x0A \xA5 \x00 \x04 \x04 \x02 \x01 \x00 \x0F \x03 \x79 \x0C " , 18 ) = = 0 ) {
isGen = MAGIC_GEN_2 ;
2020-09-12 06:31:17 +08:00
goto OUT ;
2020-09-10 07:34:29 +08:00
}
2020-09-09 08:01:36 +08:00
}
2020-09-12 06:31:17 +08:00
2020-10-29 17:53:34 +08:00
if ( is_mfc = = false ) {
2020-09-23 18:25:30 +08:00
// magic ntag test
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
SpinDelay ( 40 ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
res = iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ;
if ( res = = 2 ) {
ReaderTransmit ( rdblf0 , sizeof ( rdblf0 ) , NULL ) ;
res = ReaderReceive ( buf , par ) ;
if ( res = = 18 ) {
isGen = MAGIC_NTAG21X ;
}
2020-09-11 02:40:12 +08:00
}
2020-10-29 17:53:34 +08:00
} else {
2020-09-23 18:25:30 +08:00
// magic MFC Gen3 test
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
SpinDelay ( 40 ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
res = iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ;
if ( res = = 2 ) {
ReaderTransmit ( rdbl00 , sizeof ( rdbl00 ) , NULL ) ;
res = ReaderReceive ( buf , par ) ;
if ( res = = 18 ) {
isGen = MAGIC_GEN_3 ;
}
2020-09-12 00:17:58 +08:00
}
}
2019-03-21 19:53:05 +08:00
} ;
2019-03-28 21:19:41 +08:00
2019-03-10 07:00:59 +08:00
OUT :
2019-06-08 03:40:33 +08:00
2019-05-15 19:03:19 +08:00
data [ 0 ] = isGen ;
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_CIDENT , PM3_SUCCESS , data , sizeof ( data ) ) ;
2019-03-10 03:34:41 +08:00
// turns off
OnSuccessMagic ( ) ;
2019-03-21 19:53:05 +08:00
BigBuf_free ( ) ;
2019-03-09 15:49:41 +08:00
}
2020-05-10 22:59:38 +08:00
void MifareHasStaticNonce ( void ) {
2019-12-23 22:23:04 +08:00
// variables
2020-09-11 22:15:58 +08:00
int retval = PM3_SUCCESS ;
uint32_t nt = 0 ;
2019-12-23 22:23:04 +08:00
uint8_t * uid = BigBuf_malloc ( 10 ) ;
2020-11-02 14:50:07 +08:00
memset ( uid , 0x00 , 10 ) ;
2020-09-11 22:15:58 +08:00
uint8_t data [ 1 ] = { NONCE_FAIL } ;
2019-12-23 22:23:04 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2020-09-12 06:31:17 +08:00
2019-12-23 22:23:04 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
2020-09-11 22:15:58 +08:00
uint8_t counter = 0 ;
for ( uint8_t i = 0 ; i < 3 ; i + + ) {
iso14a_card_select_t card_info ;
2019-12-23 22:23:04 +08:00
if ( ! iso14443a_select_card ( uid , & card_info , NULL , true , 0 , true ) ) {
retval = PM3_ESOFT ;
goto OUT ;
}
2020-11-02 14:50:07 +08:00
uint8_t rec [ 4 ] = { 0x00 } ;
2020-09-11 22:15:58 +08:00
uint8_t recpar [ 1 ] = { 0x00 } ;
2020-01-14 23:00:31 +08:00
// Transmit MIFARE_CLASSIC_AUTH 0x60, block 0
2020-09-11 22:15:58 +08:00
int len = mifare_sendcmd_short ( pcs , false , MIFARE_AUTH_KEYA , 0 , rec , recpar , NULL ) ;
2019-12-23 22:23:04 +08:00
if ( len ! = 4 ) {
retval = PM3_ESOFT ;
goto OUT ;
}
// Save the tag nonce (nt)
if ( nt = = bytes_to_num ( rec , 4 ) ) {
2020-09-11 22:15:58 +08:00
counter + + ;
2019-12-23 22:23:04 +08:00
}
nt = bytes_to_num ( rec , 4 ) ;
2020-09-11 20:09:38 +08:00
// some cards with static nonce need to be reset before next query
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2020-02-25 03:39:12 +08:00
CHK_TIMEOUT ( ) ;
2020-11-07 08:32:43 +08:00
2020-11-02 14:50:07 +08:00
memset ( rec , 0x00 , sizeof ( rec ) ) ;
2019-12-23 22:23:04 +08:00
}
2020-09-11 22:15:58 +08:00
if ( counter ) {
Dbprintf ( " %u static nonce %08x " , data [ 0 ] , nt ) ;
data [ 0 ] = NONCE_STATIC ;
} else {
data [ 0 ] = NONCE_NORMAL ;
}
2019-12-23 22:23:04 +08:00
OUT :
reply_ng ( CMD_HF_MIFARE_STATIC_NONCE , retval , data , sizeof ( data ) ) ;
// turns off
OnSuccessMagic ( ) ;
BigBuf_free ( ) ;
crypto1_deinit ( pcs ) ;
}
2020-05-10 22:59:38 +08:00
void OnSuccessMagic ( void ) {
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void OnErrorMagic ( uint8_t reason ) {
2019-03-10 03:34:41 +08:00
// ACK, ISOK, reason,0,0,0
2019-05-15 19:47:46 +08:00
reply_mix ( CMD_ACK , 0 , reason , 0 , 0 , 0 ) ;
2019-03-10 03:34:41 +08:00
OnSuccessMagic ( ) ;
2019-03-09 15:49:41 +08:00
}
2020-09-06 03:32:11 +08:00
int DoGen3Cmd ( uint8_t * cmd , uint8_t cmd_len ) {
int retval = PM3_SUCCESS ;
uint8_t * par = BigBuf_malloc ( MAX_PARITY_SIZE ) ;
uint8_t * buf = BigBuf_malloc ( PM3_CMD_DATA_SIZE ) ;
LED_B_ON ( ) ;
uint32_t save_iso14a_timeout = iso14a_get_timeout ( ) ;
iso14a_set_timeout ( 13560000 / 1000 / ( 8 * 16 ) * 2000 ) ; // 2 seconds timeout
ReaderTransmit ( cmd , cmd_len , NULL ) ;
int res = ReaderReceive ( buf , par ) ;
2020-09-09 04:01:39 +08:00
if ( res = = 4 & & memcmp ( buf , " \x90 \x00 \xfd \x07 " , 4 ) = = 0 ) {
2020-09-06 03:32:11 +08:00
// timeout for card memory reset
SpinDelay ( 1000 ) ;
} else {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Card operation not completed " ) ;
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
}
iso14a_set_timeout ( save_iso14a_timeout ) ;
LED_B_OFF ( ) ;
return retval ;
}
void MifareGen3UID ( uint8_t uidlen , uint8_t * uid ) {
int retval = PM3_SUCCESS ;
uint8_t uid_cmd [ 5 ] = { 0x90 , 0xfb , 0xcc , 0xcc , 0x07 } ;
uint8_t * old_uid = BigBuf_malloc ( 10 ) ;
uint8_t * cmd = BigBuf_malloc ( sizeof ( uid_cmd ) + uidlen + 2 ) ;
iso14a_card_select_t * card_info = ( iso14a_card_select_t * ) BigBuf_malloc ( sizeof ( iso14a_card_select_t ) ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
2021-04-11 19:58:04 +08:00
if ( iso14443a_select_card ( old_uid , card_info , NULL , true , 0 , true ) = = false ) {
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
if ( card_info - > uidlen ! = uidlen ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Wrong UID length " ) ;
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
memcpy ( cmd , uid_cmd , sizeof ( uid_cmd ) ) ;
memcpy ( & cmd [ sizeof ( uid_cmd ) ] , uid , uidlen ) ;
AddCrc14A ( cmd , sizeof ( uid_cmd ) + uidlen ) ;
retval = DoGen3Cmd ( cmd , sizeof ( uid_cmd ) + uidlen + 2 ) ;
OUT :
reply_ng ( CMD_HF_MIFARE_GEN3UID , retval , old_uid , uidlen ) ;
// turns off
OnSuccessMagic ( ) ;
BigBuf_free ( ) ;
}
void MifareGen3Blk ( uint8_t block_len , uint8_t * block ) {
# define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2)
int retval = PM3_SUCCESS ;
uint8_t block_cmd [ 5 ] = { 0x90 , 0xf0 , 0xcc , 0xcc , 0x10 } ;
uint8_t * uid = BigBuf_malloc ( 10 ) ;
uint8_t * cmd = BigBuf_malloc ( sizeof ( block_cmd ) + MAX_MIFARE_FRAME_SIZE ) ;
iso14a_card_select_t * card_info = ( iso14a_card_select_t * ) BigBuf_malloc ( sizeof ( iso14a_card_select_t ) ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
2021-04-11 19:58:04 +08:00
if ( iso14443a_select_card ( uid , card_info , NULL , true , 0 , true ) = = false ) {
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
bool doReselect = false ;
if ( block_len < MIFARE_BLOCK_SIZE ) {
if ( ( mifare_sendcmd_short ( NULL , CRYPT_NONE , ISO14443A_CMD_READBLOCK , 0 , & cmd [ sizeof ( block_cmd ) ] , NULL , NULL ) ! = MAX_MIFARE_FRAME_SIZE ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Read manufacturer block failed " ) ;
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
doReselect = true ;
}
if ( block_len > 0 ) {
memcpy ( cmd , block_cmd , sizeof ( block_cmd ) ) ;
memcpy ( & cmd [ sizeof ( block_cmd ) ] , block , block_len ) ;
int ofs = sizeof ( block_cmd ) ;
if ( card_info - > uidlen = = 4 ) {
cmd [ ofs + 4 ] = cmd [ ofs + 0 ] ^ cmd [ ofs + 1 ] ^ cmd [ ofs + 2 ] ^ cmd [ ofs + 3 ] ;
ofs + = 5 ;
} else if ( card_info - > uidlen = = 7 ) {
ofs + = 7 ;
} else {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Wrong Card UID length " ) ;
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
cmd [ ofs + + ] = card_info - > sak ;
cmd [ ofs + + ] = card_info - > atqa [ 0 ] ;
cmd [ ofs + + ] = card_info - > atqa [ 1 ] ;
AddCrc14A ( cmd , sizeof ( block_cmd ) + MIFARE_BLOCK_SIZE ) ;
if ( doReselect ) {
if ( ! iso14443a_select_card ( uid , NULL , NULL , true , 0 , true ) ) {
retval = PM3_ESOFT ;
goto OUT ;
}
}
retval = DoGen3Cmd ( cmd , sizeof ( block_cmd ) + MAX_MIFARE_FRAME_SIZE ) ;
}
OUT :
reply_ng ( CMD_HF_MIFARE_GEN3BLK , retval , & cmd [ sizeof ( block_cmd ) ] , MIFARE_BLOCK_SIZE ) ;
// turns off
OnSuccessMagic ( ) ;
BigBuf_free ( ) ;
}
void MifareGen3Freez ( void ) {
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
2021-04-11 19:58:04 +08:00
int retval = PM3_SUCCESS ;
uint8_t freeze_cmd [ 7 ] = { 0x90 , 0xfd , 0x11 , 0x11 , 0x00 , 0xe7 , 0x91 } ;
uint8_t * uid = BigBuf_malloc ( 10 ) ;
if ( iso14443a_select_card ( uid , NULL , NULL , true , 0 , true ) = = false ) {
2020-09-06 03:32:11 +08:00
retval = PM3_ESOFT ;
goto OUT ;
}
retval = DoGen3Cmd ( freeze_cmd , sizeof ( freeze_cmd ) ) ;
OUT :
reply_ng ( CMD_HF_MIFARE_GEN3FREEZ , retval , NULL , 0 ) ;
// turns off
OnSuccessMagic ( ) ;
BigBuf_free ( ) ;
}
2021-12-31 16:24:10 +08:00
void MifareG4ReadBlk ( uint8_t blockno , uint8_t * pwd ) {
2021-06-24 20:59:33 +08:00
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
int retval = PM3_SUCCESS ;
uint8_t * par = BigBuf_malloc ( MAX_PARITY_SIZE ) ;
uint8_t * buf = BigBuf_malloc ( PM3_CMD_DATA_SIZE ) ;
uint8_t * uid = BigBuf_malloc ( 10 ) ;
if ( iso14443a_select_card ( uid , NULL , NULL , true , 0 , true ) = = false ) {
retval = PM3_ESOFT ;
goto OUT ;
}
LED_B_ON ( ) ;
uint32_t save_iso14a_timeout = iso14a_get_timeout ( ) ;
iso14a_set_timeout ( 13560000 / 1000 / ( 8 * 16 ) * 1000 ) ; // 2 seconds timeout
2021-12-31 19:45:21 +08:00
2021-06-24 20:59:33 +08:00
uint8_t cmd [ ] = { 0xCF , 0x00 , 0x00 , 0x00 , 0x00 , 0xCE , blockno , 0x00 , 0x00 } ;
2021-12-31 16:24:10 +08:00
memcpy ( cmd + 1 , pwd , 4 ) ;
2021-06-24 20:59:33 +08:00
AddCrc14A ( cmd , sizeof ( cmd ) - 2 ) ;
ReaderTransmit ( cmd , sizeof ( cmd ) , NULL ) ;
int res = ReaderReceive ( buf , par ) ;
if ( res ! = 18 ) {
retval = PM3_ESOFT ;
}
iso14a_set_timeout ( save_iso14a_timeout ) ;
LED_B_OFF ( ) ;
OUT :
2021-12-31 16:24:10 +08:00
reply_ng ( CMD_HF_MIFARE_G4_RDBL , retval , buf , 18 ) ;
2021-06-24 20:59:33 +08:00
// turns off
OnSuccessMagic ( ) ;
BigBuf_free ( ) ;
}
2019-05-15 18:52:22 +08:00
void MifareSetMod ( uint8_t * datain ) {
uint8_t mod = datain [ 0 ] ;
uint64_t ui64Key = bytes_to_num ( datain + 1 , 6 ) ;
2019-03-10 03:34:41 +08:00
// variables
2019-05-22 17:58:48 +08:00
uint16_t isOK = PM3_EUNDEF ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0 } ;
uint32_t cuid = 0 ;
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs = & mpcs ;
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 ) {
2019-03-10 07:00:59 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-03-10 07:00:59 +08:00
if ( mifare_classic_auth ( pcs , cuid , 0 , 0 , ui64Key , AUTH_FIRST ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Auth error " ) ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-06-08 00:41:39 +08:00
int respLen ;
2019-12-27 06:41:30 +08:00
if ( ( ( respLen = mifare_sendcmd_short ( pcs , CRYPT_ALL , 0x43 , mod , receivedAnswer , receivedAnswerPar , NULL ) ) ! = 1 ) | | ( receivedAnswer [ 0 ] ! = 0x0a ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " SetMod error; response[0]: %hhX, len: %d " , receivedAnswer [ 0 ] , respLen ) ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-03-10 07:00:59 +08:00
if ( mifare_classic_halt ( pcs , cuid ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Halt error " ) ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-05-15 18:52:22 +08:00
isOK = PM3_SUCCESS ;
2019-03-10 03:34:41 +08:00
break ;
}
2019-10-18 22:58:24 +08:00
crypto1_deinit ( pcs ) ;
2019-03-10 03:34:41 +08:00
LED_B_ON ( ) ;
2019-08-04 01:17:00 +08:00
reply_ng ( CMD_HF_MIFARE_SETMOD , isOK , NULL , 0 ) ;
2019-03-10 03:34:41 +08:00
LED_B_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2019-03-09 15:49:41 +08:00
}
//
// DESFIRE
//
2019-03-10 18:20:22 +08:00
void Mifare_DES_Auth1 ( uint8_t arg0 , uint8_t * datain ) {
2019-03-21 22:19:18 +08:00
uint8_t dataout [ 12 ] = { 0x00 } ;
2019-03-10 03:34:41 +08:00
uint8_t uid [ 10 ] = { 0x00 } ;
uint32_t cuid = 0 ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
int len = iso14443a_select_card ( uid , NULL , & cuid , true , 0 , false ) ;
2019-03-10 07:00:59 +08:00
if ( ! len ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 1 ) ;
return ;
} ;
2019-03-10 07:00:59 +08:00
if ( mifare_desfire_des_auth1 ( cuid , dataout ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Authentication part1: Fail. " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 4 ) ;
return ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) DbpString ( " AUTH 1 FINISHED " ) ;
2019-05-29 01:20:56 +08:00
reply_mix ( CMD_ACK , 1 , cuid , 0 , dataout , sizeof ( dataout ) ) ;
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void Mifare_DES_Auth2 ( uint32_t arg0 , uint8_t * datain ) {
2019-03-10 03:34:41 +08:00
uint32_t cuid = arg0 ;
uint8_t key [ 16 ] = { 0x00 } ;
2019-03-21 22:19:18 +08:00
uint8_t dataout [ 12 ] = { 0x00 } ;
uint8_t isOK = 0 ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
memcpy ( key , datain , 16 ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
isOK = mifare_desfire_des_auth2 ( cuid , key , dataout ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( isOK ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) Dbprintf ( " Authentication part2: Failed " ) ;
2019-03-10 03:34:41 +08:00
OnError ( 4 ) ;
return ;
}
2019-03-09 15:49:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) DbpString ( " AUTH 2 FINISHED " ) ;
2019-03-09 15:49:41 +08:00
2019-04-18 18:43:35 +08:00
reply_old ( CMD_ACK , isOK , 0 , 0 , dataout , sizeof ( dataout ) ) ;
2019-03-10 03:34:41 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
set_tracing ( false ) ;
2019-03-12 07:12:26 +08:00
}
2019-11-08 17:28:29 +08:00
//
// Tear-off attack against MFU.
2019-11-08 19:00:21 +08:00
// - Moebius et al
2021-03-08 06:43:53 +08:00
void MifareU_Otp_Tearoff ( uint8_t blno , uint32_t tearoff_time , uint8_t * data_testwrite ) {
2021-02-24 06:53:08 +08:00
uint8_t blockNo = blno ;
2019-11-08 17:28:29 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) DbpString ( " Preparing OTP tear-off " ) ;
2019-11-08 19:00:21 +08:00
2020-10-13 01:08:29 +08:00
if ( tearoff_time > 43000 )
tearoff_time = 43000 ;
2021-08-22 05:02:27 +08:00
g_tearoff_delay_us = tearoff_time ;
g_tearoff_enabled = true ;
2020-10-12 00:03:29 +08:00
2019-11-08 17:28:29 +08:00
LEDsoff ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
// write cmd to send, include CRC
2019-11-08 19:00:21 +08:00
// 1b write, 1b block, 4b data, 2 crc
2020-11-05 19:06:12 +08:00
uint8_t cmd [ ] = {
2020-11-07 08:32:43 +08:00
MIFARE_ULC_WRITE , blockNo ,
data_testwrite [ 0 ] , data_testwrite [ 1 ] , data_testwrite [ 2 ] , data_testwrite [ 3 ] ,
0 , 0
} ;
2019-11-08 17:28:29 +08:00
AddCrc14A ( cmd , sizeof ( cmd ) - 2 ) ;
2020-10-11 15:51:56 +08:00
2019-11-08 19:00:21 +08:00
// anticollision / select card
2019-11-08 17:28:29 +08:00
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2019-11-08 17:28:29 +08:00
OnError ( 1 ) ;
2020-11-05 19:06:12 +08:00
reply_ng ( CMD_HF_MFU_OTP_TEAROFF , PM3_EFAILED , NULL , 0 ) ;
2019-11-08 17:28:29 +08:00
return ;
} ;
2019-11-08 19:00:21 +08:00
// send
LED_D_ON ( ) ;
2021-03-08 06:43:53 +08:00
ReaderTransmit ( cmd , sizeof ( cmd ) , NULL ) ;
tearoff_hook ( ) ;
2019-11-08 17:28:29 +08:00
reply_ng ( CMD_HF_MFU_OTP_TEAROFF , PM3_SUCCESS , NULL , 0 ) ;
}
2020-10-13 01:08:29 +08:00
//
// Tear-off attack against MFU counter
2020-11-05 19:06:12 +08:00
void MifareU_Counter_Tearoff ( uint8_t counter , uint32_t tearoff_time , uint8_t * datain ) {
2020-10-13 01:08:29 +08:00
if ( tearoff_time > 43000 )
tearoff_time = 43000 ;
LEDsoff ( ) ;
iso14443a_setup ( FPGA_HF_ISO14443A_READER_LISTEN ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
// Send MFU counter increase cmd
uint8_t cmd [ ] = {
2020-10-20 07:00:23 +08:00
MIFARE_ULEV1_INCR_CNT ,
counter ,
2020-11-07 08:32:43 +08:00
datain [ 0 ] , // lsb
datain [ 1 ] ,
datain [ 2 ] , // msb
datain [ 3 ] , // rfu
2020-10-20 07:00:23 +08:00
0 ,
0 ,
} ;
2020-10-13 01:08:29 +08:00
AddCrc14A ( cmd , sizeof ( cmd ) - 2 ) ;
// anticollision / select card
if ( ! iso14443a_select_card ( NULL , NULL , NULL , true , 0 , true ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " Can't select card " ) ;
2020-10-13 01:08:29 +08:00
OnError ( 1 ) ;
2020-10-29 19:26:43 +08:00
switch_off ( ) ;
LEDsoff ( ) ;
2020-10-13 01:08:29 +08:00
return ;
} ;
// send
ReaderTransmit ( cmd , sizeof ( cmd ) , NULL ) ;
LED_D_ON ( ) ;
SpinDelayUsPrecision ( tearoff_time ) ;
switch_off ( ) ;
2020-10-29 19:26:43 +08:00
LEDsoff ( ) ;
2020-10-13 01:08:29 +08:00
reply_ng ( CMD_HF_MFU_COUNTER_TEAROFF , PM3_SUCCESS , NULL , 0 ) ;
}