]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - armsrc/iso14443a.c
REM: removed a double entry. it seems 'hf mf check' doesnt uniq-sort this file.
[proxmark3-svn] / armsrc / iso14443a.c
index 93bed2d5545ba5bf1ce2b7b04c7b22af24665e05..7c0913d83fe3072c1ff747cd218748b9d6487903 100644 (file)
@@ -1835,10 +1835,10 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) {
 // if anticollision is false, then the UID must be provided in uid_ptr[] 
 // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID)
 int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades) {
-       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 wupa[]       = { ISO14443A_CMD_WUPA };  // 0x26 - ISO14443A_CMD_REQA  0x52 - ISO14443A_CMD_WUPA
+       uint8_t sel_all[]    = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x20 };
+       uint8_t sel_uid[]    = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+       uint8_t rats[]       = { ISO14443A_CMD_RATS,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0
        uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller
        uint8_t resp_par[MAX_PARITY_SIZE] = {0};
        byte_t uid_resp[4] = {0};
@@ -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);
        }
 
+       // reset the PCB block number
+       iso14_pcb_blocknum = 0;
+       
        // check for proprietary anticollision:
        if ((resp[0] & 0x1F) == 0) return 3;
        
@@ -1977,41 +1980,37 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
                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);
-
        return 1;       
 }
 
 void iso14443a_setup(uint8_t fpga_minor_mode) {
+
        FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
        // Set up the synchronous serial port
        FpgaSetupSsc();
        // connect Demodulated Signal to ADC:
        SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
 
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
-       
        LED_D_OFF();
        // Signal field is on with the appropriate LED
        if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD ||
                fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN)
                LED_D_ON();
 
-       // Prepare the demodulation functions
-       DemodReset();
-       UartReset();
-
-       iso14a_set_timeout(10*106); // 10ms default
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
 
-       //NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
-       NextTransferTime = DELAY_ARM2AIR_AS_READER << 1;
+       SpinDelay(20);
        
        // Start the timer
        StartCountSspClk();
+       
+       // Prepare the demodulation functions
+       DemodReset();
+       UartReset();
+       NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER;
+       iso14a_set_timeout(10*106); // 20ms default     
 }
 
 int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
@@ -2044,9 +2043,9 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
        return len;
 }
 
+
 //-----------------------------------------------------------------------------
 // Read an ISO 14443a tag. Send out commands and store answers.
-//
 //-----------------------------------------------------------------------------
 void ReaderIso14443a(UsbCommand *c) {
        iso14a_command_t param = c->arg[0];
@@ -2145,10 +2144,26 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
        uint32_t nttmp1 = nt1;
        uint32_t nttmp2 = nt2;
 
-       for (uint16_t i = 1; i < 0xFFFF; ++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+1;
+               nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+2;
+               nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+3;
+               nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+4;
+               nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+5;
+               nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+6;
+               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 
        return(-99999); 
 }
@@ -2200,12 +2215,11 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
        
        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;
-       // iceman,  i add 1130 because during my observations this makse the syncronization much fast to sync.
-       sync_cycles = PRNG_SEQUENCE_LENGTH + 1130; //65536;     // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).          
+       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);
@@ -2282,7 +2296,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
        
                // we didn't calibrate our clock yet,
                // iceman: has to be calibrated every time.
-               if (first_try &&  previous_nt && !nt_attacked) { 
+               if (previous_nt && !nt_attacked) { 
 
                        nt_distance = dist_nt(previous_nt, nt);
                        
@@ -2321,7 +2335,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
                }
                LED_B_OFF();
 
-               if ((nt != nt_attacked) && nt_attacked) {       // we somehow lost sync. Try to catch up again...
+               if ( (nt != nt_attacked) && nt_attacked) {      // we somehow lost sync. Try to catch up again...
                        
                        catch_up_cycles = ABS(dist_nt(nt_attacked, nt));
                        if (catch_up_cycles == 99999) {                 // invalid nonce received. Don't resync on that one.
@@ -2464,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.
-       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);
-       ar_nr_responses[1] = nonce;
        
        // -- Determine the UID
        // Can be set from emulator memory or incoming data
@@ -2495,7 +2517,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                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)   {
@@ -2511,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
-                       ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC2, 4);                  
+                       cuid = bytes_to_num(rUIDBCC2, 4);                       
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        // BCC
@@ -2533,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
-                       ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC3, 4);
+                       cuid = bytes_to_num(rUIDBCC3, 4);
                         // CascadeTag, CT
                        rUIDBCC1[0] = 0x88;
                        rUIDBCC2[0] = 0x88;
@@ -2711,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);
 
+                               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) {                                       
@@ -2725,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);
                                }
-                               /*
+                               
                                crypto1_word(pcs, ar , 1);
                                cardRr = nr ^ crypto1_word(pcs, 0, 0);
                                
@@ -2960,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
+       /*
        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(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);
Impressum, Datenschutz