X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/ab4da50d99bb4334b86ff9bc8c5795723df37966..d31d3804fe58fc844fe19feb30be58fc0d3d107d:/armsrc/hitag2.c diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 6f5557f6..2d064565 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,18 +16,21 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" +#include "../include/hitag2.h" #include "string.h" +#include "BigBuf.h" static bool bQuiet; -bool bCrypto; -bool bAuthenticating; -bool bPwd; -bool bSuccessful; +static bool bCrypto; +static bool bAuthenticating; +static bool bPwd; +static bool bSuccessful; + + struct hitag2_tag { uint32_t uid; @@ -61,21 +64,17 @@ static struct hitag2_tag tag = { }, }; -//#define TRACE_LENGTH 3000 -//uint8_t *trace = (uint8_t *) BigBuf; -//int traceLen = 0; -//int rsamples = 0; - -#define AUTH_TABLE_OFFSET FREE_BUFFER_OFFSET -#define AUTH_TABLE_LENGTH FREE_BUFFER_SIZE -byte_t* auth_table = (byte_t *)BigBuf+AUTH_TABLE_OFFSET; -size_t auth_table_pos = 0; -size_t auth_table_len = AUTH_TABLE_LENGTH; +// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. +// Historically it used to be FREE_BUFFER_SIZE, which was 2744. +#define AUTH_TABLE_LENGTH 2744 +static byte_t* auth_table; +static size_t auth_table_pos = 0; +static size_t auth_table_len = AUTH_TABLE_LENGTH; -byte_t password[4]; -byte_t NrAr[8]; -byte_t key[8]; -uint64_t cipher_state; +static byte_t password[4]; +static byte_t NrAr[8]; +static byte_t key[8]; +static uint64_t cipher_state; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ // Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007. @@ -153,18 +152,14 @@ static u32 _hitag2_byte (u64 * x) return c; } -size_t nbytes(size_t nbits) { - return (nbits/8)+((nbits%8)>0); -} - -int hitag2_reset(void) +static int hitag2_reset(void) { tag.state = TAG_STATE_RESET; tag.crypto_active = 0; return 0; } -int hitag2_init(void) +static int hitag2_init(void) { // memcpy(&tag, &resetdata, sizeof(tag)); hitag2_reset(); @@ -280,7 +275,8 @@ static void hitag_send_frame(const byte_t* frame, size_t frame_len) LOW(GPIO_SSC_DOUT); } -void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) + +static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { byte_t rx_air[HITAG_FRAME_LEN]; @@ -399,8 +395,8 @@ void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, si break; } -// LogTrace(rx,nbytes(rxlen),0,0,false); -// LogTrace(tx,nbytes(*txlen),0,0,true); +// LogTraceHitag(rx,rxlen,0,0,false); +// LogTraceHitag(tx,*txlen,0,0,true); if(tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); @@ -437,6 +433,7 @@ static void hitag_reader_send_bit(int bit) { LED_A_OFF(); } + static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) { // Send the content of the frame @@ -455,7 +452,7 @@ static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) size_t blocknr; -bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { // Reset the transmission frame length *txlen = 0; @@ -510,7 +507,7 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) return true; } -bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { // Reset the transmission frame length *txlen = 0; @@ -524,11 +521,32 @@ bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { case 0: { // Stop if there is no answer while we are in crypto mode (after sending NrAr) if (bCrypto) { - DbpString("Authentication failed!"); - return false; - } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); + // Failed during authentication + if (bAuthenticating) { + DbpString("Authentication failed!"); + return false; + } else { + // Failed reading a block, could be (read/write) locked, skip block and re-authenticate + if (blocknr == 1) { + // Write the low part of the key in memory + memcpy(tag.sectors[1],key+2,4); + } else if (blocknr == 2) { + // Write the high part of the key in memory + tag.sectors[2][0] = 0x00; + tag.sectors[2][1] = 0x00; + tag.sectors[2][2] = key[0]; + tag.sectors[2][3] = key[1]; + } else { + // Just put zero's in the memory (of the unreadable block) + memset(tag.sectors[blocknr],0x00,4); + } + blocknr++; + bCrypto = false; + } + } else { + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } } break; // Received UID, crypto tag answer @@ -582,7 +600,7 @@ bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { } -bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { // Reset the transmission frame length *txlen = 0; @@ -622,7 +640,9 @@ bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txl return true; } -bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + +static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length *txlen = 0; @@ -632,12 +652,19 @@ bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_ case 0: { // Stop if there is no answer while we are in crypto mode (after sending NrAr) if (bCrypto) { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); + + // Removing failed entry from authentiations table + memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8); + auth_table_len -= 8; + + // Return if we reached the end of the authentications table bCrypto = false; - if ((auth_table_pos+8) == auth_table_len) { + if (auth_table_pos == auth_table_len) { return false; } - auth_table_pos += 8; + + // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) memcpy(NrAr,auth_table+auth_table_pos,8); } *txlen = 5; @@ -670,6 +697,7 @@ bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_ return true; } + void SnoopHitag(uint32_t type) { int frame_count; int response; @@ -682,20 +710,23 @@ void SnoopHitag(uint32_t type) { byte_t rx[HITAG_FRAME_LEN]; size_t rxlen=0; - // Clean up trace and prepare it for storing frames - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); - auth_table_len = 0; auth_table_pos = 0; + BigBuf_free(); + auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); + + // Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); DbpString("Starting Hitag2 snoop"); LED_D_ON(); // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -711,7 +742,7 @@ void SnoopHitag(uint32_t type) { AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - // Disable timer during configuration + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, @@ -832,7 +863,7 @@ void SnoopHitag(uint32_t type) { // Check if frame was captured if(rxlen > 0) { frame_count++; - if (!LogTrace(rx,nbytes(rxlen),response,0,reader_frame)) { + if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) { DbpString("Trace full"); break; } @@ -891,13 +922,17 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { bool bQuitTraceFull = false; bQuiet = false; - // Clean up trace and prepare it for storing frames - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); auth_table_len = 0; auth_table_pos = 0; + byte_t* auth_table; + BigBuf_free(); + auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); + // Clean up trace and prepare it for storing frames + set_tracing(TRUE); + clear_trace(); + DbpString("Starting Hitag2 simulation"); LED_D_ON(); hitag2_init(); @@ -918,7 +953,8 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -937,21 +973,21 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - // Disable timer during configuration + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Reset the received frame, frame count and timing info memset(rx,0x00,sizeof(rx)); frame_count = 0; response = 0; overflow = 0; + + // Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while(!BUTTON_PRESS()) { // Watchdog hit @@ -995,7 +1031,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { if(rxlen > 4) { frame_count++; if (!bQuiet) { - if (!LogTrace(rx,nbytes(rxlen),response,0,true)) { + if (!LogTraceHitag(rx,rxlen,response,0,true)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1024,7 +1060,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { hitag_send_frame(tx,txlen); // Store the frame in the trace if (!bQuiet) { - if (!LogTrace(tx,nbytes(txlen),0,0,false)) { + if (!LogTraceHitag(tx,txlen,0,0,false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1055,9 +1091,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -// Dbprintf("frame received: %d",frame_count); -// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); -// DbpString("All done"); + + DbpString("Sim Stopped"); + } void ReaderHitag(hitag_function htf, hitag_data* htd) { @@ -1076,20 +1112,22 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { bool bStop; bool bQuitTraceFull = false; - // Reset the return status - bSuccessful = false; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + // Reset the return status + bSuccessful = false; // Clean up trace and prepare it for storing frames - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); + set_tracing(TRUE); + clear_trace(); + DbpString("Starting Hitag reader family"); // Check configuration switch(htf) { case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); + Dbprintf("List identifier in password mode"); memcpy(password,htd->pwd.password,4); - blocknr = 0; + blocknr = 0; bQuitTraceFull = false; bQuiet = false; bPwd = false; @@ -1101,25 +1139,25 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { Dbhexdump(8,NrAr,false); bQuiet = false; bCrypto = false; - bAuthenticating = false; + bAuthenticating = false; bQuitTraceFull = true; } break; case RHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); + memcpy(key,htd->crypto.key,4); //HACK; 4 or 6?? I read both in the code. Dbhexdump(6,key,false); - blocknr = 0; + blocknr = 0; bQuiet = false; bCrypto = false; - bAuthenticating = false; + bAuthenticating = false; bQuitTraceFull = true; } break; case RHT2F_TEST_AUTH_ATTEMPTS: { Dbprintf("Testing %d authentication attempts",(auth_table_len/8)); auth_table_pos = 0; - memcpy(NrAr,auth_table,8); + memcpy(NrAr, auth_table, 8); bQuitTraceFull = false; bQuiet = false; bCrypto = false; @@ -1205,7 +1243,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { if(rxlen > 0) { frame_count++; if (!bQuiet) { - if (!LogTrace(rx,nbytes(rxlen),response,0,false)) { + if (!LogTraceHitag(rx,rxlen,response,0,false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1259,7 +1297,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTrace(tx,nbytes(txlen),HITAG_T_WAIT_2,0,true)) { + if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { if (bQuitTraceFull) { break; } else {