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
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;
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;
}
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;
#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
#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)
{
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;
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]);
}
-
uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles)
{
bool isResponse;
// 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);
}
}
}
}
-
}
char *crc = crcError ? "!crc" :" ";
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;
// 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);
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]));
}
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);
int CmdHF14ASim(const char *Cmd);
int CmdHF14ASnoop(const char *Cmd);
-
+char* getTagInfo(uint8_t uid);
#endif
#include "cmdhf14b.h"
#include "cmdmain.h"
-
static int CmdHelp(const char *Cmd);
int CmdHF14BDemod(const char *Cmd)
int CmdHF14BList(const char *Cmd)
{
- uint8_t got[960];
+ uint8_t got[TRACE_BUFFER_SIZE];
GetFromBigBuf(got,sizeof(got),0);
WaitForResponse(CMD_ACK,NULL);
int prev = -1;
for(;;) {
- if(i >= 900) {
- break;
- }
+
+ if(i >= TRACE_BUFFER_SIZE) { break; }
bool isResponse;
int timestamp = *((uint32_t *)(got+i));
if(len > 100) {
break;
}
- if(i + len >= 900) {
+ if(i + len >= TRACE_BUFFER_SIZE) {
break;
}
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;
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);
if (isOK != 1) return 1;\r
\r
// execute original function from util nonce2key\r
- if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key))\r
- {\r
+ if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {\r
isOK = 2;\r
PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); \r
} else {\r
return 2;\r
}\r
}\r
+ \r
fclose(fin);\r
// Read access rights to sectors\r
\r
{\r
uint8_t sectorNo,blockNo;\r
uint8_t keyType = 0;\r
- uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\r
- uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\r
+ uint8_t key[6] = {0xFF};\r
+ uint8_t bldata[16] = {0x00};\r
uint8_t keyA[40][6];\r
uint8_t keyB[40][6];\r
uint8_t numSectors;\r
return 0;\r
}\r
\r
- if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {\r
- PrintAndLog("Could not find file dumpdata.bin");\r
- return 1;\r
- }\r
if ((fkeys = fopen("dumpkeys.bin","rb")) == NULL) {\r
PrintAndLog("Could not find file dumpkeys.bin");\r
- fclose(fdump);\r
return 1;\r
}\r
\r
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {\r
if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) {\r
PrintAndLog("File reading error (dumpkeys.bin).");\r
- fclose(fdump);\r
- fclose(fkeys);\r
return 2;\r
}\r
}\r
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {\r
if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) {\r
PrintAndLog("File reading error (dumpkeys.bin).");\r
- fclose(fdump);\r
- fclose(fkeys);\r
return 2;\r
}\r
}\r
+\r
fclose(fkeys);\r
\r
+ if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {\r
+ PrintAndLog("Could not find file dumpdata.bin");\r
+ return 1;\r
+ } \r
PrintAndLog("Restoring dumpdata.bin to card");\r
\r
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {\r
cmdp = param_getchar(Cmd, 0);\r
blockNo = param_get8(Cmd, 1);\r
ctmp = param_getchar(Cmd, 2);\r
+ \r
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {\r
PrintAndLog("Key type must be A or B");\r
return 1;\r
}\r
- if (ctmp != 'A' && ctmp != 'a') keyType = 1;\r
+ \r
+ if (ctmp != 'A' && ctmp != 'a') \r
+ keyType = 1;\r
+ \r
if (param_gethex(Cmd, 3, key, 12)) {\r
PrintAndLog("Key must include 12 HEX symbols");\r
return 1;\r
PrintAndLog("Target key type must be A or B");\r
return 1;\r
}\r
- if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;\r
+ if (ctmp != 'A' && ctmp != 'a') \r
+ trgKeyType = 1;\r
} else {\r
+ \r
switch (cmdp) {\r
case '0': SectorsCnt = 05; break;\r
case '1': SectorsCnt = 16; break;\r
}\r
}\r
\r
- \r
// nested sectors\r
iterations = 0;\r
PrintAndLog("nested...");\r
} \r
\r
FILE * f;\r
- char filename[256]={0};\r
+ char filename[FILE_PATH_SIZE]={0};\r
char buf[13];\r
uint8_t *keyBlock = NULL, *p;\r
uint8_t stKeyBlock = 20;\r
int transferToEml = 0;\r
int createDumpFile = 0;\r
\r
-\r
keyBlock = calloc(stKeyBlock, 6);\r
if (keyBlock == NULL) return 1;\r
\r
keycnt++;\r
} else {\r
// May be a dic file\r
- if ( param_getstr(Cmd, 2 + i,filename) > 255 ) {\r
+ if ( param_getstr(Cmd, 2 + i,filename) >= FILE_PATH_SIZE ) {\r
PrintAndLog("File name too long");\r
free(keyBlock);\r
return 2;\r
int CmdHF14AMfELoad(const char *Cmd)\r
{\r
FILE * f;\r
- char filename[20];\r
+ char filename[FILE_PATH_SIZE];\r
char *fnameptr = filename;\r
char buf[64];\r
uint8_t buf8[64];\r
- int i, len, blockNum;\r
+ int i, len, blockNum, numBlocks;\r
+ int nameParamNo = 1;\r
\r
memset(filename, 0, sizeof(filename));\r
memset(buf, 0, sizeof(buf));\r
\r
- if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {\r
+ char ctmp = param_getchar(Cmd, 0);\r
+ \r
+ if ( ctmp == 'h' || ctmp == 0x00) {\r
PrintAndLog("It loads emul dump from the file `filename.eml`");\r
- PrintAndLog("Usage: hf mf eload <file name w/o `.eml`>");\r
+ PrintAndLog("Usage: hf mf eload [card memory] <file name w/o `.eml`>");\r
+ PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");\r
+ PrintAndLog("");\r
PrintAndLog(" sample: hf mf eload filename");\r
+ PrintAndLog(" hf mf eload 4 filename");\r
return 0;\r
} \r
\r
- len = strlen(Cmd);\r
- if (len > 14) len = 14;\r
+ switch (ctmp) {\r
+ case '0' : numBlocks = 5*4; break;\r
+ case '1' : \r
+ case '\0': numBlocks = 16*4; break;\r
+ case '2' : numBlocks = 32*4; break;\r
+ case '4' : numBlocks = 256; break;\r
+ default: {\r
+ numBlocks = 16*4;\r
+ nameParamNo = 0;\r
+ }\r
+ }\r
+\r
+ len = param_getstr(Cmd,nameParamNo,filename);\r
+ \r
+ if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;\r
\r
- memcpy(filename, Cmd, len);\r
fnameptr += len;\r
\r
sprintf(fnameptr, ".eml"); \r
blockNum = 0;\r
while(!feof(f)){\r
memset(buf, 0, sizeof(buf));\r
+ \r
if (fgets(buf, sizeof(buf), f) == NULL) {\r
- if((blockNum == 16*4) || (blockNum == 32*4 + 8*16)) { // supports both old (1K) and new (4K) .eml files)\r
- break;\r
- }\r
+ \r
+ if (blockNum >= numBlocks) break;\r
+ \r
PrintAndLog("File reading error.");\r
fclose(f);\r
return 2;\r
}\r
+ \r
if (strlen(buf) < 32){\r
if(strlen(buf) && feof(f))\r
break;\r
fclose(f);\r
return 2;\r
}\r
+ \r
for (i = 0; i < 32; i += 2) {\r
sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]);\r
}\r
}\r
blockNum++;\r
\r
- if (blockNum >= 32*4 + 8*16) break;\r
+ if (blockNum >= numBlocks) break;\r
}\r
fclose(f);\r
\r
- if ((blockNum != 16*4) && (blockNum != 32*4 + 8*16)) {\r
- PrintAndLog("File content error. There must be 64 or 256 blocks.");\r
+ if ((blockNum != numBlocks)) {\r
+ PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks);\r
return 4;\r
}\r
PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);\r
int CmdHF14AMfESave(const char *Cmd)\r
{\r
FILE * f;\r
- char filename[20];\r
+ char filename[FILE_PATH_SIZE];\r
char * fnameptr = filename;\r
uint8_t buf[64];\r
- int i, j, len;\r
+ int i, j, len, numBlocks;\r
+ int nameParamNo = 1;\r
\r
memset(filename, 0, sizeof(filename));\r
memset(buf, 0, sizeof(buf));\r
\r
- if (param_getchar(Cmd, 0) == 'h') {\r
+ char ctmp = param_getchar(Cmd, 0);\r
+ \r
+ if ( ctmp == 'h' || ctmp == 'H') {\r
PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`");\r
- PrintAndLog("Usage: hf mf esave [file name w/o `.eml`]");\r
+ PrintAndLog(" Usage: hf mf esave [card memory] [file name w/o `.eml`]");\r
+ PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");\r
+ PrintAndLog("");\r
PrintAndLog(" sample: hf mf esave ");\r
- PrintAndLog(" hf mf esave filename");\r
+ PrintAndLog(" hf mf esave 4");\r
+ PrintAndLog(" hf mf esave 4 filename");\r
return 0;\r
} \r
\r
- len = strlen(Cmd);\r
- if (len > 14) len = 14;\r
+ switch (ctmp) {\r
+ case '0' : numBlocks = 5*4; break;\r
+ case '1' : \r
+ case '\0': numBlocks = 16*4; break;\r
+ case '2' : numBlocks = 32*4; break;\r
+ case '4' : numBlocks = 256; break;\r
+ default: {\r
+ numBlocks = 16*4;\r
+ nameParamNo = 0;\r
+ }\r
+ }\r
+\r
+ len = param_getstr(Cmd,nameParamNo,filename);\r
+ \r
+ if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;\r
\r
+ // user supplied filename?\r
if (len < 1) {\r
- // get filename\r
+ // get filename (UID from memory)\r
if (mfEmlGetMem(buf, 0, 1)) {\r
- PrintAndLog("Cant get block: %d", 0);\r
- return 1;\r
+ PrintAndLog("Can\'t get UID from block: %d", 0);\r
+ sprintf(filename, "dump.eml"); \r
}\r
for (j = 0; j < 7; j++, fnameptr += 2)\r
- sprintf(fnameptr, "%02x", buf[j]); \r
+ sprintf(fnameptr, "%02X", buf[j]); \r
} else {\r
- memcpy(filename, Cmd, len);\r
fnameptr += len;\r
}\r
\r
+ // add file extension\r
sprintf(fnameptr, ".eml"); \r
\r
// open file\r
f = fopen(filename, "w+");\r
\r
+ if ( !f ) {\r
+ PrintAndLog("Can't open file %s ", filename);\r
+ return 1;\r
+ }\r
+ \r
// put hex\r
- for (i = 0; i < 32*4 + 8*16; i++) {\r
+ for (i = 0; i < numBlocks; i++) {\r
if (mfEmlGetMem(buf, i, 1)) {\r
PrintAndLog("Cant get block: %d", i);\r
break;\r
}\r
fclose(f);\r
\r
- PrintAndLog("Saved to file: %s", filename);\r
+ PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename);\r
\r
return 0;\r
}\r
int CmdHF14AMfEKeyPrn(const char *Cmd)\r
{\r
int i;\r
+ uint8_t numSectors;\r
uint8_t data[16];\r
uint64_t keyA, keyB;\r
\r
+ if (param_getchar(Cmd, 0) == 'h') {\r
+ PrintAndLog("It prints the keys loaded in the emulator memory");\r
+ PrintAndLog("Usage: hf mf ekeyprn [card memory]");\r
+ PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");\r
+ PrintAndLog("");\r
+ PrintAndLog(" sample: hf mf ekeyprn 1");\r
+ return 0;\r
+ } \r
+\r
+ char cmdp = param_getchar(Cmd, 0);\r
+ \r
+ switch (cmdp) {\r
+ case '0' : numSectors = 5; break;\r
+ case '1' : \r
+ case '\0': numSectors = 16; break;\r
+ case '2' : numSectors = 32; break;\r
+ case '4' : numSectors = 40; break;\r
+ default: numSectors = 16;\r
+ } \r
+ \r
PrintAndLog("|---|----------------|----------------|");\r
PrintAndLog("|sec|key A |key B |");\r
PrintAndLog("|---|----------------|----------------|");\r
- for (i = 0; i < 40; i++) {\r
+ for (i = 0; i < numSectors; i++) {\r
if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) {\r
PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);\r
break;\r
int CmdHF14AMfCLoad(const char *Cmd)\r
{\r
FILE * f;\r
- char filename[20];\r
+ char filename[FILE_PATH_SIZE] = {0x00};\r
char * fnameptr = filename;\r
- char buf[64];\r
- uint8_t buf8[64];\r
+ char buf[64] = {0x00};\r
+ uint8_t buf8[64] = {0x00};\r
uint8_t fillFromEmulator = 0;\r
int i, len, blockNum, flags;\r
\r
- memset(filename, 0, sizeof(filename));\r
- memset(buf, 0, sizeof(buf));\r
+ // memset(filename, 0, sizeof(filename));\r
+ // memset(buf, 0, sizeof(buf));\r
\r
if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {\r
PrintAndLog("It loads magic Chinese card (only works with!!!) from the file `filename.eml`");\r
return 0;\r
} else {\r
len = strlen(Cmd);\r
- if (len > 14) len = 14;\r
+ if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;\r
\r
memcpy(filename, Cmd, len);\r
fnameptr += len;\r
}\r
fclose(f);\r
\r
- if (blockNum != 16 * 4){\r
+ if (blockNum != 16 * 4 && blockNum != 32 * 4 + 8 * 16){\r
PrintAndLog("File content error. There must be 64 blocks");\r
return 4;\r
}\r
int CmdHF14AMfCSave(const char *Cmd) {\r
\r
FILE * f;\r
- char filename[20];\r
+ char filename[FILE_PATH_SIZE] = {0x00};\r
char * fnameptr = filename;\r
uint8_t fillFromEmulator = 0;\r
- uint8_t buf[64];\r
+ uint8_t buf[64] = {0x00};\r
int i, j, len, flags;\r
\r
- memset(filename, 0, sizeof(filename));\r
- memset(buf, 0, sizeof(buf));\r
+ // memset(filename, 0, sizeof(filename));\r
+ // memset(buf, 0, sizeof(buf));\r
\r
if (param_getchar(Cmd, 0) == 'h') {\r
PrintAndLog("It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml`");\r
return 0;\r
} else {\r
len = strlen(Cmd);\r
- if (len > 14) len = 14;\r
+ if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;\r
\r
if (len < 1) {\r
// get filename\r
// open file\r
f = fopen(filename, "w+");\r
\r
+ if (f == NULL) {\r
+ PrintAndLog("File not found or locked.");\r
+ return 1;\r
+ }\r
+\r
// put hex\r
flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;\r
for (i = 0; i < 16 * 4; i++) {\r
{"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"},\r
{"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"},\r
{"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"},\r
- {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block into magic Chinese card"},\r
- {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block from magic Chinese card"},\r
- {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector from magic Chinese card"},\r
+ {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"},\r
+ {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"},\r
+ {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"},\r
{"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"},\r
{"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"},\r
{NULL, NULL, 0, NULL}\r
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;
}
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;
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;
}
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;
}
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
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;
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
return 0;
}
-
-
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
int CmdLFHitagList(const char *Cmd)
{
- uint8_t got[3000];
+ uint8_t got[TRACE_BUFFER_SIZE];
GetFromBigBuf(got,sizeof(got),0);
WaitForResponse(CMD_ACK,NULL);
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));
if (len > 100) {
break;
}
- if (i + len >= 1900) {
- break;
- }
+ if (i + len >= TRACE_BUFFER_SIZE) { break;}
uint8_t *frame = (got+i+9);
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;
}
}
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) {
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}
};
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++) {
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;
}
}
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,
\r
return answer\r
end,\r
+ \r
+ ------------ FILE READING\r
+ ReadDumpFile = function (filename)\r
+ \r
+ if filename == nil then \r
+ return nil, 'Filename is empty'\r
+ end\r
+ if #filename == 0 then\r
+ return nil, 'Filename length is zero'\r
+ end\r
+\r
+ infile = io.open(filename, "rb")\r
+ if infile == nil then \r
+ return nil, string.format("Could not read file %s",filename)\r
+ end\r
+ local t = infile:read("*all")\r
+ len = string.len(t)\r
+ local _,hex = bin.unpack(("H%d"):format(len),t)\r
+ io.close(infile)\r
+ return hex\r
+ end,\r
+ \r
+ ------------ string split function\r
+ Split = function( inSplitPattern, outResults )\r
+ if not outResults then\r
+ outResults = {}\r
+ end\r
+ local start = 1\r
+ local splitStart, splitEnd = string.find( self, inSplitPattern, start )\r
+ while splitStart do\r
+ table.insert( outResults, string.sub( self, start, splitStart-1 ) )\r
+ start = splitEnd + 1\r
+ splitStart, splitEnd = string.find( self, inSplitPattern, start )\r
+ end\r
+ table.insert( outResults, string.sub( self, start ) )\r
+ return outResults\r
+ end,\r
+ \r
+ ------------ CRC-16 ccitt checksums\r
+ \r
+ -- Takes a hex string and calculates a crc16\r
+ Crc16 = function(s)\r
+ if s == nil then return nil end\r
+ if #s == 0 then return nil end\r
+ if type(s) == 'string' then\r
+ local utils = require('utils')\r
+ local asc = utils.ConvertHexToAscii(s)\r
+ local hash = core.crc16(asc)\r
+ return hash\r
+ end\r
+ return nil\r
+ end,\r
+\r
+ -- input parameter is a string\r
+ -- Swaps the endianess and returns a number, \r
+ -- IE: 'cd7a' -> '7acd' -> 0x7acd\r
+ SwapEndianness = function(s, len)\r
+ if s == nil then return nil end\r
+ if #s == 0 then return '' end\r
+ if type(s) ~= 'string' then return nil end\r
+ \r
+ local retval = 0\r
+ if len == 16 then\r
+ local t = s:sub(3,4)..s:sub(1,2)\r
+ retval = tonumber(t,16)\r
+ elseif len == 24 then\r
+ local t = s:sub(5,6)..s:sub(3,4)..s:sub(1,2)\r
+ retval = tonumber(t,16)\r
+ elseif len == 32 then\r
+ local t = s:sub(7,8)..s:sub(5,6)..s:sub(3,4)..s:sub(1,2)\r
+ retval = tonumber(t,16)\r
+ end\r
+ return retval\r
+ end,\r
+ \r
+ ------------ CONVERSIONS\r
+ \r
--\r
-- Converts DECIMAL to HEX\r
- ConvertDec2Hex = function(IN)\r
+ ConvertDecToHex = function(IN)\r
local B,K,OUT,I,D=16,"0123456789ABCDEF","",0\r
while IN>0 do\r
I=I+1\r
end,\r
---\r
-- Convert Byte array to string of hex\r
- ConvertBytes2String = function(bytes)\r
- s = {}\r
+ ConvertBytesToHex = function(bytes)\r
+ if #bytes == 0 then\r
+ return ''\r
+ end\r
+ local s={}\r
for i = 1, #(bytes) do\r
s[i] = string.format("%02X",bytes[i]) \r
end\r
return table.concat(s)\r
end, \r
+ -- Convert byte array to string with ascii\r
+ ConvertBytesToAscii = function(bytes)\r
+ if #bytes == 0 then\r
+ return ''\r
+ end\r
+ local s={}\r
+ for i = 1, #(bytes) do\r
+ s[i] = string.char(bytes[i]) \r
+ end\r
+ return table.concat(s) \r
+ end, \r
+ ConvertHexToBytes = function(s)\r
+ local t={}\r
+ if s == nil then return t end\r
+ if #s == 0 then return t end\r
+ for k in s:gmatch"(%x%x)" do\r
+ table.insert(t,tonumber(k,16))\r
+ end\r
+ return t\r
+ end,\r
+ ConvertAsciiToBytes = function(s)\r
+ local t={}\r
+ if s == nil then return t end\r
+ if #s == 0 then return t end\r
+ \r
+ for k in s:gmatch"(.)" do\r
+ table.insert(t, string.byte(k))\r
+ end\r
+ return t\r
+ end,\r
+ ConvertHexToAscii = function(s)\r
+ local t={}\r
+ if s == nil then return t end\r
+ if #s == 0 then return t end\r
+ for k in s:gmatch"(%x%x)" do\r
+ table.insert(t, string.char(tonumber(k,16)))\r
+ end\r
+ return table.concat(t) \r
+ end,\r
+ \r
+ -- function convertStringToBytes(str)\r
+ -- local bytes = {}\r
+ -- local strLength = string.len(str)\r
+ -- for i=1,strLength do\r
+ -- table.insert(bytes, string.byte(str, i))\r
+ -- end\r
+\r
+ -- return bytes\r
+-- end\r
+\r
+-- function convertBytesToString(bytes)\r
+ -- local bytesLength = table.getn(bytes)\r
+ -- local str = ""\r
+ -- for i=1,bytesLength do\r
+ -- str = str .. string.char(bytes[i])\r
+ -- end\r
+\r
+ -- return str\r
+-- end\r
+\r
+-- function convertHexStringToBytes(str)\r
+ -- local bytes = {}\r
+ -- local strLength = string.len(str)\r
+ -- for k=2,strLength,2 do\r
+ -- local hexString = "0x" .. string.sub(str, (k - 1), k)\r
+ -- table.insert(bytes, hex.to_dec(hexString))\r
+ -- end\r
+\r
+ -- return bytes\r
+-- end\r
+\r
+-- function convertBytesToHexString(bytes)\r
+ -- local str = ""\r
+ -- local bytesLength = table.getn(bytes)\r
+ -- for i=1,bytesLength do\r
+ -- local hexString = string.sub(hex.to_hex(bytes[i]), 3)\r
+ -- if string.len(hexString) == 1 then\r
+ -- hexString = "0" .. hexString\r
+ -- end\r
+ -- str = str .. hexString\r
+ -- end\r
+\r
+ -- return str\r
+-- end\r
+\r
}\r
return Utils
\ No newline at end of file
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
-//#include "proxusb.h"
+
#include "proxmark3.h"
#include "proxgui.h"
#include "cmdmain.h"
#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
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.
{"clearCommandBuffer", l_clearCommandBuffer},
{"console", l_CmdConsole},
{"iso15693_crc", l_iso15693_crc},
+ {"aes", l_aes},
+ {"crc16", l_crc16},
{NULL, NULL}
};
--- /dev/null
+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
--- /dev/null
+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
#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;
}
}
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;