]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - armsrc/iso14443a.c
CHG: 'hf iclass replay' added help text.
[proxmark3-svn] / armsrc / iso14443a.c
index 5a43e2333fc39aefec63904f12bd4c16663395f8..3daab1994f089be40b7eac21517fe9bcfa0fe49d 100644 (file)
@@ -1866,6 +1866,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
                        memset(uid_ptr,0,10);
        }
 
                        memset(uid_ptr,0,10);
        }
 
+       // reset the PCB block number
+       iso14_pcb_blocknum = 0;
+       
        // check for proprietary anticollision:
        if ((resp[0] & 0x1F) == 0) return 3;
        
        // check for proprietary anticollision:
        if ((resp[0] & 0x1F) == 0) return 3;
        
@@ -1977,12 +1980,8 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
                p_hi14a_card->ats_len = len;
        }
 
                p_hi14a_card->ats_len = len;
        }
 
-       // reset the PCB block number
-       iso14_pcb_blocknum = 0;
-
        // set default timeout based on ATS
        iso14a_set_ATS_timeout(resp);
        // set default timeout based on ATS
        iso14a_set_ATS_timeout(resp);
-
        return 1;       
 }
 
        return 1;       
 }
 
@@ -2001,6 +2000,8 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
                LED_D_ON();
 
        FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
                LED_D_ON();
 
        FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
+
+       SpinDelay(20);
        
        // Start the timer
        StartCountSspClk();
        
        // Start the timer
        StartCountSspClk();
@@ -2009,7 +2010,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
        DemodReset();
        UartReset();
        NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
        DemodReset();
        UartReset();
        NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
-       iso14a_set_timeout(20*106); // 20ms default     
+       iso14a_set_timeout(10*106); // 20ms default     
 }
 
 int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
 }
 
 int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
@@ -2143,29 +2144,24 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
        uint32_t nttmp1 = nt1;
        uint32_t nttmp2 = nt2;
 
        uint32_t nttmp1 = nt1;
        uint32_t nttmp2 = nt2;
 
-       for (uint16_t i = 1; i < 32768/8; ++i) {
+       // 0xFFFF -- Half up and half down to find distance between nonces
+       for (uint16_t i = 1; i < 32768/8; i += 8) {
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -i;
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+1;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+1;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+1);
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+2;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+2;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+2);
-
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+3;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+3;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+3);
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+4;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+4;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+4);
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+5;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+5;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+5);
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+6;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+6;
-               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+6);
-               
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+7;
                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+7;
+               
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -i;
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+1);
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+2);
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+3);
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+4);
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+5);
+               nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+6);
                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+7);               
        }
        // either nt1 or nt2 are invalid nonces 
                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+7);               
        }
        // either nt1 or nt2 are invalid nonces 
@@ -2219,14 +2215,14 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
        
        BigBuf_free(); BigBuf_Clear_ext(false); 
        clear_trace();
        
        BigBuf_free(); BigBuf_Clear_ext(false); 
        clear_trace();
-       set_tracing(TRUE);      
+       set_tracing(FALSE);     
        iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
 
        sync_time = GetCountSspClk() & 0xfffffff8;
        sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).              
        nt_attacked = 0;
        
        iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
 
        sync_time = GetCountSspClk() & 0xfffffff8;
        sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).              
        nt_attacked = 0;
        
-   if (MF_DBGLEVEL >= 4)       Dbprintf("Mifare::Sync %08x", sync_time);
+   if (MF_DBGLEVEL >= 4)       Dbprintf("Mifare::Sync %u", sync_time);
                                
        if (first_try) {
                mf_nr_ar3 = 0;
                                
        if (first_try) {
                mf_nr_ar3 = 0;
@@ -2482,12 +2478,20 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                
        // Here, we collect CUID, NT, NR, AR, CUID2, NT2, NR2, AR2
        // This can be used in a reader-only attack.
                
        // Here, we collect CUID, NT, NR, AR, CUID2, NT2, NR2, AR2
        // This can be used in a reader-only attack.
-       uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0,0};
-       uint8_t ar_nr_collected = 0;
+       nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; // for 2 separate attack types (nml, moebius)
+       memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
+
+       uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; // for 2nd attack type (moebius)
+       memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
+       uint8_t nonce1_count = 0;
+       uint8_t nonce2_count = 0;
+       uint8_t moebius_n_count = 0;
+       bool gettingMoebius = false;
+       uint8_t mM = 0; // moebius_modifier for collection storage
+       bool doBufResetNext = false;
 
        // Authenticate response - nonce
        uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
 
        // Authenticate response - nonce
        uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
-       ar_nr_responses[1] = nonce;
        
        // -- Determine the UID
        // Can be set from emulator memory or incoming data
        
        // -- Determine the UID
        // Can be set from emulator memory or incoming data
@@ -2513,7 +2517,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                case 4:
                        sak_4[0] &= 0xFB;               
                        // save CUID
                case 4:
                        sak_4[0] &= 0xFB;               
                        // save CUID
-                       ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC1, 4);
+                       cuid = bytes_to_num(rUIDBCC1, 4);
                        // BCC
                        rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
                        if (MF_DBGLEVEL >= 2)   {
                        // BCC
                        rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
                        if (MF_DBGLEVEL >= 2)   {
@@ -2529,7 +2533,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                        atqa[0] |= 0x40;
                        sak_7[0] &= 0xFB;                                               
                        // save CUID
                        atqa[0] |= 0x40;
                        sak_7[0] &= 0xFB;                                               
                        // save CUID
-                       ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC2, 4);                  
+                       cuid = bytes_to_num(rUIDBCC2, 4);                       
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        // BCC
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        // BCC
@@ -2551,7 +2555,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                        atqa[0] |= 0x80;
                        sak_10[0] &= 0xFB;                                      
                        // save CUID
                        atqa[0] |= 0x80;
                        sak_10[0] &= 0xFB;                                      
                        // save CUID
-                       ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC3, 4);
+                       cuid = bytes_to_num(rUIDBCC3, 4);
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        rUIDBCC2[0] = 0x88;
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        rUIDBCC2[0] = 0x88;
@@ -2729,6 +2733,81 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                uint32_t nr = bytes_to_num(receivedCmd, 4);
                                uint32_t ar = bytes_to_num(&receivedCmd[4], 4);
 
                                uint32_t nr = bytes_to_num(receivedCmd, 4);
                                uint32_t ar = bytes_to_num(&receivedCmd[4], 4);
 
+                               if (doBufResetNext) {
+                                       // Reset, lets try again!
+                                       Dbprintf("Re-read after previous NR_AR_ATTACK, resetting buffer");
+                                       memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
+                                       memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
+                                       mM = 0;
+                                       doBufResetNext = false;
+                               }
+
+                               for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
+                                       if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) {
+
+                                               // if first auth for sector, or matches sector and keytype of previous auth
+                                               if (ar_nr_collected[i+mM] < 2) {
+                                                       // if we haven't already collected 2 nonces for this sector
+                                                       if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) {
+                                                               // Avoid duplicates... probably not necessary, ar should vary.
+                                                               if (ar_nr_collected[i+mM]==0) {
+                                                                       // first nonce collect
+                                                                       ar_nr_resp[i+mM].cuid = cuid;
+                                                                       ar_nr_resp[i+mM].sector = cardAUTHSC;
+                                                                       ar_nr_resp[i+mM].keytype = cardAUTHKEY;
+                                                                       ar_nr_resp[i+mM].nonce = nonce;
+                                                                       ar_nr_resp[i+mM].nr = nr;
+                                                                       ar_nr_resp[i+mM].ar = ar;
+                                                                       nonce1_count++;
+                                                                       // add this nonce to first moebius nonce
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid;
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC;
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY;
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce;
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr;
+                                                                       ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar;
+                                                                       ar_nr_collected[i+ATTACK_KEY_COUNT]++;
+                                                               } else { // second nonce collect (std and moebius)
+                                                                       ar_nr_resp[i+mM].nonce2 = nonce;
+                                                                       ar_nr_resp[i+mM].nr2 = nr;
+                                                                       ar_nr_resp[i+mM].ar2 = ar;
+                                                                       if (!gettingMoebius) {
+                                                                               nonce2_count++;
+                                                                               // check if this was the last second nonce we need for std attack
+                                                                               if ( nonce2_count == nonce1_count ) {
+                                                                                       // done collecting std test switch to moebius
+                                                                                       // first finish incrementing last sample
+                                                                                       ar_nr_collected[i+mM]++; 
+                                                                                       // switch to moebius collection
+                                                                                       gettingMoebius = true;
+                                                                                       mM = ATTACK_KEY_COUNT;
+                                                                                       break;
+                                                                               }
+                                                                       } else {
+                                                                               moebius_n_count++;
+                                                                               // if we've collected all the nonces we need - finish.
+
+                                                                               if (nonce1_count == moebius_n_count) {
+                                                                                       cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp));
+                                                                                       nonce1_count = 0;
+                                                                                       nonce2_count = 0;
+                                                                                       moebius_n_count = 0;
+                                                                                       gettingMoebius = false;
+                                                                                       doBufResetNext = true;
+                                                                                       finished = ( ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE));
+                                                                               }
+                                                                       }
+                                                               }
+                                                               ar_nr_collected[i+mM]++;
+                                                       }
+                                               }
+                                               // we found right spot for this nonce stop looking
+                                               break;
+                                       }
+                               }
+
+
+                               /*
                                // Collect AR/NR
                                // if(ar_nr_collected < 2 && cardAUTHSC == 2){
                                if(ar_nr_collected < 2) {                                       
                                // Collect AR/NR
                                // if(ar_nr_collected < 2 && cardAUTHSC == 2){
                                if(ar_nr_collected < 2) {                                       
@@ -2743,7 +2822,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                        // Interactive mode flag, means we need to send ACK
                                        finished = ( ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE)&& ar_nr_collected == 2);
                                }
                                        // Interactive mode flag, means we need to send ACK
                                        finished = ( ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE)&& ar_nr_collected == 2);
                                }
-                               /*
+                               
                                crypto1_word(pcs, ar , 1);
                                cardRr = nr ^ crypto1_word(pcs, 0, 0);
                                
                                crypto1_word(pcs, ar , 1);
                                cardRr = nr ^ crypto1_word(pcs, 0, 0);
                                
@@ -2978,37 +3057,45 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
        }
 
        // Interactive mode flag, means we need to send ACK
        }
 
        // Interactive mode flag, means we need to send ACK
+       /*
        if((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) {
                // May just aswell send the collected ar_nr in the response aswell
                uint8_t len = ar_nr_collected * 4 * 4;
                cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, len, 0, &ar_nr_responses, len);
        }
        if((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) {
                // May just aswell send the collected ar_nr in the response aswell
                uint8_t len = ar_nr_collected * 4 * 4;
                cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, len, 0, &ar_nr_responses, len);
        }
-
+       
+   */
        if( ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK ) && MF_DBGLEVEL >= 1 ) {
        if( ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK ) && MF_DBGLEVEL >= 1 ) {
-               if(ar_nr_collected > 1 ) {
-                       Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
-                       Dbprintf("../tools/mfkey/mfkey32v2.exe %08x %08x %08x %08x %08x %08x %08x",
-                                       ar_nr_responses[0], // CUID
-                                       ar_nr_responses[1], // NT1
-                                       ar_nr_responses[2], // NR1
-                                       ar_nr_responses[3], // AR1
-                                       // ar_nr_responses[4], // CUID2
-                                       ar_nr_responses[5],  // NT2
-                                       ar_nr_responses[6], // NR2
-                                       ar_nr_responses[7]  // AR2
-                               );
-               } else {
-                       Dbprintf("Failed to obtain two AR/NR pairs!");
-                       if(ar_nr_collected == 1 ) {
-                               Dbprintf("Only got these: UID=%08x, nonce=%08x, NR1=%08x, AR1=%08x",
-                                               ar_nr_responses[0], // CUID
-                                               ar_nr_responses[1], // NT
-                                               ar_nr_responses[2], // NR1
-                                               ar_nr_responses[3]  // AR1
-                                       );
+               for ( uint8_t   i = 0; i < ATTACK_KEY_COUNT; i++) {
+                       if (ar_nr_collected[i] == 2) {
+                               Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
+                               Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
+                                               ar_nr_resp[i].cuid,  //UID
+                                               ar_nr_resp[i].nonce, //NT
+                                               ar_nr_resp[i].nr,    //NR1
+                                               ar_nr_resp[i].ar,    //AR1
+                                               ar_nr_resp[i].nr2,   //NR2
+                                               ar_nr_resp[i].ar2    //AR2
+                                               );
+                       }
+               }       
+               for ( uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT*2; i++) {
+                       if (ar_nr_collected[i] == 2) {
+                               Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
+                               Dbprintf("../tools/mfkey/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x",
+                                               ar_nr_resp[i].cuid,  //UID
+                                               ar_nr_resp[i].nonce, //NT
+                                               ar_nr_resp[i].nr,    //NR1
+                                               ar_nr_resp[i].ar,    //AR1
+                                               ar_nr_resp[i].nonce2,//NT2
+                                               ar_nr_resp[i].nr2,   //NR2
+                                               ar_nr_resp[i].ar2    //AR2
+                                               );
                        }
                }
        }
                        }
                }
        }
+       
+       
        if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ", tracing, BigBuf_get_traceLen());
        
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
        if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ", tracing, BigBuf_get_traceLen());
        
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
Impressum, Datenschutz