From ac4ecfe35327f827aeaf8426af2662c656affd2c Mon Sep 17 00:00:00 2001
From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com>
Date: Mon, 3 Dec 2018 09:29:13 +0200
Subject: [PATCH 1/1] added mifare trailer block decoding (#726)

---
 client/cmdhfmf.c | 32 ++++++++++++++++++++++++++++++--
 client/mifare4.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 client/mifare4.h |  7 +++++++
 3 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index c382664b..fa952cb9 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -141,12 +141,26 @@ int CmdHF14AMfRdBl(const char *Cmd)
 		uint8_t isOK  = resp.arg[0] & 0xff;
 		uint8_t *data = resp.d.asBytes;
 
-		if (isOK)
+		if (isOK) {
 			PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16));
-		else
+		} else {
 			PrintAndLog("isOk:%02x", isOK);
+			return 1;
+		}
+
+		if (mfIsSectorTrailer(blockNo) && (data[6] || data[7] || data[8])) {
+			PrintAndLogEx(NORMAL, "Trailer decoded:");
+			int bln = mfFirstBlockOfSector(mfSectorNum(blockNo));
+			int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1;
+			for (int i = 0; i < 4; i++) {
+				PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &data[6]));
+				bln += blinc;
+			}
+			PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&data[9], 1));
+		}
 	} else {
 		PrintAndLog("Command execute timeout");
+		return 2;
 	}
 
   return 0;
@@ -2272,6 +2286,20 @@ int CmdHF14AMfCGetBlk(const char *Cmd) {
 		}
 
 	PrintAndLog("block data:%s", sprint_hex(memBlock, 16));
+	
+	if (mfIsSectorTrailer(blockNo)) {
+		PrintAndLogEx(NORMAL, "Trailer decoded:");
+		PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6));
+		PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6));
+		int bln = mfFirstBlockOfSector(mfSectorNum(blockNo));
+		int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1;
+		for (int i = 0; i < 4; i++) {
+			PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6]));
+			bln += blinc;
+		}
+		PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1));
+	}
+	
 	return 0;
 }
 
diff --git a/client/mifare4.c b/client/mifare4.c
index 069c54d4..419e9b23 100644
--- a/client/mifare4.c
+++ b/client/mifare4.c
@@ -17,6 +17,52 @@
 #include "ui.h"
 #include "crypto/libpcrypto.h"
 
+AccessConditions_t MFAccessConditions[] = {
+	{0x00, "read AB; write AB; increment AB; decrement transfer restore AB"},
+	{0x01, "read AB; decrement transfer restore AB"},
+	{0x02, "read AB"},
+	{0x03, "read B; write B"},
+	{0x04, "read AB; writeB"},
+	{0x05, "read B"},
+	{0x06, "read AB; write B; increment B; decrement transfer restore AB"},
+	{0x07, "none"}
+};
+
+AccessConditions_t MFAccessConditionsTrailer[] = {
+	{0x00, "read A by A; read ACCESS by A; read B by A; write B by A"},
+	{0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"},
+	{0x02, "read ACCESS by A; read B by A"},
+	{0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"},
+	{0x04, "write A by B; read ACCESS by AB; write B by B"},
+	{0x05, "read ACCESS by AB; write ACCESS by B"},
+	{0x06, "read ACCESS by AB"},
+	{0x07, "read ACCESS by AB"}
+};
+
+char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) {
+	static char StaticNone[] = "none";
+	
+	uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn;
+	uint8_t data2 = ((data[2]) & 0x0f) >> blockn;
+	uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn;
+	
+	uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01);
+
+	if (blockn == 3) {
+		for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)
+			if (MFAccessConditionsTrailer[i].cond == cond) {
+				return MFAccessConditionsTrailer[i].description;
+			}
+	} else {
+		for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++)
+			if (MFAccessConditions[i].cond == cond) {
+				return MFAccessConditions[i].description;
+			}
+	};
+	
+	return StaticNone;
+};
+
 int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) {
 	memcpy(&iv[0], session->TI, 4);
 	memcpy(&iv[4], &session->R_Ctr, 2);
diff --git a/client/mifare4.h b/client/mifare4.h
index 2453797b..5d9735da 100644
--- a/client/mifare4.h
+++ b/client/mifare4.h
@@ -38,9 +38,16 @@ typedef enum {
 	mtypWriteResp,
 } MACType_t;
 
+typedef struct {
+	uint8_t cond;
+	char *description;
+} AccessConditions_t;
+
 extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
 extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose);
 
+extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data);
+
 extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
 extern uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
 extern uint8_t mfSectorTrailer(uint8_t blockNo);
-- 
2.39.5