2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2012-07-07 00:19:05 +08:00
// Merlok - June 2011, 2012
2010-02-21 05:24:25 +08:00
// Gerhard de Koning Gans - May 2008
2010-07-13 21:39:30 +08:00
// Hagen Fritsch - June 2010
2010-02-21 08:12:52 +08:00
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2010-02-21 08:12:52 +08:00
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
2010-02-21 05:57:20 +08:00
# include "proxmark3.h"
2010-02-21 05:24:25 +08:00
# include "apps.h"
2010-02-21 06:51:00 +08:00
# include "util.h"
2010-02-21 08:10:28 +08:00
# include "string.h"
2012-12-05 07:39:18 +08:00
# include "cmd.h"
2010-02-21 08:10:28 +08:00
2010-02-21 05:24:25 +08:00
# include "iso14443crc.h"
2010-07-13 21:39:30 +08:00
# include "iso14443a.h"
2011-05-26 20:55:15 +08:00
# include "crapto1.h"
# include "mifareutil.h"
2010-02-21 05:24:25 +08:00
2010-07-13 21:39:30 +08:00
static uint32_t iso14a_timeout ;
2012-09-18 21:53:17 +08:00
uint8_t * trace = ( uint8_t * ) BigBuf + TRACE_OFFSET ;
2012-06-28 21:38:40 +08:00
int traceLen = 0 ;
int rsamples = 0 ;
int tracing = TRUE ;
uint8_t trigger = 0 ;
2012-08-25 05:00:03 +08:00
// the block number for the ISO14443-4 PCB
static uint8_t iso14_pcb_blocknum = 0 ;
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
// CARD TO READER - manchester
2010-03-05 12:14:04 +08:00
// Sequence D: 11110000 modulation with subcarrier during first half
// Sequence E: 00001111 modulation with subcarrier during second half
// Sequence F: 00000000 no modulation with subcarrier
2011-06-16 22:43:49 +08:00
// READER TO CARD - miller
2010-03-05 12:14:04 +08:00
// Sequence X: 00001100 drop after half a period
// Sequence Y: 00000000 no drop
// Sequence Z: 11000000 drop at start
# define SEC_D 0xf0
# define SEC_E 0x0f
# define SEC_F 0x00
# define SEC_X 0x0c
# define SEC_Y 0x00
# define SEC_Z 0xc0
2010-02-21 05:24:25 +08:00
2012-06-28 21:38:40 +08:00
const uint8_t OddByteParity [ 256 ] = {
2010-02-21 05:24:25 +08:00
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1
} ;
2012-06-28 21:38:40 +08:00
2012-12-05 07:39:18 +08:00
void iso14a_set_trigger ( bool enable ) {
2010-07-13 21:39:30 +08:00
trigger = enable ;
}
2012-12-05 07:39:18 +08:00
void iso14a_clear_trace ( ) {
memset ( trace , 0x44 , TRACE_SIZE ) ;
2011-06-18 02:39:54 +08:00
traceLen = 0 ;
}
2012-09-18 21:53:17 +08:00
2012-12-05 07:39:18 +08:00
void iso14a_set_tracing ( bool enable ) {
2011-06-18 02:39:54 +08:00
tracing = enable ;
}
2012-09-18 21:53:17 +08:00
2012-08-25 05:00:03 +08:00
void iso14a_set_timeout ( uint32_t timeout ) {
iso14a_timeout = timeout ;
}
2011-06-18 02:39:54 +08:00
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
// Generate the parity value for a byte sequence
2010-02-21 05:57:20 +08:00
//
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2011-05-26 20:55:15 +08:00
byte_t oddparity ( const byte_t bt )
{
2013-09-29 03:28:55 +08:00
return OddByteParity [ bt ] ;
2011-05-26 20:55:15 +08:00
}
2010-02-21 06:51:00 +08:00
uint32_t GetParity ( const uint8_t * pbtCmd , int iLen )
2010-02-21 05:24:25 +08:00
{
2013-09-29 03:28:55 +08:00
int i ;
uint32_t dwPar = 0 ;
2010-03-05 12:14:04 +08:00
2013-09-29 03:28:55 +08:00
// Generate the encrypted data
for ( i = 0 ; i < iLen ; i + + ) {
// Save the encrypted parity bit
dwPar | = ( ( OddByteParity [ pbtCmd [ i ] ] ) < < i ) ;
}
return dwPar ;
2010-02-21 05:24:25 +08:00
}
2010-07-13 21:39:30 +08:00
void AppendCrc14443a ( uint8_t * data , int len )
2010-02-21 05:24:25 +08:00
{
2013-09-29 03:28:55 +08:00
ComputeCrc14443 ( CRC_14443_A , data , len , data + len , data + len + 1 ) ;
2010-02-21 05:24:25 +08:00
}
2012-06-28 21:38:40 +08:00
// The function LogTrace() is also used by the iClass implementation in iClass.c
2012-07-07 23:29:51 +08:00
int RAMFUNC LogTrace ( const uint8_t * btBytes , int iLen , int iSamples , uint32_t dwParity , int bReader )
2010-02-21 05:24:25 +08:00
{
// Return when trace is full
2012-06-29 18:24:05 +08:00
if ( traceLen > = TRACE_SIZE ) return FALSE ;
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
// Trace the random, i'm curious
rsamples + = iSamples ;
trace [ traceLen + + ] = ( ( rsamples > > 0 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( rsamples > > 8 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( rsamples > > 16 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( rsamples > > 24 ) & 0xff ) ;
if ( ! bReader ) {
trace [ traceLen - 1 ] | = 0x80 ;
}
trace [ traceLen + + ] = ( ( dwParity > > 0 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( dwParity > > 8 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( dwParity > > 16 ) & 0xff ) ;
trace [ traceLen + + ] = ( ( dwParity > > 24 ) & 0xff ) ;
trace [ traceLen + + ] = iLen ;
memcpy ( trace + traceLen , btBytes , iLen ) ;
traceLen + = iLen ;
return TRUE ;
}
//-----------------------------------------------------------------------------
// The software UART that receives commands from the reader, and its state
// variables.
//-----------------------------------------------------------------------------
2012-07-07 00:19:05 +08:00
static tUart Uart ;
2010-02-21 05:24:25 +08:00
2010-10-08 18:23:04 +08:00
static RAMFUNC int MillerDecoding ( int bit )
2010-02-21 05:24:25 +08:00
{
2012-06-12 20:21:26 +08:00
//int error = 0;
2010-02-21 05:24:25 +08:00
int bitright ;
if ( ! Uart . bitBuffer ) {
Uart . bitBuffer = bit ^ 0xFF0 ;
return FALSE ;
}
else {
Uart . bitBuffer < < = 4 ;
Uart . bitBuffer ^ = bit ;
}
2010-02-21 06:51:00 +08:00
int EOC = FALSE ;
2010-02-21 05:24:25 +08:00
if ( Uart . state ! = STATE_UNSYNCD ) {
Uart . posCnt + + ;
if ( ( Uart . bitBuffer & Uart . syncBit ) ^ Uart . syncBit ) {
bit = 0x00 ;
}
else {
bit = 0x01 ;
}
if ( ( ( Uart . bitBuffer < < 1 ) & Uart . syncBit ) ^ Uart . syncBit ) {
bitright = 0x00 ;
}
else {
bitright = 0x01 ;
}
if ( bit ! = bitright ) { bit = bitright ; }
if ( Uart . posCnt = = 1 ) {
// measurement first half bitperiod
if ( ! bit ) {
Uart . drop = DROP_FIRST_HALF ;
}
}
else {
// measurement second half bitperiod
if ( ! bit & ( Uart . drop = = DROP_NONE ) ) {
Uart . drop = DROP_SECOND_HALF ;
}
else if ( ! bit ) {
// measured a drop in first and second half
// which should not be possible
Uart . state = STATE_ERROR_WAIT ;
2012-06-12 20:21:26 +08:00
//error = 0x01;
2010-02-21 05:24:25 +08:00
}
Uart . posCnt = 0 ;
switch ( Uart . state ) {
case STATE_START_OF_COMMUNICATION :
Uart . shiftReg = 0 ;
if ( Uart . drop = = DROP_SECOND_HALF ) {
// error, should not happen in SOC
Uart . state = STATE_ERROR_WAIT ;
2012-06-12 20:21:26 +08:00
//error = 0x02;
2010-02-21 05:24:25 +08:00
}
else {
// correct SOC
Uart . state = STATE_MILLER_Z ;
}
break ;
case STATE_MILLER_Z :
Uart . bitCnt + + ;
Uart . shiftReg > > = 1 ;
if ( Uart . drop = = DROP_NONE ) {
// logic '0' followed by sequence Y
// end of communication
Uart . state = STATE_UNSYNCD ;
EOC = TRUE ;
}
// if(Uart.drop == DROP_FIRST_HALF) {
// Uart.state = STATE_MILLER_Z; stay the same
// we see a logic '0' }
if ( Uart . drop = = DROP_SECOND_HALF ) {
// we see a logic '1'
Uart . shiftReg | = 0x100 ;
Uart . state = STATE_MILLER_X ;
}
break ;
case STATE_MILLER_X :
Uart . shiftReg > > = 1 ;
if ( Uart . drop = = DROP_NONE ) {
// sequence Y, we see a '0'
Uart . state = STATE_MILLER_Y ;
Uart . bitCnt + + ;
}
if ( Uart . drop = = DROP_FIRST_HALF ) {
// Would be STATE_MILLER_Z
// but Z does not follow X, so error
Uart . state = STATE_ERROR_WAIT ;
2012-06-12 20:21:26 +08:00
//error = 0x03;
2010-02-21 05:24:25 +08:00
}
if ( Uart . drop = = DROP_SECOND_HALF ) {
// We see a '1' and stay in state X
Uart . shiftReg | = 0x100 ;
Uart . bitCnt + + ;
}
break ;
case STATE_MILLER_Y :
Uart . bitCnt + + ;
Uart . shiftReg > > = 1 ;
if ( Uart . drop = = DROP_NONE ) {
// logic '0' followed by sequence Y
// end of communication
Uart . state = STATE_UNSYNCD ;
EOC = TRUE ;
}
if ( Uart . drop = = DROP_FIRST_HALF ) {
// we see a '0'
Uart . state = STATE_MILLER_Z ;
}
if ( Uart . drop = = DROP_SECOND_HALF ) {
// We see a '1' and go to state X
Uart . shiftReg | = 0x100 ;
Uart . state = STATE_MILLER_X ;
}
break ;
case STATE_ERROR_WAIT :
// That went wrong. Now wait for at least two bit periods
// and try to sync again
if ( Uart . drop = = DROP_NONE ) {
Uart . highCnt = 6 ;
Uart . state = STATE_UNSYNCD ;
}
break ;
default :
Uart . state = STATE_UNSYNCD ;
Uart . highCnt = 0 ;
break ;
}
Uart . drop = DROP_NONE ;
// should have received at least one whole byte...
if ( ( Uart . bitCnt = = 2 ) & & EOC & & ( Uart . byteCnt > 0 ) ) {
return TRUE ;
}
if ( Uart . bitCnt = = 9 ) {
Uart . output [ Uart . byteCnt ] = ( Uart . shiftReg & 0xff ) ;
Uart . byteCnt + + ;
Uart . parityBits < < = 1 ;
Uart . parityBits ^ = ( ( Uart . shiftReg > > 8 ) & 0x01 ) ;
if ( EOC ) {
// when End of Communication received and
// all data bits processed..
return TRUE ;
}
Uart . bitCnt = 0 ;
}
/*if(error) {
Uart . output [ Uart . byteCnt ] = 0xAA ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = error & 0xFF ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = 0xAA ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = ( Uart . bitBuffer > > 8 ) & 0xFF ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = Uart . bitBuffer & 0xFF ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = ( Uart . syncBit > > 3 ) & 0xFF ;
Uart . byteCnt + + ;
Uart . output [ Uart . byteCnt ] = 0xAA ;
Uart . byteCnt + + ;
return TRUE ;
} */
}
}
else {
bit = Uart . bitBuffer & 0xf0 ;
bit > > = 4 ;
bit ^ = 0x0F ;
if ( bit ) {
// should have been high or at least (4 * 128) / fc
// according to ISO this should be at least (9 * 128 + 20) / fc
if ( Uart . highCnt = = 8 ) {
// we went low, so this could be start of communication
// it turns out to be safer to choose a less significant
// syncbit... so we check whether the neighbour also represents the drop
Uart . posCnt = 1 ; // apparently we are busy with our first half bit period
Uart . syncBit = bit & 8 ;
Uart . samples = 3 ;
if ( ! Uart . syncBit ) { Uart . syncBit = bit & 4 ; Uart . samples = 2 ; }
else if ( bit & 4 ) { Uart . syncBit = bit & 4 ; Uart . samples = 2 ; bit < < = 2 ; }
if ( ! Uart . syncBit ) { Uart . syncBit = bit & 2 ; Uart . samples = 1 ; }
else if ( bit & 2 ) { Uart . syncBit = bit & 2 ; Uart . samples = 1 ; bit < < = 1 ; }
if ( ! Uart . syncBit ) { Uart . syncBit = bit & 1 ; Uart . samples = 0 ;
2011-02-05 00:25:31 +08:00
if ( Uart . syncBit & & ( Uart . bitBuffer & 8 ) ) {
2010-02-21 05:24:25 +08:00
Uart . syncBit = 8 ;
// the first half bit period is expected in next sample
Uart . posCnt = 0 ;
Uart . samples = 3 ;
}
}
else if ( bit & 1 ) { Uart . syncBit = bit & 1 ; Uart . samples = 0 ; }
Uart . syncBit < < = 4 ;
Uart . state = STATE_START_OF_COMMUNICATION ;
Uart . drop = DROP_FIRST_HALF ;
Uart . bitCnt = 0 ;
Uart . byteCnt = 0 ;
Uart . parityBits = 0 ;
2012-06-12 20:21:26 +08:00
//error = 0;
2010-02-21 05:24:25 +08:00
}
else {
Uart . highCnt = 0 ;
}
}
else {
if ( Uart . highCnt < 8 ) {
Uart . highCnt + + ;
}
}
}
return FALSE ;
}
//=============================================================================
// ISO 14443 Type A - Manchester
//=============================================================================
2012-07-07 00:19:05 +08:00
static tDemod Demod ;
2010-02-21 05:24:25 +08:00
2010-10-08 18:23:04 +08:00
static RAMFUNC int ManchesterDecoding ( int v )
2010-02-21 05:24:25 +08:00
{
int bit ;
int modulation ;
2012-06-12 20:21:26 +08:00
//int error = 0;
2010-02-21 05:24:25 +08:00
if ( ! Demod . buff ) {
Demod . buff = 1 ;
Demod . buffer = v ;
return FALSE ;
}
else {
bit = Demod . buffer ;
Demod . buffer = v ;
}
if ( Demod . state = = DEMOD_UNSYNCD ) {
Demod . output [ Demod . len ] = 0xfa ;
Demod . syncBit = 0 ;
//Demod.samples = 0;
Demod . posCount = 1 ; // This is the first half bit period, so after syncing handle the second part
2011-02-05 00:25:31 +08:00
if ( bit & 0x08 ) {
Demod . syncBit = 0x08 ;
2010-02-21 05:24:25 +08:00
}
2011-02-05 00:25:31 +08:00
if ( bit & 0x04 ) {
if ( Demod . syncBit ) {
bit < < = 4 ;
}
Demod . syncBit = 0x04 ;
}
2010-02-21 05:24:25 +08:00
2011-02-05 00:25:31 +08:00
if ( bit & 0x02 ) {
if ( Demod . syncBit ) {
bit < < = 2 ;
2010-02-21 05:24:25 +08:00
}
2011-02-05 00:25:31 +08:00
Demod . syncBit = 0x02 ;
2010-02-21 05:24:25 +08:00
}
2011-02-05 03:43:48 +08:00
if ( bit & 0x01 & & Demod . syncBit ) {
2011-02-05 00:25:31 +08:00
Demod . syncBit = 0x01 ;
}
2010-02-21 05:24:25 +08:00
if ( Demod . syncBit ) {
Demod . len = 0 ;
Demod . state = DEMOD_START_OF_COMMUNICATION ;
Demod . sub = SUB_FIRST_HALF ;
Demod . bitCount = 0 ;
Demod . shiftReg = 0 ;
Demod . parityBits = 0 ;
Demod . samples = 0 ;
if ( Demod . posCount ) {
2010-07-13 21:39:30 +08:00
if ( trigger ) LED_A_OFF ( ) ;
2010-02-21 05:24:25 +08:00
switch ( Demod . syncBit ) {
case 0x08 : Demod . samples = 3 ; break ;
case 0x04 : Demod . samples = 2 ; break ;
case 0x02 : Demod . samples = 1 ; break ;
case 0x01 : Demod . samples = 0 ; break ;
}
}
2012-06-12 20:21:26 +08:00
//error = 0;
2010-02-21 05:24:25 +08:00
}
}
else {
//modulation = bit & Demod.syncBit;
modulation = ( ( bit < < 1 ) ^ ( ( Demod . buffer & 0x08 ) > > 3 ) ) & Demod . syncBit ;
Demod . samples + = 4 ;
if ( Demod . posCount = = 0 ) {
Demod . posCount = 1 ;
if ( modulation ) {
Demod . sub = SUB_FIRST_HALF ;
}
else {
Demod . sub = SUB_NONE ;
}
}
else {
Demod . posCount = 0 ;
if ( modulation & & ( Demod . sub = = SUB_FIRST_HALF ) ) {
if ( Demod . state ! = DEMOD_ERROR_WAIT ) {
Demod . state = DEMOD_ERROR_WAIT ;
Demod . output [ Demod . len ] = 0xaa ;
2012-06-12 20:21:26 +08:00
//error = 0x01;
2010-02-21 05:24:25 +08:00
}
}
else if ( modulation ) {
Demod . sub = SUB_SECOND_HALF ;
}
switch ( Demod . state ) {
case DEMOD_START_OF_COMMUNICATION :
if ( Demod . sub = = SUB_FIRST_HALF ) {
Demod . state = DEMOD_MANCHESTER_D ;
}
else {
Demod . output [ Demod . len ] = 0xab ;
Demod . state = DEMOD_ERROR_WAIT ;
2012-06-12 20:21:26 +08:00
//error = 0x02;
2010-02-21 05:24:25 +08:00
}
break ;
case DEMOD_MANCHESTER_D :
case DEMOD_MANCHESTER_E :
if ( Demod . sub = = SUB_FIRST_HALF ) {
Demod . bitCount + + ;
Demod . shiftReg = ( Demod . shiftReg > > 1 ) ^ 0x100 ;
Demod . state = DEMOD_MANCHESTER_D ;
}
else if ( Demod . sub = = SUB_SECOND_HALF ) {
Demod . bitCount + + ;
Demod . shiftReg > > = 1 ;
Demod . state = DEMOD_MANCHESTER_E ;
}
else {
Demod . state = DEMOD_MANCHESTER_F ;
}
break ;
case DEMOD_MANCHESTER_F :
// Tag response does not need to be a complete byte!
if ( Demod . len > 0 | | Demod . bitCount > 0 ) {
if ( Demod . bitCount > 0 ) {
Demod . shiftReg > > = ( 9 - Demod . bitCount ) ;
Demod . output [ Demod . len ] = Demod . shiftReg & 0xff ;
Demod . len + + ;
// No parity bit, so just shift a 0
Demod . parityBits < < = 1 ;
}
Demod . state = DEMOD_UNSYNCD ;
return TRUE ;
}
else {
Demod . output [ Demod . len ] = 0xad ;
Demod . state = DEMOD_ERROR_WAIT ;
2012-06-12 20:21:26 +08:00
//error = 0x03;
2010-02-21 05:24:25 +08:00
}
break ;
case DEMOD_ERROR_WAIT :
Demod . state = DEMOD_UNSYNCD ;
break ;
default :
Demod . output [ Demod . len ] = 0xdd ;
Demod . state = DEMOD_UNSYNCD ;
break ;
}
if ( Demod . bitCount > = 9 ) {
Demod . output [ Demod . len ] = Demod . shiftReg & 0xff ;
Demod . len + + ;
Demod . parityBits < < = 1 ;
Demod . parityBits ^ = ( ( Demod . shiftReg > > 8 ) & 0x01 ) ;
Demod . bitCount = 0 ;
Demod . shiftReg = 0 ;
}
/*if(error) {
Demod . output [ Demod . len ] = 0xBB ;
Demod . len + + ;
Demod . output [ Demod . len ] = error & 0xFF ;
Demod . len + + ;
Demod . output [ Demod . len ] = 0xBB ;
Demod . len + + ;
Demod . output [ Demod . len ] = bit & 0xFF ;
Demod . len + + ;
Demod . output [ Demod . len ] = Demod . buffer & 0xFF ;
Demod . len + + ;
Demod . output [ Demod . len ] = Demod . syncBit & 0xFF ;
Demod . len + + ;
Demod . output [ Demod . len ] = 0xBB ;
Demod . len + + ;
return TRUE ;
} */
}
} // end (state != UNSYNCED)
return FALSE ;
}
//=============================================================================
// Finally, a `sniffer' for ISO 14443 Type A
// Both sides of communication!
//=============================================================================
//-----------------------------------------------------------------------------
// Record the sequence of commands sent by the reader to the tag, with
// triggering so that we start recording at the point that the tag is moved
// near the reader.
//-----------------------------------------------------------------------------
2012-07-07 23:29:51 +08:00
void RAMFUNC SnoopIso14443a ( uint8_t param ) {
// param:
// bit 0 - trigger from first card answer
// bit 1 - trigger from first reader 7-bit request
LEDsoff ( ) ;
// init trace buffer
2013-09-29 03:28:55 +08:00
iso14a_clear_trace ( ) ;
2012-07-07 23:29:51 +08:00
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
// triggered == FALSE -- to wait first for card
int triggered = ! ( param & 0x03 ) ;
// The command (reader -> tag) that we're receiving.
2010-02-21 05:24:25 +08:00
// The length of a received command will in most cases be no more than 18 bytes.
// So 32 should be enough!
2012-07-07 23:29:51 +08:00
uint8_t * receivedCmd = ( ( ( uint8_t * ) BigBuf ) + RECV_CMD_OFFSET ) ;
// The response (tag -> reader) that we're receiving.
uint8_t * receivedResponse = ( ( ( uint8_t * ) BigBuf ) + RECV_RES_OFFSET ) ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
// As we receive stuff, we copy it from receivedCmd or receivedResponse
// into trace, along with its length and other annotations.
//uint8_t *trace = (uint8_t *)BigBuf;
// The DMA buffer, used to stream samples from the FPGA
int8_t * dmaBuf = ( ( int8_t * ) BigBuf ) + DMA_BUFFER_OFFSET ;
int8_t * data = dmaBuf ;
int maxDataLen = 0 ;
int dataLen = 0 ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
// Set up the demodulator for tag -> reader responses.
Demod . output = receivedResponse ;
Demod . len = 0 ;
Demod . state = DEMOD_UNSYNCD ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
// Set up the demodulator for the reader -> tag commands
memset ( & Uart , 0 , sizeof ( Uart ) ) ;
Uart . output = receivedCmd ;
Uart . byteCntMax = 32 ; // was 100 (greg)//////////////////
Uart . state = STATE_UNSYNCD ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
// Setup for the DMA.
FpgaSetupSsc ( ) ;
FpgaSetupSscDma ( ( uint8_t * ) dmaBuf , DMA_BUFFER_SIZE ) ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
// And put the FPGA in the appropriate mode
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2010-06-26 16:24:21 +08:00
2012-07-07 23:29:51 +08:00
// Count of samples received so far, so that we can include timing
// information in the trace buffer.
rsamples = 0 ;
// And now we loop, receiving samples.
while ( true ) {
if ( BUTTON_PRESS ( ) ) {
DbpString ( " cancelled by button " ) ;
goto done ;
}
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
LED_A_ON ( ) ;
WDT_HIT ( ) ;
2010-02-21 05:24:25 +08:00
2012-07-07 23:29:51 +08:00
int register readBufDataP = data - dmaBuf ;
int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC - > PDC_RCR ;
if ( readBufDataP < = dmaBufDataP ) {
dataLen = dmaBufDataP - readBufDataP ;
} else {
dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP + 1 ;
}
// test for length of buffer
if ( dataLen > maxDataLen ) {
maxDataLen = dataLen ;
if ( dataLen > 400 ) {
Dbprintf ( " blew circular buffer! dataLen=0x%x " , dataLen ) ;
goto done ;
}
}
if ( dataLen < 1 ) continue ;
// primary buffer was stopped( <-- we lost data!
if ( ! AT91C_BASE_PDC_SSC - > PDC_RCR ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dmaBuf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( ! AT91C_BASE_PDC_SSC - > PDC_RNCR ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dmaBuf ;
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
LED_A_OFF ( ) ;
rsamples + = 4 ;
if ( MillerDecoding ( ( data [ 0 ] & 0xF0 ) > > 4 ) ) {
LED_C_ON ( ) ;
// check - if there is a short 7bit request from reader
if ( ( ! triggered ) & & ( param & 0x02 ) & & ( Uart . byteCnt = = 1 ) & & ( Uart . bitCnt = 9 ) ) triggered = TRUE ;
if ( triggered ) {
if ( ! LogTrace ( receivedCmd , Uart . byteCnt , 0 - Uart . samples , Uart . parityBits , TRUE ) ) break ;
}
/* And ready to receive another command. */
Uart . state = STATE_UNSYNCD ;
/* And also reset the demod code, which might have been */
/* false-triggered by the commands from the reader. */
Demod . state = DEMOD_UNSYNCD ;
LED_B_OFF ( ) ;
}
if ( ManchesterDecoding ( data [ 0 ] & 0x0F ) ) {
LED_B_ON ( ) ;
if ( ! LogTrace ( receivedResponse , Demod . len , 0 - Demod . samples , Demod . parityBits , FALSE ) ) break ;
if ( ( ! triggered ) & & ( param & 0x01 ) ) triggered = TRUE ;
// And ready to receive another response.
memset ( & Demod , 0 , sizeof ( Demod ) ) ;
Demod . output = receivedResponse ;
Demod . state = DEMOD_UNSYNCD ;
LED_C_OFF ( ) ;
}
data + + ;
if ( data > dmaBuf + DMA_BUFFER_SIZE ) {
data = dmaBuf ;
}
} // main cycle
DbpString ( " COMMAND FINISHED " ) ;
2010-02-21 05:24:25 +08:00
done :
2012-07-07 23:29:51 +08:00
AT91C_BASE_PDC_SSC - > PDC_PTCR = AT91C_PDC_RXTDIS ;
Dbprintf ( " maxDataLen=%x, Uart.state=%x, Uart.byteCnt=%x " , maxDataLen , Uart . state , Uart . byteCnt ) ;
Dbprintf ( " Uart.byteCntMax=%x, traceLen=%x, Uart.output[0]=%08x " , Uart . byteCntMax , traceLen , ( int ) Uart . output [ 0 ] ) ;
LEDsoff ( ) ;
2010-02-21 05:24:25 +08:00
}
//-----------------------------------------------------------------------------
// Prepare tag messages
//-----------------------------------------------------------------------------
2011-06-16 22:43:49 +08:00
static void CodeIso14443aAsTagPar ( const uint8_t * cmd , int len , uint32_t dwParity )
2010-02-21 05:24:25 +08:00
{
2011-06-16 22:43:49 +08:00
int i ;
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
ToSendReset ( ) ;
2010-02-21 05:24:25 +08:00
// Correction bit, might be removed when not needed
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 1 ) ; // 1
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
2011-06-16 22:43:49 +08:00
2010-02-21 05:24:25 +08:00
// Send startbit
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_D ;
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
for ( i = 0 ; i < len ; i + + ) {
int j ;
uint8_t b = cmd [ i ] ;
2010-02-21 05:24:25 +08:00
// Data bits
for ( j = 0 ; j < 8 ; j + + ) {
if ( b & 1 ) {
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_D ;
2010-02-21 05:24:25 +08:00
} else {
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_E ;
2011-06-16 22:43:49 +08:00
}
b > > = 1 ;
}
2010-02-21 05:24:25 +08:00
2011-06-25 21:03:01 +08:00
// Get the parity bit
2011-06-16 22:43:49 +08:00
if ( ( dwParity > > i ) & 0x01 ) {
ToSend [ + + ToSendMax ] = SEC_D ;
2010-02-21 05:24:25 +08:00
} else {
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_E ;
2010-02-21 05:24:25 +08:00
}
2011-06-16 22:43:49 +08:00
}
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
// Send stopbit
ToSend [ + + ToSendMax ] = SEC_F ;
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
// Convert from last byte pos to length
ToSendMax + + ;
}
static void CodeIso14443aAsTag ( const uint8_t * cmd , int len ) {
CodeIso14443aAsTagPar ( cmd , len , GetParity ( cmd , len ) ) ;
2010-02-21 05:24:25 +08:00
}
//-----------------------------------------------------------------------------
// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4
//-----------------------------------------------------------------------------
2011-06-16 22:43:49 +08:00
static void CodeStrangeAnswerAsTag ( )
2010-02-21 05:24:25 +08:00
{
int i ;
2013-09-29 03:28:55 +08:00
ToSendReset ( ) ;
2010-02-21 05:24:25 +08:00
// Correction bit, might be removed when not needed
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 1 ) ; // 1
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
// Send startbit
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_D ;
2010-02-21 05:24:25 +08:00
// 0
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_E ;
2010-02-21 05:24:25 +08:00
// 0
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_E ;
2010-02-21 05:24:25 +08:00
// 1
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_D ;
2010-02-21 05:24:25 +08:00
2013-09-29 03:28:55 +08:00
// Send stopbit
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_F ;
2010-02-21 05:24:25 +08:00
// Flush the buffer in FPGA!!
for ( i = 0 ; i < 5 ; i + + ) {
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_F ;
2010-02-21 05:24:25 +08:00
}
2013-09-29 03:28:55 +08:00
// Convert from last byte pos to length
ToSendMax + + ;
2011-06-16 22:43:49 +08:00
}
2010-02-21 05:24:25 +08:00
2011-06-16 22:43:49 +08:00
static void Code4bitAnswerAsTag ( uint8_t cmd )
{
int i ;
2013-09-29 03:28:55 +08:00
ToSendReset ( ) ;
2011-06-16 22:43:49 +08:00
// Correction bit, might be removed when not needed
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 1 ) ; // 1
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
ToSendStuffBit ( 0 ) ;
// Send startbit
ToSend [ + + ToSendMax ] = SEC_D ;
uint8_t b = cmd ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( b & 1 ) {
ToSend [ + + ToSendMax ] = SEC_D ;
} else {
ToSend [ + + ToSendMax ] = SEC_E ;
}
b > > = 1 ;
}
// Send stopbit
ToSend [ + + ToSendMax ] = SEC_F ;
// Flush the buffer in FPGA!!
for ( i = 0 ; i < 5 ; i + + ) {
ToSend [ + + ToSendMax ] = SEC_F ;
}
2013-09-29 03:28:55 +08:00
// Convert from last byte pos to length
ToSendMax + + ;
2010-02-21 05:24:25 +08:00
}
//-----------------------------------------------------------------------------
// Wait for commands from reader
// Stop when button is pressed
// Or return TRUE when command is captured
//-----------------------------------------------------------------------------
2010-02-21 06:51:00 +08:00
static int GetIso14443aCommandFromReader ( uint8_t * received , int * len , int maxLen )
2010-02-21 05:24:25 +08:00
{
// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
// only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN ) ;
// Now run a `software UART' on the stream of incoming samples.
Uart . output = received ;
Uart . byteCntMax = maxLen ;
Uart . state = STATE_UNSYNCD ;
for ( ; ; ) {
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) return FALSE ;
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) {
AT91C_BASE_SSC - > SSC_THR = 0x00 ;
}
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
2010-02-21 06:51:00 +08:00
uint8_t b = ( uint8_t ) AT91C_BASE_SSC - > SSC_RHR ;
2010-02-21 05:24:25 +08:00
if ( MillerDecoding ( ( b & 0xf0 ) > > 4 ) ) {
* len = Uart . byteCnt ;
return TRUE ;
}
if ( MillerDecoding ( b & 0x0f ) ) {
* len = Uart . byteCnt ;
return TRUE ;
}
}
}
}
2013-03-28 22:02:00 +08:00
2011-06-10 21:35:10 +08:00
static int EmSendCmd14443aRaw ( uint8_t * resp , int respLen , int correctionNeeded ) ;
2013-03-28 22:02:00 +08:00
int EmSend4bitEx ( uint8_t resp , int correctionNeeded ) ;
int EmSend4bit ( uint8_t resp ) ;
int EmSendCmdExPar ( uint8_t * resp , int respLen , int correctionNeeded , uint32_t par ) ;
int EmSendCmdExPar ( uint8_t * resp , int respLen , int correctionNeeded , uint32_t par ) ;
int EmSendCmdEx ( uint8_t * resp , int respLen , int correctionNeeded ) ;
int EmSendCmd ( uint8_t * resp , int respLen ) ;
int EmSendCmdPar ( uint8_t * resp , int respLen , uint32_t par ) ;
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
// Main loop of simulated tag: receive commands from reader, decide what
// response to send, and send it.
//-----------------------------------------------------------------------------
2013-03-28 22:02:00 +08:00
void SimulateIso14443aTag ( int tagType , int uid_1st , int uid_2nd , byte_t * data )
2010-02-21 05:24:25 +08:00
{
2013-09-29 03:28:55 +08:00
// Enable and clear the trace
2012-06-29 18:24:05 +08:00
tracing = TRUE ;
2013-09-29 03:28:55 +08:00
iso14a_clear_trace ( ) ;
2012-06-29 18:24:05 +08:00
2010-02-21 05:24:25 +08:00
// This function contains the tag emulation
2012-06-29 18:24:05 +08:00
uint8_t sak ;
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
uint8_t response1 [ 2 ] ;
switch ( tagType ) {
case 1 : { // MIFARE Classic
// Says: I am Mifare 1k - original line
response1 [ 0 ] = 0x04 ;
response1 [ 1 ] = 0x00 ;
sak = 0x08 ;
} break ;
case 2 : { // MIFARE Ultralight
// Says: I am a stupid memory tag, no crypto
response1 [ 0 ] = 0x04 ;
response1 [ 1 ] = 0x00 ;
sak = 0x00 ;
} break ;
case 3 : { // MIFARE DESFire
// Says: I am a DESFire tag, ph33r me
response1 [ 0 ] = 0x04 ;
response1 [ 1 ] = 0x03 ;
sak = 0x20 ;
} break ;
case 4 : { // ISO/IEC 14443-4
// Says: I am a javacard (JCOP)
response1 [ 0 ] = 0x04 ;
response1 [ 1 ] = 0x00 ;
sak = 0x28 ;
} break ;
default : {
Dbprintf ( " Error: unkown tagtype (%d) " , tagType ) ;
return ;
} break ;
}
// The second response contains the (mandatory) first 24 bits of the UID
uint8_t response2 [ 5 ] ;
// Check if the uid uses the (optional) part
uint8_t response2a [ 5 ] ;
if ( uid_2nd ) {
response2 [ 0 ] = 0x88 ;
num_to_bytes ( uid_1st , 3 , response2 + 1 ) ;
num_to_bytes ( uid_2nd , 4 , response2a ) ;
response2a [ 4 ] = response2a [ 0 ] ^ response2a [ 1 ] ^ response2a [ 2 ] ^ response2a [ 3 ] ;
// Configure the ATQA and SAK accordingly
response1 [ 0 ] | = 0x40 ;
sak | = 0x04 ;
} else {
num_to_bytes ( uid_1st , 4 , response2 ) ;
// Configure the ATQA and SAK accordingly
response1 [ 0 ] & = 0xBF ;
sak & = 0xFB ;
}
// Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID.
response2 [ 4 ] = response2 [ 0 ] ^ response2 [ 1 ] ^ response2 [ 2 ] ^ response2 [ 3 ] ;
// Prepare the mandatory SAK (for 4 and 7 byte UID)
uint8_t response3 [ 3 ] ;
response3 [ 0 ] = sak ;
ComputeCrc14443 ( CRC_14443_A , response3 , 1 , & response3 [ 1 ] , & response3 [ 2 ] ) ;
// Prepare the optional second SAK (for 7 byte UID), drop the cascade bit
uint8_t response3a [ 3 ] ;
response3a [ 0 ] = sak & 0xFB ;
ComputeCrc14443 ( CRC_14443_A , response3a , 1 , & response3a [ 1 ] , & response3a [ 2 ] ) ;
2012-06-29 20:09:24 +08:00
uint8_t response5 [ ] = { 0x00 , 0x00 , 0x00 , 0x00 } ; // Very random tag nonce
uint8_t response6 [ ] = { 0x03 , 0x3B , 0x00 , 0x00 , 0x00 } ; // dummy ATS (pseudo-ATR), answer to RATS
ComputeCrc14443 ( CRC_14443_A , response6 , 3 , & response6 [ 3 ] , & response6 [ 4 ] ) ;
2012-06-29 18:24:05 +08:00
2013-04-24 18:58:12 +08:00
uint8_t * resp = NULL ;
2012-06-29 20:09:24 +08:00
int respLen ;
2010-02-21 05:24:25 +08:00
2013-09-29 03:28:55 +08:00
// Longest possible response will be 16 bytes + 2 CRC = 18 bytes
2010-02-21 05:24:25 +08:00
// This will need
// 144 data bits (18 * 8)
// 18 parity bits
// 2 Start and stop
// 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA)
// 1 just for the case
// ----------- +
// 166
//
// 166 bytes, since every bit that needs to be send costs us a byte
//
2012-06-29 20:09:24 +08:00
// Respond with card type
uint8_t * resp1 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET ) ;
int resp1Len ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Anticollision cascade1 - respond with uid
uint8_t * resp2 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + 166 ) ;
int resp2Len ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Anticollision cascade2 - respond with 2nd half of uid if asked
// we're only going to be asked if we set the 1st byte of the UID (during cascade1) to 0x88
uint8_t * resp2a = ( ( ( uint8_t * ) BigBuf ) + 1140 ) ;
int resp2aLen ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Acknowledge select - cascade 1
uint8_t * resp3 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + ( 166 * 2 ) ) ;
int resp3Len ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Acknowledge select - cascade 2
uint8_t * resp3a = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + ( 166 * 3 ) ) ;
int resp3aLen ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Response to a read request - not implemented atm
uint8_t * resp4 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + ( 166 * 4 ) ) ;
2013-03-28 22:02:00 +08:00
// int resp4Len;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Authenticate response - nonce
uint8_t * resp5 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + ( 166 * 5 ) ) ;
int resp5Len ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// Authenticate response - nonce
uint8_t * resp6 = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET + ( 166 * 6 ) ) ;
int resp6Len ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
uint8_t * receivedCmd = ( ( ( uint8_t * ) BigBuf ) + RECV_CMD_OFFSET ) ;
int len ;
2010-02-21 05:24:25 +08:00
// To control where we are in the protocol
int order = 0 ;
int lastorder ;
// Just to allow some checks
int happened = 0 ;
int happened2 = 0 ;
2012-06-29 18:24:05 +08:00
int cmdsRecvd = 0 ;
uint8_t * respdata = NULL ;
int respsize = 0 ;
2013-03-28 22:02:00 +08:00
// uint8_t nack = 0x04;
2010-02-21 05:24:25 +08:00
2012-06-29 18:24:05 +08:00
memset ( receivedCmd , 0x44 , RECV_CMD_SIZE ) ;
2010-02-21 05:24:25 +08:00
// Prepare the responses of the anticollision phase
// there will be not enough time to do this at the moment the reader sends it REQA
// Answer to request
CodeIso14443aAsTag ( response1 , sizeof ( response1 ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp1 , ToSend , ToSendMax ) ; resp1Len = ToSendMax ;
2010-02-21 05:24:25 +08:00
// Send our UID (cascade 1)
CodeIso14443aAsTag ( response2 , sizeof ( response2 ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp2 , ToSend , ToSendMax ) ; resp2Len = ToSendMax ;
2010-02-21 05:24:25 +08:00
// Answer to select (cascade1)
CodeIso14443aAsTag ( response3 , sizeof ( response3 ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp3 , ToSend , ToSendMax ) ; resp3Len = ToSendMax ;
2010-02-21 05:24:25 +08:00
// Send the cascade 2 2nd part of the uid
CodeIso14443aAsTag ( response2a , sizeof ( response2a ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp2a , ToSend , ToSendMax ) ; resp2aLen = ToSendMax ;
2010-02-21 05:24:25 +08:00
// Answer to select (cascade 2)
CodeIso14443aAsTag ( response3a , sizeof ( response3a ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp3a , ToSend , ToSendMax ) ; resp3aLen = ToSendMax ;
2010-02-21 05:24:25 +08:00
// Strange answer is an example of rare message size (3 bits)
2011-06-16 22:43:49 +08:00
CodeStrangeAnswerAsTag ( ) ;
2013-03-28 22:02:00 +08:00
memcpy ( resp4 , ToSend , ToSendMax ) ; // resp4Len = ToSendMax;
2010-02-21 05:24:25 +08:00
// Authentication answer (random nonce)
CodeIso14443aAsTag ( response5 , sizeof ( response5 ) ) ;
2012-06-29 20:09:24 +08:00
memcpy ( resp5 , ToSend , ToSendMax ) ; resp5Len = ToSendMax ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// dummy ATS (pseudo-ATR), answer to RATS
CodeIso14443aAsTag ( response6 , sizeof ( response6 ) ) ;
memcpy ( resp6 , ToSend , ToSendMax ) ; resp6Len = ToSendMax ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
FpgaSetupSsc ( ) ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
cmdsRecvd = 0 ;
2010-02-21 05:24:25 +08:00
2012-06-29 20:09:24 +08:00
LED_A_ON ( ) ;
for ( ; ; ) {
2012-06-29 18:24:05 +08:00
if ( ! GetIso14443aCommandFromReader ( receivedCmd , & len , RECV_CMD_SIZE ) ) {
2012-06-29 20:09:24 +08:00
DbpString ( " button press " ) ;
break ;
}
2013-03-28 22:02:00 +08:00
2013-09-29 03:28:55 +08:00
if ( tracing ) {
2013-03-28 22:02:00 +08:00
LogTrace ( receivedCmd , len , 0 , Uart . parityBits , TRUE ) ;
2013-09-29 03:28:55 +08:00
}
2013-03-28 22:02:00 +08:00
2012-06-29 20:09:24 +08:00
// doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated
// Okay, look at the command now.
lastorder = order ;
if ( receivedCmd [ 0 ] = = 0x26 ) { // Received a REQUEST
2010-02-21 05:24:25 +08:00
resp = resp1 ; respLen = resp1Len ; order = 1 ;
2012-06-29 18:24:05 +08:00
respdata = response1 ;
respsize = sizeof ( response1 ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 0 ] = = 0x52 ) { // Received a WAKEUP
2010-02-21 05:24:25 +08:00
resp = resp1 ; respLen = resp1Len ; order = 6 ;
2012-06-29 18:24:05 +08:00
respdata = response1 ;
respsize = sizeof ( response1 ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 1 ] = = 0x20 & & receivedCmd [ 0 ] = = 0x93 ) { // Received request for UID (cascade 1)
2010-02-21 05:24:25 +08:00
resp = resp2 ; respLen = resp2Len ; order = 2 ;
2012-06-29 18:24:05 +08:00
respdata = response2 ;
respsize = sizeof ( response2 ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 1 ] = = 0x20 & & receivedCmd [ 0 ] = = 0x95 ) { // Received request for UID (cascade 2)
2010-02-21 05:24:25 +08:00
resp = resp2a ; respLen = resp2aLen ; order = 20 ;
2012-06-29 18:24:05 +08:00
respdata = response2a ;
respsize = sizeof ( response2a ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 1 ] = = 0x70 & & receivedCmd [ 0 ] = = 0x93 ) { // Received a SELECT (cascade 1)
2010-02-21 05:24:25 +08:00
resp = resp3 ; respLen = resp3Len ; order = 3 ;
2012-06-29 18:24:05 +08:00
respdata = response3 ;
respsize = sizeof ( response3 ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 1 ] = = 0x70 & & receivedCmd [ 0 ] = = 0x95 ) { // Received a SELECT (cascade 2)
2010-02-21 05:24:25 +08:00
resp = resp3a ; respLen = resp3aLen ; order = 30 ;
2012-06-29 18:24:05 +08:00
respdata = response3a ;
respsize = sizeof ( response3a ) ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 0 ] = = 0x30 ) { // Received a (plain) READ
2013-03-28 22:02:00 +08:00
// resp = resp4; respLen = resp4Len; order = 4; // Do nothing
// respdata = &nack;
// respsize = sizeof(nack); // 4-bit answer
2013-09-29 03:28:55 +08:00
EmSendCmdEx ( data + ( 4 * receivedCmd [ 0 ] ) , 16 , false ) ;
2012-06-29 20:09:24 +08:00
Dbprintf ( " Read request from reader: %x %x " , receivedCmd [ 0 ] , receivedCmd [ 1 ] ) ;
2013-09-29 03:28:55 +08:00
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
respLen = 0 ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 0 ] = = 0x50 ) { // Received a HALT
2013-03-07 20:22:12 +08:00
// DbpString("Reader requested we HALT!:");
2012-06-29 20:09:24 +08:00
// Do not respond
resp = resp1 ; respLen = 0 ; order = 0 ;
2012-06-29 18:24:05 +08:00
respdata = NULL ;
respsize = 0 ;
2012-06-29 20:09:24 +08:00
} else if ( receivedCmd [ 0 ] = = 0x60 | | receivedCmd [ 0 ] = = 0x61 ) { // Received an authentication request
2010-02-21 05:24:25 +08:00
resp = resp5 ; respLen = resp5Len ; order = 7 ;
2012-06-29 20:09:24 +08:00
respdata = response5 ;
respsize = sizeof ( response5 ) ;
} else if ( receivedCmd [ 0 ] = = 0xE0 ) { // Received a RATS request
resp = resp6 ; respLen = resp6Len ; order = 70 ;
respdata = response6 ;
respsize = sizeof ( response6 ) ;
2012-06-29 18:24:05 +08:00
} else {
2013-03-07 20:22:12 +08:00
if ( order = = 7 & & len = = 8 ) {
uint32_t nr = bytes_to_num ( receivedCmd , 4 ) ;
uint32_t ar = bytes_to_num ( receivedCmd + 4 , 4 ) ;
Dbprintf ( " Auth attempt {nr}{ar}: %08x %08x " , nr , ar ) ;
} else {
// Never seen this command before
Dbprintf ( " Received unknown command (len=%d): " , len ) ;
Dbhexdump ( len , receivedCmd , false ) ;
}
// Do not respond
resp = resp1 ; respLen = 0 ; order = 0 ;
respdata = NULL ;
respsize = 0 ;
2012-06-29 18:24:05 +08:00
}
2010-02-21 05:24:25 +08:00
// Count number of wakeups received after a halt
if ( order = = 6 & & lastorder = = 5 ) { happened + + ; }
// Count number of other messages after a halt
if ( order ! = 6 & & lastorder = = 5 ) { happened2 + + ; }
// Look at last parity bit to determine timing of answer
if ( ( Uart . parityBits & 0x01 ) | | receivedCmd [ 0 ] = = 0x52 ) {
// 1236, so correction bit needed
2012-06-12 20:21:26 +08:00
//i = 0;
2010-02-21 05:24:25 +08:00
}
if ( cmdsRecvd > 999 ) {
DbpString ( " 1000 commands later... " ) ;
2012-06-29 20:09:24 +08:00
break ;
} else {
2010-02-21 05:24:25 +08:00
cmdsRecvd + + ;
}
2012-06-29 18:24:05 +08:00
if ( respLen > 0 ) {
EmSendCmd14443aRaw ( resp , respLen , receivedCmd [ 0 ] = = 0x52 ) ;
}
if ( tracing ) {
if ( respdata ! = NULL ) {
LogTrace ( respdata , respsize , 0 , SwapBits ( GetParity ( respdata , respsize ) , respsize ) , FALSE ) ;
}
2012-06-29 18:47:07 +08:00
if ( traceLen > TRACE_SIZE ) {
DbpString ( " Trace full " ) ;
break ;
}
2012-06-29 18:24:05 +08:00
}
2010-02-21 05:24:25 +08:00
2012-06-29 18:24:05 +08:00
memset ( receivedCmd , 0x44 , RECV_CMD_SIZE ) ;
2012-06-29 20:09:24 +08:00
}
2010-02-21 05:24:25 +08:00
Dbprintf ( " %x %x %x " , happened , happened2 , cmdsRecvd ) ;
LED_A_OFF ( ) ;
}
2013-09-15 17:33:17 +08:00
// prepare a delayed transfer. This simply shifts ToSend[] by a number
// of bits specified in the delay parameter.
void PrepareDelayedTransfer ( uint16_t delay )
{
uint8_t bitmask = 0 ;
uint8_t bits_to_shift = 0 ;
uint8_t bits_shifted = 0 ;
delay & = 0x07 ;
if ( delay ) {
for ( uint16_t i = 0 ; i < delay ; i + + ) {
bitmask | = ( 0x01 < < i ) ;
}
ToSend [ + + ToSendMax ] = 0x00 ;
for ( uint16_t i = 0 ; i < ToSendMax ; i + + ) {
bits_to_shift = ToSend [ i ] & bitmask ;
ToSend [ i ] = ToSend [ i ] > > delay ;
ToSend [ i ] = ToSend [ i ] | ( bits_shifted < < ( 8 - delay ) ) ;
bits_shifted = bits_to_shift ;
}
}
}
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[].
2013-09-15 17:33:17 +08:00
// Parameter timing:
// if NULL: ignored
// if == 0: return time of transfer
// if != 0: delay transfer until time specified
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2013-09-15 17:33:17 +08:00
static void TransmitFor14443a ( const uint8_t * cmd , int len , uint32_t * timing )
2010-02-21 05:24:25 +08:00
{
2013-09-15 17:33:17 +08:00
int c ;
2010-02-21 05:57:20 +08:00
2013-09-15 17:33:17 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD ) ;
2010-02-21 05:57:20 +08:00
2013-09-15 17:33:17 +08:00
if ( timing ) {
if ( * timing = = 0 ) { // Measure time
* timing = ( GetCountMifare ( ) + 8 ) & 0xfffffff8 ;
} else {
PrepareDelayedTransfer ( * timing & 0x00000007 ) ; // Delay transfer (fine tuning - up to 7 MF clock ticks)
}
if ( MF_DBGLEVEL > = 4 & & GetCountMifare ( ) > = ( * timing & 0xfffffff8 ) ) Dbprintf ( " TransmitFor14443a: Missed timing " ) ;
while ( GetCountMifare ( ) < ( * timing & 0xfffffff8 ) ) ; // Delay transfer (multiple of 8 MF clock ticks)
}
for ( c = 0 ; c < 10 ; ) { // standard delay for each transfer (allow tag to be ready after last transmission)
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) {
AT91C_BASE_SSC - > SSC_THR = 0x00 ;
c + + ;
}
}
c = 0 ;
for ( ; ; ) {
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) {
AT91C_BASE_SSC - > SSC_THR = cmd [ c ] ;
c + + ;
if ( c > = len ) {
break ;
}
}
}
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
}
//-----------------------------------------------------------------------------
2013-04-03 16:45:04 +08:00
// Prepare reader command (in bits, support short frames) to send to FPGA
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2013-04-03 16:45:04 +08:00
void CodeIso14443aBitsAsReaderPar ( const uint8_t * cmd , int bits , uint32_t dwParity )
2010-02-21 05:24:25 +08:00
{
int i , j ;
int last ;
2010-02-21 06:51:00 +08:00
uint8_t b ;
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
ToSendReset ( ) ;
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
// Start of Communication (Seq. Z)
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Z ;
2010-02-21 05:24:25 +08:00
last = 0 ;
2010-02-21 05:57:20 +08:00
2013-04-03 16:45:04 +08:00
size_t bytecount = nbytes ( bits ) ;
2010-02-21 05:24:25 +08:00
// Generate send structure for the data bits
2013-04-03 16:45:04 +08:00
for ( i = 0 ; i < bytecount ; i + + ) {
2010-02-21 05:24:25 +08:00
// Get the current byte to send
b = cmd [ i ] ;
2013-04-03 16:45:04 +08:00
size_t bitsleft = MIN ( ( bits - ( i * 8 ) ) , 8 ) ;
2010-02-21 05:57:20 +08:00
2013-04-03 16:45:04 +08:00
for ( j = 0 ; j < bitsleft ; j + + ) {
2010-02-21 05:24:25 +08:00
if ( b & 1 ) {
// Sequence X
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_X ;
2010-02-21 05:24:25 +08:00
last = 1 ;
} else {
if ( last = = 0 ) {
// Sequence Z
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Z ;
2010-02-21 05:24:25 +08:00
} else {
// Sequence Y
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Y ;
2010-02-21 05:24:25 +08:00
last = 0 ;
}
}
b > > = 1 ;
}
2010-02-21 05:57:20 +08:00
2013-04-03 16:45:04 +08:00
// Only transmit (last) parity bit if we transmitted a complete byte
if ( j = = 8 ) {
// Get the parity bit
if ( ( dwParity > > i ) & 0x01 ) {
// Sequence X
ToSend [ + + ToSendMax ] = SEC_X ;
last = 1 ;
2010-02-21 05:24:25 +08:00
} else {
2013-04-03 16:45:04 +08:00
if ( last = = 0 ) {
// Sequence Z
ToSend [ + + ToSendMax ] = SEC_Z ;
} else {
// Sequence Y
ToSend [ + + ToSendMax ] = SEC_Y ;
last = 0 ;
}
2010-02-21 05:24:25 +08:00
}
}
}
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
// End of Communication
if ( last = = 0 ) {
// Sequence Z
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Z ;
2010-02-21 05:24:25 +08:00
} else {
// Sequence Y
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Y ;
2010-02-21 05:24:25 +08:00
last = 0 ;
}
// Sequence Y
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Y ;
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
// Just to be sure!
2010-03-05 12:14:04 +08:00
ToSend [ + + ToSendMax ] = SEC_Y ;
ToSend [ + + ToSendMax ] = SEC_Y ;
ToSend [ + + ToSendMax ] = SEC_Y ;
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
// Convert from last character reference to length
ToSendMax + + ;
}
2013-04-03 16:45:04 +08:00
//-----------------------------------------------------------------------------
// Prepare reader command to send to FPGA
//-----------------------------------------------------------------------------
void CodeIso14443aAsReaderPar ( const uint8_t * cmd , int len , uint32_t dwParity )
{
CodeIso14443aBitsAsReaderPar ( cmd , len * 8 , dwParity ) ;
}
2011-06-10 21:35:10 +08:00
//-----------------------------------------------------------------------------
// Wait for commands from reader
// Stop when button is pressed (return 1) or field was gone (return 2)
// Or return 0 when command is captured
//-----------------------------------------------------------------------------
static int EmGetCmd ( uint8_t * received , int * len , int maxLen )
{
* len = 0 ;
uint32_t timer = 0 , vtime = 0 ;
int analogCnt = 0 ;
int analogAVG = 0 ;
// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
// only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN ) ;
// Set ADC to read field strength
AT91C_BASE_ADC - > ADC_CR = AT91C_ADC_SWRST ;
AT91C_BASE_ADC - > ADC_MR =
ADC_MODE_PRESCALE ( 32 ) |
ADC_MODE_STARTUP_TIME ( 16 ) |
ADC_MODE_SAMPLE_HOLD_TIME ( 8 ) ;
AT91C_BASE_ADC - > ADC_CHER = ADC_CHANNEL ( ADC_CHAN_HF ) ;
// start ADC
AT91C_BASE_ADC - > ADC_CR = AT91C_ADC_START ;
// Now run a 'software UART' on the stream of incoming samples.
Uart . output = received ;
Uart . byteCntMax = maxLen ;
Uart . state = STATE_UNSYNCD ;
for ( ; ; ) {
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) return 1 ;
// test if the field exists
if ( AT91C_BASE_ADC - > ADC_SR & ADC_END_OF_CONVERSION ( ADC_CHAN_HF ) ) {
analogCnt + + ;
analogAVG + = AT91C_BASE_ADC - > ADC_CDR [ ADC_CHAN_HF ] ;
AT91C_BASE_ADC - > ADC_CR = AT91C_ADC_START ;
if ( analogCnt > = 32 ) {
if ( ( 33000 * ( analogAVG / analogCnt ) > > 10 ) < MF_MINFIELDV ) {
vtime = GetTickCount ( ) ;
if ( ! timer ) timer = vtime ;
// 50ms no field --> card to idle state
if ( vtime - timer > 50 ) return 2 ;
} else
if ( timer ) timer = 0 ;
analogCnt = 0 ;
analogAVG = 0 ;
}
}
// transmit none
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) {
AT91C_BASE_SSC - > SSC_THR = 0x00 ;
}
// receive and test the miller decoding
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
volatile uint8_t b = ( uint8_t ) AT91C_BASE_SSC - > SSC_RHR ;
if ( MillerDecoding ( ( b & 0xf0 ) > > 4 ) ) {
* len = Uart . byteCnt ;
2011-06-16 22:43:49 +08:00
if ( tracing ) LogTrace ( received , * len , GetDeltaCountUS ( ) , Uart . parityBits , TRUE ) ;
2011-06-10 21:35:10 +08:00
return 0 ;
}
if ( MillerDecoding ( b & 0x0f ) ) {
* len = Uart . byteCnt ;
2011-06-16 22:43:49 +08:00
if ( tracing ) LogTrace ( received , * len , GetDeltaCountUS ( ) , Uart . parityBits , TRUE ) ;
2011-06-10 21:35:10 +08:00
return 0 ;
}
}
}
}
static int EmSendCmd14443aRaw ( uint8_t * resp , int respLen , int correctionNeeded )
{
int i , u = 0 ;
uint8_t b = 0 ;
// Modulate Manchester
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD ) ;
AT91C_BASE_SSC - > SSC_THR = 0x00 ;
FpgaSetupSsc ( ) ;
// include correction bit
i = 1 ;
if ( ( Uart . parityBits & 0x01 ) | | correctionNeeded ) {
// 1236, so correction bit needed
i = 0 ;
}
// send cycle
for ( ; ; ) {
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
volatile uint8_t b = ( uint8_t ) AT91C_BASE_SSC - > SSC_RHR ;
( void ) b ;
}
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) {
if ( i > respLen ) {
2011-06-16 22:43:49 +08:00
b = 0xff ; // was 0x00
2011-06-10 21:35:10 +08:00
u + + ;
} else {
b = resp [ i ] ;
i + + ;
}
AT91C_BASE_SSC - > SSC_THR = b ;
if ( u > 4 ) break ;
}
if ( BUTTON_PRESS ( ) ) {
break ;
}
}
return 0 ;
}
2011-06-16 22:43:49 +08:00
int EmSend4bitEx ( uint8_t resp , int correctionNeeded ) {
Code4bitAnswerAsTag ( resp ) ;
2011-06-14 23:28:21 +08:00
int res = EmSendCmd14443aRaw ( ToSend , ToSendMax , correctionNeeded ) ;
2011-06-16 22:43:49 +08:00
if ( tracing ) LogTrace ( & resp , 1 , GetDeltaCountUS ( ) , GetParity ( & resp , 1 ) , FALSE ) ;
2011-06-14 23:28:21 +08:00
return res ;
2011-06-10 21:35:10 +08:00
}
2011-06-16 22:43:49 +08:00
int EmSend4bit ( uint8_t resp ) {
return EmSend4bitEx ( resp , 0 ) ;
}
int EmSendCmdExPar ( uint8_t * resp , int respLen , int correctionNeeded , uint32_t par ) {
CodeIso14443aAsTagPar ( resp , respLen , par ) ;
int res = EmSendCmd14443aRaw ( ToSend , ToSendMax , correctionNeeded ) ;
if ( tracing ) LogTrace ( resp , respLen , GetDeltaCountUS ( ) , par , FALSE ) ;
return res ;
}
int EmSendCmdEx ( uint8_t * resp , int respLen , int correctionNeeded ) {
return EmSendCmdExPar ( resp , respLen , correctionNeeded , GetParity ( resp , respLen ) ) ;
}
int EmSendCmd ( uint8_t * resp , int respLen ) {
return EmSendCmdExPar ( resp , respLen , 0 , GetParity ( resp , respLen ) ) ;
}
int EmSendCmdPar ( uint8_t * resp , int respLen , uint32_t par ) {
return EmSendCmdExPar ( resp , respLen , 0 , par ) ;
2011-06-10 21:35:10 +08:00
}
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
// Wait a certain time for tag response
// If a response is captured return TRUE
// If it takes to long return FALSE
//-----------------------------------------------------------------------------
2010-02-21 06:51:00 +08:00
static int GetIso14443aAnswerFromTag ( uint8_t * receivedResponse , int maxLen , int * samples , int * elapsed ) //uint8_t *buffer
2010-02-21 05:24:25 +08:00
{
// buffer needs to be 512 bytes
int c ;
// Set FPGA mode to "reader listen mode", no modulation (listen
2010-07-13 21:39:30 +08:00
// only, since we are receiving, not transmitting).
// Signal field is on with the appropriate LED
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN ) ;
2013-07-09 01:56:05 +08:00
2010-07-13 21:39:30 +08:00
// Now get the answer from the card
Demod . output = receivedResponse ;
Demod . len = 0 ;
Demod . state = DEMOD_UNSYNCD ;
2010-02-21 05:24:25 +08:00
2010-02-21 06:51:00 +08:00
uint8_t b ;
2010-02-21 05:24:25 +08:00
if ( elapsed ) * elapsed = 0 ;
c = 0 ;
for ( ; ; ) {
2010-07-13 21:39:30 +08:00
WDT_HIT ( ) ;
2010-02-21 05:24:25 +08:00
2013-09-15 17:33:17 +08:00
// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
// AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
// if (elapsed) (*elapsed)++;
// }
2010-07-13 21:39:30 +08:00
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
if ( c < iso14a_timeout ) { c + + ; } else { return FALSE ; }
b = ( uint8_t ) AT91C_BASE_SSC - > SSC_RHR ;
2010-03-05 12:14:04 +08:00
if ( ManchesterDecoding ( ( b > > 4 ) & 0xf ) ) {
2010-02-21 05:24:25 +08:00
* samples = ( ( c - 1 ) < < 3 ) + 4 ;
return TRUE ;
}
if ( ManchesterDecoding ( b & 0x0f ) ) {
* samples = c < < 3 ;
return TRUE ;
}
2010-07-13 21:39:30 +08:00
}
}
2010-02-21 05:24:25 +08:00
}
2013-09-15 17:33:17 +08:00
void ReaderTransmitBitsPar ( uint8_t * frame , int bits , uint32_t par , uint32_t * timing )
2010-02-21 05:24:25 +08:00
{
2013-09-15 17:33:17 +08:00
2013-04-03 19:18:01 +08:00
CodeIso14443aBitsAsReaderPar ( frame , bits , par ) ;
2010-02-21 05:24:25 +08:00
// Select the card
2013-09-15 17:33:17 +08:00
TransmitFor14443a ( ToSend , ToSendMax , timing ) ;
2010-07-13 21:39:30 +08:00
if ( trigger )
LED_A_ON ( ) ;
2013-04-03 19:18:01 +08:00
2010-02-21 05:24:25 +08:00
// Store reader command in buffer
2013-04-03 19:18:01 +08:00
if ( tracing ) LogTrace ( frame , nbytes ( bits ) , 0 , par , TRUE ) ;
2010-02-21 05:24:25 +08:00
}
2013-09-15 17:33:17 +08:00
void ReaderTransmitPar ( uint8_t * frame , int len , uint32_t par , uint32_t * timing )
2013-04-03 19:18:01 +08:00
{
2013-09-15 17:33:17 +08:00
ReaderTransmitBitsPar ( frame , len * 8 , par , timing ) ;
2013-04-03 19:18:01 +08:00
}
2010-02-21 05:24:25 +08:00
2013-09-15 17:33:17 +08:00
void ReaderTransmit ( uint8_t * frame , int len , uint32_t * timing )
2010-02-21 05:24:25 +08:00
{
// Generate parity and redirect
2013-09-15 17:33:17 +08:00
ReaderTransmitBitsPar ( frame , len * 8 , GetParity ( frame , len ) , timing ) ;
2010-02-21 05:24:25 +08:00
}
2010-02-21 06:51:00 +08:00
int ReaderReceive ( uint8_t * receivedAnswer )
2010-02-21 05:24:25 +08:00
{
int samples = 0 ;
2011-05-26 20:55:15 +08:00
if ( ! GetIso14443aAnswerFromTag ( receivedAnswer , 160 , & samples , 0 ) ) return FALSE ;
2010-02-21 05:24:25 +08:00
if ( tracing ) LogTrace ( receivedAnswer , Demod . len , samples , Demod . parityBits , FALSE ) ;
2010-06-26 16:24:21 +08:00
if ( samples = = 0 ) return FALSE ;
return Demod . len ;
2010-02-21 05:24:25 +08:00
}
2011-05-31 19:31:20 +08:00
int ReaderReceivePar ( uint8_t * receivedAnswer , uint32_t * parptr )
{
int samples = 0 ;
if ( ! GetIso14443aAnswerFromTag ( receivedAnswer , 160 , & samples , 0 ) ) return FALSE ;
if ( tracing ) LogTrace ( receivedAnswer , Demod . len , samples , Demod . parityBits , FALSE ) ;
* parptr = Demod . parityBits ;
if ( samples = = 0 ) return FALSE ;
return Demod . len ;
}
2010-06-26 16:24:21 +08:00
/* performs iso14443a anticolision procedure
2010-07-13 21:39:30 +08:00
* fills the uid pointer unless NULL
* fills resp_data unless NULL */
2013-02-27 21:23:38 +08:00
int iso14443a_select_card ( byte_t * uid_ptr , iso14a_card_select_t * p_hi14a_card , uint32_t * cuid_ptr ) {
2013-05-03 14:58:24 +08:00
uint8_t wupa [ ] = { 0x52 } ; // 0x26 - REQA 0x52 - WAKE-UP
uint8_t sel_all [ ] = { 0x93 , 0x20 } ;
uint8_t sel_uid [ ] = { 0x93 , 0x70 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
uint8_t rats [ ] = { 0xE0 , 0x80 , 0x00 , 0x00 } ; // FSD=256, FSDI=8, CID=0
uint8_t * resp = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET ) ; // was 3560 - tied to other size changes
2013-02-27 21:23:38 +08:00
byte_t uid_resp [ 4 ] ;
size_t uid_resp_len ;
2010-02-21 05:24:25 +08:00
2013-05-03 14:58:24 +08:00
uint8_t sak = 0x04 ; // cascade uid
int cascade_level = 0 ;
int len ;
2013-02-27 21:23:38 +08:00
2013-05-03 14:58:24 +08:00
// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
2013-09-15 17:33:17 +08:00
ReaderTransmitBitsPar ( wupa , 7 , 0 , NULL ) ;
2013-05-03 14:58:24 +08:00
// Receive the ATQA
if ( ! ReaderReceive ( resp ) ) return 0 ;
2012-12-05 07:39:18 +08:00
// Dbprintf("atqa: %02x %02x",resp[0],resp[1]);
2013-07-09 01:56:05 +08:00
2013-05-03 14:58:24 +08:00
if ( p_hi14a_card ) {
memcpy ( p_hi14a_card - > atqa , resp , 2 ) ;
2013-02-27 21:23:38 +08:00
p_hi14a_card - > uidlen = 0 ;
memset ( p_hi14a_card - > uid , 0 , 10 ) ;
}
2013-09-29 03:28:55 +08:00
2013-02-27 21:23:38 +08:00
// clear uid
if ( uid_ptr ) {
2013-07-09 01:56:05 +08:00
memset ( uid_ptr , 0 , 10 ) ;
2013-02-27 21:23:38 +08:00
}
2013-05-03 14:58:24 +08:00
// OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in
// which case we need to make a cascade 2 request and select - this is a long UID
// While the UID is not complete, the 3nd bit (from the right) is set in the SAK.
for ( ; sak & 0x04 ; cascade_level + + ) {
// SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97)
sel_uid [ 0 ] = sel_all [ 0 ] = 0x93 + cascade_level * 2 ;
// SELECT_ALL
2013-09-15 17:33:17 +08:00
ReaderTransmit ( sel_all , sizeof ( sel_all ) , NULL ) ;
2013-05-03 14:58:24 +08:00
if ( ! ReaderReceive ( resp ) ) return 0 ;
2013-09-29 03:28:55 +08:00
2013-05-03 14:58:24 +08:00
// First backup the current uid
2013-02-27 21:23:38 +08:00
memcpy ( uid_resp , resp , 4 ) ;
uid_resp_len = 4 ;
// Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]);
2013-09-29 03:28:55 +08:00
// calculate crypto UID. Always use last 4 Bytes.
if ( cuid_ptr ) {
* cuid_ptr = bytes_to_num ( uid_resp , 4 ) ;
2013-02-27 21:23:38 +08:00
}
2010-02-21 05:57:20 +08:00
2013-05-03 14:58:24 +08:00
// Construct SELECT UID command
2013-09-29 03:28:55 +08:00
memcpy ( sel_uid + 2 , resp , 5 ) ;
2013-05-03 14:58:24 +08:00
AppendCrc14443a ( sel_uid , 7 ) ;
2013-09-15 17:33:17 +08:00
ReaderTransmit ( sel_uid , sizeof ( sel_uid ) , NULL ) ;
2010-07-13 21:39:30 +08:00
2013-05-03 14:58:24 +08:00
// Receive the SAK
if ( ! ReaderReceive ( resp ) ) return 0 ;
sak = resp [ 0 ] ;
2013-02-27 21:23:38 +08:00
// Test if more parts of the uid are comming
if ( ( sak & 0x04 ) & & uid_resp [ 0 ] = = 0x88 ) {
// Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of:
// http://www.nxp.com/documents/application_note/AN10927.pdf
2013-05-03 14:58:24 +08:00
memcpy ( uid_resp , uid_resp + 1 , 3 ) ;
2013-02-27 21:23:38 +08:00
uid_resp_len = 3 ;
}
2013-09-29 03:28:55 +08:00
2013-02-27 21:23:38 +08:00
if ( uid_ptr ) {
memcpy ( uid_ptr + ( cascade_level * 3 ) , uid_resp , uid_resp_len ) ;
}
2013-09-29 03:28:55 +08:00
2013-02-27 21:23:38 +08:00
if ( p_hi14a_card ) {
memcpy ( p_hi14a_card - > uid + ( cascade_level * 3 ) , uid_resp , uid_resp_len ) ;
p_hi14a_card - > uidlen + = uid_resp_len ;
}
2013-05-03 14:58:24 +08:00
}
2013-02-27 21:23:38 +08:00
2013-05-03 14:58:24 +08:00
if ( p_hi14a_card ) {
p_hi14a_card - > sak = sak ;
p_hi14a_card - > ats_len = 0 ;
}
2010-07-13 21:39:30 +08:00
2013-05-03 14:58:24 +08:00
if ( ( sak & 0x20 ) = = 0 ) {
return 2 ; // non iso14443a compliant tag
2013-02-27 21:23:38 +08:00
}
2010-07-13 21:39:30 +08:00
2013-05-03 14:58:24 +08:00
// Request for answer to select
2013-03-27 20:23:59 +08:00
AppendCrc14443a ( rats , 2 ) ;
2013-09-15 17:33:17 +08:00
ReaderTransmit ( rats , sizeof ( rats ) , NULL ) ;
2013-07-09 01:56:05 +08:00
2013-03-27 20:23:59 +08:00
if ( ! ( len = ReaderReceive ( resp ) ) ) return 0 ;
if ( p_hi14a_card ) {
2013-05-03 14:58:24 +08:00
memcpy ( p_hi14a_card - > ats , resp , sizeof ( p_hi14a_card - > ats ) ) ;
p_hi14a_card - > ats_len = len ;
}
2013-09-29 03:28:55 +08:00
2013-05-03 14:58:24 +08:00
// reset the PCB block number
iso14_pcb_blocknum = 0 ;
return 1 ;
2010-06-26 16:24:21 +08:00
}
2010-02-21 05:24:25 +08:00
2010-06-26 16:24:21 +08:00
void iso14443a_setup ( ) {
2013-09-15 17:33:17 +08:00
// Set up the synchronous serial port
FpgaSetupSsc ( ) ;
2010-06-26 16:24:21 +08:00
// Start from off (no field generated)
// Signal field is off with the appropriate LED
2013-09-15 17:33:17 +08:00
// LED_D_OFF();
// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// SpinDelay(50);
2010-02-21 05:24:25 +08:00
2010-06-26 16:24:21 +08:00
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2010-02-21 05:57:20 +08:00
2010-06-26 16:24:21 +08:00
// Now give it time to spin up.
// Signal field is on with the appropriate LED
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD ) ;
2013-09-15 17:33:17 +08:00
SpinDelay ( 7 ) ; // iso14443-3 specifies 5ms max.
2010-07-13 21:39:30 +08:00
iso14a_timeout = 2048 ; //default
2010-06-26 16:24:21 +08:00
}
2010-02-21 05:24:25 +08:00
2010-07-13 21:39:30 +08:00
int iso14_apdu ( uint8_t * cmd , size_t cmd_len , void * data ) {
uint8_t real_cmd [ cmd_len + 4 ] ;
real_cmd [ 0 ] = 0x0a ; //I-Block
2012-08-25 05:00:03 +08:00
// put block number into the PCB
real_cmd [ 0 ] | = iso14_pcb_blocknum ;
2010-07-13 21:39:30 +08:00
real_cmd [ 1 ] = 0x00 ; //CID: 0 //FIXME: allow multiple selected cards
memcpy ( real_cmd + 2 , cmd , cmd_len ) ;
AppendCrc14443a ( real_cmd , cmd_len + 2 ) ;
2013-09-15 17:33:17 +08:00
ReaderTransmit ( real_cmd , cmd_len + 4 , NULL ) ;
2010-07-13 21:39:30 +08:00
size_t len = ReaderReceive ( data ) ;
2012-08-25 05:00:03 +08:00
uint8_t * data_bytes = ( uint8_t * ) data ;
if ( ! len )
return 0 ; //DATA LINK ERROR
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
else if ( len > = 4 // PCB+CID+CRC = 4 bytes
& & ( ( data_bytes [ 0 ] & 0xC0 ) = = 0 // I-Block
| | ( data_bytes [ 0 ] & 0xD0 ) = = 0x80 ) // R-Block with ACK bit set to 0
& & ( data_bytes [ 0 ] & 0x01 ) = = iso14_pcb_blocknum ) // equal block numbers
{
iso14_pcb_blocknum ^ = 1 ;
}
2010-07-13 21:39:30 +08:00
return len ;
}
2010-06-26 16:24:21 +08:00
//-----------------------------------------------------------------------------
// Read an ISO 14443a tag. Send out commands and store answers.
//
//-----------------------------------------------------------------------------
2012-12-05 07:39:18 +08:00
void ReaderIso14443a ( UsbCommand * c )
2010-06-26 16:24:21 +08:00
{
2010-07-13 21:39:30 +08:00
iso14a_command_t param = c - > arg [ 0 ] ;
uint8_t * cmd = c - > d . asBytes ;
size_t len = c - > arg [ 1 ] ;
2013-09-29 03:28:55 +08:00
size_t lenbits = c - > arg [ 2 ] ;
2013-09-15 17:33:17 +08:00
uint32_t arg0 = 0 ;
byte_t buf [ USB_CMD_DATA_SIZE ] ;
2012-12-05 07:39:18 +08:00
2013-09-29 03:28:55 +08:00
if ( param & ISO14A_CONNECT ) {
iso14a_clear_trace ( ) ;
}
2013-09-15 17:33:17 +08:00
iso14a_set_tracing ( true ) ;
2010-02-21 05:57:20 +08:00
2013-02-27 21:23:38 +08:00
if ( param & ISO14A_REQUEST_TRIGGER ) {
2013-09-15 17:33:17 +08:00
iso14a_set_trigger ( 1 ) ;
}
2010-02-21 05:24:25 +08:00
2010-07-13 21:39:30 +08:00
if ( param & ISO14A_CONNECT ) {
iso14443a_setup ( ) ;
2013-09-29 03:28:55 +08:00
if ( ! ( param & ISO14A_NO_SELECT ) ) {
iso14a_card_select_t * card = ( iso14a_card_select_t * ) buf ;
arg0 = iso14443a_select_card ( NULL , card , NULL ) ;
cmd_send ( CMD_ACK , arg0 , card - > uidlen , 0 , buf , sizeof ( iso14a_card_select_t ) ) ;
}
2010-07-13 21:39:30 +08:00
}
2010-02-21 05:57:20 +08:00
2010-07-13 21:39:30 +08:00
if ( param & ISO14A_SET_TIMEOUT ) {
iso14a_timeout = c - > arg [ 2 ] ;
}
2010-02-21 05:57:20 +08:00
2010-07-13 21:39:30 +08:00
if ( param & ISO14A_SET_TIMEOUT ) {
iso14a_timeout = c - > arg [ 2 ] ;
}
2010-02-21 05:57:20 +08:00
2010-07-13 21:39:30 +08:00
if ( param & ISO14A_APDU ) {
2012-12-05 07:39:18 +08:00
arg0 = iso14_apdu ( cmd , len , buf ) ;
2013-02-27 21:23:38 +08:00
cmd_send ( CMD_ACK , arg0 , 0 , 0 , buf , sizeof ( buf ) ) ;
2010-07-13 21:39:30 +08:00
}
2010-02-21 05:57:20 +08:00
2010-07-13 21:39:30 +08:00
if ( param & ISO14A_RAW ) {
if ( param & ISO14A_APPEND_CRC ) {
AppendCrc14443a ( cmd , len ) ;
len + = 2 ;
2010-02-21 05:24:25 +08:00
}
2013-09-29 03:28:55 +08:00
if ( lenbits > 0 ) {
ReaderTransmitBitsPar ( cmd , lenbits , GetParity ( cmd , lenbits / 8 ) , NULL ) ;
} else {
ReaderTransmit ( cmd , len , NULL ) ;
}
2012-12-05 07:39:18 +08:00
arg0 = ReaderReceive ( buf ) ;
2013-09-15 17:33:17 +08:00
cmd_send ( CMD_ACK , arg0 , 0 , 0 , buf , sizeof ( buf ) ) ;
2010-07-13 21:39:30 +08:00
}
2010-02-21 05:24:25 +08:00
2013-02-27 21:23:38 +08:00
if ( param & ISO14A_REQUEST_TRIGGER ) {
2013-09-15 17:33:17 +08:00
iso14a_set_trigger ( 0 ) ;
}
2010-02-21 05:24:25 +08:00
2013-02-27 21:23:38 +08:00
if ( param & ISO14A_NO_DISCONNECT ) {
2010-07-13 21:39:30 +08:00
return ;
2013-09-15 17:33:17 +08:00
}
2010-02-21 05:24:25 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
}
2012-08-25 05:00:03 +08:00
2013-07-09 01:56:05 +08:00
// Determine the distance between two nonces.
// Assume that the difference is small, but we don't know which is first.
// Therefore try in alternating directions.
int32_t dist_nt ( uint32_t nt1 , uint32_t nt2 ) {
uint16_t i ;
uint32_t nttmp1 , nttmp2 ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
if ( nt1 = = nt2 ) return 0 ;
nttmp1 = nt1 ;
nttmp2 = nt2 ;
for ( i = 1 ; i < 32768 ; i + + ) {
nttmp1 = prng_successor ( nttmp1 , 1 ) ;
if ( nttmp1 = = nt2 ) return i ;
nttmp2 = prng_successor ( nttmp2 , 1 ) ;
if ( nttmp2 = = nt1 ) return - i ;
}
return ( - 99999 ) ; // either nt1 or nt2 are invalid nonces
2013-06-27 05:13:02 +08:00
}
2013-07-09 01:56:05 +08:00
//-----------------------------------------------------------------------------
// Recover several bits of the cypher stream. This implements (first stages of)
// the algorithm described in "The Dark Side of Security by Obscurity and
// Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime"
// (article by Nicolas T. Courtois, 2009)
//-----------------------------------------------------------------------------
void ReaderMifare ( bool first_try )
{
// Mifare AUTH
uint8_t mf_auth [ ] = { 0x60 , 0x00 , 0xf5 , 0x7b } ;
uint8_t mf_nr_ar [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
static uint8_t mf_nr_ar3 ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
uint8_t * receivedAnswer = ( ( ( uint8_t * ) BigBuf ) + FREE_BUFFER_OFFSET ) ;
traceLen = 0 ;
tracing = false ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
byte_t nt_diff = 0 ;
byte_t par = 0 ;
//byte_t par_mask = 0xff;
static byte_t par_low = 0 ;
bool led_on = TRUE ;
uint8_t uid [ 10 ] ;
uint32_t cuid ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
uint32_t nt , previous_nt ;
static uint32_t nt_attacked = 0 ;
byte_t par_list [ 8 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
byte_t ks_list [ 8 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
static uint32_t sync_time ;
static uint32_t sync_cycles ;
int catch_up_cycles = 0 ;
int last_catch_up = 0 ;
uint16_t consecutive_resyncs = 0 ;
int isOK = 0 ;
2013-06-27 05:13:02 +08:00
2013-07-09 01:56:05 +08:00
if ( first_try ) {
StartCountMifare ( ) ;
mf_nr_ar3 = 0 ;
iso14443a_setup ( ) ;
while ( ( GetCountMifare ( ) & 0xffff0000 ) ! = 0x10000 ) ; // wait for counter to reset and "warm up"
2013-09-15 17:33:17 +08:00
sync_time = GetCountMifare ( ) & 0xfffffff8 ;
2013-07-09 01:56:05 +08:00
sync_cycles = 65536 ; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
nt_attacked = 0 ;
nt = 0 ;
par = 0 ;
}
else {
// we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same)
// nt_attacked = prng_successor(nt_attacked, 1);
mf_nr_ar3 + + ;
mf_nr_ar [ 3 ] = mf_nr_ar3 ;
par = par_low ;
}
2010-02-21 05:57:20 +08:00
2010-02-21 05:24:25 +08:00
LED_A_ON ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
2013-07-09 01:56:05 +08:00
for ( uint16_t i = 0 ; TRUE ; i + + ) {
WDT_HIT ( ) ;
2010-02-21 05:57:20 +08:00
2013-07-09 01:56:05 +08:00
// Test if the action was cancelled
if ( BUTTON_PRESS ( ) ) {
break ;
}
LED_C_ON ( ) ;
2010-02-21 05:57:20 +08:00
2013-07-09 01:56:05 +08:00
if ( ! iso14443a_select_card ( uid , NULL , & cuid ) ) {
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Mifare: Can't select card " ) ;
2013-07-09 01:56:05 +08:00
continue ;
}
//keep the card active
2011-05-31 19:31:20 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD ) ;
2010-02-21 05:57:20 +08:00
2013-09-15 17:33:17 +08:00
// CodeIso14443aBitsAsReaderPar(mf_auth, sizeof(mf_auth)*8, GetParity(mf_auth, sizeof(mf_auth)*8));
2013-07-09 01:56:05 +08:00
2013-09-15 17:33:17 +08:00
sync_time = ( sync_time & 0xfffffff8 ) + sync_cycles + catch_up_cycles ;
2013-07-09 01:56:05 +08:00
catch_up_cycles = 0 ;
// if we missed the sync time already, advance to the next nonce repeat
while ( GetCountMifare ( ) > sync_time ) {
2013-09-15 17:33:17 +08:00
sync_time = ( sync_time & 0xfffffff8 ) + sync_cycles ;
2013-07-09 01:56:05 +08:00
}
2010-02-21 05:57:20 +08:00
2013-09-15 17:33:17 +08:00
// Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
ReaderTransmit ( mf_auth , sizeof ( mf_auth ) , & sync_time ) ;
2011-05-31 19:31:20 +08:00
2013-07-09 01:56:05 +08:00
// Receive the (4 Byte) "random" nonce
if ( ! ReaderReceive ( receivedAnswer ) ) {
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Mifare: Couldn't receive tag nonce " ) ;
2013-07-09 01:56:05 +08:00
continue ;
}
previous_nt = nt ;
nt = bytes_to_num ( receivedAnswer , 4 ) ;
// Transmit reader nonce with fake par
2013-09-15 17:33:17 +08:00
ReaderTransmitPar ( mf_nr_ar , sizeof ( mf_nr_ar ) , par , NULL ) ;
2013-07-09 01:56:05 +08:00
if ( first_try & & previous_nt & & ! nt_attacked ) { // we didn't calibrate our clock yet
int nt_distance = dist_nt ( previous_nt , nt ) ;
if ( nt_distance = = 0 ) {
nt_attacked = nt ;
}
else {
if ( nt_distance = = - 99999 ) { // invalid nonce received, try again
continue ;
}
sync_cycles = ( sync_cycles - nt_distance ) ;
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d \n " , i , nt_distance , sync_cycles ) ;
2013-07-09 01:56:05 +08:00
continue ;
}
}
if ( ( nt ! = nt_attacked ) & & nt_attacked ) { // we somehow lost sync. Try to catch up again...
catch_up_cycles = - dist_nt ( nt_attacked , nt ) ;
if ( catch_up_cycles = = 99999 ) { // invalid nonce received. Don't resync on that one.
catch_up_cycles = 0 ;
continue ;
}
if ( catch_up_cycles = = last_catch_up ) {
consecutive_resyncs + + ;
}
else {
last_catch_up = catch_up_cycles ;
consecutive_resyncs = 0 ;
}
if ( consecutive_resyncs < 3 ) {
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up... \n " , i , - catch_up_cycles , consecutive_resyncs ) ;
2013-07-09 01:56:05 +08:00
}
else {
sync_cycles = sync_cycles + catch_up_cycles ;
2013-09-15 17:33:17 +08:00
if ( MF_DBGLEVEL > = 3 ) Dbprintf ( " Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d. \n " , i , - catch_up_cycles , sync_cycles ) ;
2013-07-09 01:56:05 +08:00
}
continue ;
}
consecutive_resyncs = 0 ;
// Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding
if ( ReaderReceive ( receivedAnswer ) )
{
2013-09-15 17:33:17 +08:00
catch_up_cycles = 8 ; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
2013-07-09 01:56:05 +08:00
if ( nt_diff = = 0 )
{
par_low = par & 0x07 ; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change
}
led_on = ! led_on ;
if ( led_on ) LED_B_ON ( ) ; else LED_B_OFF ( ) ;
par_list [ nt_diff ] = par ;
ks_list [ nt_diff ] = receivedAnswer [ 0 ] ^ 0x05 ;
// Test if the information is complete
if ( nt_diff = = 0x07 ) {
isOK = 1 ;
break ;
}
nt_diff = ( nt_diff + 1 ) & 0x07 ;
mf_nr_ar [ 3 ] = ( mf_nr_ar [ 3 ] & 0x1F ) | ( nt_diff < < 5 ) ;
par = par_low ;
} else {
if ( nt_diff = = 0 & & first_try )
{
par + + ;
} else {
par = ( ( ( par > > 3 ) + 1 ) < < 3 ) | par_low ;
}
}
}
LogTrace ( ( const uint8_t * ) & nt , 4 , 0 , GetParity ( ( const uint8_t * ) & nt , 4 ) , TRUE ) ;
LogTrace ( par_list , 8 , 0 , GetParity ( par_list , 8 ) , TRUE ) ;
LogTrace ( ks_list , 8 , 0 , GetParity ( ks_list , 8 ) , TRUE ) ;
mf_nr_ar [ 3 ] & = 0x1F ;
byte_t buf [ 28 ] ;
memcpy ( buf + 0 , uid , 4 ) ;
num_to_bytes ( nt , 4 , buf + 4 ) ;
memcpy ( buf + 8 , par_list , 8 ) ;
memcpy ( buf + 16 , ks_list , 8 ) ;
memcpy ( buf + 24 , mf_nr_ar , 4 ) ;
cmd_send ( CMD_ACK , isOK , 0 , 0 , buf , 28 ) ;
// Thats it...
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
tracing = TRUE ;
2011-05-26 20:55:15 +08:00
}
2013-07-09 01:56:05 +08:00
2011-05-26 20:55:15 +08:00
//-----------------------------------------------------------------------------
// MIFARE 1K simulate.
//
//-----------------------------------------------------------------------------
void Mifare1ksim ( uint8_t arg0 , uint8_t arg1 , uint8_t arg2 , uint8_t * datain )
{
2011-06-01 22:12:11 +08:00
int cardSTATE = MFEMUL_NOFIELD ;
2011-06-18 02:39:54 +08:00
int _7BUID = 0 ;
2011-06-10 21:35:10 +08:00
int vHf = 0 ; // in mV
2012-06-12 20:21:26 +08:00
//int nextCycleTimeout = 0;
2011-06-16 22:43:49 +08:00
int res ;
2011-06-24 00:49:39 +08:00
// uint32_t timer = 0;
2011-06-14 23:28:21 +08:00
uint32_t selTimer = 0 ;
uint32_t authTimer = 0 ;
uint32_t par = 0 ;
2011-06-10 21:35:10 +08:00
int len = 0 ;
2011-06-16 22:43:49 +08:00
uint8_t cardWRBL = 0 ;
2011-06-10 21:35:10 +08:00
uint8_t cardAUTHSC = 0 ;
uint8_t cardAUTHKEY = 0xff ; // no authentication
2012-06-12 20:21:26 +08:00
//uint32_t cardRn = 0;
2011-06-24 00:49:39 +08:00
uint32_t cardRr = 0 ;
2011-06-10 21:35:10 +08:00
uint32_t cuid = 0 ;
2012-06-12 20:21:26 +08:00
//uint32_t rn_enc = 0;
2011-06-24 00:49:39 +08:00
uint32_t ans = 0 ;
2011-06-25 21:03:01 +08:00
uint32_t cardINTREG = 0 ;
uint8_t cardINTBLOCK = 0 ;
2011-06-10 21:35:10 +08:00
struct Crypto1State mpcs = { 0 , 0 } ;
struct Crypto1State * pcs ;
pcs = & mpcs ;
2011-06-16 22:43:49 +08:00
uint8_t * receivedCmd = eml_get_bigbufptr_recbuf ( ) ;
uint8_t * response = eml_get_bigbufptr_sendbuf ( ) ;
2011-06-10 21:35:10 +08:00
2011-06-18 02:39:54 +08:00
static uint8_t rATQA [ ] = { 0x04 , 0x00 } ; // Mifare classic 1k 4BUID
2011-06-10 21:35:10 +08:00
2011-06-14 23:28:21 +08:00
static uint8_t rUIDBCC1 [ ] = { 0xde , 0xad , 0xbe , 0xaf , 0x62 } ;
static uint8_t rUIDBCC2 [ ] = { 0xde , 0xad , 0xbe , 0xaf , 0x62 } ; // !!!
2011-06-10 21:35:10 +08:00
2011-06-14 23:28:21 +08:00
static uint8_t rSAK [ ] = { 0x08 , 0xb6 , 0xdd } ;
2011-06-18 02:39:54 +08:00
static uint8_t rSAK1 [ ] = { 0x04 , 0xda , 0x17 } ;
2011-06-10 21:35:10 +08:00
2011-06-25 21:03:01 +08:00
static uint8_t rAUTH_NT [ ] = { 0x01 , 0x02 , 0x03 , 0x04 } ;
// static uint8_t rAUTH_NT[] = {0x1a, 0xac, 0xff, 0x4f};
2011-06-14 23:28:21 +08:00
static uint8_t rAUTH_AT [ ] = { 0x00 , 0x00 , 0x00 , 0x00 } ;
2011-06-25 21:03:01 +08:00
2011-06-14 23:28:21 +08:00
// clear trace
traceLen = 0 ;
tracing = true ;
2011-06-24 00:49:39 +08:00
// Authenticate response - nonce
uint32_t nonce = bytes_to_num ( rAUTH_NT , 4 ) ;
2011-06-10 21:35:10 +08:00
2011-06-18 02:39:54 +08:00
// get UID from emul memory
emlGetMemBt ( receivedCmd , 7 , 1 ) ;
_7BUID = ! ( receivedCmd [ 0 ] = = 0x00 ) ;
if ( ! _7BUID ) { // ---------- 4BUID
rATQA [ 0 ] = 0x04 ;
emlGetMemBt ( rUIDBCC1 , 0 , 4 ) ;
rUIDBCC1 [ 4 ] = rUIDBCC1 [ 0 ] ^ rUIDBCC1 [ 1 ] ^ rUIDBCC1 [ 2 ] ^ rUIDBCC1 [ 3 ] ;
} else { // ---------- 7BUID
rATQA [ 0 ] = 0x44 ;
rUIDBCC1 [ 0 ] = 0x88 ;
emlGetMemBt ( & rUIDBCC1 [ 1 ] , 0 , 3 ) ;
rUIDBCC1 [ 4 ] = rUIDBCC1 [ 0 ] ^ rUIDBCC1 [ 1 ] ^ rUIDBCC1 [ 2 ] ^ rUIDBCC1 [ 3 ] ;
emlGetMemBt ( rUIDBCC2 , 3 , 4 ) ;
rUIDBCC2 [ 4 ] = rUIDBCC2 [ 0 ] ^ rUIDBCC2 [ 1 ] ^ rUIDBCC2 [ 2 ] ^ rUIDBCC2 [ 3 ] ;
}
2011-06-10 21:35:10 +08:00
// -------------------------------------- test area
2011-06-01 22:12:11 +08:00
2011-06-10 21:35:10 +08:00
// -------------------------------------- END test area
2011-06-16 22:43:49 +08:00
// start mkseconds counter
StartCountUS ( ) ;
2011-06-10 21:35:10 +08:00
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
FpgaSetupSsc ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN ) ;
SpinDelay ( 200 ) ;
2011-06-25 21:03:01 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Started. 7buid=%d " , _7BUID ) ;
2011-06-16 22:43:49 +08:00
// calibrate mkseconds counter
GetDeltaCountUS ( ) ;
2011-06-10 21:35:10 +08:00
while ( true ) {
WDT_HIT ( ) ;
2011-06-16 22:43:49 +08:00
if ( BUTTON_PRESS ( ) ) {
break ;
}
2011-06-10 21:35:10 +08:00
// find reader field
// Vref = 3300mV, and an 10:1 voltage divider on the input
// can measure voltages up to 33000 mV
if ( cardSTATE = = MFEMUL_NOFIELD ) {
vHf = ( 33000 * AvgAdc ( ADC_CHAN_HF ) ) > > 10 ;
if ( vHf > MF_MINFIELDV ) {
2011-06-25 21:03:01 +08:00
cardSTATE_TO_IDLE ( ) ;
2011-06-10 21:35:10 +08:00
LED_A_ON ( ) ;
}
}
if ( cardSTATE ! = MFEMUL_NOFIELD ) {
2012-06-29 18:24:05 +08:00
res = EmGetCmd ( receivedCmd , & len , RECV_CMD_SIZE ) ; // (+ nextCycleTimeout)
2011-06-10 21:35:10 +08:00
if ( res = = 2 ) {
cardSTATE = MFEMUL_NOFIELD ;
LEDsoff ( ) ;
continue ;
}
if ( res ) break ;
}
2012-06-12 20:21:26 +08:00
//nextCycleTimeout = 0;
2011-06-16 22:43:49 +08:00
2011-06-10 21:35:10 +08:00
// if (len) Dbprintf("len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]);
2011-06-14 23:28:21 +08:00
if ( len ! = 4 & & cardSTATE ! = MFEMUL_NOFIELD ) { // len != 4 <---- speed up the code 4 authentication
2011-06-16 22:43:49 +08:00
// REQ or WUP request in ANY state and WUP in HALTED state
2011-06-14 23:28:21 +08:00
if ( len = = 1 & & ( ( receivedCmd [ 0 ] = = 0x26 & & cardSTATE ! = MFEMUL_HALTED ) | | receivedCmd [ 0 ] = = 0x52 ) ) {
selTimer = GetTickCount ( ) ;
EmSendCmdEx ( rATQA , sizeof ( rATQA ) , ( receivedCmd [ 0 ] = = 0x52 ) ) ;
cardSTATE = MFEMUL_SELECT1 ;
// init crypto block
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
crypto1_destroy ( pcs ) ;
cardAUTHKEY = 0xff ;
}
}
2011-06-10 21:35:10 +08:00
2011-06-01 22:12:11 +08:00
switch ( cardSTATE ) {
case MFEMUL_NOFIELD : {
break ;
}
2011-06-10 21:35:10 +08:00
case MFEMUL_HALTED : {
2011-06-14 23:28:21 +08:00
break ;
2011-06-10 21:35:10 +08:00
}
2011-06-01 22:12:11 +08:00
case MFEMUL_IDLE : {
break ;
}
case MFEMUL_SELECT1 : {
2011-06-10 21:35:10 +08:00
// select all
if ( len = = 2 & & ( receivedCmd [ 0 ] = = 0x93 & & receivedCmd [ 1 ] = = 0x20 ) ) {
EmSendCmd ( rUIDBCC1 , sizeof ( rUIDBCC1 ) ) ;
2011-06-25 21:03:01 +08:00
break ;
2011-06-10 21:35:10 +08:00
}
// select card
2011-06-14 23:28:21 +08:00
if ( len = = 9 & &
( receivedCmd [ 0 ] = = 0x93 & & receivedCmd [ 1 ] = = 0x70 & & memcmp ( & receivedCmd [ 2 ] , rUIDBCC1 , 4 ) = = 0 ) ) {
2011-06-18 02:39:54 +08:00
if ( ! _7BUID )
EmSendCmd ( rSAK , sizeof ( rSAK ) ) ;
else
EmSendCmd ( rSAK1 , sizeof ( rSAK1 ) ) ;
2011-06-10 21:35:10 +08:00
cuid = bytes_to_num ( rUIDBCC1 , 4 ) ;
2011-06-18 02:39:54 +08:00
if ( ! _7BUID ) {
cardSTATE = MFEMUL_WORK ;
2011-06-25 21:03:01 +08:00
LED_B_ON ( ) ;
if ( MF_DBGLEVEL > = 4 ) Dbprintf ( " --> WORK. anticol1 time: %d " , GetTickCount ( ) - selTimer ) ;
break ;
2011-06-18 02:39:54 +08:00
} else {
cardSTATE = MFEMUL_SELECT2 ;
break ;
}
2011-06-10 21:35:10 +08:00
}
2011-06-01 22:12:11 +08:00
break ;
}
case MFEMUL_SELECT2 : {
2011-06-25 21:03:01 +08:00
if ( ! len ) break ;
2011-06-18 02:39:54 +08:00
if ( len = = 2 & & ( receivedCmd [ 0 ] = = 0x95 & & receivedCmd [ 1 ] = = 0x20 ) ) {
2011-06-10 21:35:10 +08:00
EmSendCmd ( rUIDBCC2 , sizeof ( rUIDBCC2 ) ) ;
2011-06-18 02:39:54 +08:00
break ;
}
2011-06-10 21:35:10 +08:00
2011-06-18 02:39:54 +08:00
// select 2 card
if ( len = = 9 & &
( receivedCmd [ 0 ] = = 0x95 & & receivedCmd [ 1 ] = = 0x70 & & memcmp ( & receivedCmd [ 2 ] , rUIDBCC2 , 4 ) = = 0 ) ) {
EmSendCmd ( rSAK , sizeof ( rSAK ) ) ;
cuid = bytes_to_num ( rUIDBCC2 , 4 ) ;
cardSTATE = MFEMUL_WORK ;
LED_B_ON ( ) ;
2011-06-25 21:03:01 +08:00
if ( MF_DBGLEVEL > = 4 ) Dbprintf ( " --> WORK. anticol2 time: %d " , GetTickCount ( ) - selTimer ) ;
2011-06-18 02:39:54 +08:00
break ;
}
2011-06-25 21:03:01 +08:00
// i guess there is a command). go into the work state.
if ( len ! = 4 ) break ;
cardSTATE = MFEMUL_WORK ;
goto lbWORK ;
2011-06-01 22:12:11 +08:00
}
case MFEMUL_AUTH1 : {
2011-06-10 21:35:10 +08:00
if ( len = = 8 ) {
2011-06-24 00:49:39 +08:00
// --- crypto
2012-06-12 20:21:26 +08:00
//rn_enc = bytes_to_num(receivedCmd, 4);
//cardRn = rn_enc ^ crypto1_word(pcs, rn_enc , 1);
2011-06-24 00:49:39 +08:00
cardRr = bytes_to_num ( & receivedCmd [ 4 ] , 4 ) ^ crypto1_word ( pcs , 0 , 0 ) ;
// test if auth OK
if ( cardRr ! = prng_successor ( nonce , 64 ) ) {
2011-06-25 21:03:01 +08:00
if ( MF_DBGLEVEL > = 4 ) Dbprintf ( " AUTH FAILED. cardRr=%08x, succ=%08x " , cardRr , prng_successor ( nonce , 64 ) ) ;
cardSTATE_TO_IDLE ( ) ;
2011-06-24 00:49:39 +08:00
break ;
}
ans = prng_successor ( nonce , 96 ) ^ crypto1_word ( pcs , 0 , 0 ) ;
num_to_bytes ( ans , 4 , rAUTH_AT ) ;
// --- crypto
EmSendCmd ( rAUTH_AT , sizeof ( rAUTH_AT ) ) ;
2011-06-14 23:28:21 +08:00
cardSTATE = MFEMUL_AUTH2 ;
} else {
2011-06-25 21:03:01 +08:00
cardSTATE_TO_IDLE ( ) ;
2011-06-10 21:35:10 +08:00
}
2011-06-14 23:28:21 +08:00
if ( cardSTATE ! = MFEMUL_AUTH2 ) break ;
2011-06-01 22:12:11 +08:00
}
case MFEMUL_AUTH2 : {
2011-06-10 21:35:10 +08:00
LED_C_ON ( ) ;
2011-06-14 23:28:21 +08:00
cardSTATE = MFEMUL_WORK ;
2011-06-25 21:03:01 +08:00
if ( MF_DBGLEVEL > = 4 ) Dbprintf ( " AUTH COMPLETED. sec=%d, key=%d time=%d " , cardAUTHSC , cardAUTHKEY , GetTickCount ( ) - authTimer ) ;
2011-06-01 22:12:11 +08:00
break ;
}
2011-06-10 21:35:10 +08:00
case MFEMUL_WORK : {
2011-06-25 21:03:01 +08:00
lbWORK : if ( len = = 0 ) break ;
2011-06-14 23:28:21 +08:00
2011-06-24 00:49:39 +08:00
if ( cardAUTHKEY = = 0xff ) {
// first authentication
if ( len = = 4 & & ( receivedCmd [ 0 ] = = 0x60 | | receivedCmd [ 0 ] = = 0x61 ) ) {
authTimer = GetTickCount ( ) ;
cardAUTHSC = receivedCmd [ 1 ] / 4 ; // received block num
cardAUTHKEY = receivedCmd [ 0 ] - 0x60 ;
// --- crypto
crypto1_create ( pcs , emlGetKey ( cardAUTHSC , cardAUTHKEY ) ) ;
ans = nonce ^ crypto1_word ( pcs , cuid ^ nonce , 0 ) ;
num_to_bytes ( nonce , 4 , rAUTH_AT ) ;
EmSendCmd ( rAUTH_AT , sizeof ( rAUTH_AT ) ) ;
// --- crypto
// last working revision
// EmSendCmd14443aRaw(resp1, resp1Len, 0);
// LogTrace(NULL, 0, GetDeltaCountUS(), 0, true);
cardSTATE = MFEMUL_AUTH1 ;
2012-06-12 20:21:26 +08:00
//nextCycleTimeout = 10;
2011-06-24 00:49:39 +08:00
break ;
}
} else {
// decrypt seqence
mf_crypto1_decrypt ( pcs , receivedCmd , len ) ;
// nested authentication
if ( len = = 4 & & ( receivedCmd [ 0 ] = = 0x60 | | receivedCmd [ 0 ] = = 0x61 ) ) {
authTimer = GetTickCount ( ) ;
cardAUTHSC = receivedCmd [ 1 ] / 4 ; // received block num
cardAUTHKEY = receivedCmd [ 0 ] - 0x60 ;
// --- crypto
crypto1_create ( pcs , emlGetKey ( cardAUTHSC , cardAUTHKEY ) ) ;
ans = nonce ^ crypto1_word ( pcs , cuid ^ nonce , 0 ) ;
num_to_bytes ( ans , 4 , rAUTH_AT ) ;
EmSendCmd ( rAUTH_AT , sizeof ( rAUTH_AT ) ) ;
// --- crypto
cardSTATE = MFEMUL_AUTH1 ;
2012-06-12 20:21:26 +08:00
//nextCycleTimeout = 10;
2011-06-24 00:49:39 +08:00
break ;
}
}
2011-06-14 23:28:21 +08:00
2011-06-16 22:43:49 +08:00
// rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued
// BUT... ACK --> NACK
if ( len = = 1 & & receivedCmd [ 0 ] = = CARD_ACK ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
// rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK)
if ( len = = 1 & & receivedCmd [ 0 ] = = CARD_NACK_NA ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_ACK ) ) ;
break ;
2011-06-14 23:28:21 +08:00
}
// read block
if ( len = = 4 & & receivedCmd [ 0 ] = = 0x30 ) {
2011-06-24 00:49:39 +08:00
if ( receivedCmd [ 1 ] > = 16 * 4 | | receivedCmd [ 1 ] / 4 ! = cardAUTHSC ) {
2011-06-16 22:43:49 +08:00
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
emlGetMem ( response , receivedCmd [ 1 ] , 1 ) ;
AppendCrc14443a ( response , 16 ) ;
mf_crypto1_encrypt ( pcs , response , 18 , & par ) ;
EmSendCmdPar ( response , 18 , par ) ;
2011-06-14 23:28:21 +08:00
break ;
}
// write block
if ( len = = 4 & & receivedCmd [ 0 ] = = 0xA0 ) {
2011-06-24 00:49:39 +08:00
if ( receivedCmd [ 1 ] > = 16 * 4 | | receivedCmd [ 1 ] / 4 ! = cardAUTHSC ) {
2011-06-16 22:43:49 +08:00
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_ACK ) ) ;
2012-06-12 20:21:26 +08:00
//nextCycleTimeout = 50;
2011-06-16 22:43:49 +08:00
cardSTATE = MFEMUL_WRITEBL2 ;
cardWRBL = receivedCmd [ 1 ] ;
2011-06-14 23:28:21 +08:00
break ;
2011-06-10 21:35:10 +08:00
}
2011-06-16 22:43:49 +08:00
2011-06-25 21:03:01 +08:00
// works with cardINTREG
// increment, decrement, restore
if ( len = = 4 & & ( receivedCmd [ 0 ] = = 0xC0 | | receivedCmd [ 0 ] = = 0xC1 | | receivedCmd [ 0 ] = = 0xC2 ) ) {
if ( receivedCmd [ 1 ] > = 16 * 4 | |
receivedCmd [ 1 ] / 4 ! = cardAUTHSC | |
emlCheckValBl ( receivedCmd [ 1 ] ) ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_ACK ) ) ;
if ( receivedCmd [ 0 ] = = 0xC1 )
cardSTATE = MFEMUL_INTREG_INC ;
if ( receivedCmd [ 0 ] = = 0xC0 )
cardSTATE = MFEMUL_INTREG_DEC ;
if ( receivedCmd [ 0 ] = = 0xC2 )
cardSTATE = MFEMUL_INTREG_REST ;
cardWRBL = receivedCmd [ 1 ] ;
break ;
}
// transfer
if ( len = = 4 & & receivedCmd [ 0 ] = = 0xB0 ) {
if ( receivedCmd [ 1 ] > = 16 * 4 | | receivedCmd [ 1 ] / 4 ! = cardAUTHSC ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
if ( emlSetValBl ( cardINTREG , cardINTBLOCK , receivedCmd [ 1 ] ) )
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
else
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_ACK ) ) ;
break ;
}
2011-06-10 21:35:10 +08:00
// halt
2011-06-14 23:28:21 +08:00
if ( len = = 4 & & ( receivedCmd [ 0 ] = = 0x50 & & receivedCmd [ 1 ] = = 0x00 ) ) {
2011-06-10 21:35:10 +08:00
LED_B_OFF ( ) ;
2011-06-14 23:28:21 +08:00
LED_C_OFF ( ) ;
2011-06-25 21:03:01 +08:00
cardSTATE = MFEMUL_HALTED ;
if ( MF_DBGLEVEL > = 4 ) Dbprintf ( " --> HALTED. Selected time: %d ms " , GetTickCount ( ) - selTimer ) ;
2011-06-14 23:28:21 +08:00
break ;
2011-06-10 21:35:10 +08:00
}
2011-06-24 00:49:39 +08:00
2011-06-16 22:43:49 +08:00
// command not allowed
if ( len = = 4 ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
break ;
}
2011-06-24 00:49:39 +08:00
// case break
break ;
2011-06-16 22:43:49 +08:00
}
case MFEMUL_WRITEBL2 : {
if ( len = = 18 ) {
mf_crypto1_decrypt ( pcs , receivedCmd , len ) ;
emlSetMem ( receivedCmd , cardWRBL , 1 ) ;
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_ACK ) ) ;
cardSTATE = MFEMUL_WORK ;
break ;
2011-06-24 00:49:39 +08:00
} else {
2011-06-25 21:03:01 +08:00
cardSTATE_TO_IDLE ( ) ;
2011-06-24 00:49:39 +08:00
break ;
2011-06-16 22:43:49 +08:00
}
break ;
2011-06-01 22:12:11 +08:00
}
2011-06-25 21:03:01 +08:00
case MFEMUL_INTREG_INC : {
mf_crypto1_decrypt ( pcs , receivedCmd , len ) ;
memcpy ( & ans , receivedCmd , 4 ) ;
if ( emlGetValBl ( & cardINTREG , & cardINTBLOCK , cardWRBL ) ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
cardSTATE_TO_IDLE ( ) ;
break ;
}
cardINTREG = cardINTREG + ans ;
cardSTATE = MFEMUL_WORK ;
break ;
}
case MFEMUL_INTREG_DEC : {
mf_crypto1_decrypt ( pcs , receivedCmd , len ) ;
memcpy ( & ans , receivedCmd , 4 ) ;
if ( emlGetValBl ( & cardINTREG , & cardINTBLOCK , cardWRBL ) ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
cardSTATE_TO_IDLE ( ) ;
break ;
}
cardINTREG = cardINTREG - ans ;
cardSTATE = MFEMUL_WORK ;
break ;
}
case MFEMUL_INTREG_REST : {
mf_crypto1_decrypt ( pcs , receivedCmd , len ) ;
memcpy ( & ans , receivedCmd , 4 ) ;
if ( emlGetValBl ( & cardINTREG , & cardINTBLOCK , cardWRBL ) ) {
EmSend4bit ( mf_crypto1_encrypt4bit ( pcs , CARD_NACK_NA ) ) ;
cardSTATE_TO_IDLE ( ) ;
break ;
}
cardSTATE = MFEMUL_WORK ;
break ;
}
2011-06-01 22:12:11 +08:00
}
}
2011-06-10 21:35:10 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2011-06-14 23:28:21 +08:00
// add trace trailer
2011-06-16 22:43:49 +08:00
memset ( rAUTH_NT , 0x44 , 4 ) ;
2011-06-14 23:28:21 +08:00
LogTrace ( rAUTH_NT , 4 , 0 , 0 , TRUE ) ;
2011-06-25 21:03:01 +08:00
if ( MF_DBGLEVEL > = 1 ) Dbprintf ( " Emulator stopped. Tracing: %d trace length: %d " , tracing , traceLen ) ;
2010-02-21 05:24:25 +08:00
}
2012-07-07 00:19:05 +08:00
//-----------------------------------------------------------------------------
// MIFARE sniffer.
//
//-----------------------------------------------------------------------------
2012-07-07 23:29:51 +08:00
void RAMFUNC SniffMifare ( uint8_t param ) {
// param:
// bit 0 - trigger from first card answer
// bit 1 - trigger from first reader 7-bit request
2012-07-11 23:52:33 +08:00
// C(red) A(yellow) B(green)
2012-07-07 00:19:05 +08:00
LEDsoff ( ) ;
// init trace buffer
2012-09-18 21:53:17 +08:00
iso14a_clear_trace ( ) ;
2012-07-07 00:19:05 +08:00
// The command (reader -> tag) that we're receiving.
// The length of a received command will in most cases be no more than 18 bytes.
// So 32 should be enough!
uint8_t * receivedCmd = ( ( ( uint8_t * ) BigBuf ) + RECV_CMD_OFFSET ) ;
// The response (tag -> reader) that we're receiving.
uint8_t * receivedResponse = ( ( ( uint8_t * ) BigBuf ) + RECV_RES_OFFSET ) ;
// As we receive stuff, we copy it from receivedCmd or receivedResponse
// into trace, along with its length and other annotations.
//uint8_t *trace = (uint8_t *)BigBuf;
// The DMA buffer, used to stream samples from the FPGA
int8_t * dmaBuf = ( ( int8_t * ) BigBuf ) + DMA_BUFFER_OFFSET ;
2012-07-07 23:29:51 +08:00
int8_t * data = dmaBuf ;
int maxDataLen = 0 ;
int dataLen = 0 ;
2012-07-07 00:19:05 +08:00
// Set up the demodulator for tag -> reader responses.
Demod . output = receivedResponse ;
Demod . len = 0 ;
Demod . state = DEMOD_UNSYNCD ;
// Set up the demodulator for the reader -> tag commands
memset ( & Uart , 0 , sizeof ( Uart ) ) ;
Uart . output = receivedCmd ;
Uart . byteCntMax = 32 ; // was 100 (greg)//////////////////
Uart . state = STATE_UNSYNCD ;
// Setup for the DMA.
FpgaSetupSsc ( ) ;
FpgaSetupSscDma ( ( uint8_t * ) dmaBuf , DMA_BUFFER_SIZE ) ;
// And put the FPGA in the appropriate mode
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2012-07-11 23:52:33 +08:00
// init sniffer
MfSniffInit ( ) ;
int sniffCounter = 0 ;
2012-07-07 00:19:05 +08:00
// And now we loop, receiving samples.
while ( true ) {
2012-07-07 23:29:51 +08:00
if ( BUTTON_PRESS ( ) ) {
DbpString ( " cancelled by button " ) ;
goto done ;
}
2012-07-07 00:19:05 +08:00
LED_A_ON ( ) ;
WDT_HIT ( ) ;
2012-07-11 23:52:33 +08:00
if ( + + sniffCounter > 65 ) {
if ( MfSniffSend ( 2000 ) ) {
2012-07-16 22:49:51 +08:00
FpgaEnableSscDma ( ) ;
2012-07-11 23:52:33 +08:00
}
sniffCounter = 0 ;
}
2012-07-07 23:29:51 +08:00
int register readBufDataP = data - dmaBuf ;
int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC - > PDC_RCR ;
if ( readBufDataP < = dmaBufDataP ) {
dataLen = dmaBufDataP - readBufDataP ;
} else {
dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP + 1 ;
}
// test for length of buffer
if ( dataLen > maxDataLen ) {
maxDataLen = dataLen ;
if ( dataLen > 400 ) {
Dbprintf ( " blew circular buffer! dataLen=0x%x " , dataLen ) ;
2012-07-07 00:19:05 +08:00
goto done ;
}
}
2012-07-07 23:29:51 +08:00
if ( dataLen < 1 ) continue ;
2012-07-07 00:19:05 +08:00
2012-07-07 23:29:51 +08:00
// primary buffer was stopped( <-- we lost data!
if ( ! AT91C_BASE_PDC_SSC - > PDC_RCR ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dmaBuf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
2012-07-16 22:49:51 +08:00
Dbprintf ( " RxEmpty ERROR!!! data length:%d " , dataLen ) ; // temporary
2012-07-07 23:29:51 +08:00
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( ! AT91C_BASE_PDC_SSC - > PDC_RNCR ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dmaBuf ;
2012-07-07 00:19:05 +08:00
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
2012-07-07 23:29:51 +08:00
LED_A_OFF ( ) ;
2012-07-07 00:19:05 +08:00
2012-07-07 23:29:51 +08:00
if ( MillerDecoding ( ( data [ 0 ] & 0xF0 ) > > 4 ) ) {
2012-07-11 23:52:33 +08:00
LED_C_INV ( ) ;
2012-07-07 23:29:51 +08:00
// check - if there is a short 7bit request from reader
2012-07-17 23:19:15 +08:00
if ( MfSniffLogic ( receivedCmd , Uart . byteCnt , Uart . parityBits , Uart . bitCnt , TRUE ) ) break ;
2012-07-07 23:29:51 +08:00
2012-07-07 00:19:05 +08:00
/* And ready to receive another command. */
Uart . state = STATE_UNSYNCD ;
2012-07-11 23:52:33 +08:00
/* And also reset the demod code */
2012-07-07 00:19:05 +08:00
Demod . state = DEMOD_UNSYNCD ;
}
2012-07-07 23:29:51 +08:00
if ( ManchesterDecoding ( data [ 0 ] & 0x0F ) ) {
2012-07-11 23:52:33 +08:00
LED_C_INV ( ) ;
2012-07-07 00:19:05 +08:00
2012-07-17 23:19:15 +08:00
if ( MfSniffLogic ( receivedResponse , Demod . len , Demod . parityBits , Demod . bitCount , FALSE ) ) break ;
2012-07-07 00:19:05 +08:00
// And ready to receive another response.
memset ( & Demod , 0 , sizeof ( Demod ) ) ;
Demod . output = receivedResponse ;
Demod . state = DEMOD_UNSYNCD ;
2012-07-11 23:52:33 +08:00
/* And also reset the uart code */
Uart . state = STATE_UNSYNCD ;
2012-07-07 00:19:05 +08:00
}
2012-07-07 23:29:51 +08:00
data + + ;
if ( data > dmaBuf + DMA_BUFFER_SIZE ) {
data = dmaBuf ;
2012-07-07 00:19:05 +08:00
}
} // main cycle
DbpString ( " COMMAND FINISHED " ) ;
done :
2012-07-16 22:49:51 +08:00
FpgaDisableSscDma ( ) ;
2012-07-11 23:52:33 +08:00
MfSniffEnd ( ) ;
2012-07-16 22:49:51 +08:00
Dbprintf ( " maxDataLen=%x, Uart.state=%x, Uart.byteCnt=%x Uart.byteCntMax=%x " , maxDataLen , Uart . state , Uart . byteCnt , Uart . byteCntMax ) ;
2012-07-07 00:19:05 +08:00
LEDsoff ( ) ;
2013-04-24 18:58:12 +08:00
}