]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - armsrc/iso14443a.c
ADD: There were lot of calls to enable tracing, but very few to turn it of afterwar...
[proxmark3-svn] / armsrc / iso14443a.c
index 9b7efaf6834bb5e4e98b4ca72be5470348c35607..22ada94f8ec9b876356d4398a3cb84413e6e3919 100644 (file)
@@ -565,16 +565,18 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
        // param:
        // bit 0 - trigger from first card answer
        // bit 1 - trigger from first reader 7-bit request
-       
        LEDsoff();
 
-
        iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER);
        
        // Allocate memory from BigBuf for some buffers
        // free all previous allocations first
        BigBuf_free();
-
+       
+       // init trace buffer
+       clear_trace();
+       set_tracing(TRUE);
+       
        // The command (reader -> tag) that we're receiving.
        uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
        uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE);
@@ -586,10 +588,6 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
        // The DMA buffer, used to stream samples from the FPGA
        uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
 
-       // init trace buffer
-       clear_trace();
-       set_tracing(TRUE);
-
        uint8_t *data = dmaBuf;
        uint8_t previous_data = 0;
        int maxDataLen = 0;
@@ -715,12 +713,13 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
                }
        } // main cycle
 
-       DbpString("COMMAND FINISHED");
-
        FpgaDisableSscDma();
+       LEDsoff();
+
        Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len);
        Dbprintf("traceLen=%d, Uart.output[0]=%08x", BigBuf_get_traceLen(), (uint32_t)Uart.output[0]);
-       LEDsoff();
+       
+       set_tracing(FALSE);     
 }
 
 //-----------------------------------------------------------------------------
@@ -938,7 +937,7 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) {
 // Main loop of simulated tag: receive commands from reader, decide what
 // response to send, and send it.
 //-----------------------------------------------------------------------------
-void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
+void SimulateIso14443aTag(int tagType, int flags, byte_t* data)
 {
 
        //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
@@ -950,10 +949,10 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
        uint8_t sak;
                                        
        // PACK response to PWD AUTH for EV1/NTAG
-       uint8_t response8[4];
+       uint8_t response8[4] =  {0,0,0,0};
        
        // The first response contains the ATQA (note: bytes are transmitted in reverse order).
-       uint8_t response1[2];
+       uint8_t response1[2] =  {0,0};
        
        switch (tagType) {
                case 1: { // MIFARE Classic
@@ -1050,7 +1049,7 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
        response3a[0] = sak & 0xFB;
        ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);
 
-       uint8_t response5[] = { 0x01, 0x01, 0x01, 0x01 }; // Very random tag nonce
+       uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce
        uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: 
        // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, 
        // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
@@ -1154,9 +1153,9 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
                } else if(receivedCmd[0] == 0x30) {     // Received a (plain) READ
                        uint8_t block = receivedCmd[1];
                        if ( tagType == 7 ) {
-                               uint8_t start = 4 * block;
+                               uint16_t start = 4 * block;
                                
-                               if ( block < 4 ) {
+                               /*if ( block < 4 ) {
                                    //NTAG 215
                                        uint8_t blockdata[50] = {
                                        data[0],data[1],data[2], 0x88 ^ data[0] ^ data[1] ^ data[2],
@@ -1170,12 +1169,12 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
                                        0x00,0x00};
                                        AppendCrc14443a(blockdata+start, 16);
                                        EmSendCmdEx( blockdata+start, MAX_MIFARE_FRAME_SIZE, false);
-                               } else {        
+                               } else {*/      
                                        uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
                                        emlGetMemBt( emdata, start, 16);
                                        AppendCrc14443a(emdata, 16);
                                        EmSendCmdEx(emdata, sizeof(emdata), false);                             
-                               }
+                               //}
                                p_response = NULL;
                                
                        } else {                        
@@ -1276,6 +1275,16 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
                                                                ar_nr_responses[8], // AR2
                                                                ar_nr_responses[9]  // NR2
                                                        );
+                                                       Dbprintf("../tools/mfkey/mfkey32v2 %06x%08x %08x %08x %08x %08x %08x %08x",
+                                                               ar_nr_responses[0], // UID1
+                                                               ar_nr_responses[1], // UID2
+                                                               ar_nr_responses[2], // NT1
+                                                               ar_nr_responses[3], // AR1
+                                                               ar_nr_responses[4], // NR1
+                                                               ar_nr_responses[7], // NT2
+                                                               ar_nr_responses[8], // AR2
+                                                               ar_nr_responses[9]  // NR2
+                                                               );
                                        }
                                        uint8_t len = ar_nr_collected*5*4;
                                        cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,len,0,&ar_nr_responses,len);
@@ -1292,15 +1301,22 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
                        if ( tagType == 7 ) {
                                p_response =  &responses[8]; // PACK response
                                uint32_t pwd = bytes_to_num(receivedCmd+1,4);
-                               Dbprintf("Auth attempt: %08x", pwd);    
+                               
+                               if ( MF_DBGLEVEL >= 3)  Dbprintf("Auth attempt: %08x", pwd);    
                        }
                }
                else {
                        // Check for ISO 14443A-4 compliant commands, look at left nibble
                        switch (receivedCmd[0]) {
-
+                               case 0x02:
+                               case 0x03: {  // IBlock (command no CID)
+                                       dynamic_response_info.response[0] = receivedCmd[0];
+                                       dynamic_response_info.response[1] = 0x90;
+                                       dynamic_response_info.response[2] = 0x00;
+                                       dynamic_response_info.response_n = 3;
+                               } break;
                                case 0x0B:
-                               case 0x0A: { // IBlock (command)
+                               case 0x0A: { // IBlock (command CID)
                                  dynamic_response_info.response[0] = receivedCmd[0];
                                  dynamic_response_info.response[1] = 0x00;
                                  dynamic_response_info.response[2] = 0x90;
@@ -1320,15 +1336,17 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
                                  dynamic_response_info.response_n = 2;
                                } break;
                                  
-                               case 0xBA: { //
-                                 memcpy(dynamic_response_info.response,"\xAB\x00",2);
-                                 dynamic_response_info.response_n = 2;
+                               case 0xBA: { // ping / pong
+                                       dynamic_response_info.response[0] = 0xAB;
+                                       dynamic_response_info.response[1] = 0x00;
+                                       dynamic_response_info.response_n = 2;
                                } break;
 
                                case 0xCA:
                                case 0xC2: { // Readers sends deselect command
-                                 memcpy(dynamic_response_info.response,"\xCA\x00",2);
-                                 dynamic_response_info.response_n = 2;
+                                       dynamic_response_info.response[0] = 0xCA;
+                                       dynamic_response_info.response[1] = 0x00;
+                                       dynamic_response_info.response_n = 2;
                                } break;
 
                                default: {
@@ -1399,12 +1417,15 @@ void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
        }
 
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       set_tracing(FALSE);
        BigBuf_free_keep_EM();
        LED_A_OFF();
        
-       Dbprintf("-[ Wake ups after halt [%d]", happened);
-       Dbprintf("-[ Messages after halt [%d]", happened2);
-       Dbprintf("-[ Num of received cmd [%d]", cmdsRecvd);
+       if (MF_DBGLEVEL >= 4){
+               Dbprintf("-[ Wake ups after halt [%d]", happened);
+               Dbprintf("-[ Messages after halt [%d]", happened2);
+               Dbprintf("-[ Num of received cmd [%d]", cmdsRecvd);
+       }
 }
 
 
@@ -1815,7 +1836,6 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive
        }
 }
 
-
 void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing)
 {
        CodeIso14443aBitsAsReaderPar(frame, bits, par);
@@ -1831,13 +1851,11 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t
        }
 }
 
-
 void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing)
 {
   ReaderTransmitBitsPar(frame, len*8, par, timing);
 }
 
-
 void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
 {
   // Generate parity and redirect
@@ -1846,7 +1864,6 @@ void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
   ReaderTransmitBitsPar(frame, len, par, timing);
 }
 
-
 void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing)
 {
   // Generate parity and redirect
@@ -2166,6 +2183,7 @@ void ReaderIso14443a(UsbCommand *c)
        }
 
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       set_tracing(FALSE);
        LEDsoff();
 }
 
@@ -2183,7 +2201,7 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
        nttmp1 = nt1;
        nttmp2 = nt2;
        
-       for (i = 1; i < 32768; i++) {
+       for (i = 1; i < 0xFFFF; i++) {
                nttmp1 = prng_successor(nttmp1, 1);
                if (nttmp1 == nt2) return i;
                nttmp2 = prng_successor(nttmp2, 1);
@@ -2233,19 +2251,20 @@ void ReaderMifare(bool first_try)
        byte_t par_list[8] = {0x00};
        byte_t ks_list[8] = {0x00};
 
+   #define PRNG_SEQUENCE_LENGTH  (1 << 16);
        static uint32_t sync_time = 0;
-       static uint32_t sync_cycles = 0;
+       static int32_t sync_cycles = 0;
        int catch_up_cycles = 0;
        int last_catch_up = 0;
+       uint16_t elapsed_prng_sequences;
        uint16_t consecutive_resyncs = 0;
        int isOK = 0;
 
        if (first_try) { 
                mf_nr_ar3 = 0;
                sync_time = GetCountSspClk() & 0xfffffff8;
-               sync_cycles = 65536;                                                                    // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
+               sync_cycles = PRNG_SEQUENCE_LENGTH; //65536;    //0x10000                       // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
                nt_attacked = 0;
-               nt = 0;
                par[0] = 0;
        }
        else {
@@ -2260,8 +2279,17 @@ void ReaderMifare(bool first_try)
        LED_C_OFF();
        
 
-       #define DARKSIDE_MAX_TRIES      32              // number of tries to sync on PRNG cycle. Then give up.
-       uint16_t unsuccessfull_tries = 0;
+       #define MAX_UNEXPECTED_RANDOM   4               // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
+       #define MAX_SYNC_TRIES                  32
+       #define NUM_DEBUG_INFOS                 8               // per strategy
+       #define MAX_STRATEGY                    3
+       uint16_t unexpected_random = 0;
+       uint16_t sync_tries = 0;
+       int16_t debug_info_nr = -1;
+       uint16_t strategy = 0;
+       int32_t debug_info[MAX_STRATEGY][NUM_DEBUG_INFOS];
+       uint32_t select_time;
+       uint32_t halt_time;
   
        for(uint16_t i = 0; TRUE; i++) {
                
@@ -2274,21 +2302,60 @@ void ReaderMifare(bool first_try)
                        break;
                }
                
+               if (strategy == 2) {
+                       // test with additional hlt command
+                       halt_time = 0;
+                       int len = mifare_sendcmd_short(NULL, false, 0x50, 0x00, receivedAnswer, receivedAnswerPar, &halt_time);
+                       if (len && MF_DBGLEVEL >= 3) {
+                               Dbprintf("Unexpected response of %d bytes to hlt command (additional debugging).", len);
+                       }
+               }
+
+               if (strategy == 3) {
+                       // test with FPGA power off/on
+                       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+                       SpinDelay(200);
+                       iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
+                       SpinDelay(100);
+               }
+               
                if(!iso14443a_select_card(uid, NULL, &cuid)) {
                        if (MF_DBGLEVEL >= 1)   Dbprintf("Mifare: Can't select card");
                        continue;
                }
+               select_time = GetCountSspClk();
 
-               sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles;
-               catch_up_cycles = 0;
+               elapsed_prng_sequences = 1;
+               if (debug_info_nr == -1) {
+                       sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles;
+                       catch_up_cycles = 0;
 
-               // if we missed the sync time already, advance to the next nonce repeat
-               while(GetCountSspClk() > sync_time) {
-                       sync_time = (sync_time & 0xfffffff8) + sync_cycles;
-               }
+                       // if we missed the sync time already, advance to the next nonce repeat
+                       while(GetCountSspClk() > sync_time) {
+                               elapsed_prng_sequences++;
+                               sync_time = (sync_time & 0xfffffff8) + sync_cycles;
+                       }
 
-               // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) 
-               ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
+                       // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) 
+                       ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
+               } else {
+                       // collect some information on tag nonces for debugging:
+                       #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH
+                       if (strategy == 0) {
+                               // nonce distances at fixed time after card select:
+                               sync_time = select_time + DEBUG_FIXED_SYNC_CYCLES;
+                       } else if (strategy == 1) {
+                               // nonce distances at fixed time between authentications:
+                               sync_time = sync_time + DEBUG_FIXED_SYNC_CYCLES;
+                       } else if (strategy == 2) {
+                               // nonce distances at fixed time after halt:
+                               sync_time = halt_time + DEBUG_FIXED_SYNC_CYCLES;
+                       } else {
+                               // nonce_distances at fixed time after power on
+                               sync_time = DEBUG_FIXED_SYNC_CYCLES;
+                       }
+                       ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
+               }                       
 
                // Receive the (4 Byte) "random" nonce
                if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) {
@@ -2306,19 +2373,37 @@ void ReaderMifare(bool first_try)
                        int nt_distance = dist_nt(previous_nt, nt);
                        if (nt_distance == 0) {
                                nt_attacked = nt;
-                       }
-                       else {
+                       } else {
                                if (nt_distance == -99999) { // invalid nonce received
-                                       unsuccessfull_tries++;
-                                       if (!nt_attacked && unsuccessfull_tries > DARKSIDE_MAX_TRIES) {
+                                       unexpected_random++;
+                                       if (unexpected_random > MAX_UNEXPECTED_RANDOM) {
                                                isOK = -3;              // Card has an unpredictable PRNG. Give up      
                                                break;
                                        } else {
                                                continue;               // continue trying...
                                        }
                                }
-                               sync_cycles = (sync_cycles - nt_distance);
-                               if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
+                               if (++sync_tries > MAX_SYNC_TRIES) {
+                                       if (strategy > MAX_STRATEGY || MF_DBGLEVEL < 3) {
+                                               isOK = -4;                      // Card's PRNG runs at an unexpected frequency or resets unexpectedly
+                                               break;
+                                       } else {                                // continue for a while, just to collect some debug info
+                                               debug_info[strategy][debug_info_nr] = nt_distance;
+                                               debug_info_nr++;
+                                               if (debug_info_nr == NUM_DEBUG_INFOS) {
+                                                       strategy++;
+                                                       debug_info_nr = 0;
+                                               }
+                                               continue;
+                                       }
+                               }
+                               sync_cycles = (sync_cycles - nt_distance/elapsed_prng_sequences);
+                               if (sync_cycles <= 0) {
+                                       sync_cycles += PRNG_SEQUENCE_LENGTH;
+                               }
+                               if (MF_DBGLEVEL >= 3) {
+                                       Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
+                               }
                                continue;
                        }
                }
@@ -2329,6 +2414,7 @@ void ReaderMifare(bool first_try)
                                catch_up_cycles = 0;
                                continue;
                        }
+                       catch_up_cycles /= elapsed_prng_sequences;
                        if (catch_up_cycles == last_catch_up) {
                                consecutive_resyncs++;
                        }
@@ -2342,6 +2428,9 @@ void ReaderMifare(bool first_try)
                        else {  
                                sync_cycles = sync_cycles + catch_up_cycles;
                                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);
+                               last_catch_up = 0;
+                               catch_up_cycles = 0;
+                               consecutive_resyncs = 0;
                        }
                        continue;
                }
@@ -2349,12 +2438,10 @@ void ReaderMifare(bool first_try)
                consecutive_resyncs = 0;
                
                // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding
-               if (ReaderReceive(receivedAnswer, receivedAnswerPar))
-               {
+               if (ReaderReceive(receivedAnswer, receivedAnswerPar)) {
                        catch_up_cycles = 8;    // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
        
-                       if (nt_diff == 0)
-                       {
+                       if (nt_diff == 0) {
                                par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change
                        }
 
@@ -2390,8 +2477,17 @@ void ReaderMifare(bool first_try)
 
        mf_nr_ar[3] &= 0x1F;
        
-       byte_t buf[28] = {0x00};
+       if (isOK == -4) {
+               if (MF_DBGLEVEL >= 3) {
+                       for (uint16_t i = 0; i <= MAX_STRATEGY; i++) {
+                               for(uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) {
+                                       Dbprintf("collected debug info[%d][%d] = %d", i, j, debug_info[i][j]);
+                               }
+                       }
+               }
+       }
        
+       byte_t buf[28];
        memcpy(buf + 0,  uid, 4);
        num_to_bytes(nt, 4, buf + 4);
        memcpy(buf + 8,  par_list, 8);
@@ -2407,8 +2503,7 @@ void ReaderMifare(bool first_try)
        set_tracing(FALSE);
 }
 
-
- /*
+/**
   *MIFARE 1K simulate.
   *
   *@param flags :
@@ -2914,6 +3009,16 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                        ar_nr_responses[8], // AR2
                                        ar_nr_responses[9]  // NR2
                                        );
+                       Dbprintf("../tools/mfkey/mfkey32v2 %06x%08x %08x %08x %08x %08x %08x %08x",
+                                       ar_nr_responses[0], // UID1
+                                       ar_nr_responses[1], // UID2
+                                       ar_nr_responses[2], // NT1
+                                       ar_nr_responses[3], // AR1
+                                       ar_nr_responses[4], // NR1
+                                       ar_nr_responses[7], // NT2
+                                       ar_nr_responses[8], // AR2
+                                       ar_nr_responses[9]  // NR2
+                                       );
                } else {
                        Dbprintf("Failed to obtain two AR/NR pairs!");
                        if(ar_nr_collected > 0 ) {
@@ -2928,6 +3033,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                }
        }
        if (MF_DBGLEVEL >= 1)   Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ", tracing, BigBuf_get_traceLen());
+       
+       set_tracing(FALSE);
 }
 
 
@@ -3067,6 +3174,7 @@ void RAMFUNC SniffMifare(uint8_t param) {
 
                                        // And reset the Miller decoder including its (now outdated) input buffer
                                        UartInit(receivedCmd, receivedCmdPar);
+                                       // why not UartReset?
                                }
                                TagIsActive = (Demod.state != DEMOD_UNSYNCD);
                        }
@@ -3081,11 +3189,9 @@ void RAMFUNC SniffMifare(uint8_t param) {
 
        } // main cycle
 
-       DbpString("COMMAND FINISHED");
-
        FpgaDisableSscDma();
        MfSniffEnd();
-       
-       Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len);
        LEDsoff();
+       Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len);
+       set_tracing(FALSE);
 }
Impressum, Datenschutz