From 664e132f882e04cf8aafe9a6d8fc137d57816ab8 Mon Sep 17 00:00:00 2001
From: pwpiwi <pwpiwi@users.noreply.github.com>
Date: Thu, 8 Feb 2018 14:50:03 +0100
Subject: [PATCH] hf mf mifare: * prevent WDT crash on repeated tries * comes
 with faster execution as side effect * use uint8_t instead of byte_t *
 populate ar instead of (correctly) assuming that it is zero * remove the
 "will take a few seconds longer" message because it is no longer true

---
 armsrc/iso14443a.c  | 28 +++++++++++++---------------
 client/mifarehost.c | 17 ++++++++---------
 2 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 6703cc65..a8273e5e 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -2151,9 +2151,7 @@ void ReaderMifare(bool first_try)
 	uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
 	uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
 
-	if (first_try) { 
-		iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
-	}
+	iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
 	
 	// free eventually allocated BigBuf memory. We want all for tracing.
 	BigBuf_free();
@@ -2161,9 +2159,9 @@ void ReaderMifare(bool first_try)
 	clear_trace();
 	set_tracing(true);
 
-	byte_t nt_diff = 0;
+	uint8_t nt_diff = 0;
 	uint8_t par[1] = {0};	// maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
-	static byte_t par_low = 0;
+	static uint8_t par_low = 0;
 	bool led_on = true;
 	uint8_t uid[10]  ={0};
 	uint32_t cuid;
@@ -2171,11 +2169,11 @@ void ReaderMifare(bool first_try)
 	uint32_t nt = 0;
 	uint32_t previous_nt = 0;
 	static uint32_t nt_attacked = 0;
-	byte_t par_list[8] = {0x00};
-	byte_t ks_list[8] = {0x00};
+	uint8_t par_list[8] = {0x00};
+	uint8_t ks_list[8] = {0x00};
 
 	#define PRNG_SEQUENCE_LENGTH  (1 << 16);
-	static uint32_t sync_time;
+	uint32_t sync_time = GetCountSspClk() & 0xfffffff8;
 	static int32_t sync_cycles;
 	int catch_up_cycles = 0;
 	int last_catch_up = 0;
@@ -2185,10 +2183,9 @@ void ReaderMifare(bool first_try)
 
 	if (first_try) { 
 		mf_nr_ar3 = 0;
-		sync_time = GetCountSspClk() & 0xfffffff8;
+		par[0] = par_low = 0;
 		sync_cycles = PRNG_SEQUENCE_LENGTH;							// theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces).
 		nt_attacked = 0;
-		par[0] = 0;
 	}
 	else {
 		// we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same)
@@ -2204,6 +2201,7 @@ void ReaderMifare(bool first_try)
 
 	#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 SYNC_TIME_BUFFER		16		// if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle
 	#define NUM_DEBUG_INFOS			8		// per strategy
 	#define MAX_STRATEGY			3
 	uint16_t unexpected_random = 0;
@@ -2253,8 +2251,8 @@ void ReaderMifare(bool first_try)
 			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) {
+			// if we missed the sync time already or are about to miss it, advance to the next nonce repeat
+			while(sync_time < GetCountSspClk() + SYNC_TIME_BUFFER) {
 				elapsed_prng_sequences++;
 				sync_time = (sync_time & 0xfffffff8) + sync_cycles;
 			}
@@ -2410,14 +2408,14 @@ void ReaderMifare(bool first_try)
 		}
 	}
 	
-	byte_t buf[28];
+	uint8_t buf[32];
 	memcpy(buf + 0,  uid, 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);
+	memcpy(buf + 24, mf_nr_ar, 8);
 		
-	cmd_send(CMD_ACK, isOK, 0, 0, buf, 28);
+	cmd_send(CMD_ACK, isOK, 0, 0, buf, 32);
 
 	// Thats it...
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
diff --git a/client/mifarehost.c b/client/mifarehost.c
index 2bd21077..471fbc42 100644
--- a/client/mifarehost.c
+++ b/client/mifarehost.c
@@ -73,13 +73,12 @@ static uint32_t intersection(uint64_t *list1, uint64_t *list2)
 
 
 // Darkside attack (hf mf mifare)
-static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
+static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
 	struct Crypto1State *states;
-	uint32_t i, pos, rr; //nr_diff;
+	uint32_t i, pos;
 	uint8_t bt, ks3x[8], par[8][8];
 	uint64_t key_recovered;
-	static uint64_t *keylist;
-	rr = 0;
+	uint64_t *keylist;
 
 	// Reset the last three significant bits of the reader nonce
 	nr &= 0xffffff1f;
@@ -92,7 +91,7 @@ static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_i
 		}
 	}
 
-	states = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0));
+	states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
 
 	if (states == NULL) {
 		*keys = NULL;
@@ -116,7 +115,7 @@ static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_i
 int mfDarkside(uint64_t *key)
 {
 	uint32_t uid = 0;
-	uint32_t nt = 0, nr = 0;
+	uint32_t nt = 0, nr = 0, ar = 0;
 	uint64_t par_list = 0, ks_list = 0;
 	uint64_t *keylist = NULL, *last_keylist = NULL;
 	uint32_t keycount = 0;
@@ -159,18 +158,18 @@ int mfDarkside(uint64_t *key)
 				nt =  (uint32_t)bytes_to_num(resp.d.asBytes +  4, 4);
 				par_list = bytes_to_num(resp.d.asBytes +  8, 8);
 				ks_list = bytes_to_num(resp.d.asBytes +  16, 8);
-				nr = bytes_to_num(resp.d.asBytes + 24, 4);
+				nr = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4);
+				ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4);
 				break;
 			}
 		}
 
 		if (par_list == 0 && c.arg[0] == true) {
 			PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication.");
-			PrintAndLog("Attack will take a few seconds longer because we need two consecutive successful runs.");
 		}
 		c.arg[0] = false;
 
-		keycount = nonce2key(uid, nt, nr, par_list, ks_list, &keylist);
+		keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist);
 
 		if (keycount == 0) {
 			PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);
-- 
2.39.5