From c188b1b9b24b65a60c594364b474edba7c4ab8a2 Mon Sep 17 00:00:00 2001
From: iceman1001 <iceman@iuse.se>
Date: Fri, 27 Nov 2015 16:24:00 +0100
Subject: [PATCH 1/1] ADD: @go_tus simple bruteforce for t55xx,  refactored a
 bit. ADD: @pwpiwi 's implementation of Hardnested

---
 armsrc/appmain.c             |   5 +-
 armsrc/apps.h                |   1 +
 armsrc/epa.c                 |   2 +-
 armsrc/iso14443a.c           |  32 ++++---
 armsrc/iso14443a.h           |   2 +-
 armsrc/mifarecmd.c           | 162 +++++++++++++++++++++++++++++++----
 armsrc/mifaredesfire.c       |   4 +-
 client/Makefile              |   1 +
 client/cmddata.c             |  21 +++--
 client/cmdhfmf.c             | 100 +++++++++++++++++++++
 client/cmdhfmf.h             |   1 +
 client/cmdlft55xx.c          |  77 ++++++++++++++---
 client/cmdlft55xx.h          |   2 +
 client/data.c                |  10 +--
 client/hid-flasher/usb_cmd.h |   2 +
 client/lualibs/commands.lua  |   1 +
 common/lfdemod.h             |   1 +
 include/usb_cmd.h            |   1 +
 18 files changed, 367 insertions(+), 58 deletions(-)

diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index b29a6101..4cbf5acd 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -432,7 +432,7 @@ void StandAloneMode14a()
 						SpinDelay(300);
 					}
 				}
-				if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid))
+				if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0))
 					continue;
 				else
 				{
@@ -1131,6 +1131,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
 		case CMD_MIFAREU_WRITEBL:
 			MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes);
 			break;
+		case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES:
+			MifareAcquireEncryptedNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+			break;
 		case CMD_MIFARE_NESTED:
 			MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
 			break;
diff --git a/armsrc/apps.h b/armsrc/apps.h
index 3baf11ae..83cd94ec 100644
--- a/armsrc/apps.h
+++ b/armsrc/apps.h
@@ -132,6 +132,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 //void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
 void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
 void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
+void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
 void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
 void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
 void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
diff --git a/armsrc/epa.c b/armsrc/epa.c
index 737e633f..b89d4956 100644
--- a/armsrc/epa.c
+++ b/armsrc/epa.c
@@ -529,7 +529,7 @@ int EPA_Setup()
 	// power up the field
 	iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
 	// select the card
-	return_code = iso14443a_select_card(uid, &card_select_info, NULL);
+	return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0);
 	if (return_code == 1) {
 	// send the PPS request
 	ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index e2137832..29d9728a 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -1896,10 +1896,12 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
 	return Demod.len;
 }
 
-/* performs iso14443a anticollision procedure
- * 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) {
+// performs iso14443a anticollision (optional) and card select procedure
+// fills the uid and cuid pointer unless NULL
+// fills the card info record unless NULL
+// 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};
@@ -1914,7 +1916,7 @@ 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, NULL);
+    ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
 	
 	// Receive the ATQA
 	if(!ReaderReceive(resp, resp_par)) return 0;
@@ -1925,10 +1927,12 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 		memset(p_hi14a_card->uid,0,10);
 	}
 
+	if (anticollision) {
 	// clear uid
 	if (uid_ptr) {
 		memset(uid_ptr,0,10);
 	}
+	}
 
 	// check for proprietary anticollision:
 	if ((resp[0] & 0x1F) == 0) {
@@ -1942,6 +1946,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 		// SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97)
 		sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
 
+		if (anticollision) {
 		// SELECT_ALL
 		ReaderTransmit(sel_all, sizeof(sel_all), NULL);
 		if (!ReaderReceive(resp, resp_par)) return 0;
@@ -1977,6 +1982,14 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 		} else {		// no collision, use the response to SELECT_ALL as current uid
 			memcpy(uid_resp, resp, 4);
 		}
+		} else {
+			if (cascade_level < num_cascades - 1) {
+				uid_resp[0] = 0x88;
+				memcpy(uid_resp+1, uid_ptr+cascade_level*3, 3);
+			} else {
+				memcpy(uid_resp, uid_ptr+cascade_level*3, 4);
+			}
+		}
 		uid_resp_len = 4;
 
 		// calculate crypto UID. Always use last 4 Bytes.
@@ -1986,7 +1999,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 
 		// Construct SELECT UID command
 		sel_uid[1] = 0x70;													// transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC)
-		memcpy(sel_uid+2, uid_resp, 4);										// the UID
+		memcpy(sel_uid+2, uid_resp, 4);										// the UID received during anticollision, or the provided UID
 		sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5];  	// calculate and add BCC
 		AppendCrc14443a(sel_uid, 7);										// calculate and add CRC
 		ReaderTransmit(sel_uid, sizeof(sel_uid), NULL);
@@ -2002,11 +2015,10 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 			uid_resp[0] = uid_resp[1];
 			uid_resp[1] = uid_resp[2];
 			uid_resp[2] = uid_resp[3]; 
-
 			uid_resp_len = 3;
 		}
 
-		if(uid_ptr) {
+		if(uid_ptr && anticollision) {
 			memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len);
 		}
 
@@ -2127,7 +2139,7 @@ void ReaderIso14443a(UsbCommand *c)
 		iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
 		if(!(param & ISO14A_NO_SELECT)) {
 			iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
-			arg0 = iso14443a_select_card(NULL,card,NULL);
+			arg0 = iso14443a_select_card(NULL,card,NULL, true, 0);
 			cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t));
 		}
 	}
@@ -2325,7 +2337,7 @@ void ReaderMifare(bool first_try)
 			SpinDelay(100);
 		}
 		
-		if(!iso14443a_select_card(uid, NULL, &cuid)) {
+		if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 			if (MF_DBGLEVEL >= 1)	Dbprintf("Mifare: Can't select card");
 			continue;
 		}
diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h
index 81871dc7..c9da0da7 100644
--- a/armsrc/iso14443a.h
+++ b/armsrc/iso14443a.h
@@ -83,7 +83,7 @@ extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
 
 extern void iso14443a_setup(uint8_t fpga_minor_mode);
 extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
-extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr);
+extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades);
 extern void iso14a_set_trigger(bool enable);
 
 #endif /* __ISO14443A_H */
diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c
index 1e42d5b4..be25273d 100644
--- a/armsrc/mifarecmd.c
+++ b/armsrc/mifarecmd.c
@@ -49,7 +49,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	LED_C_OFF();
 
 	while (true) {
-		if(!iso14443a_select_card(uid, NULL, &cuid)) {
+		if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 			if (MF_DBGLEVEL >= 1)	Dbprintf("Can't select card");
 			break;
 		};
@@ -96,7 +96,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
 
 	clear_trace();
 
-	if(!iso14443a_select_card(NULL, NULL, NULL)) {
+	if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
 		OnError(0);
 		return;
@@ -131,7 +131,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
 
 	clear_trace();
 
-	int len = iso14443a_select_card(NULL, NULL, NULL);
+	int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
 	if(!len) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
 		OnError(1);
@@ -207,7 +207,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	LED_C_OFF();
 
 	isOK = 1;
-	if(!iso14443a_select_card(uid, NULL, &cuid)) {
+	if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 		isOK = 0;
 		if (MF_DBGLEVEL >= 1)	Dbprintf("Can't select card");
 	}
@@ -271,7 +271,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
 		return;
 	}
 
-	int len = iso14443a_select_card(NULL, NULL, NULL);
+	int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
 	if (!len) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len);
 		OnError(1);
@@ -373,7 +373,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	LED_C_OFF();
 
 	while (true) {
-			if(!iso14443a_select_card(uid, NULL, &cuid)) {
+			if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 			if (MF_DBGLEVEL >= 1)	Dbprintf("Can't select card");
 			break;
 		};
@@ -427,7 +427,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
 	clear_trace();
 	iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
 
-	if(!iso14443a_select_card(uid, NULL, NULL)) {
+	if(!iso14443a_select_card(uid, NULL, NULL, true, 0)) {
 		if (MF_DBGLEVEL >= 1)   Dbprintf("Can't select card");
 		OnError(0);
 		return;
@@ -473,7 +473,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
 
 	clear_trace();
 
-	if(!iso14443a_select_card(NULL, NULL, NULL)) {
+	if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
 		OnError(0);
 		return;
@@ -532,7 +532,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
 
 	clear_trace();
 
-	if(!iso14443a_select_card(NULL, NULL, NULL)) {
+	if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
 		OnError(0);
 		return;
@@ -597,6 +597,138 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
 }
 
 
+//-----------------------------------------------------------------------------
+// acquire encrypted nonces in order to perform the attack described in
+// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
+// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on 
+// Computer and Communications Security, 2015
+//-----------------------------------------------------------------------------
+void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain)
+{
+	uint64_t ui64Key = 0;
+	uint8_t uid[10];
+	uint32_t cuid;
+	uint8_t cascade_levels = 0;
+	struct Crypto1State mpcs = {0, 0};
+	struct Crypto1State *pcs;
+	pcs = &mpcs;
+	uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
+	int16_t isOK = 0;
+	uint8_t par_enc[1];
+	uint8_t nt_par_enc = 0;
+	uint8_t buf[USB_CMD_DATA_SIZE];
+	uint32_t timeout;
+	
+	uint8_t blockNo = arg0 & 0xff;
+	uint8_t keyType = (arg0 >> 8) & 0xff;
+	uint8_t targetBlockNo = arg1 & 0xff;
+	uint8_t targetKeyType = (arg1 >> 8) & 0xff;
+	ui64Key = bytes_to_num(datain, 6);
+	bool initialize = flags & 0x0001;
+	bool slow = flags & 0x0002;
+	bool field_off = flags & 0x0004;
+	
+	#define AUTHENTICATION_TIMEOUT 848			// card times out 1ms after wrong authentication (according to NXP documentation)
+	#define PRE_AUTHENTICATION_LEADTIME 400		// some (non standard) cards need a pause after select before they are ready for first authentication 
+	
+	LED_A_ON();
+	LED_C_OFF();
+
+	if (initialize) {
+		iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
+		clear_trace();
+		set_tracing(true);
+	}
+	
+	LED_C_ON();
+	
+	uint16_t num_nonces = 0;
+	bool have_uid = false;
+	for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) {
+
+		// Test if the action was cancelled
+		if(BUTTON_PRESS()) {
+			isOK = 2;
+			field_off = true;
+			break;
+		}
+
+		if (!have_uid) { // need a full select cycle to get the uid first
+			iso14a_card_select_t card_info;		
+			if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0)) {
+				if (MF_DBGLEVEL >= 1)	Dbprintf("AcquireNonces: Can't select card (ALL)");
+				continue;
+			}
+			switch (card_info.uidlen) {
+				case 4 : cascade_levels = 1; break;
+				case 7 : cascade_levels = 2; break;
+				case 10: cascade_levels = 3; break;
+				default: break;
+			}
+			have_uid = true;	
+		} else { // no need for anticollision. We can directly select the card
+			if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels)) {
+				if (MF_DBGLEVEL >= 1)	Dbprintf("AcquireNonces: Can't select card (UID)");
+				continue;
+			}
+		}
+		
+		if (slow) {
+			timeout = GetCountSspClk() + PRE_AUTHENTICATION_LEADTIME;
+			while(GetCountSspClk() < timeout);
+		}
+
+		uint32_t nt1;
+		if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
+			if (MF_DBGLEVEL >= 1)	Dbprintf("AcquireNonces: Auth1 error");
+			continue;
+		}
+
+		// nested authentication
+		uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL);
+		if (len != 4) {
+			if (MF_DBGLEVEL >= 1)	Dbprintf("AcquireNonces: Auth2 error len=%d", len);
+			continue;
+		}
+	
+		// send a dummy byte as reader response in order to trigger the cards authentication timeout
+		uint8_t dummy_answer = 0;
+		ReaderTransmit(&dummy_answer, 1, NULL);
+		timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
+		
+		num_nonces++;
+		if (num_nonces % 2) {
+			memcpy(buf+i, receivedAnswer, 4);
+			nt_par_enc = par_enc[0] & 0xf0;
+		} else {
+			nt_par_enc |= par_enc[0] >> 4;
+			memcpy(buf+i+4, receivedAnswer, 4);
+			memcpy(buf+i+8, &nt_par_enc, 1);
+			i += 9;
+		}
+
+		// wait for the card to become ready again
+		while(GetCountSspClk() < timeout);
+	
+	}
+
+	LED_C_OFF();
+	
+	crypto1_destroy(pcs);
+	
+	LED_B_ON();
+	cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
+	LED_B_OFF();
+
+	if (MF_DBGLEVEL >= 3)	DbpString("AcquireEncryptedNonces finished");
+
+	if (field_off) {
+		FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+		LEDsoff();
+	}
+}
+
+
 //-----------------------------------------------------------------------------
 // MIFARE nested authentication. 
 // 
@@ -668,7 +800,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
 				continue;
 			}
 
-			if(!iso14443a_select_card(uid, NULL, &cuid)) {
+			if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 				if (MF_DBGLEVEL >= 1)	Dbprintf("Nested: Can't select card");
 				rtr--;
 				continue;
@@ -741,7 +873,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
 				continue;
 			}
 
-			if(!iso14443a_select_card(uid, NULL, &cuid)) {
+			if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 				if (MF_DBGLEVEL >= 1)	Dbprintf("Nested: Can't select card");
 				continue;
 			};
@@ -857,7 +989,7 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 			if (MF_DBGLEVEL >= 1)	Dbprintf("ChkKeys: Halt error");
 		}
 
-		if(!iso14443a_select_card(uid, NULL, &cuid)) {
+		if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 			if (OLD_MF_DBGLEVEL >= 1)	Dbprintf("ChkKeys: Can't select card");
 			break;
 		};
@@ -952,7 +1084,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
 	
 	bool isOK = true;
 
-	if(!iso14443a_select_card(uid, NULL, &cuid)) {
+	if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 		isOK = false;
 		if (MF_DBGLEVEL >= 1)	Dbprintf("Can't select card");
 	}
@@ -1051,7 +1183,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain){
 
 	// read UID and return to client
 	if (workFlags & MAGIC_UID) {
-		if(!iso14443a_select_card(uid, NULL, &cuid)) {
+		if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
 			if (MF_DBGLEVEL >= MF_DBG_ERROR)	Dbprintf("Can't select card");
 			OnErrorMagic(MAGIC_UID);
 		};
@@ -1222,7 +1354,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
 	iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
 	clear_trace();
 
-	int len = iso14443a_select_card(uid, NULL, &cuid);
+	int len = iso14443a_select_card(uid, NULL, &cuid, true, 0);
 	if(!len) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
 		OnError(1);
diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c
index cacd767f..8336d793 100644
--- a/armsrc/mifaredesfire.c
+++ b/armsrc/mifaredesfire.c
@@ -25,7 +25,7 @@ bool InitDesfireCard(){
 	byte_t cardbuf[USB_CMD_DATA_SIZE] = {0x00};
 	iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf;
 	
-	int len = iso14443a_select_card(NULL,card,NULL);
+	int len = iso14443a_select_card(NULL,card,NULL,true,0);
 
 	if (!len) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR)
@@ -114,7 +114,7 @@ void MifareDesfireGetInformation(){
 
 	// card select - information
 	iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf;
-	byte_t isOK = iso14443a_select_card(NULL, card, NULL);
+	byte_t isOK = iso14443a_select_card(NULL, card, NULL, true, 0);
 	if ( isOK == 0) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) {
 			Dbprintf("Can't select card");
diff --git a/client/Makefile b/client/Makefile
index bcd59397..27617a5d 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -109,6 +109,7 @@ CMDSRCS = 	nonce2key/crapto1.c\
 			cmdhficlass.c \
 			cmdhfmf.c \
             cmdhfmfu.c \
+cmdhfmfhard.c \
 			cmdhfmfdes.c \
 			cmdhftopaz.c \
 			cmdhw.c \
diff --git a/client/cmddata.c b/client/cmddata.c
index aaff0302..aeabd985 100644
--- a/client/cmddata.c
+++ b/client/cmddata.c
@@ -1987,7 +1987,11 @@ int getSamples(const char *Cmd, bool silent)
 	GetFromBigBuf(got,n,0);
 	PrintAndLog("Data fetched");
 	UsbCommand response;
-	WaitForResponse(CMD_ACK, &response);
+	if ( !WaitForResponseTimeout(CMD_ACK, &response, 10000) ) {
+        PrintAndLog("timeout while waiting for reply.");
+		return 1;
+    }
+	
 	uint8_t bits_per_sample = 8;
 
 	//Old devices without this feature would send 0 at arg[0]
@@ -2030,9 +2034,9 @@ int CmdTuneSamples(const char *Cmd)
 	int timeout = 0;
 	printf("\nMeasuring antenna characteristics, please wait...");
 
-	UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING};
+	UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING, {0,0,0}};
+	clearCommandBuffer();
 	SendCommand(&c);
-
 	UsbCommand resp;
 	while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) {
 		timeout++;
@@ -2080,7 +2084,6 @@ int CmdTuneSamples(const char *Cmd)
 		ShowGraphWindow();
 		RepaintGraphWindow();
 	}
-
 	return 0;
 }
 
@@ -2096,7 +2099,7 @@ int CmdLoad(const char *Cmd)
 	
 	FILE *f = fopen(filename, "r");
 	if (!f) {
-		 PrintAndLog("couldn't open '%s'", filename);
+		PrintAndLog("couldn't open '%s'", filename);
 		return 0;
 	}
 
@@ -2115,11 +2118,13 @@ int CmdLoad(const char *Cmd)
 int CmdLtrim(const char *Cmd)
 {
 	int ds = atoi(Cmd);
-	if (GraphTraceLen<=0) return 0;
+
+	if (GraphTraceLen <= 0) return 0;
+
 	for (int i = ds; i < GraphTraceLen; ++i)
 		GraphBuffer[i-ds] = GraphBuffer[i];
-	GraphTraceLen -= ds;
 
+	GraphTraceLen -= ds;
 	RepaintGraphWindow();
 	return 0;
 }
@@ -2128,9 +2133,7 @@ int CmdLtrim(const char *Cmd)
 int CmdRtrim(const char *Cmd)
 {
 	int ds = atoi(Cmd);
-
 	GraphTraceLen = ds;
-
 	RepaintGraphWindow();
 	return 0;
 }
diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index 1d1dc2f4..ae380b3c 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -9,6 +9,7 @@
 //-----------------------------------------------------------------------------
 
 #include "cmdhfmf.h"
+#include "cmdhfmfhard.h"
 #include "nonce2key/nonce2key.h"
 
 static int CmdHelp(const char *Cmd);
@@ -791,6 +792,104 @@ int CmdHF14AMfNested(const char *Cmd)
 	return 0;
 }
 
+
+int CmdHF14AMfNestedHard(const char *Cmd)
+{
+	uint8_t blockNo = 0;
+	uint8_t keyType = 0;
+	uint8_t trgBlockNo = 0;
+	uint8_t trgKeyType = 0;
+	uint8_t key[6] = {0, 0, 0, 0, 0, 0};
+	
+	char ctmp;
+	ctmp = param_getchar(Cmd, 0);
+	if (ctmp != 'R' && ctmp != 'r' && strlen(Cmd) < 20) {
+		PrintAndLog("Usage:");
+		PrintAndLog("      hf mf hardnested <block number> <key A|B> <key (12 hex symbols)>");
+		PrintAndLog("                       <target block number> <target key A|B> [w] [s]");
+		PrintAndLog("  or  hf mf hardnested r");
+		PrintAndLog(" ");
+		PrintAndLog("Options: ");
+		PrintAndLog("      w: Acquire nonces and write them to binary file nonces.bin");
+		PrintAndLog("      s: Slower acquisition (required by some non standard cards)");
+		PrintAndLog("      r: Read nonces.bin and start attack");
+		PrintAndLog(" ");
+		PrintAndLog("      sample1: hf mf hardnested 0 A FFFFFFFFFFFF 4 A");
+		PrintAndLog("      sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w");
+		PrintAndLog("      sample3: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s");
+		PrintAndLog("      sample4: hf mf hardnested r");
+
+		return 0;
+	}	
+	
+	bool nonce_file_read = false;
+	bool nonce_file_write = false;
+	bool slow = false;
+	
+	if (ctmp == 'R' || ctmp == 'r') {
+
+		nonce_file_read = true;
+
+	} else {
+
+		blockNo = param_get8(Cmd, 0);
+		ctmp = param_getchar(Cmd, 1);
+		if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
+			PrintAndLog("Key type must be A or B");
+			return 1;
+		}
+		if (ctmp != 'A' && ctmp != 'a') { 
+			keyType = 1;
+		}
+		
+		if (param_gethex(Cmd, 2, key, 12)) {
+			PrintAndLog("Key must include 12 HEX symbols");
+			return 1;
+		}
+		
+		trgBlockNo = param_get8(Cmd, 3);
+		ctmp = param_getchar(Cmd, 4);
+		if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
+			PrintAndLog("Target key type must be A or B");
+			return 1;
+		}
+		if (ctmp != 'A' && ctmp != 'a') {
+			trgKeyType = 1;
+		}
+
+		uint16_t i = 5;
+		while ((ctmp = param_getchar(Cmd, i))) {
+			if (ctmp == 's' || ctmp == 'S') {
+				slow = true;
+			} else if (ctmp == 'w' || ctmp == 'W') {
+				nonce_file_write = true;
+			} else {
+				PrintAndLog("Possible options are w and/or s");
+				return 1;
+			}
+			i++;
+		}
+	}
+
+	PrintAndLog("--target block no:%3d, target key type:%c, file action: %s, Slow: %s ", 
+			trgBlockNo, 
+			trgKeyType?'B':'A', 
+			nonce_file_write?"write":nonce_file_read?"read":"none",
+			slow?"Yes":"No");
+	int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_read, nonce_file_write, slow);
+	if (isOK) {
+		switch (isOK) {
+			case 1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
+			case 2 : PrintAndLog("Button pressed. Aborted.\n"); break;
+			default : break;
+		}
+		return 2;
+	}
+
+	return 0;
+}
+
+
 int CmdHF14AMfChk(const char *Cmd)
 {
 	if (strlen(Cmd)<3) {
@@ -2017,6 +2116,7 @@ static command_t CommandTable[] =
   {"chk",		CmdHF14AMfChk,			0, "Test block keys"},
   {"mifare",	CmdHF14AMifare,			0, "Read parity error messages."},
   {"nested",	CmdHF14AMfNested,		0, "Test nested authentication"},
+	{"hardnested", 	CmdHF14AMfNestedHard, 	0, "Nested attack for hardened Mifare cards"},
   {"sniff",		CmdHF14AMfSniff,		0, "Sniff card-reader communication"},
   {"sim",		CmdHF14AMf1kSim,		0, "Simulate MIFARE card"},
   {"eclr",		CmdHF14AMfEClear,		0, "Clear simulator memory block"},
diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h
index 19adbe30..31c84dc4 100644
--- a/client/cmdhfmf.h
+++ b/client/cmdhfmf.h
@@ -38,6 +38,7 @@ int CmdHF14AMfUWrBl(const char* cmd);
 int CmdHF14AMfChk(const char* cmd);
 int CmdHF14AMifare(const char* cmd);
 int CmdHF14AMfNested(const char* cmd);
+int CmdHF14AMfNestedHard(const char *Cmd);
 int CmdHF14AMfSniff(const char* cmd);
 int CmdHF14AMf1kSim(const char* cmd);
 int CmdHF14AMfEClear(const char* cmd);
diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c
index d864c9ed..2605784e 100644
--- a/client/cmdlft55xx.c
+++ b/client/cmdlft55xx.c
@@ -134,7 +134,7 @@ int usage_t55xx_detect(){
 	PrintAndLog("Examples:");
 	PrintAndLog("      lf t55xx detect");
 	PrintAndLog("      lf t55xx detect 1");
-	PrintAndLog("      lf t55xx detect 11223344");
+	PrintAndLog("      lf t55xx detect p 11223344");
 	PrintAndLog("");
 	return 0;
 }
@@ -149,6 +149,14 @@ int usage_t55xx_wakup(){
     PrintAndLog("      lf t55xx wakeup p 11223344  - send wakeup password");
 	return 0;
 }
+int usage_t55xx_bruteforce(){
+    PrintAndLog("Usage: lf t55xx bruteforce <start password> <end password>");
+    PrintAndLog("       password must be 4 bytes (8 hex symbols)");
+    PrintAndLog("Examples:");
+    PrintAndLog("       lf t55xx bruteforce aaaaaaaa bbbbbbbb");
+    PrintAndLog("");
+    return 0;
+}
 
 static int CmdHelp(const char *Cmd);
 
@@ -1307,20 +1315,61 @@ int CmdT55xxWipe(const char *Cmd) {
 	return 0;
 }
 
+int CmdT55xxBruteForce(const char *Cmd) {
+    uint32_t start_password = 0x00000000; //start password
+    uint32_t end_password   = 0xFFFFFFFF; //end   password
+
+    bool found = false;
+    char cmdp = param_getchar(Cmd, 0);
+    if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce();
+
+    start_password = param_get32ex(Cmd, 0, 0, 16);
+	end_password = param_get32ex(Cmd, 1, 0, 16);
+	
+	if ( start_password == end_password ) return usage_t55xx_bruteforce();
+	
+    PrintAndLog("Start Password %08x", start_password);
+    PrintAndLog("  End Password %08x", end_password);
+	
+    int i = start_password;
+
+    while ((!found) && (i <= end_password)){
+
+		AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, TRUE, i);
+		found = tryDetectModulation();
+        
+		if (found)
+			break;
+        
+        if ((i % 0x100) == 0) printf("[%08x], ",i);
+
+		i++;
+    }
+    
+    PrintAndLog("");
+	
+    if (found)
+		PrintAndLog("Found Password [%08x]", i);
+    else
+		PrintAndLog("NOT Found Last Password [%08x]", i);
+    return 0;
+}
+
 static command_t CommandTable[] = {
-  {"help",   CmdHelp,           1, "This help"},
-  {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"},
-  {"detect",   CmdT55xxDetect,    1, "[1] Try detecting the tag modulation from reading the configuration block."},
-  {"read",     CmdT55xxReadBlock, 0, "b <block> p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]"},
-  {"resetread",CmdResetRead,      0, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"},
-  {"write",    CmdT55xxWriteBlock,0, "b <block> d <data> p [password] [1] -- Write T55xx block data. Optional [p password], [page1]"},
-  {"trace",    CmdT55xxReadTrace, 1, "[1] Show T55x7 traceability data (page 1/ blk 0-1)"},
-  {"info",     CmdT55xxInfo,      1, "[1] Show T55x7 configuration data (page 0/ blk 0)"},
-  {"dump",     CmdT55xxDump,      0, "[password] [o] Dump T55xx card block 0-7. Optional [password], [override]"},
-  {"special", special,          0, "Show block changes with 64 different offsets"},
-  {"wakeup", CmdT55xxWakeUp,    0, "Send AOR wakeup command"},
-  {"wipe",     CmdT55xxWipe,      0, "Wipe a T55xx tag and set defaults (will destroy any data on tag)"},
-  {NULL, NULL, 0, NULL}
+	{"help",		CmdHelp,           1, "This help"},
+	{"bruceforce",	CmdT55xxBruteForce,0, "Simple bruteforce attack to find password"},
+	{"config",		CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"},
+	{"detect",		CmdT55xxDetect,    1, "[1] Try detecting the tag modulation from reading the configuration block."},
+	{"dump",		CmdT55xxDump,      0, "[password] [o] Dump T55xx card block 0-7. Optional [password], [override]"},
+	{"info",		CmdT55xxInfo,      1, "[1] Show T55x7 configuration data (page 0/ blk 0)"},
+	{"read",		CmdT55xxReadBlock, 0, "b <block> p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]"},
+	{"resetread",	CmdResetRead,      0, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"},
+	{"special",		special,           0, "Show block changes with 64 different offsets"},	
+	{"trace",		CmdT55xxReadTrace, 1, "[1] Show T55x7 traceability data (page 1/ blk 0-1)"},
+	{"wakeup",		CmdT55xxWakeUp,    0, "Send AOR wakeup command"},
+	{"wipe",		CmdT55xxWipe,      0, "Wipe a T55xx tag and set defaults (will destroy any data on tag)"},
+	{"write",		CmdT55xxWriteBlock,0, "b <block> d <data> p [password] [1] -- Write T55xx block data. Optional [p password], [page1]"},
+	{NULL, NULL, 0, NULL}
 };
 
 int CmdLFT55XX(const char *Cmd) {
diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h
index a58fa44e..77963fde 100644
--- a/client/cmdlft55xx.h
+++ b/client/cmdlft55xx.h
@@ -75,6 +75,7 @@ int CmdT55xxInfo(const char *Cmd);
 int CmdT55xxDetect(const char *Cmd);
 int CmdResetRead(const char *Cmd);
 int CmdT55xxWipe(const char *Cmd);
+int CmdT55xxBruteForce(const char *Cmd);
 
 char * GetBitRateStr(uint32_t id);
 char * GetSaferStr(uint32_t id);
@@ -92,4 +93,5 @@ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5)
 int special(const char *Cmd);
 int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password );
 
+bool detectPassword(int password);
 #endif
diff --git a/client/data.c b/client/data.c
index 4d7d1e41..1725944e 100644
--- a/client/data.c
+++ b/client/data.c
@@ -17,9 +17,9 @@
 
 uint8_t* sample_buf;
 
-void GetFromBigBuf(uint8_t *dest, int bytes, int start_index)
-{
-  sample_buf = dest;
-  UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
-  SendCommand(&c);
+void GetFromBigBuf(uint8_t *dest, int bytes, int start_index) {
+	sample_buf = dest;
+	UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
+	clearCommandBuffer();
+	SendCommand(&c);
 }
diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h
index 01b2d83b..be0cf9ce 100644
--- a/client/hid-flasher/usb_cmd.h
+++ b/client/hid-flasher/usb_cmd.h
@@ -168,6 +168,8 @@ typedef struct{
 
 #define CMD_READER_MIFARE                                                 0x0611
 #define CMD_MIFARE_NESTED                                                 0x0612
+#define	CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES                               0x0613
+
 
 #define CMD_MIFARE_READBL                                                 0x0620
 #define CMD_MIFAREU_READBL                                                0x0720
diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua
index 957c99b4..92fc9bb0 100644
--- a/client/lualibs/commands.lua
+++ b/client/lualibs/commands.lua
@@ -129,6 +129,7 @@ local _commands = {
 
 	CMD_READER_MIFARE =                                                  0x0611,
 	CMD_MIFARE_NESTED =                                                  0x0612,
+	CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES =                                0x0613,
 
 	CMD_MIFARE_READBL =                                                  0x0620,
 	CMD_MIFAREU_READBL =                                                 0x0720,
diff --git a/common/lfdemod.h b/common/lfdemod.h
index 20eb6769..a1d99e11 100644
--- a/common/lfdemod.h
+++ b/common/lfdemod.h
@@ -16,6 +16,7 @@
 #include <stdint.h>
 
 //generic
+uint8_t justNoise(uint8_t *BitStream, size_t size);
 size_t   addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType);
 int      askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType);
 int      BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert);
diff --git a/include/usb_cmd.h b/include/usb_cmd.h
index ff20fde7..d2f746a7 100644
--- a/include/usb_cmd.h
+++ b/include/usb_cmd.h
@@ -171,6 +171,7 @@ typedef struct{
 
 #define CMD_READER_MIFARE                                                 0x0611
 #define CMD_MIFARE_NESTED                                                 0x0612
+#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES                               0x0613
 
 #define CMD_MIFARE_READBL                                                 0x0620
 #define CMD_MIFAREU_READBL                                                0x0720
-- 
2.39.5