]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - armsrc/hitag2.c
FIX: LF TI WRITE inparameters didn't get copied by sscanf. This removes the "PRIu64...
[proxmark3-svn] / armsrc / hitag2.c
index a2c1d82323ab7a65abb1f830a201926d5143cea5..f9005c7176bcfe412526dca28e5a9bc221b89598 100644 (file)
 // (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"
 
 static bool bQuiet;
 
-bool bCrypto;
-bool bAuthenticating;
-bool bPwd;
-bool bSuccessful;
+static bool bCrypto;
+static bool bAuthenticating;
+static bool bPwd;
+static bool bSuccessful;
+
+
+static int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader)
+{
+  static uint16_t traceLen = 0;
+  uint8_t *trace = BigBuf_get_addr();
+
+  // Return when trace is full
+  if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + nbytes(iBits) > BigBuf_max_traceLen()) return FALSE;
+  
+  // 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++] = iBits;
+  memcpy(trace + traceLen, btBytes, nbytes(iBits));
+  traceLen += nbytes(iBits);
+  return TRUE;
+}
 
 struct hitag2_tag {
        uint32_t uid;
@@ -61,21 +89,17 @@ static struct hitag2_tag tag = {
     },
 };
 
-//#define TRACE_LENGTH 3000
-//uint8_t *trace = (uint8_t *) BigBuf;
-//int traceLen = 0;
-//int rsamples = 0;
+// 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;
 
-#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;
-
-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 +177,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 +300,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 +420,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 +458,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 +477,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 +532,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;
        
@@ -603,7 +625,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;
        
@@ -643,7 +665,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;
        
@@ -653,12 +677,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;
@@ -691,6 +722,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;
@@ -703,20 +735,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
+       iso14a_set_tracing(TRUE);
+       iso14a_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();
@@ -732,7 +767,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,
@@ -853,7 +888,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;
                        }
@@ -912,13 +947,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
+       iso14a_set_tracing(TRUE);
+       iso14a_clear_trace();
+
        DbpString("Starting Hitag2 simulation");
        LED_D_ON();
        hitag2_init();
@@ -939,7 +978,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();
@@ -958,21 +998,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
@@ -1016,7 +1056,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;
@@ -1045,7 +1085,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;
@@ -1076,9 +1116,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) {
@@ -1097,20 +1137,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();
+       iso14a_set_tracing(TRUE);
+       iso14a_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;
@@ -1122,25 +1164,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;
@@ -1226,7 +1268,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;
@@ -1280,7 +1322,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 {
Impressum, Datenschutz