From b915fda392487a876ccc7b0c8b79a1b31ca5e398 Mon Sep 17 00:00:00 2001
From: iceman1001 <iceman@iuse.se>
Date: Wed, 7 Jan 2015 22:00:29 +0100
Subject: [PATCH] FIX: a solution for the issue "hf mf esave - always saves 4K"
 FIX: a solution for the issue "hf eload, esave, cload, save - filepath
 variable too short" CHG: minor code clean up. ADD: AES / CRC16 for lua. (and
 tnp3xx scripts.) ADD: tnp3dump.lua  script to dump tnp3xx tags. ADD:
 tnp3sim.lua script to let PM3 imitate an tnp3xx tag. Needs to be tested live

---
 client/cmddata.c            |  25 ++-
 client/cmdhf.c              |  33 +++-
 client/cmdhf14a.c           |   5 +-
 client/cmdhf14a.h           |   2 +-
 client/cmdhf14b.c           |  10 +-
 client/cmdhflegic.c         |  21 ++-
 client/cmdhfmf.c            | 196 +++++++++++++-------
 client/cmdlf.c              |  26 ++-
 client/cmdlfem4x.c          |  16 +-
 client/cmdlfhitag.c         |  56 ++++--
 client/cmdmain.c            |   2 +
 client/flasher.c            |   3 -
 client/lualibs/commands.lua |   7 +-
 client/lualibs/utils.lua    | 171 ++++++++++++++++-
 client/proxmark3.c          |   2 +-
 client/scripting.c          |  52 ++++++
 client/scripts/tnp3dump.lua | 272 +++++++++++++++++++++++++++
 client/scripts/tnp3sim.lua  | 355 ++++++++++++++++++++++++++++++++++++
 client/util.c               |  18 +-
 19 files changed, 1138 insertions(+), 134 deletions(-)
 create mode 100644 client/scripts/tnp3dump.lua
 create mode 100644 client/scripts/tnp3sim.lua

diff --git a/client/cmddata.c b/client/cmddata.c
index 3ac8db25..d05f3fa1 100644
--- a/client/cmddata.c
+++ b/client/cmddata.c
@@ -696,7 +696,7 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating
 
   int lowLen = sizeof (LowTone) / sizeof (int);
   int highLen = sizeof (HighTone) / sizeof (int);
-  int convLen = (highLen > lowLen) ? highLen : lowLen; //if highlen > lowLen then highlen else lowlen
+  int convLen = (highLen > lowLen) ? highLen : lowLen;
   uint32_t hi = 0, lo = 0;
 
   int i, j;
@@ -942,9 +942,16 @@ int CmdTuneSamples(const char *Cmd)
 
 int CmdLoad(const char *Cmd)
 {
-  FILE *f = fopen(Cmd, "r");
+   char filename[FILE_PATH_SIZE] = {0x00};
+   int len = 0;
+
+   len = strlen(Cmd);
+   if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
+   memcpy(filename, Cmd, len);
+	
+   FILE *f = fopen(filename, "r");
   if (!f) {
-    PrintAndLog("couldn't open '%s'", Cmd);
+     PrintAndLog("couldn't open '%s'", filename);
     return 0;
   }
 
@@ -1250,9 +1257,17 @@ int CmdPlot(const char *Cmd)
 
 int CmdSave(const char *Cmd)
 {
-  FILE *f = fopen(Cmd, "w");
+   char filename[FILE_PATH_SIZE] = {0x00};
+   int len = 0;
+
+   len = strlen(Cmd);
+   if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
+   memcpy(filename, Cmd, len);
+   
+
+  FILE *f = fopen(filename, "w");
   if(!f) {
-    PrintAndLog("couldn't open '%s'", Cmd);
+    PrintAndLog("couldn't open '%s'", filename);
     return 0;
   }
   int i;
diff --git a/client/cmdhf.c b/client/cmdhf.c
index 550f8e86..b53742e4 100644
--- a/client/cmdhf.c
+++ b/client/cmdhf.c
@@ -47,9 +47,11 @@ int CmdHFTune(const char *Cmd)
 #define iso14443_CMD_WUPA       0x52
 #define iso14443_CMD_SELECT     0x93
 #define iso14443_CMD_SELECT_2   0x95
+#define iso14443_CMD_SELECT_3   0x97
 #define iso14443_CMD_REQ        0x26
 #define iso14443_CMD_READBLOCK  0x30
 #define iso14443_CMD_WRITEBLOCK 0xA0
+#define iso14443_CMD_WRITE		0xA2
 #define iso14443_CMD_INC        0xC0
 #define iso14443_CMD_DEC        0xC1
 #define iso14443_CMD_RESTORE    0xC2
@@ -57,6 +59,15 @@ int CmdHFTune(const char *Cmd)
 #define iso14443_CMD_HALT       0x50
 #define iso14443_CMD_RATS       0xE0
 
+#define iso14443_CMD_AUTH_KEYA	0x60
+#define iso14443_CMD_AUTH_KEYB	0x61
+
+#define iso14443_CMD_AUTH_STEP1	0x1A
+#define iso14443_CMD_AUTH_STEP2	0xAA
+#define iso14443_CMD_AUTH_RESPONSE	0xAF
+
+#define CHINESE_BACKDOOR_INIT   0x40 
+#define CHINESE_BACKDOOR_STEP2   0x43 
 
 void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 {
@@ -76,12 +87,22 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 	case iso14443_CMD_REQ:         snprintf(exp,size,"REW"); break;
 	case iso14443_CMD_READBLOCK:   snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
 	case iso14443_CMD_WRITEBLOCK:  snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
+	case iso14443_CMD_WRITE:	   snprintf(exp,size,"WRITE"); break;
 	case iso14443_CMD_INC:         snprintf(exp,size,"INC(%d)",cmd[1]); break;
 	case iso14443_CMD_DEC:         snprintf(exp,size,"DEC(%d)",cmd[1]); break;
 	case iso14443_CMD_RESTORE:     snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
 	case iso14443_CMD_TRANSFER:    snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break;
 	case iso14443_CMD_HALT:        snprintf(exp,size,"HALT"); break;
 	case iso14443_CMD_RATS:        snprintf(exp,size,"RATS"); break;
+	
+	case iso14443_CMD_AUTH_KEYA:   snprintf(exp,size,"AUTH KEY A"); break;
+	case iso14443_CMD_AUTH_KEYB:   snprintf(exp,size,"AUTH KEY B"); break;
+	case iso14443_CMD_AUTH_STEP1:  snprintf(exp,size,"AUTH REQ NONCE"); break;
+	case iso14443_CMD_AUTH_STEP2:  snprintf(exp,size,"AUTH STEP 2"); break;
+	case iso14443_CMD_AUTH_RESPONSE:  snprintf(exp,size,"AUTH RESPONSE"); break;
+	
+	case CHINESE_BACKDOOR_INIT:    snprintf(exp,size,"BACKDOOR INIT");break;
+	case CHINESE_BACKDOOR_STEP2:    snprintf(exp,size,"BACKDOOR STEP2");break;
 	default:                       snprintf(exp,size,"?"); break;
 	}
 	return;
@@ -89,7 +110,6 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 
 void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 {
-
 	if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ)
 	{
 		  snprintf(exp,size,"READ(%d)",cmd[1]);
@@ -112,7 +132,6 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 }
 
 
-
 uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles)
 {
 	bool isResponse;
@@ -178,8 +197,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
 				// Rough guess that this is a command from the reader
 				// For iClass the command byte is not part of the CRC
 				ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2);
-			}
-			else {
+			} else {
 				// For other data.. CRC might not be applicable (UPDATE commands etc.)
 				ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2);
 			}
@@ -199,7 +217,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
 				}
 			}
 		}
-
 	}
 	char *crc = crcError ? "!crc" :"    ";
 
@@ -207,8 +224,10 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
 
 	if(!isResponse)
 	{
-		if(iclass)	annotateIclass(explanation,sizeof(explanation),frame,data_len);
-		else annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
+		if(iclass)
+			annotateIclass(explanation,sizeof(explanation),frame,data_len);
+		else 
+			annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
 	}
 
 	int num_lines = (data_len - 1)/16 + 1;
diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c
index 40173d83..0298f509 100644
--- a/client/cmdhf14a.c
+++ b/client/cmdhf14a.c
@@ -111,7 +111,7 @@ const manufactureName manufactureMapping[] = {
 // get a product description based on the UID
 //		uid[8] 	tag uid
 // returns description of the best match	
-static char* getTagInfo(uint8_t uid) {
+char* getTagInfo(uint8_t uid) {
 
 	int i, best = -1;	
 	int len = sizeof(manufactureMapping) / sizeof(manufactureName);
@@ -168,6 +168,7 @@ int CmdHF14AReader(const char *Cmd)
 	PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]);
 
 	// Double & triple sized UID, can be mapped to a manufacturer.
+	// HACK: does this apply for Ultralight cards?
 	if ( card.uidlen > 4 ) {
 		PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0]));
 	}
@@ -624,7 +625,7 @@ static void waitCmd(uint8_t iSelect)
     UsbCommand resp;
     char *hexout;
 
-    if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+    if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
         recv = resp.d.asBytes;
         uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0];
         PrintAndLog("received %i octets",iLen);
diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h
index d2e203a1..aa35dec6 100644
--- a/client/cmdhf14a.h
+++ b/client/cmdhf14a.h
@@ -20,5 +20,5 @@ int CmdHF14AReader(const char *Cmd);
 int CmdHF14ASim(const char *Cmd);
 int CmdHF14ASnoop(const char *Cmd);
 
-
+char* getTagInfo(uint8_t uid);
 #endif
diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c
index 7e4cbd00..713959f2 100644
--- a/client/cmdhf14b.c
+++ b/client/cmdhf14b.c
@@ -23,7 +23,6 @@
 #include "cmdhf14b.h"
 #include "cmdmain.h"
 
-
 static int CmdHelp(const char *Cmd);
 
 int CmdHF14BDemod(const char *Cmd)
@@ -146,7 +145,7 @@ demodError:
 
 int CmdHF14BList(const char *Cmd)
 {
-  uint8_t got[960];
+  uint8_t got[TRACE_BUFFER_SIZE];
   GetFromBigBuf(got,sizeof(got),0);
   WaitForResponse(CMD_ACK,NULL);
 
@@ -158,9 +157,8 @@ int CmdHF14BList(const char *Cmd)
   int prev = -1;
 
   for(;;) {
-    if(i >= 900) {
-      break;
-    }
+    
+	if(i >= TRACE_BUFFER_SIZE) { break; }
 
     bool isResponse;
     int timestamp = *((uint32_t *)(got+i));
@@ -177,7 +175,7 @@ int CmdHF14BList(const char *Cmd)
     if(len > 100) {
       break;
     }
-    if(i + len >= 900) {
+    if(i + len >= TRACE_BUFFER_SIZE) {
       break;
     }
 
diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c
index bf874b62..35ba1f28 100644
--- a/client/cmdhflegic.c
+++ b/client/cmdhflegic.c
@@ -218,7 +218,24 @@ int CmdLegicRFRead(const char *Cmd)
 
 int CmdLegicLoad(const char *Cmd)
 {
-    FILE *f = fopen(Cmd, "r");
+	char filename[FILE_PATH_SIZE] = {0x00};
+	int len = 0;
+	
+	if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
+		PrintAndLog("It loads datasamples from the file `filename`");
+		PrintAndLog("Usage:  hf legic load <file name>");
+		PrintAndLog(" sample: hf legic load filename");
+		return 0;
+	}
+
+	len = strlen(Cmd);	
+	if (len > FILE_PATH_SIZE) {
+		PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE);
+		return 0;
+	}
+	memcpy(filename, Cmd, len);
+
+    FILE *f = fopen(filename, "r");
     if(!f) {
         PrintAndLog("couldn't open '%s'", Cmd);
         return -1;
@@ -251,7 +268,7 @@ int CmdLegicSave(const char *Cmd)
   int requested = 1024;
   int offset = 0;
   int delivered = 0;
-  char filename[1024];
+  char filename[FILE_PATH_SIZE];
   uint8_t got[1024];
   
   sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index 46a11b56..7ad6e0a1 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -66,8 +66,7 @@ start:
 	if (isOK != 1) return 1;
 	
 	// execute original function from util nonce2key
-	if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key))
-	{
+	if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {
 		isOK = 2;
 		PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);	
 	} else {
@@ -512,6 +511,7 @@ int CmdHF14AMfDump(const char *Cmd)
 			return 2;
 		}
 	}
+	
 	fclose(fin);
 	// Read access rights to sectors
 
@@ -629,8 +629,8 @@ int CmdHF14AMfRestore(const char *Cmd)
 {
 	uint8_t sectorNo,blockNo;
 	uint8_t keyType = 0;
-	uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-	uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	uint8_t key[6] = {0xFF};
+	uint8_t bldata[16] = {0x00};
 	uint8_t keyA[40][6];
 	uint8_t keyB[40][6];
 	uint8_t numSectors;
@@ -657,21 +657,14 @@ int CmdHF14AMfRestore(const char *Cmd)
 		return 0;
 	}
 
-	if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {
-		PrintAndLog("Could not find file dumpdata.bin");
-		return 1;
-	}
 	if ((fkeys = fopen("dumpkeys.bin","rb")) == NULL) {
 		PrintAndLog("Could not find file dumpkeys.bin");
-		fclose(fdump);
 		return 1;
 	}
 	
 	for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
 		if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) {
 			PrintAndLog("File reading error (dumpkeys.bin).");
-			fclose(fdump);
-			fclose(fkeys);
 			return 2;
 		}
 	}
@@ -679,13 +672,16 @@ int CmdHF14AMfRestore(const char *Cmd)
 	for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
 		if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) {
 			PrintAndLog("File reading error (dumpkeys.bin).");
-			fclose(fdump);
-			fclose(fkeys);
 			return 2;
 		}
 	}
+
 	fclose(fkeys);
 
+	if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {
+		PrintAndLog("Could not find file dumpdata.bin");
+		return 1;
+	}	
 	PrintAndLog("Restoring dumpdata.bin to card");
 
 	for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
@@ -773,11 +769,15 @@ int CmdHF14AMfNested(const char *Cmd)
 	cmdp = param_getchar(Cmd, 0);
 	blockNo = param_get8(Cmd, 1);
 	ctmp = param_getchar(Cmd, 2);
+	
 	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 (ctmp != 'A' && ctmp != 'a') 
+		keyType = 1;
+		
 	if (param_gethex(Cmd, 3, key, 12)) {
 		PrintAndLog("Key must include 12 HEX symbols");
 		return 1;
@@ -791,8 +791,10 @@ int CmdHF14AMfNested(const char *Cmd)
 			PrintAndLog("Target key type must be A or B");
 			return 1;
 		}
-		if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;
+		if (ctmp != 'A' && ctmp != 'a') 
+			trgKeyType = 1;
 	} else {
+				
 		switch (cmdp) {
 			case '0': SectorsCnt = 05; break;
 			case '1': SectorsCnt = 16; break;
@@ -869,7 +871,6 @@ int CmdHF14AMfNested(const char *Cmd)
 			}
 		}
 		
-		
 		// nested sectors
 		iterations = 0;
 		PrintAndLog("nested...");
@@ -972,7 +973,7 @@ int CmdHF14AMfChk(const char *Cmd)
 	}	
 
 	FILE * f;
-	char filename[256]={0};
+	char filename[FILE_PATH_SIZE]={0};
 	char buf[13];
 	uint8_t *keyBlock = NULL, *p;
 	uint8_t stKeyBlock = 20;
@@ -988,7 +989,6 @@ int CmdHF14AMfChk(const char *Cmd)
 	int transferToEml = 0;
 	int createDumpFile = 0;
 
-
 	keyBlock = calloc(stKeyBlock, 6);
 	if (keyBlock == NULL) return 1;
 
@@ -1065,7 +1065,7 @@ int CmdHF14AMfChk(const char *Cmd)
 			keycnt++;
 		} else {
 			// May be a dic file
-			if ( param_getstr(Cmd, 2 + i,filename) > 255 ) {
+			if ( param_getstr(Cmd, 2 + i,filename) >= FILE_PATH_SIZE ) {
 				PrintAndLog("File name too long");
 				free(keyBlock);
 				return 2;
@@ -1346,26 +1346,44 @@ int CmdHF14AMfESet(const char *Cmd)
 int CmdHF14AMfELoad(const char *Cmd)
 {
 	FILE * f;
-	char filename[20];
+	char filename[FILE_PATH_SIZE];
 	char *fnameptr = filename;
 	char buf[64];
 	uint8_t buf8[64];
-	int i, len, blockNum;
+	int i, len, blockNum, numBlocks;
+	int nameParamNo = 1;
 	
 	memset(filename, 0, sizeof(filename));
 	memset(buf, 0, sizeof(buf));
 
-	if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
+	char ctmp = param_getchar(Cmd, 0);
+		
+	if ( ctmp == 'h' || ctmp == 0x00) {
 		PrintAndLog("It loads emul dump from the file `filename.eml`");
-		PrintAndLog("Usage:  hf mf eload <file name w/o `.eml`>");
+		PrintAndLog("Usage:  hf mf eload [card memory] <file name w/o `.eml`>");
+		PrintAndLog("  [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
+		PrintAndLog("");
 		PrintAndLog(" sample: hf mf eload filename");
+		PrintAndLog("         hf mf eload 4 filename");
 		return 0;
 	}	
 
-	len = strlen(Cmd);
-	if (len > 14) len = 14;
+	switch (ctmp) {
+		case '0' : numBlocks = 5*4; break;
+		case '1' : 
+		case '\0': numBlocks = 16*4; break;
+		case '2' : numBlocks = 32*4; break;
+		case '4' : numBlocks = 256; break;
+		default:  {
+			numBlocks = 16*4;
+			nameParamNo = 0;
+		}
+	}
+
+	len = param_getstr(Cmd,nameParamNo,filename);
+	
+	if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
 
-	memcpy(filename, Cmd, len);
 	fnameptr += len;
 
 	sprintf(fnameptr, ".eml"); 
@@ -1380,14 +1398,16 @@ int CmdHF14AMfELoad(const char *Cmd)
 	blockNum = 0;
 	while(!feof(f)){
 		memset(buf, 0, sizeof(buf));
+		
 		if (fgets(buf, sizeof(buf), f) == NULL) {
-			if((blockNum == 16*4) || (blockNum == 32*4 + 8*16)) {	// supports both old (1K) and new (4K) .eml files)
-				break;
-			}
+			
+			if (blockNum >= numBlocks) break;
+			
 			PrintAndLog("File reading error.");
 			fclose(f);
 			return 2;
 		}
+		
 		if (strlen(buf) < 32){
 			if(strlen(buf) && feof(f))
 				break;
@@ -1395,6 +1415,7 @@ int CmdHF14AMfELoad(const char *Cmd)
 			fclose(f);
 			return 2;
 		}
+		
 		for (i = 0; i < 32; i += 2) {
 			sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]);
 		}
@@ -1406,12 +1427,12 @@ int CmdHF14AMfELoad(const char *Cmd)
 		}
 		blockNum++;
 		
-		if (blockNum >= 32*4 + 8*16) break;
+		if (blockNum >= numBlocks) break;
 	}
 	fclose(f);
 	
-	if ((blockNum != 16*4) && (blockNum != 32*4 + 8*16)) {
-		PrintAndLog("File content error. There must be 64 or 256 blocks.");
+	if ((blockNum != numBlocks)) {
+		PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks);
 		return 4;
 	}
 	PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);
@@ -1422,45 +1443,70 @@ int CmdHF14AMfELoad(const char *Cmd)
 int CmdHF14AMfESave(const char *Cmd)
 {
 	FILE * f;
-	char filename[20];
+	char filename[FILE_PATH_SIZE];
 	char * fnameptr = filename;
 	uint8_t buf[64];
-	int i, j, len;
+	int i, j, len, numBlocks;
+	int nameParamNo = 1;
 	
 	memset(filename, 0, sizeof(filename));
 	memset(buf, 0, sizeof(buf));
 
-	if (param_getchar(Cmd, 0) == 'h') {
+	char ctmp = param_getchar(Cmd, 0);
+	
+	if ( ctmp == 'h' || ctmp == 'H') {
 		PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`");
-		PrintAndLog("Usage:  hf mf esave [file name w/o `.eml`]");
+		PrintAndLog(" Usage:  hf mf esave [card memory] [file name w/o `.eml`]");
+		PrintAndLog("  [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
+		PrintAndLog("");
 		PrintAndLog(" sample: hf mf esave ");
-		PrintAndLog("         hf mf esave filename");
+		PrintAndLog("         hf mf esave 4");
+		PrintAndLog("         hf mf esave 4 filename");
 		return 0;
 	}	
 
-	len = strlen(Cmd);
-	if (len > 14) len = 14;
+	switch (ctmp) {
+		case '0' : numBlocks = 5*4; break;
+		case '1' : 
+		case '\0': numBlocks = 16*4; break;
+		case '2' : numBlocks = 32*4; break;
+		case '4' : numBlocks = 256; break;
+		default:  {
+			numBlocks = 16*4;
+			nameParamNo = 0;
+		}
+	}
+
+	len = param_getstr(Cmd,nameParamNo,filename);
+	
+	if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
 	
+	// user supplied filename?
 	if (len < 1) {
-		// get filename
+		// get filename (UID from memory)
 		if (mfEmlGetMem(buf, 0, 1)) {
-			PrintAndLog("Cant get block: %d", 0);
-			return 1;
+			PrintAndLog("Can\'t get UID from block: %d", 0);
+			sprintf(filename, "dump.eml"); 
 		}
 		for (j = 0; j < 7; j++, fnameptr += 2)
-			sprintf(fnameptr, "%02x", buf[j]); 
+			sprintf(fnameptr, "%02X", buf[j]); 
 	} else {
-		memcpy(filename, Cmd, len);
 		fnameptr += len;
 	}
 
+	// add file extension
 	sprintf(fnameptr, ".eml"); 
 	
 	// open file
 	f = fopen(filename, "w+");
 
+	if ( !f ) {
+		PrintAndLog("Can't open file %s ", filename);
+		return 1;
+	}
+	
 	// put hex
-	for (i = 0; i < 32*4 + 8*16; i++) {
+	for (i = 0; i < numBlocks; i++) {
 		if (mfEmlGetMem(buf, i, 1)) {
 			PrintAndLog("Cant get block: %d", i);
 			break;
@@ -1471,7 +1517,7 @@ int CmdHF14AMfESave(const char *Cmd)
 	}
 	fclose(f);
 	
-	PrintAndLog("Saved to file: %s", filename);
+	PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename);
 	
   return 0;
 }
@@ -1520,13 +1566,34 @@ int CmdHF14AMfECFill(const char *Cmd)
 int CmdHF14AMfEKeyPrn(const char *Cmd)
 {
 	int i;
+	uint8_t numSectors;
 	uint8_t data[16];
 	uint64_t keyA, keyB;
 	
+	if (param_getchar(Cmd, 0) == 'h') {
+		PrintAndLog("It prints the keys loaded in the emulator memory");
+		PrintAndLog("Usage:  hf mf ekeyprn [card memory]");
+		PrintAndLog("  [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
+		PrintAndLog("");
+		PrintAndLog(" sample: hf mf ekeyprn 1");
+		return 0;
+	}	
+
+	char cmdp = param_getchar(Cmd, 0);
+	
+	switch (cmdp) {
+		case '0' : numSectors = 5; break;
+		case '1' : 
+		case '\0': numSectors = 16; break;
+		case '2' : numSectors = 32; break;
+		case '4' : numSectors = 40; break;
+		default:   numSectors = 16;
+	}		
+	
 	PrintAndLog("|---|----------------|----------------|");
 	PrintAndLog("|sec|key A           |key B           |");
 	PrintAndLog("|---|----------------|----------------|");
-	for (i = 0; i < 40; i++) {
+	for (i = 0; i < numSectors; i++) {
 		if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) {
 			PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
 			break;
@@ -1616,15 +1683,15 @@ int CmdHF14AMfCSetBlk(const char *Cmd)
 int CmdHF14AMfCLoad(const char *Cmd)
 {
 	FILE * f;
-	char filename[20];
+	char filename[FILE_PATH_SIZE] = {0x00};
 	char * fnameptr = filename;
-	char buf[64];
-	uint8_t buf8[64];
+	char buf[64] = {0x00};
+	uint8_t buf8[64] = {0x00};
 	uint8_t fillFromEmulator = 0;
 	int i, len, blockNum, flags;
 	
-	memset(filename, 0, sizeof(filename));
-	memset(buf, 0, sizeof(buf));
+	// memset(filename, 0, sizeof(filename));
+	// memset(buf, 0, sizeof(buf));
 
 	if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
 		PrintAndLog("It loads magic Chinese card (only works with!!!) from the file `filename.eml`");
@@ -1657,7 +1724,7 @@ int CmdHF14AMfCLoad(const char *Cmd)
 		return 0;
 	} else {
 		len = strlen(Cmd);
-		if (len > 14) len = 14;
+		if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
 
 		memcpy(filename, Cmd, len);
 		fnameptr += len;
@@ -1702,7 +1769,7 @@ int CmdHF14AMfCLoad(const char *Cmd)
 		}
 		fclose(f);
 	
-		if (blockNum != 16 * 4){
+		if (blockNum != 16 * 4 && blockNum != 32 * 4 + 8 * 16){
 			PrintAndLog("File content error. There must be 64 blocks");
 			return 4;
 		}
@@ -1780,14 +1847,14 @@ int CmdHF14AMfCGetSc(const char *Cmd) {
 int CmdHF14AMfCSave(const char *Cmd) {
 
 	FILE * f;
-	char filename[20];
+	char filename[FILE_PATH_SIZE] = {0x00};
 	char * fnameptr = filename;
 	uint8_t fillFromEmulator = 0;
-	uint8_t buf[64];
+	uint8_t buf[64] = {0x00};
 	int i, j, len, flags;
 	
-	memset(filename, 0, sizeof(filename));
-	memset(buf, 0, sizeof(buf));
+	// memset(filename, 0, sizeof(filename));
+	// memset(buf, 0, sizeof(buf));
 
 	if (param_getchar(Cmd, 0) == 'h') {
 		PrintAndLog("It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml`");
@@ -1822,7 +1889,7 @@ int CmdHF14AMfCSave(const char *Cmd) {
 		return 0;
 	} else {
 		len = strlen(Cmd);
-		if (len > 14) len = 14;
+		if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
 	
 		if (len < 1) {
 			// get filename
@@ -1842,6 +1909,11 @@ int CmdHF14AMfCSave(const char *Cmd) {
 		// open file
 		f = fopen(filename, "w+");
 
+		if (f == NULL) {
+			PrintAndLog("File not found or locked.");
+			return 1;
+		}
+
 		// put hex
 		flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;
 		for (i = 0; i < 16 * 4; i++) {
@@ -2021,9 +2093,9 @@ static command_t CommandTable[] =
   {"ecfill",	CmdHF14AMfECFill,		0, "Fill simulator memory with help of keys from simulator"},
   {"ekeyprn",	CmdHF14AMfEKeyPrn,		0, "Print keys from simulator memory"},
   {"csetuid",	CmdHF14AMfCSetUID,		0, "Set UID for magic Chinese card"},
-  {"csetblk",	CmdHF14AMfCSetBlk,		0, "Write block into magic Chinese card"},
-  {"cgetblk",	CmdHF14AMfCGetBlk,		0, "Read block from magic Chinese card"},
-  {"cgetsc",	CmdHF14AMfCGetSc,		0, "Read sector from magic Chinese card"},
+  {"csetblk",	CmdHF14AMfCSetBlk,		0, "Write block - Magic Chinese card"},
+  {"cgetblk",	CmdHF14AMfCGetBlk,		0, "Read block - Magic Chinese card"},
+  {"cgetsc",	CmdHF14AMfCGetSc,		0, "Read sector - Magic Chinese card"},
   {"cload",		CmdHF14AMfCLoad,		0, "Load dump into magic Chinese card"},
   {"csave",		CmdHF14AMfCSave,		0, "Save dump from magic Chinese card into file or emulator"},
   {NULL, NULL, 0, NULL}
diff --git a/client/cmdlf.c b/client/cmdlf.c
index 41dcca57..572cda6c 100644
--- a/client/cmdlf.c
+++ b/client/cmdlf.c
@@ -380,10 +380,8 @@ static void ChkBitstream(const char *str)
   int i;
 
   /* convert to bitstream if necessary */
-  for (i = 0; i < (int)(GraphTraceLen / 2); i++)
-  {
-    if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)
-    {
+	for (i = 0; i < (int)(GraphTraceLen / 2); i++){
+		if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) {
       CmdBitstream(str);
       break;
     }
@@ -556,11 +554,25 @@ int CmdVchDemod(const char *Cmd)
 int CmdLFfind(const char *Cmd)
 {
   int ans=0;
-  if (!offline){
+	char cmdp = param_getchar(Cmd, 0);
+	
+	if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') {
+		PrintAndLog("Usage:  lf search <0|1>");
+		PrintAndLog("     <use data from Graphbuffer>, if not set, try reading data from tag.");
+		PrintAndLog("");
+		PrintAndLog("    sample: lf search");
+		PrintAndLog("          : lf search 1");
+		return 0;
+	}
+
+	if (!offline || (cmdp != '1') ){
     ans=CmdLFRead("");
-    ans=CmdSamples("20000");
+	ans=CmdSamples("20000");
+	} else if (GraphTraceLen < 1000) {
+		PrintAndLog("Data in Graphbuffer was too small.");
+		return 0;
   }
-  if (GraphTraceLen<1000) return 0;
+
   PrintAndLog("Checking for known tags:");
   ans=Cmdaskmandemod("");
   if (ans>0) return 1;
diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c
index 32a0ff7c..e0d88c24 100644
--- a/client/cmdlfem4x.c
+++ b/client/cmdlfem4x.c
@@ -507,12 +507,12 @@ int CmdEM410xWrite(const char *Cmd)
 
 int CmdReadWord(const char *Cmd)
 {
-  int Word = 16; //default to invalid word
+	int Word = -1; //default to invalid word
   UsbCommand c;
   
   sscanf(Cmd, "%d", &Word);
   
-  if (Word > 15) {
+	if ( (Word > 15) | (Word < 0) ) {
     PrintAndLog("Word must be between 0 and 15");
     return 1;
   }
@@ -530,13 +530,13 @@ int CmdReadWord(const char *Cmd)
 
 int CmdReadWordPWD(const char *Cmd)
 {
-  int Word = 16; //default to invalid word
+	int Word = -1; //default to invalid word
   int Password = 0xFFFFFFFF; //default to blank password
   UsbCommand c;
   
   sscanf(Cmd, "%d %x", &Word, &Password);
   
-  if (Word > 15) {
+	if ( (Word > 15) | (Word < 0) ) {
     PrintAndLog("Word must be between 0 and 15");
     return 1;
   }
@@ -565,7 +565,7 @@ int CmdWriteWord(const char *Cmd)
     return 1;
   }
   
-  PrintAndLog("Writting word %d with data %08X", Word, Data);
+  PrintAndLog("Writing word %d with data %08X", Word, Data);
   
   c.cmd = CMD_EM4X_WRITE_WORD;
   c.d.asBytes[0] = 0x0; //Normal mode
@@ -578,7 +578,7 @@ int CmdWriteWord(const char *Cmd)
 
 int CmdWriteWordPWD(const char *Cmd)
 {
-  int Word = 8; //default to invalid word
+  int Word = 16; //default to invalid word
   int Data = 0xFFFFFFFF; //default to blank data
   int Password = 0xFFFFFFFF; //default to blank password
   UsbCommand c;
@@ -590,7 +590,7 @@ int CmdWriteWordPWD(const char *Cmd)
     return 1;
   }
   
-  PrintAndLog("Writting word %d with data %08X and password %08X", Word, Data, Password);
+  PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
   
   c.cmd = CMD_EM4X_WRITE_WORD;
   c.d.asBytes[0] = 0x1; //Password mode
@@ -601,8 +601,6 @@ int CmdWriteWordPWD(const char *Cmd)
   return 0;
 }
 
-
-
 static command_t CommandTable[] =
 {
   {"help", CmdHelp, 1, "This help"},
diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c
index ab4a2609..549c427c 100644
--- a/client/cmdlfhitag.c
+++ b/client/cmdlfhitag.c
@@ -29,7 +29,7 @@ size_t nbytes(size_t nbits) {
 
 int CmdLFHitagList(const char *Cmd)
 {
-  uint8_t got[3000];
+  uint8_t got[TRACE_BUFFER_SIZE];
   GetFromBigBuf(got,sizeof(got),0);
   WaitForResponse(CMD_ACK,NULL);
 
@@ -39,11 +39,25 @@ int CmdLFHitagList(const char *Cmd)
 
   int i = 0;
   int prev = -1;
+  int len = strlen(Cmd);
+
+  char filename[FILE_PATH_SIZE]  = { 0x00 };
+  FILE* pf = NULL;
+  	
+  if (len > FILE_PATH_SIZE) 
+     len = FILE_PATH_SIZE;
+  memcpy(filename, Cmd, len);
+   
+  if (strlen(filename) > 0) {
+	if ((pf = fopen(filename,"wb")) == NULL) {
+		PrintAndLog("Error: Could not open file [%s]",filename);
+		return 1;
+	}
+  }
 
   for (;;) {
-    if(i >= 1900) {
-      break;
-    }
+  
+    if(i >= TRACE_BUFFER_SIZE) { break; }
 
     bool isResponse;
     int timestamp = *((uint32_t *)(got+i));
@@ -68,9 +82,7 @@ int CmdLFHitagList(const char *Cmd)
     if (len > 100) {
       break;
     }
-    if (i + len >= 1900) {
-      break;
-    }
+    if (i + len >= TRACE_BUFFER_SIZE) { break;}
 
     uint8_t *frame = (got+i+9);
 
@@ -103,18 +115,22 @@ int CmdLFHitagList(const char *Cmd)
       line);
 
 
-//   if (pf) {
-//      fprintf(pf," +%7d:  %3d: %s %s\n",
-//					(prev < 0 ? 0 : (timestamp - prev)),
-//					bits,
-//					(isResponse ? "TAG" : "   "),
-//					line);
-//    }
+   if (pf) {
+      fprintf(pf," +%7d:  %3d: %s %s\n",
+					(prev < 0 ? 0 : (timestamp - prev)),
+					bits,
+					(isResponse ? "TAG" : "   "),
+					line);
+    }
 	
     prev = timestamp;
     i += (len + 9);
   }
   
+  if (pf) {
+    fclose(pf);
+	PrintAndLog("Recorded activity succesfully written to file: %s", filename);
+  }
 
   return 0;
 }
@@ -126,12 +142,14 @@ int CmdLFHitagSnoop(const char *Cmd) {
 }
 
 int CmdLFHitagSim(const char *Cmd) {
+    
   UsbCommand c = {CMD_SIMULATE_HITAG};
-	char filename[256] = { 0x00 };
+	char filename[FILE_PATH_SIZE] = { 0x00 };
 	FILE* pf;
 	bool tag_mem_supplied;
-
-	param_getstr(Cmd,0,filename);
+	int len = strlen(Cmd);
+	if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
+	memcpy(filename, Cmd, len);
 	
 	if (strlen(filename) > 0) {
 		if ((pf = fopen(filename,"rb+")) == NULL) {
@@ -227,9 +245,9 @@ int CmdLFHitagReader(const char *Cmd) {
 static command_t CommandTable[] = 
 {
   {"help",    CmdHelp,           1, "This help"},
-  {"list",    CmdLFHitagList,    1, "List Hitag trace history"},
+  {"list",    CmdLFHitagList,    1, "<outfile> List Hitag trace history"},
   {"reader",  CmdLFHitagReader,  1, "Act like a Hitag Reader"},
-  {"sim",     CmdLFHitagSim,     1, "Simulate Hitag transponder"},
+  {"sim",     CmdLFHitagSim,     1, "<infile> Simulate Hitag transponder"},
   {"snoop",   CmdLFHitagSnoop,   1, "Eavesdrop Hitag communication"},
 		{NULL, NULL, 0, NULL}
 };
diff --git a/client/cmdmain.c b/client/cmdmain.c
index b6517caa..15cb3f98 100644
--- a/client/cmdmain.c
+++ b/client/cmdmain.c
@@ -132,9 +132,11 @@ int getCommand(UsbCommand* response)
 bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
   
   UsbCommand resp;
+	
 	if (response == NULL)
     response = &resp;
 
+
   // Wait until the command is received
   for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
 
diff --git a/client/flasher.c b/client/flasher.c
index 2a24ba8f..c273c1f3 100644
--- a/client/flasher.c
+++ b/client/flasher.c
@@ -52,11 +52,8 @@ void ReceiveCommand(UsbCommand* rxcmd) {
   while (true) {
     rxlen = sizeof(UsbCommand) - (prx-prxcmd);
     if (uart_receive(sp,prx,&rxlen)) {
-//      printf("received [%zd] bytes\n",rxlen);
       prx += rxlen;
       if ((prx-prxcmd) >= sizeof(UsbCommand)) {
-//        printf("received: ");
-//        cmd_debug(rxcmd);
         return;
       }
     }
diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua
index e93d0a97..13b9c8e7 100644
--- a/client/lualibs/commands.lua
+++ b/client/lualibs/commands.lua
@@ -104,8 +104,11 @@ local _commands = {
 	CMD_MIFARE_EML_MEMSET =                                              0x0602,
 	CMD_MIFARE_EML_MEMGET =                                              0x0603,
 	CMD_MIFARE_EML_CARDLOAD =                                            0x0604,
-	CMD_MIFARE_EML_CSETBLOCK =                                           0x0605,
-	CMD_MIFARE_EML_CGETBLOCK =                                           0x0606,
+	
+	--// magic chinese card commands
+	CMD_MIFARE_CSETBLOCK =                                               0x0605,
+	CMD_MIFARE_CGETBLOCK =                                               0x0606,
+	CMD_MIFARE_CIDENT =                                                  0x0607,
 
 	CMD_SIMULATE_MIFARE_CARD =                                           0x0610,
 
diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua
index 3d27d5b6..e84f70ad 100644
--- a/client/lualibs/utils.lua
+++ b/client/lualibs/utils.lua
@@ -33,9 +33,86 @@ local Utils =
 
 		return answer
 	end,
+	
+	------------ FILE READING
+	ReadDumpFile = function (filename)
+	
+		if filename == nil then 
+			return nil, 'Filename is empty'
+		end
+		if #filename == 0 then
+			return nil, 'Filename length is zero'
+		end
+
+		infile = io.open(filename, "rb")
+		if infile == nil then 
+			return nil, string.format("Could not read file %s",filename)
+		end
+		local t = infile:read("*all")
+		len = string.len(t)
+		local  _,hex = bin.unpack(("H%d"):format(len),t)
+		io.close(infile)
+		return hex
+	end,
+	
+	------------ string split function
+	Split = function( inSplitPattern, outResults )
+		if not outResults then
+			outResults = {}
+		end
+		local start = 1
+		local splitStart, splitEnd = string.find( self, inSplitPattern, start )
+		while splitStart do
+			table.insert( outResults, string.sub( self, start, splitStart-1 ) )
+			start = splitEnd + 1
+			splitStart, splitEnd = string.find( self, inSplitPattern, start )
+		end
+		table.insert( outResults, string.sub( self, start ) )
+		return outResults
+	end,
+	
+	------------ CRC-16 ccitt checksums
+	
+	-- Takes a hex string and calculates a crc16
+	Crc16 = function(s)
+		if s == nil then return nil end
+		if #s == 0 then return nil end
+		if  type(s) == 'string' then
+			local utils = require('utils')
+			local asc = utils.ConvertHexToAscii(s)
+			local hash = core.crc16(asc)
+			return hash
+		end
+		return nil
+	end,
+
+	-- input parameter is a string
+	-- Swaps the endianess and returns a number,  
+	-- IE:  'cd7a' -> '7acd'  -> 0x7acd
+	SwapEndianness = function(s, len)
+		if s == nil then return nil end
+		if #s == 0 then return '' end
+		if  type(s) ~= 'string' then return nil end
+		
+		local retval = 0
+		if len == 16 then
+			local t = s:sub(3,4)..s:sub(1,2)
+			retval = tonumber(t,16)
+		elseif len == 24 then
+			local t = s:sub(5,6)..s:sub(3,4)..s:sub(1,2)
+			retval = tonumber(t,16)
+		elseif len == 32 then
+			local t = s:sub(7,8)..s:sub(5,6)..s:sub(3,4)..s:sub(1,2)
+			retval = tonumber(t,16)
+		end
+		return retval
+	end,
+	
+	------------ CONVERSIONS
+	
 	--
 	-- Converts DECIMAL to HEX
-    ConvertDec2Hex = function(IN)
+    ConvertDecToHex = function(IN)
 		local B,K,OUT,I,D=16,"0123456789ABCDEF","",0
 		while IN>0 do
 			I=I+1
@@ -46,12 +123,100 @@ local Utils =
 	end,
 	---
 	-- Convert Byte array to string of hex
-	ConvertBytes2String = function(bytes)
-		s = {}
+	ConvertBytesToHex = function(bytes)
+		if #bytes == 0 then
+			return ''
+		end
+		local s={}
 		for i = 1, #(bytes) do
 			s[i] =   string.format("%02X",bytes[i]) 
 		end
 		return table.concat(s)
 	end,	
+	-- Convert byte array to string with ascii
+    ConvertBytesToAscii = function(bytes)
+		if #bytes == 0 then
+			return ''
+		end
+		local s={}
+		for i = 1, #(bytes) do
+			s[i] = string.char(bytes[i]) 
+		end
+		return table.concat(s)		
+	end,	 
+	ConvertHexToBytes = function(s)
+		local t={}
+		if s == nil then return t end
+		if #s == 0 then return t end
+		for k in s:gmatch"(%x%x)" do
+			table.insert(t,tonumber(k,16))
+		end
+		return t
+	end,
+	ConvertAsciiToBytes = function(s)
+		local t={}
+		if s == nil then return t end
+		if #s == 0 then return t end
+		
+		for k in s:gmatch"(.)" do
+			table.insert(t, string.byte(k))
+		end
+		return t
+	end,
+	ConvertHexToAscii = function(s)
+		local t={}
+		if s == nil then return t end
+		if #s == 0 then return t end
+		for k in s:gmatch"(%x%x)" do
+			table.insert(t, string.char(tonumber(k,16)))
+		end
+		return  table.concat(t)	
+	end,
+	
+	-- function convertStringToBytes(str)
+	-- local bytes = {}
+	-- local strLength = string.len(str)
+	-- for i=1,strLength do
+		-- table.insert(bytes, string.byte(str, i))
+	-- end
+
+	-- return bytes
+-- end
+
+-- function convertBytesToString(bytes)
+	-- local bytesLength = table.getn(bytes)
+	-- local str = ""
+	-- for i=1,bytesLength do
+		-- str = str .. string.char(bytes[i])
+	-- end
+
+	-- return str
+-- end
+
+-- function convertHexStringToBytes(str)
+	-- local bytes = {}
+	-- local strLength = string.len(str)
+	-- for k=2,strLength,2 do
+		-- local hexString = "0x" .. string.sub(str, (k - 1), k)
+		-- table.insert(bytes, hex.to_dec(hexString))
+	-- end
+
+	-- return bytes
+-- end
+
+-- function convertBytesToHexString(bytes)
+	-- local str = ""
+	-- local bytesLength = table.getn(bytes)
+	-- for i=1,bytesLength do
+		-- local hexString = string.sub(hex.to_hex(bytes[i]), 3)
+		-- if string.len(hexString) == 1 then
+			-- hexString = "0" .. hexString
+		-- end
+		-- str = str .. hexString
+	-- end
+
+	-- return str
+-- end
+
 }
 return Utils
\ No newline at end of file
diff --git a/client/proxmark3.c b/client/proxmark3.c
index 8a967c7f..0e2a698c 100644
--- a/client/proxmark3.c
+++ b/client/proxmark3.c
@@ -16,7 +16,7 @@
 #include <unistd.h>
 #include <readline/readline.h>
 #include <readline/history.h>
-//#include "proxusb.h"
+
 #include "proxmark3.h"
 #include "proxgui.h"
 #include "cmdmain.h"
diff --git a/client/scripting.c b/client/scripting.c
index 963bb64c..eed5544b 100644
--- a/client/scripting.c
+++ b/client/scripting.c
@@ -18,6 +18,8 @@
 #include "util.h"
 #include "nonce2key/nonce2key.h"
 #include "../common/iso15693tools.h"
+#include <openssl/aes.h>   
+#include "../common/crc16.h"
 /**
  * The following params expected:
  *  UsbCommand c
@@ -224,6 +226,54 @@ static int l_iso15693_crc(lua_State *L)
     return 1;
 }
 
+/*
+ Simple AES 128 cbc hook up to OpenSSL.
+ params:  key, input
+*/
+static int l_aes(lua_State *L)
+{
+	//Check number of arguments
+	int i;
+    size_t size;
+    const char *p_key = luaL_checklstring(L, 1, &size);
+    if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
+
+    const char *p_encTxt = luaL_checklstring(L, 2, &size);
+    
+	unsigned char indata[AES_BLOCK_SIZE] = {0x00};
+	unsigned char outdata[AES_BLOCK_SIZE] = {0x00};
+    unsigned char aes_key[AES_BLOCK_SIZE] = {0x00};
+	unsigned char iv[AES_BLOCK_SIZE] = {0x00};
+	
+	// convert key to bytearray
+	for (i = 0; i < 32; i += 2) {
+		sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]);
+	}
+	
+	// convert input to bytearray
+	for (i = 0; i < 32; i += 2) {
+		sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
+	}
+	
+	AES_KEY key;
+	AES_set_decrypt_key(aes_key, 128, &key);
+    AES_cbc_encrypt(indata, outdata, sizeof(indata), &key, iv, AES_DECRYPT);
+
+    //Push decrypted array as a string
+	lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+	return 1;// return 1 to signal one return value
+}
+
+static int l_crc16(lua_State *L)
+{
+	size_t size;
+	const char *p_str = luaL_checklstring(L, 1, &size);
+		
+	uint16_t retval = crc16_ccitt( (uint8_t*) p_str, size);
+    lua_pushinteger(L, (int) retval);
+    return 1;
+}
+
 /**
  * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be
  * able to do "require('foobar')" if foobar.lua is within lualibs folder.
@@ -261,6 +311,8 @@ int set_pm3_libraries(lua_State *L)
         {"clearCommandBuffer",          l_clearCommandBuffer},
         {"console",                      l_CmdConsole},
         {"iso15693_crc",                 l_iso15693_crc},
+		{"aes",                         l_aes},
+		{"crc16",                       l_crc16},
         {NULL, NULL}
     };
 
diff --git a/client/scripts/tnp3dump.lua b/client/scripts/tnp3dump.lua
new file mode 100644
index 00000000..520161b9
--- /dev/null
+++ b/client/scripts/tnp3dump.lua
@@ -0,0 +1,272 @@
+local cmds = require('commands')
+local getopt = require('getopt')
+local bin = require('bin')
+local lib14a = require('read14a')
+local utils = require('utils')
+local md5 = require('md5')
+local dumplib = require('html_dumplib')
+local toyNames = require('default_toys')
+
+example =[[
+	1. script run tnp3dump
+	2. script run tnp3dump -n
+	3. script run tnp3dump -k aabbccddeeff
+	4. script run tnp3dump -k aabbccddeeff -n
+	5. script run tnp3dump -o myfile 
+	6. script run tnp3dump -n -o myfile 
+	7. script run tnp3dump -k aabbccddeeff -n -o myfile 
+]]
+author = "Iceman"
+usage = "script run tnp3dump -k <key> -n -o <filename>"
+desc =[[
+This script will try to dump the contents of a Mifare TNP3xxx card.
+It will need a valid KeyA in order to find the other keys and decode the card.
+Arguments:
+	-h             : this help
+	-k <key>       : Sector 0 Key A.
+	-n             : Use the nested cmd to find all keys
+	-o             : filename for the saved dumps
+]]
+
+local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
+
+local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
+local DEBUG = false -- the debug flag
+local numBlocks = 64
+local numSectors = 16
+--- 
+-- A debug printout-function
+function dbg(args)
+	if not DEBUG then
+		return
+	end
+	
+    if type(args) == "table" then
+		local i = 1
+		while result[i] do
+			dbg(result[i])
+			i = i+1
+		end
+	else
+		print("###", args)
+	end	
+end	
+--- 
+-- This is only meant to be used when errors occur
+function oops(err)
+	print("ERROR: ",err)
+end
+--- 
+-- Usage help
+function help()
+	print(desc)
+	print("Example usage")
+	print(example)
+end
+--
+-- Exit message
+function ExitMsg(msg)
+	print( string.rep('--',20) )
+	print( string.rep('--',20) )
+	print(msg)
+	print()
+end
+
+local function readdumpkeys(infile)
+	 t = infile:read("*all")
+	 len = string.len(t)
+	 local len,hex = bin.unpack(("H%d"):format(len),t)
+	 return hex
+end
+
+local function waitCmd()
+	local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
+	if response then
+		local count,cmd,arg0 = bin.unpack('LL',response)
+		if(arg0==1) then
+			local count,arg1,arg2,data = bin.unpack('LLH511',response,count)
+			return data:sub(1,32)
+		else
+			return nil, "Couldn't read block.." 
+		end
+	end
+	return nil, "No response from device"
+end
+
+local function computeCrc16(s)
+	local hash = core.crc16(utils.ConvertHexToAscii(s))	
+	return hash
+end
+
+local function reverseCrcBytes(crc)
+	crc2 = crc:sub(3,4)..crc:sub(1,2)
+	return tonumber(crc2,16)
+end
+
+local function main(args)
+
+	print( string.rep('--',20) )
+	print( string.rep('--',20) )
+	
+	local keyA
+	local cmd
+	local err
+	local useNested = false
+	local cmdReadBlockString = 'hf mf rdbl %d A %s'
+	local input = "dumpkeys.bin"
+	local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S");
+
+	-- Arguments for the script
+	for o, a in getopt.getopt(args, 'hk:no:') do
+		if o == "h" then return help() end		
+		if o == "k" then keyA = a end
+		if o == "n" then useNested = true end
+		if o == "o" then outputTemplate = a end		
+	end
+
+	-- validate input args.
+	keyA =  keyA or '4b0b20107ccb'
+	if #(keyA) ~= 12 then
+		return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA))
+	end
+
+	-- Turn off Debug
+	local cmdSetDbgOff = "hf mf dbg 0"
+	core.console( cmdSetDbgOff) 
+	
+	result, err = lib14a.read1443a(false)
+	if not result then
+		return oops(err)
+	end
+
+	core.clearCommandBuffer()
+	
+	if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
+		return oops('This is not a TNP3xxx tag. aborting.')
+	end	
+
+	-- Show tag info
+	print((' Found tag : %s'):format(result.name))
+	print(('Using keyA : %s'):format(keyA))
+
+	--Trying to find the other keys
+	if useNested then
+	  core.console( ('hf mf nested 1 0 A %s d'):format(keyA) )
+	end
+	
+	core.clearCommandBuffer()
+	
+	-- Loading keyfile
+	print('Loading dumpkeys.bin')
+	local hex, err = utils.ReadDumpFile(input)
+	if not hex then
+		return oops(err)
+	end
+
+	local akeys = hex:sub(0,12*16)
+
+	-- Read block 0
+	cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA}
+	err = core.SendCommand(cmd:getBytes())
+	if err then return oops(err) end
+	local block0, err = waitCmd()
+	if err then return oops(err) end
+	
+	-- Read block 1
+	cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA}
+	err = core.SendCommand(cmd:getBytes())
+	if err then return oops(err) end
+	local block1, err = waitCmd()
+	if err then return oops(err) end
+
+	local key
+	local pos = 0
+	local blockNo
+	local blocks = {}
+
+	print('Reading card data')
+	core.clearCommandBuffer()
+		
+	-- main loop
+	io.write('Decrypting blocks > ')
+	for blockNo = 0, numBlocks-1, 1 do
+
+		if core.ukbhit() then
+			print("aborted by user")
+			break
+		end
+	
+		pos = (math.floor( blockNo / 4 ) * 12)+1
+		key = akeys:sub(pos, pos + 11 )
+		cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key}
+		local err = core.SendCommand(cmd:getBytes())
+		if err then return oops(err) end
+		local blockdata, err = waitCmd()
+		if err then return oops(err) end		
+
+		if  blockNo%4 ~= 3 then
+			if blockNo < 8 then
+				-- Block 0-7 not encrypted
+				blocks[blockNo+1] = ('%02d  :: %s'):format(blockNo,blockdata) 
+			else
+				local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT)	
+				local baseStr = utils.ConvertHexToAscii(base)
+				local md5hash = md5.sumhexa(baseStr)
+				local aestest = core.aes(md5hash, blockdata)
+
+				local hex = utils.ConvertAsciiToBytes(aestest)
+				hex = utils.ConvertBytesToHex(hex)
+
+				-- blocks with zero not encrypted.
+				if string.find(blockdata, '^0+$') then
+					blocks[blockNo+1] = ('%02d  :: %s'):format(blockNo,blockdata) 
+				else
+					blocks[blockNo+1] = ('%02d  :: %s'):format(blockNo,hex)
+					io.write( blockNo..',')
+				end		
+			end
+		else
+			-- Sectorblocks, not encrypted
+			blocks[blockNo+1] = ('%02d  :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) 
+		end
+	end
+	io.write('\n')
+	
+	core.clearCommandBuffer()
+		
+	-- Print results
+	local bindata = {}
+	local emldata = ''
+
+	for _,s in pairs(blocks) do
+		local slice = s:sub(8,#s)
+		local str = utils.ConvertBytesToAscii(
+				 utils.ConvertHexToBytes(slice)
+				)
+		emldata = emldata..slice..'\n'
+		for c in (str):gmatch('.') do
+			bindata[#bindata+1] = c
+		end
+	end 
+	
+	-- Write dump to files
+	if not DEBUG then
+		local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin')
+		print(("Wrote a BIN dump to the file %s"):format(foo))
+		local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml')
+		print(("Wrote a EML dump to the file %s"):format(bar))
+	end
+
+	local uid = block0:sub(1,8)
+	local itemtype = block1:sub(1,4)
+	local cardid = block1:sub(9,24)
+
+	-- Show info 
+	print( string.rep('--',20) )
+	print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
+	print( ('       UID : 0x%s'):format(uid) )
+	print( ('    CARDID : 0x%s'):format(cardid ) )	
+	print( string.rep('--',20) )
+
+end
+main(args)
\ No newline at end of file
diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua
new file mode 100644
index 00000000..f43dafa2
--- /dev/null
+++ b/client/scripts/tnp3sim.lua
@@ -0,0 +1,355 @@
+local cmds = require('commands')
+local getopt = require('getopt')
+local bin = require('bin')
+local lib14a = require('read14a')
+local utils = require('utils')
+local md5 = require('md5')
+local toyNames = require('default_toys')
+
+example =[[
+	1. script run tnp3sim
+	2. script run tnp3sim -m
+	3. script run tnp3sim -m -i myfile
+]]
+author = "Iceman"
+usage = "script run tnp3sim -h -m -i <filename>"
+desc =[[
+This script will try to load a binary datadump of a Mifare TNP3xxx card.
+It vill try to validate all checksums and view some information stored in the dump
+For an experimental mode, it tries to manipulate some data.
+At last it sends all data to the PM3 device memory where it can be used in the command  "hf mf sim"
+
+Arguments:
+	-h             : this help
+	-m             : Maxed out items (experimental)
+	-i             : filename for the datadump to read (bin)
+]]
+
+local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
+local DEBUG = true -- the debug flag
+--- 
+-- A debug printout-function
+function dbg(args)
+	if not DEBUG then
+		return
+	end
+	
+    if type(args) == "table" then
+		local i = 1
+		while result[i] do
+			dbg(result[i])
+			i = i+1
+		end
+	else
+		print("###", args)
+	end	
+end	
+--- 
+-- This is only meant to be used when errors occur
+function oops(err)
+	print("ERROR: ",err)
+end
+--- 
+-- Usage help
+function help()
+	print(desc)
+	print("Example usage")
+	print(example)
+end
+--
+-- Exit message
+function ExitMsg(msg)
+	print( string.rep('--',20) )
+	print( string.rep('--',20) )
+	print(msg)
+	print()
+end
+
+
+local function writedumpfile(infile)
+	 t = infile:read("*all")
+	 len = string.len(t)
+	 local len,hex = bin.unpack(("H%d"):format(len),t)
+	 return hex
+end
+-- blocks with data
+-- there are two dataareas, in block 8 or block 36,   ( 1==8 ,
+-- checksum type =  0, 1, 2, 3
+local function GetCheckSum(blocks, dataarea, chksumtype)
+
+	local crc
+	local area = 36
+	if  dataarea == 1 then
+		area = 8
+	end
+	
+	if chksumtype == 0 then
+		crc = blocks[1]:sub(29,32)
+	elseif chksumtype == 1 then
+		crc = blocks[area]:sub(29,32)
+	elseif chksumtype == 2 then	
+		crc = blocks[area]:sub(25,28)
+	elseif chksumtype == 3 then
+		crc = blocks[area]:sub(21,24)		
+	end
+	return utils.SwapEndianness(crc,16)
+end
+
+local function SetCheckSum(blocks, chksumtype)
+
+	if blocks == nil then return nil, 'Argument \"blocks\" nil' end
+	local newcrc
+	local area1 = 8
+	local area2 = 36
+	
+	if chksumtype == 0 then
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0))	
+		blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
+	elseif chksumtype == 1 then
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1))	
+		blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1))	
+		blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
+	elseif chksumtype == 2 then	
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2))	
+		blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32)
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2))	
+		blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32)
+	elseif chksumtype == 3 then
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3))	
+		blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32)
+		newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3))	
+		blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32)
+	end
+end
+
+function CalcCheckSum(blocks, dataarea, chksumtype)
+	local area = 36
+	if dataarea == 1 then
+		area = 8
+	end
+	
+	if chksumtype == 0 then
+		data = blocks[0]..blocks[1]:sub(1,28)
+	elseif chksumtype == 1 then
+		data = blocks[area]:sub(1,28)..'0500'
+	elseif chksumtype == 2 then	
+		data =	blocks[area+1]..blocks[area+2]..blocks[area+4]
+	elseif chksumtype == 3 then
+		data =  blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0)	
+	end
+	return utils.Crc16(data)
+end
+
+local function ValidateCheckSums(blocks)
+
+	local isOk, crc, calc
+	-- Checksum Type 0
+	crc = GetCheckSum(blocks,1,0)
+	calc = CalcCheckSum(blocks, 1, 0)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end
+	io.write( ('TYPE 0       : %04x = %04x -- %s\n'):format(crc,calc,isOk))
+
+	-- Checksum Type 1 (DATAAREAHEADER 1)
+	crc = GetCheckSum(blocks,1,1)
+	calc = CalcCheckSum(blocks,1,1)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end
+	io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+	
+	-- Checksum Type 1 (DATAAREAHEADER 2)
+	crc = GetCheckSum(blocks,2,1)
+	calc = CalcCheckSum(blocks,2,1)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end
+	io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+	
+	-- Checksum Type 2 (DATAAREA 1)
+	crc = GetCheckSum(blocks,1,2)
+	calc = CalcCheckSum(blocks,1,2)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end	
+	io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+
+	-- Checksum Type 2 (DATAAREA 2)
+	crc = GetCheckSum(blocks,2,2)
+	calc = CalcCheckSum(blocks,2,2)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end	
+	io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+
+	-- Checksum Type 3 (DATAAREA 1)
+	crc = GetCheckSum(blocks,1,3)
+	calc = CalcCheckSum(blocks,1,3)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end	
+	io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+
+	-- Checksum Type 3 (DATAAREA 2)
+	crc = GetCheckSum(blocks,2,3)
+	calc = CalcCheckSum(blocks,2,3)
+	if crc == calc then isOk='Ok' else isOk = 'Error' end	
+	io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
+end
+
+
+local function LoadEmulator(blocks)
+	local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
+	local cmd
+	local blockdata
+	for _,b in pairs(blocks) do 
+		
+		blockdata = b
+		
+		if  _%4 ~= 3 then
+			if (_ >= 8 and _<=21)  or  (_ >= 36 and _<=49) then
+				local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT)	
+				local baseStr = utils.ConvertHexToAscii(base)
+				local key = md5.sumhexa(baseStr)
+				local enc = core.aes(key, blockdata)
+				local hex = utils.ConvertAsciiToBytes(enc)
+				hex = utils.ConvertBytesToHex(hex)
+			
+				blockdata = hex
+				io.write( _..',')
+			end
+		end
+
+		cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata}
+		local err = core.SendCommand(cmd:getBytes())
+		if err then 
+			return err
+		end
+	end
+	io.write('\n')
+end
+
+local function main(args)
+
+	print( string.rep('--',20) )
+	print( string.rep('--',20) )
+	
+	local result, err, hex
+	local maxed = false
+	local inputTemplate = "dumpdata.bin"
+	local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M");
+	
+		-- Arguments for the script
+	for o, a in getopt.getopt(args, 'hmi:o:') do
+		if o == "h" then return help() end		
+		if o == "m" then maxed = true end
+		if o == "o" then outputTemplate = a end		
+		if o == "i" then inputTemplate = a end
+	end
+	
+	-- Turn off Debug
+	local cmdSetDbgOff = "hf mf dbg 0"
+	core.console( cmdSetDbgOff) 
+	
+	-- Look for tag present on reader,
+	result, err = lib14a.read1443a(false)
+	if not result then return oops(err)	end
+
+	core.clearCommandBuffer()
+	
+	if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
+		return oops('This is not a TNP3xxx tag. aborting.')
+	end	
+
+	-- Show tag info
+	print((' Found tag : %s'):format(result.name))
+	
+	-- Load dump.bin file
+	print( (' Load data from %s'):format(inputTemplate))
+	hex, err = utils.ReadDumpFile(inputTemplate)
+	if not hex then return oops(err) end
+	
+	local blocks = {}
+	local blockindex = 0
+	for i = 1, #hex, 32 do
+		blocks[blockindex] = hex:sub(i,i+31)
+		blockindex = blockindex + 1
+	end
+
+	if DEBUG then
+		print('Validating checksums in the loaded datadump')
+		ValidateCheckSums(blocks)
+	end
+	
+	--
+	print( string.rep('--',20) )	
+	print(' Gathering info')
+	local uid = blocks[0]:sub(1,8)
+	local itemtype = blocks[1]:sub(1,4)
+	local cardid = blocks[1]:sub(9,24)
+
+	-- Show info 
+	print( string.rep('--',20) )
+	print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
+	print( ('       UID : 0x%s'):format(uid) )
+	print( ('    CARDID : 0x%s'):format(cardid ) )	
+	print( string.rep('--',20) )
+
+	-- lets do something.
+	-- 
+	local experience = blocks[8]:sub(1,6)
+	print(('Experience  : %d'):format(utils.SwapEndianness(experience,24)))
+	local money = blocks[8]:sub(7,10)
+	print(('Money       : %d'):format(utils.SwapEndianness(money,16)))
+	local fairy = blocks[9]:sub(1,8)
+	--FD0F = Left, FF0F = Right
+	local path = 'not choosen'
+	if fairy:sub(2,2) == 'D' then
+		path = 'Left'
+	elseif fairy:sub(2,2) == 'F' then
+		path = 'Right'
+	end
+	print(('Fairy       : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path))
+	
+	local hat = blocks[9]:sub(8,11)
+	print(('Hat         : %d'):format(utils.SwapEndianness(hat,16)))
+	
+	--0x0D    0x29    0x0A    0x02    16-bit hero points value. Maximum 100.
+	local heropoints = blocks[13]:sub(20,23)
+	print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16)))
+
+	--0x10    0x2C    0x0C    0x04    32 bit flag value indicating heroic challenges completed.
+	local challenges = blocks[16]:sub(25,32)
+	print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32)))
+	
+	if maxed then
+		print('Lets try to max out some values')
+		-- max out money, experience
+		--print (blocks[8])
+		blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32)
+		blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32)
+		--print (blocks[8])
+	
+		-- max out hero challenges
+		--print (blocks[16])
+		blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF'
+		blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF'
+		--print (blocks[16])
+		
+		-- max out heropoints
+		--print (blocks[13])
+		blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32)
+		blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32)
+		--print (blocks[13])
+	
+		-- Update Checksums
+		print('Updating all checksums')
+		SetCheckSum(blocks, 3)
+		SetCheckSum(blocks, 2)
+		SetCheckSum(blocks, 1)
+		SetCheckSum(blocks, 0)
+	
+		print('Validating all checksums')	
+		ValidateCheckSums(blocks)
+	end
+	
+	--Load dumpdata to emulator memory
+	if DEBUG then
+		print('Sending dumpdata to emulator memory')
+		err = LoadEmulator(blocks)
+		if err then return oops(err) end	
+		core.clearCommandBuffer()
+		print('The simulation is now prepared.\n --> run \"hf mf sim 5 '..uid..'\" <--')
+	end
+end
+main(args)
\ No newline at end of file
diff --git a/client/util.c b/client/util.c
index a077aae9..b8d5c316 100644
--- a/client/util.c
+++ b/client/util.c
@@ -46,12 +46,18 @@ int ukbhit(void) {
 #endif
 
 // log files functions
-void AddLogLine(char *fileName, char *extData, char *c) {
+void AddLogLine(char *file, char *extData, char *c) {
 	FILE *fLog = NULL;
-
-	fLog = fopen(fileName, "a");
+    char filename[FILE_PATH_SIZE] = {0x00};
+    int len = 0;
+
+    len = strlen(file);
+    if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
+    memcpy(filename, file, len);
+   
+	fLog = fopen(filename, "a");
 	if (!fLog) {
-		printf("Could not append log file %s", fileName);
+		printf("Could not append log file %s", filename);
 		return;
 	}
 
@@ -103,11 +109,13 @@ void print_hex(const uint8_t * data, const size_t len)
 }
 
 char * sprint_hex(const uint8_t * data, const size_t len) {
+	
+	int maxLen = ( len > 1024/3) ? 1024/3 : len;
 	static char buf[1024];
 	char * tmp = buf;
 	size_t i;
 
-	for (i=0; i < len && i < 1024/3; i++, tmp += 3)
+	for (i=0; i < maxLen; ++i, tmp += 3)
 		sprintf(tmp, "%02x ", data[i]);
 
 	return buf;
-- 
2.39.5