From fb23d2047f304283a2a61d82932bd1aa9f0b170d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 2 Oct 2023 20:11:23 +0200 Subject: [PATCH] reworked the JSON format for 14a, 14b, 15, cryptorf, lto, NDEF.\nDeprecated EML format. Pm3 client do not save EML files any more.nPm3 client will continue to load EML files. --- CHANGELOG.md | 2 + client/src/cmdflashmem.c | 3 +- client/src/cmdflashmemspiffs.c | 13 +- client/src/cmdhf14a.c | 20 +- client/src/cmdhf14b.c | 12 +- client/src/cmdhf15.c | 54 ++-- client/src/cmdhfcryptorf.c | 15 +- client/src/cmdhffudan.c | 9 +- client/src/cmdhficlass.c | 20 +- client/src/cmdhflegic.c | 8 +- client/src/cmdhflto.c | 3 +- client/src/cmdhfmf.c | 86 ++---- client/src/cmdhfmfdes.c | 6 +- client/src/cmdhfmfp.c | 20 +- client/src/cmdhfmfu.c | 24 +- client/src/cmdhfst25ta.c | 11 +- client/src/cmdhftopaz.c | 6 +- client/src/cmdhfxerox.c | 15 +- client/src/cmdlfem4x05.c | 4 +- client/src/cmdlfem4x50.c | 12 +- client/src/cmdlfhitag.c | 2 +- client/src/cmdlft55xx.c | 10 +- client/src/fileutils.c | 502 +++++++++++++++++++++++++-------- client/src/fileutils.h | 45 ++- client/src/nfc/ndef.c | 30 ++ client/src/nfc/ndef.h | 2 +- include/iclass_cmd.h | 2 +- 27 files changed, 617 insertions(+), 319 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bde51946..873bc53ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Changed the json file formats for mfc, 14b, 15, legic, cryptorf, ndef (@iceman1001) + - Depricated the EML file format when saving dump files. (@iceman1001) - Added `sim014.bin` - new sim module firmware v4.42 with improved ISO7816 Protocol T0 support (@gentilkiwi) - Added datasheet for sim module (@iceman1001) - Changed `smart raw --timeout` - allows for a custom timeout (@iceman1001) diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index 2cfe3849c..9d1f5605f 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -379,8 +379,7 @@ static int CmdFlashMemDump(const char *Cmd) { } if (filename[0] != '\0') { - saveFile(filename, ".bin", dump, len); - saveFileEML(filename, dump, len, 16); + pm3_save_dump(filename, dump, len, jsfRaw); } free(dump); diff --git a/client/src/cmdflashmemspiffs.c b/client/src/cmdflashmemspiffs.c index e84b3e597..218109755 100644 --- a/client/src/cmdflashmemspiffs.c +++ b/client/src/cmdflashmemspiffs.c @@ -370,14 +370,13 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { "Dumps device SPIFFS file to a local file\n" "Size is handled by first sending a STAT command against file to verify existence", "mem spiffs dump -s tag.bin --> download binary file from device\n" - "mem spiffs dump -s tag.bin -d aaa -e --> download tag.bin, save as aaa.eml format" + "mem spiffs dump -s tag.bin -d a001 -e --> download tag.bin, save as `a001.bin`" ); void *argtable[] = { arg_param_begin, arg_str1("s", "src", "", "SPIFFS file to save"), arg_str0("d", "dest", "", "file name to save to "), - arg_lit0("e", "eml", "also save in EML format"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -390,7 +389,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { char dest[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, FILE_PATH_SIZE, &dlen); - bool eml = arg_get_lit(ctx, 3); CLIParserFree(ctx); // get size from spiffs itself ! @@ -433,15 +431,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { else saveFile(fn, ".bin", dump, len); // default - if (eml) { - uint8_t eml_len = 16; - if (strstr(fn, "class") != NULL) - eml_len = 8; - else if (strstr(fn, "mfu") != NULL) - eml_len = 4; - - saveFileEML(fn, dump, len, eml_len); - } free(dump); return PM3_SUCCESS; } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index ecd57e181..439641f09 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2748,6 +2748,7 @@ int CmdHF14ANdefRead(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); bool verbose = arg_get_lit(ctx, 2); + bool verbose2 = arg_get_lit(ctx, 2) > 1; CLIParserFree(ctx); bool activate_field = true; @@ -2934,11 +2935,24 @@ int CmdHF14ANdefRead(const char *Cmd) { memcpy(ndef_file + (i - offset), response, segment_size); } - if (fnlen != 0) { - saveFile(filename, ".bin", ndef_file, ndef_size); - } + if (verbose2) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("NDEF raw") " ----------------"); + print_buffer(ndef_file, ndef_size, 1); + } NDEFRecordsDecodeAndPrint(ndef_file, ndef_size, verbose); + + pm3_save_dump(filename, ndef_file, ndef_size, jsfNDEF); + + if (verbose == false) { + PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -v`") " for more details"); + } else { + if (verbose2 == false) { + PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -vv`") " for more details"); + } + } + free(ndef_file); return PM3_SUCCESS; } diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 1ba73e797..59a452fb6 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1546,7 +1546,7 @@ static int CmdHF14BDump(const char *Cmd) { } size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE; - pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE); + pm3_save_dump(filename, data, datalen, jsf14b_v2); } } @@ -2121,9 +2121,13 @@ int CmdHF14BNdefRead(const char *Cmd) { goto out; } - if (fnlen != 0) { - saveFile(filename, ".bin", response + 2, resplen - 4); - } + // get total NDEF length before save. If fails, we save it all + size_t n = 0; + if (NDEFGetTotalLength(response + 2, resplen - 4, &n) != PM3_SUCCESS) + n = resplen - 4; + + pm3_save_dump(filename, response + 2, n, jsfNDEF); + res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose); out: diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 75b972871..eea85272a 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -62,7 +62,7 @@ typedef struct { uint8_t lock; - uint8_t block[4]; + uint8_t block[8]; } t15memory_t; // structure and database for uid -> tagtype lookups @@ -1143,14 +1143,14 @@ static int CmdHF15ELoad(const char *Cmd) { static int CmdHF15ESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 15 esave", - "Save emulator memory into three files (BIN/EML/JSON) ", + "Save emulator memory into two files (BIN/JSON) ", "hf 15 esave -f hf-15-01020304" "hf 15 esave -b 8 -c 42 -f hf-15-01020304" ); void *argtable[] = { arg_param_begin, arg_str1("f", "file", "", "filename of dump"), - arg_int0("b", "blocksize", "", "block size, defaults to 4"), + arg_int0(NULL, "bsize", "", "block size, defaults to 4"), arg_int0("c", "count", "", "number of blocks to export, defaults to all"), arg_param_end }; @@ -1176,13 +1176,18 @@ static int CmdHF15ESave(const char *Cmd) { } PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); - if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); free(dump); return PM3_ETIMEOUT; } - pm3_save_dump(filename, dump, bytes, jsf15, blocksize); + if (blocksize == 8) { + pm3_save_dump(filename, dump, bytes, jsf15_v3); + } else { + pm3_save_dump(filename, dump, bytes, jsf15_v2); + } + free(dump); return PM3_SUCCESS; } @@ -1604,9 +1609,12 @@ static int CmdHF15Dump(const char *Cmd) { // memory. t15memory_t mem[256]; - uint8_t data[256 * 4] = {0}; + uint8_t data[256 * 8] = {0}; memset(data, 0, sizeof(data)); + // keep track of which block length tag returned? + uint8_t blklen = 4; + for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) { req[10] = blocknum; @@ -1646,9 +1654,15 @@ static int CmdHF15Dump(const char *Cmd) { break; } + // lock byte value mem[blocknum].lock = resp.data.asBytes[0]; - memcpy(mem[blocknum].block, resp.data.asBytes + 1, 4); - memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4); + + // is tag responding with 4 or 8 bytes? + if (resp.length == 11) { + blklen = 8; + } + memcpy(mem[blocknum].block, resp.data.asBytes + 1, blklen); + memcpy(data + (blocknum * 4), resp.data.asBytes + 1, blklen); retry = 0; blocknum++; @@ -1659,6 +1673,10 @@ static int CmdHF15Dump(const char *Cmd) { DropField(); + if (blklen == 8) { + PrintAndLogEx(INFO, "8 byte block length detected"); + } + PrintAndLogEx(NORMAL, "\n"); PrintAndLogEx(INFO, "block# | data |lck| ascii"); PrintAndLogEx(INFO, "---------+--------------+---+----------"); @@ -1672,9 +1690,9 @@ static int CmdHF15Dump(const char *Cmd) { PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s" , i , i - , sprint_hex(mem[i].block, 4) + , sprint_hex(mem[i].block, blklen) , lck - , sprint_ascii(mem[i].block, 4) + , sprint_ascii(mem[i].block, blklen) ); } PrintAndLogEx(NORMAL, ""); @@ -1687,8 +1705,11 @@ static int CmdHF15Dump(const char *Cmd) { FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid)); } - size_t datalen = blocknum * 4; - pm3_save_dump(filename, data, datalen, jsf15, 4); + if (blklen == 8) { + pm3_save_dump(filename, data, (blocknum * blklen), jsf15_v3); + } else { + pm3_save_dump(filename, data, (blocknum * blklen), jsf15_v2); + } return PM3_SUCCESS; } @@ -2000,15 +2021,16 @@ static int CmdHF15Readblock(const char *Cmd) { return PM3_EWRONGANSWER; } + // print response char lck[16] = {0}; if (data[1]) { - snprintf(lck, sizeof(lck), _RED_("%d"), data[1]); + snprintf(lck, sizeof(lck), _RED_("%02X"), data[1]); } else { - snprintf(lck, sizeof(lck), "%d", data[1]); + snprintf(lck, sizeof(lck), "%02X", data[1]); } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, " #%3d |lck| ascii", block); + PrintAndLogEx(INFO, "#%3d |lck| ascii", block); PrintAndLogEx(INFO, "------------+---+------"); PrintAndLogEx(INFO, "%s| %s | %s", sprint_hex(data + 2, resp.length - 4), lck, sprint_ascii(data + 2, resp.length - 4)); PrintAndLogEx(NORMAL, ""); @@ -2834,7 +2856,7 @@ static int CmdHF15View(const char *Cmd) { ); void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "filename of dump (bin/eml/json)"), + arg_str1("f", "file", "", "filename of dump"), // arg_lit0("z", "dense", "dense dump output style"), arg_param_end }; diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index 552c25590..12e522f2a 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -414,9 +414,8 @@ static int CmdHFCryptoRFDump(const char *Cmd) { FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); } - saveFileEML(filename, data, datalen, 4); - saveFile(filename, ".bin", data, datalen); - // json? + pm3_save_dump(filename, data, datalen, jsfCryptorf); + return switch_off_field_cryptorf(); } @@ -486,14 +485,14 @@ static int CmdHFCryptoRFESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cryptorf esave", - "Save emulator memory to bin/eml/json file\n" + "Save emulator memory to to two files (bin/json)\n" "if filename is not supplied, UID will be used.", "hf cryptorf esave\n" "hf cryptorf esave -f filename" ); void *argtable[] = { arg_param_begin, - arg_str0("f", "file", "", "filename of dumpfile"), + arg_str0("f", "file", "", "filename of dump"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -527,11 +526,7 @@ static int CmdHFCryptoRFESave(const char *Cmd) { FillFileNameByUID(fptr, data, "-dump", 4); } - saveFile(filename, ".bin", data, numofbytes); - //needs to change - saveFileEML(filename, data, numofbytes, 8); - //needs to change - saveFileJSON(filename, jsfRaw, data, numofbytes, NULL); + pm3_save_dump(filename, data, numofbytes, jsfCryptorf); free(data); return PM3_SUCCESS; } diff --git a/client/src/cmdhffudan.c b/client/src/cmdhffudan.c index 53e580e1b..7403afeb6 100644 --- a/client/src/cmdhffudan.c +++ b/client/src/cmdhffudan.c @@ -339,14 +339,7 @@ static int CmdHFFudanDump(const char *Cmd) { free(fptr); } - saveFile(dataFilename, ".bin", (uint8_t *)carddata, sizeof(carddata)); - saveFileEML(dataFilename, (uint8_t *)carddata, sizeof(carddata), MAX_FUDAN_BLOCK_SIZE); - - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = (uint8_t *)carddata; - xdump.dumplen = sizeof(carddata); - saveFileJSON(dataFilename, jsfFudan, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_dump(dataFilename, (uint8_t *)carddata, sizeof(carddata), jsfFudan); return PM3_SUCCESS; } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 86dda89cd..08ed01068 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -19,8 +19,8 @@ #include "cmdhficlass.h" #include #include "cliparser.h" -#include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "cmdparser.h" // command_t +#include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" #include "util_posix.h" #include "comms.h" @@ -34,13 +34,13 @@ #include "cardhelper.h" #include "wiegand_formats.h" #include "wiegand_formatutils.h" -#include "cmdsmartcard.h" // smart select fct +#include "cmdsmartcard.h" // smart select fct #include "proxendian.h" #include "iclass_cmd.h" -#include "crypto/asn1utils.h" // ASN1 decoder +#include "crypto/asn1utils.h" // ASN1 decoder #include "preferences.h" -#define PICOPASS_BLOCK_SIZE 8 + #define NUM_CSNS 9 #define MAC_ITEM_SIZE 24 // csn(8) + epurse(8) + nr(4) + mac(4) = 24 bytes #define ICLASS_KEYS_MAX 8 @@ -1016,7 +1016,7 @@ static int CmdHFiClassELoad(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "filename of dump (bin/eml/json)"), + arg_str1("f", "file", "", "filename of dump"), arg_lit0("m", "mem", "use RDV4 spiffs"), arg_lit0("v", "verbose", "verbose output"), arg_param_end @@ -1149,7 +1149,7 @@ static int CmdHFiClassESave(const char *Cmd) { FillFileNameByUID(fptr, dump, "-dump", 8); } - pm3_save_dump(filename, dump, bytes, jsfIclass, PICOPASS_BLOCK_SIZE); + pm3_save_dump(filename, dump, bytes, jsfIclass); free(dump); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file"); @@ -1497,7 +1497,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { strcat(fptr, "hf-iclass-"); FillFileNameByUID(fptr, hdr->csn, "-dump-decrypted", sizeof(hdr->csn)); - pm3_save_dump(fptr, decrypted, decryptedlen, jsfIclass, PICOPASS_BLOCK_SIZE); + pm3_save_dump(fptr, decrypted, decryptedlen, jsfIclass); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen, dense_output); @@ -2045,7 +2045,7 @@ write_dump: // save the dump to .bin file PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8); - pm3_save_dump(filename, tag_data, bytes_got, jsfIclass, PICOPASS_BLOCK_SIZE); + pm3_save_dump(filename, tag_data, bytes_got, jsfIclass); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt -f") "` to decrypt dump file"); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file"); @@ -3026,7 +3026,7 @@ static int CmdHFiClassView(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "filename of dump (bin/eml/json)"), + arg_str1("f", "file", "", "filename of dump"), arg_int0(NULL, "first", "", "Begin printing from this block (default first user block)"), arg_int0(NULL, "last", "", "End printing at this block (default 0, ALL)"), arg_lit0("v", "verbose", "verbose output"), diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 488f8dcb2..676ed3911 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -858,7 +858,7 @@ static int CmdLegicReader(const char *Cmd) { static int CmdLegicDump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf legic dump", - "Read all memory from LEGIC Prime tags and saves to (bin/eml/json) dump file\n" + "Read all memory from LEGIC Prime tags and saves to (bin/json) dump file\n" "It autodetects card type (MIM22, MIM256, MIM1024)", "hf legic dump --> use UID as filename\n" "hf legic dump -f myfile \n" @@ -951,7 +951,7 @@ static int CmdLegicDump(const char *Cmd) { FillFileNameByUID(filename, data, "-dump", 4); } - pm3_save_dump(filename, data, readlen, jsfLegic, LEGIC_BLOCK_SIZE); + pm3_save_dump(filename, data, readlen, jsfLegic_v2); free(data); return PM3_SUCCESS; } @@ -1119,7 +1119,7 @@ static int CmdLegicELoad(const char *Cmd) { static int CmdLegicESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf legic esave", - "Saves a (bin/eml/json) dump file of emulator memory", + "Saves a (bin/json) dump file of emulator memory", "hf legic esave --> uses UID as filename\n" "hf legic esave -f myfile --22\n" "hf legic esave -f myfile --22 --de\n" @@ -1188,7 +1188,7 @@ static int CmdLegicESave(const char *Cmd) { legic_xor(data, numofbytes); } - pm3_save_dump(filename, data, numofbytes, jsfLegic, LEGIC_BLOCK_SIZE); + pm3_save_dump(filename, data, numofbytes, jsfLegic_v2); return PM3_SUCCESS; } diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index d11f0c6d1..e263c850e 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -771,8 +771,7 @@ static int CmdHfLTODump(const char *Cmd) { char *fptr = filename + snprintf(filename, sizeof(filename), "hf-lto-"); FillFileNameByUID(fptr, dump, "-dump", 5); } - saveFile(filename, ".bin", dump, dump_len); - saveFileEML(filename, dump, dump_len, 32); + pm3_save_dump(filename, dump, dump_len, jsfLto); free(dump); return PM3_SUCCESS; } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 7f8be4fbf..1267235de 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -472,7 +472,7 @@ void mf_print_sector_hdr(uint8_t sector) { static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno, uint8_t *block) { uint8_t data[26]; - memcpy(data, key, MFKEY_SIZE); + memcpy(data, key, MIFARE_KEY_SIZE); memcpy(data + 10, block, MFBLOCK_SIZE); clearCommandBuffer(); @@ -1230,14 +1230,7 @@ static int CmdHF14AMfDump(const char *Cmd) { free(fptr); } - saveFile(dataFilename, ".bin", mem, bytes); - saveFileEML(dataFilename, mem, bytes, MFBLOCK_SIZE); - - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = mem; - xdump.dumplen = bytes; - saveFileJSON(dataFilename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_mf_dump(dataFilename, mem, bytes, jsfCardMemory); free(mem); return PM3_SUCCESS; } @@ -3164,13 +3157,7 @@ all_found: strncpy(filename, fptr, sizeof(filename) - 1); free(fptr); - saveFile(filename, ".bin", dump, bytes); - saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = dump; - xdump.dumplen = bytes; - saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory); // Generate and show statistics t1 = msclock() - t1; @@ -4452,7 +4439,7 @@ static int CmdHF14AMfESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf esave", - "Save emulator memory into three files (BIN/EML/JSON) ", + "Save emulator memory into two files (bin//json) ", "hf mf esave\n" "hf mf esave --4k\n" "hf mf esave --4k -f hf-mf-01020304.eml" @@ -4522,30 +4509,7 @@ static int CmdHF14AMfESave(const char *Cmd) { FillFileNameByUID(fptr, dump, "-dump", 4); } - saveFile(filename, ".bin", dump, bytes); - saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); - - iso14a_mf_extdump_t xdump = {0}; - xdump.card_info.ats_len = 0; - // Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA - if ((dump[0] ^ dump[1] ^ dump[2] ^ dump[3]) == dump[4] && (dump[6] & 0xc0) == 0) { - xdump.card_info.uidlen = 4; - memcpy(xdump.card_info.uid, dump, xdump.card_info.uidlen); - xdump.card_info.sak = dump[5]; - memcpy(xdump.card_info.atqa, &dump[6], sizeof(xdump.card_info.atqa)); - } - // Check for 7 bytes UID: double size uid bits in ATQA - else if ((dump[8] & 0xc0) == 0x40) { - xdump.card_info.uidlen = 7; - memcpy(xdump.card_info.uid, dump, xdump.card_info.uidlen); - xdump.card_info.sak = dump[7]; - memcpy(xdump.card_info.atqa, &dump[8], sizeof(xdump.card_info.atqa)); - } else { - PrintAndLogEx(WARNING, "Invalid dump. UID/SAK/ATQA not found"); - } - xdump.dump = dump; - xdump.dumplen = bytes; - saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory); free(dump); return PM3_SUCCESS; } @@ -5217,7 +5181,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { static int CmdHF14AMfCSave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf csave", - "Save magic gen1a card memory into three files (BIN/EML/JSON)" + "Save magic gen1a card memory into two files (bin/json)" "or into emulator memory", "hf mf csave\n" "hf mf csave --4k" @@ -5364,13 +5328,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); } - saveFile(filename, ".bin", dump, bytes); - saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = dump; - xdump.dumplen = bytes; - saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory); free(dump); return PM3_SUCCESS; } @@ -6176,16 +6134,19 @@ int CmdHFMFNDEFRead(const char *Cmd) { print_buffer(data, datalen, 1); } - if (fnlen != 0) { - saveFile(filename, ".bin", data, datalen); - } - res = NDEFDecodeAndPrint(data, datalen, verbose); if (res != PM3_SUCCESS) { PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); res = NDEFRecordsDecodeAndPrint(data, datalen, verbose); } + // get total NDEF length before save. If fails, we save it all + size_t n = 0; + if (NDEFGetTotalLength(data, datalen, &n) != PM3_SUCCESS) + n = datalen; + + pm3_save_dump(filename, data, n, jsfNDEF); + if (verbose == false) { PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -v`") " for more details"); } else { @@ -6282,8 +6243,8 @@ int CmdHFMFNDEFFormat(const char *Cmd) { // init keys to default key - uint8_t keyA[MIFARE_4K_MAXSECTOR][MFKEY_SIZE]; - uint8_t keyB[MIFARE_4K_MAXSECTOR][MFKEY_SIZE]; + uint8_t keyA[MIFARE_4K_MAXSECTOR][MIFARE_KEY_SIZE]; + uint8_t keyB[MIFARE_4K_MAXSECTOR][MIFARE_KEY_SIZE]; for (uint8_t i = 0; i < MIFARE_4K_MAXSECTOR; i++) { memcpy(keyA[i], g_mifare_default_key, sizeof(g_mifare_default_key)); @@ -6314,7 +6275,6 @@ int CmdHFMFNDEFFormat(const char *Cmd) { DropField(); } - // load key file if exist if (strlen(keyFilename)) { // @@ -7402,7 +7362,6 @@ static int CmdHF14AMfView(const char *Cmd) { block_cnt = MIFARE_4K_MAXBLOCK; if (verbose) { - PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt); } @@ -7896,7 +7855,7 @@ static int CmdHF14AGen4Save(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gsave", - "Save `magic gen4 gtu` card memory into three files (BIN/EML/JSON)" + "Save `magic gen4 gtu` card memory into two files (bin/json)" "or into emulator memory", "hf mf gsave\n" "hf mf gsave --4k\n" @@ -7908,7 +7867,7 @@ static int CmdHF14AGen4Save(const char *Cmd) { arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"), arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), - arg_str0("p", "pwd", "", "password 4bytes"), + arg_str0("p", "pwd", "", "password 4 bytes"), arg_str0("f", "file", "", "filename of dump"), arg_lit0(NULL, "emu", "to emulator memory"), arg_param_end @@ -8079,14 +8038,7 @@ static int CmdHF14AGen4Save(const char *Cmd) { FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); } - saveFile(filename, ".bin", dump, bytes); - saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = dump; - xdump.dumplen = bytes; - saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); - + pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory); free(dump); return PM3_SUCCESS; } diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 03dcea842..59abee163 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1126,9 +1126,9 @@ static int CmdHF14aDesChk(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes chk", "Checks keys with MIFARE DESFire card.", "hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n" - "hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n" - "hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys from dictionary against aid 0x123456\n" - "hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json\n" + "hf mfdes chk -d mfdes_default_keys -> check keys against all existing aid on card\n" + "hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys against aid 0x123456\n" + "hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to `keys.json`\n" "hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00"); void *argtable[] = { diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index c0078819b..9d854290e 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -1448,14 +1448,7 @@ static int CmdHFMFPDump(const char *Cmd) { free(fptr); } - saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES); - saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE); - - iso14a_mf_extdump_t xdump; - xdump.card_info = card; - xdump.dump = mem; - xdump.dumplen = MIFARE_4K_MAX_BYTES; - saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + pm3_save_mf_dump(filename, dump, MIFARE_4K_MAX_BYTES, jsfCardMemory); */ free(mem); return PM3_SUCCESS; @@ -1746,16 +1739,19 @@ int CmdHFMFPNDEFRead(const char *Cmd) { print_buffer(data, datalen, 1); } - if (fnlen != 0) { - saveFile(filename, ".bin", data, datalen); - } - res = NDEFDecodeAndPrint(data, datalen, verbose); if (res != PM3_SUCCESS) { PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); res = NDEFRecordsDecodeAndPrint(data, datalen, verbose); } + // get total NDEF length before save. If fails, we save it all + size_t n = 0; + if (NDEFGetTotalLength(data, datalen, &n) != PM3_SUCCESS) + n = datalen; + + pm3_save_dump(filename, data, n, jsfNDEF); + if (verbose == false) { PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details"); } else { diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 13b8c9cb4..8c46ad992 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2677,7 +2677,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { } uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; - pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); + pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory); if (is_partial) { PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); @@ -2840,7 +2840,7 @@ int CmdHF14MfUTamper(const char *Cmd) { static int CmdHF14AMfURestore(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfu restore", - "Restore MIFARE Ultralight/NTAG dump file to tag.\n", + "Restore MIFARE Ultralight/NTAG dump file (bin/eml/json) to tag.\n", "hf mfu restore -f myfile -s -> special write\n" "hf mfu restore -f myfile -k AABBCCDD -s -> special write, use key\n" "hf mfu restore -f myfile -k AABBCCDD -ser -> special write, use key, write dump pwd, ..." @@ -2848,7 +2848,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "specify dump filename (bin/eml/json)"), + arg_str1("f", "file", "", "specify dump filename"), arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), arg_lit0("l", NULL, "swap entered key's endianness"), arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"), @@ -4443,14 +4443,20 @@ int CmdHF14MfuNDEFRead(const char *Cmd) { } DropField(); - if (fnlen != 0) { - saveFile(filename, ".bin", records, (size_t)maxsize); - } + status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize, verbose); if (status != PM3_SUCCESS) { status = NDEFDecodeAndPrint(records, (size_t)maxsize, verbose); } + // get total NDEF length before save. If fails, we save it all + size_t n = 0; + if (NDEFGetTotalLength(records, maxsize, &n) != PM3_SUCCESS) + n = maxsize; + + pm3_save_dump(filename, records, n, jsfNDEF); + + char *jooki = strstr((char *)records, "s.jooki.rocks/s/?s="); if (jooki) { jooki += 17; @@ -4557,12 +4563,12 @@ static int CmdHF14AMfuEView(const char *Cmd) { static int CmdHF14AMfuESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfu esave", - "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json)\n" + "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/json)\n" "By default number of pages saved depends on defined tag type.\n" "You can override this with option --end.", "hf mfu esave\n" "hf mfu esave --end 255 -> saves whole memory\n" - "hf mfu esave -f hf-mfu-04010203040506-dump.json" + "hf mfu esave -f hf-mfu-04010203040506-dump" ); void *argtable[] = { @@ -4613,7 +4619,7 @@ static int CmdHF14AMfuESave(const char *Cmd) { // save dump. Last block contains PACK + RFU uint16_t datalen = (end + 1) * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; - res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); + res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory); free(dump); return res; diff --git a/client/src/cmdhfst25ta.c b/client/src/cmdhfst25ta.c index 86dfe0584..fe6e2e94c 100644 --- a/client/src/cmdhfst25ta.c +++ b/client/src/cmdhfst25ta.c @@ -404,10 +404,15 @@ int CmdHFST25TANdefRead(const char *Cmd) { return PM3_ESOFT; } - if (fnlen != 0) { - saveFile(filename, ".bin", response + 2, resplen - 4); - } NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose); + + // get total NDEF length before save. If fails, we save it all + size_t n = 0; + if (NDEFGetTotalLength(response, resplen, &n) != PM3_SUCCESS) + n = resplen; + + pm3_save_dump(filename, response + 2, n, jsfNDEF); + return PM3_SUCCESS; } diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index 649882416..97ba7e5f0 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -897,9 +897,9 @@ static int CmdHFTopazDump(const char *Cmd) { } if (topaz_tag.size) - pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz, TOPAZ_BLOCK_SIZE); + pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz); else - pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz, TOPAZ_BLOCK_SIZE); + pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz); if (set_dynamic) { free(topaz_tag.dynamic_memory); @@ -916,7 +916,7 @@ static int CmdHFTopazView(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "filename of dump (bin/eml/json)"), + arg_str1("f", "file", "", "filename of dump"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); diff --git a/client/src/cmdhfxerox.c b/client/src/cmdhfxerox.c index fec69855e..5f6f1e11c 100644 --- a/client/src/cmdhfxerox.c +++ b/client/src/cmdhfxerox.c @@ -611,9 +611,7 @@ static int CmdHFXeroxDump(const char *Cmd) { int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - bool decrypt = arg_get_lit(ctx, 2); - CLIParserFree(ctx); iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11); @@ -682,7 +680,6 @@ static int CmdHFXeroxDump(const char *Cmd) { PrintAndLogEx(NORMAL, "." NOLF); fflush(stdout); -// PrintAndLogEx(INPLACE, "blk %3d", blocknum); } } @@ -773,23 +770,13 @@ static int CmdHFXeroxDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); if (0 == filename[0]) { // generate filename from uid - /* - PrintAndLogEx(INFO, "Using UID as filename"); - - sprintf(filename, "hf-xerox-%02X%02X%02X%02X%02X%02X%02X%02X-dump%s", - card.uid[7],card.uid[6],card.uid[5],card.uid[4],card.uid[3],card.uid[2],card.uid[1],card.uid[0], - decrypt ? "-dec" : ""); - */ char *fptr = filename; PrintAndLogEx(INFO, "Using UID as filename"); fptr += snprintf(fptr, sizeof(filename), "hf-xerox-"); FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen); } - size_t datalen = blocknum * 4; - saveFile(filename, ".bin", data, datalen); - saveFileEML(filename, data, datalen, 4); -// saveFileJSON(filename, jsf15, data, datalen, NULL); + pm3_save_dump(filename, data, blocknum * 4, jsf14b_v2); return PM3_SUCCESS; } diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 665518a40..862be6f9c 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -709,9 +709,9 @@ int CmdEM4x05Dump(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); if (card_type == EM_4369 || card_type == EM_4469) - pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69, 4); + pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69); else - pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05, 4); + pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05); } PrintAndLogEx(NORMAL, ""); return success; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a304a84fe..d44d71dcf 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -194,7 +194,7 @@ int CmdEM4x50ELoad(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "dump filename (bin/eml/json)"), + arg_str1("f", "file", "", "dump filename"), arg_param_end }; @@ -223,7 +223,7 @@ int CmdEM4x50ELoad(const char *Cmd) { int CmdEM4x50ESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 esave", - "Saves bin/eml/json dump file of emulator memory.", + "Saves bin/json dump file of emulator memory.", "lf em 4x50 esave -> use UID as filename\n" "lf em 4x50 esave -f mydump\n" ); @@ -264,7 +264,7 @@ int CmdEM4x50ESave(const char *Cmd) { FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); } - pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50, 4); + pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50); return PM3_SUCCESS; } @@ -796,7 +796,7 @@ int CmdEM4x50Reader(const char *Cmd) { int CmdEM4x50Dump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 dump", - "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format", + "Reads all blocks/words from EM4x50 tag and saves dump in (bin/json) format", "lf em 4x50 dump\n" "lf em 4x50 dump -f mydump\n" "lf em 4x50 dump -p 12345678\n" @@ -805,7 +805,7 @@ int CmdEM4x50Dump(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("f", "file", "", "specify dump filename (bin/eml/json)"), + arg_str0("f", "file", "", "specify dump filename"), arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; @@ -867,7 +867,7 @@ int CmdEM4x50Dump(const char *Cmd) { memcpy(data + (i * 4), words[i].byte, 4); } - pm3_save_dump(filename, data, sizeof(data), jsfEM4x50, 4); + pm3_save_dump(filename, data, sizeof(data), jsfEM4x50); return PM3_SUCCESS; } diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 1cbae7bd3..45206750f 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -1127,7 +1127,7 @@ static int CmdLFHitag2Dump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Dumping tag memory..."); - pm3_save_dump(filename, data, 48, jsfHitag, 4); + pm3_save_dump(filename, data, 48, jsfHitag); return PM3_SUCCESS; } diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 9ce8219c2..e9da9de64 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -2217,7 +2217,7 @@ static int CmdT55xxDump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf t55xx dump", "This command dumps a T55xx card Page 0 block 0-7.\n" - "It will create three files (bin/eml/json)", + "It will create two files (bin/json)", "lf t55xx dump\n" "lf t55xx dump -p aabbccdd --override\n" "lf t55xx dump -f my_lf_dump" @@ -2315,17 +2315,13 @@ static int CmdT55xxDump(const char *Cmd) { } // Swap endian so the files match the txt display - uint32_t data[T55x7_BLOCK_COUNT]; + uint32_t data[T55x7_BLOCK_COUNT] = {0}; for (int i = 0; i < T55x7_BLOCK_COUNT; i++) { data[i] = BSWAP_32(cardmem[i].blockdata); } - // saveFileEML will add .eml extension to filename - // saveFile (binary) passes in the .bin extension. - saveFileJSON(filename, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL); - saveFileEML(filename, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t)); - saveFile(filename, ".bin", data, sizeof(data)); + pm3_save_dump(filename, (uint8_t*)data, (T55x7_BLOCK_COUNT * sizeof(uint32_t)), jsfT55x7); } return PM3_SUCCESS; diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 7383c396f..8ed6e01ee 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -27,9 +27,7 @@ #include "proxmark3.h" #include "util.h" #include "cmdhficlass.h" // pagemap -#include "protocols.h" // iclass defines -#include "cmdhftopaz.h" // TOPAZ defines -#include "mifare/mifaredefault.h" // MFP / AES defines +#include "iclass_cmd.h" #ifdef _WIN32 #include "scandir.h" @@ -329,12 +327,8 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, } } - char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path); - if (fileName == NULL) { - return PM3_EMALLOC; - } - int retval = PM3_SUCCESS; + char path[PATH_MAX_LENGTH] = {0}; json_t *root = json_object(); JsonSaveStr(root, "Created", "proxmark3"); @@ -344,26 +338,26 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "raw", data, datalen); break; } - case jsfCardMemory: { + case jsfMfc_v2: { iso14a_mf_extdump_t *xdump = (iso14a_mf_extdump_t *)(void *) data; - JsonSaveStr(root, "FileType", "mfcard"); + JsonSaveStr(root, "FileType", "mfc v2"); JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump->card_info.uid, xdump->card_info.uidlen); JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump->card_info.atqa, 2); JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump->card_info.sak), 1); - for (size_t i = 0; i < (xdump->dumplen / 16); i++) { - char path[PATH_MAX_LENGTH] = {0}; + for (size_t i = 0; i < (xdump->dumplen / MFBLOCK_SIZE); i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); - JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16], 16); + JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE], MFBLOCK_SIZE); if (mfIsSectorTrailer(i)) { snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", mfSectorNum(i)); - JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16], 6); + JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE], 6); snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", mfSectorNum(i)); - JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16 + 10], 6); + JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE + 10], 6); - uint8_t *adata = &xdump->dump[i * 16 + 6]; + uint8_t *adata = &xdump->dump[i * MFBLOCK_SIZE + 6]; snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i)); - JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16 + 6], 4); + JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE + 6], 4); snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3); JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata)); @@ -390,7 +384,7 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump->card_info.atqa, 2); JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump->card_info.sak), 1); for (size_t i = 0; i < (xdump->dumplen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; + snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 4], 4); } @@ -405,8 +399,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, memcpy(uid, tmp->data, 3); memcpy(uid + 3, tmp->data + 4, 4); - char path[PATH_MAX_LENGTH] = {0}; - JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid)); JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version)); JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo)); @@ -420,11 +412,12 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, } // size of header 56b - size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / 4; + + size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / MFU_BLOCK_SIZE; for (size_t i = 0; i < len; i++) { snprintf(path, sizeof(path), "$.blocks.%zu", i); - JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4); + JsonSaveBufAsHexCompact(root, path, tmp->data + (i * MFU_BLOCK_SIZE), MFU_BLOCK_SIZE); } break; } @@ -436,7 +429,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid)); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } @@ -460,10 +452,10 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.AIA", hdr->app_issuer_area, sizeof(hdr->app_issuer_area)); } - for (size_t i = 0; i < (datalen / 8); i++) { - char path[PATH_MAX_LENGTH] = {0}; + for (size_t i = 0; i < (datalen / PICOPASS_BLOCK_SIZE); i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); - JsonSaveBufAsHexCompact(root, path, data + (i * 8), 8); + JsonSaveBufAsHexCompact(root, path, data + (i * PICOPASS_BLOCK_SIZE), PICOPASS_BLOCK_SIZE); } break; @@ -475,25 +467,49 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf)); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } break; } - case jsf14b: { - JsonSaveStr(root, "FileType", "14b"); - JsonSaveBufAsHexCompact(root, "raw", data, datalen); + case jsf14b_v2: { + JsonSaveStr(root, "FileType", "14b v2"); + for (size_t i = 0; i < datalen / 4; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 4], 4); + } break; } - case jsf15: { - JsonSaveStr(root, "FileType", "15693"); - JsonSaveBufAsHexCompact(root, "raw", data, datalen); + // handles ISO15693 w blocksize of 4 bytes + case jsf15_v2: { + JsonSaveStr(root, "FileType", "15693 v2"); + for (size_t i = 0; i < datalen / 4; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 4], 4); + } break; } - case jsfLegic: { - JsonSaveStr(root, "FileType", "legic"); - JsonSaveBufAsHexCompact(root, "raw", data, datalen); + // handles ISO15693 w blocksize of 8 bytes + case jsf15_v3: { + JsonSaveStr(root, "FileType", "15693 v3"); + for (size_t i = 0; i < datalen / 8; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 8], 8); + } + break; + } + case jsfLegic_v2: { + JsonSaveStr(root, "FileType", "legic v2"); + JsonSaveBufAsHexCompact(root, "$.Card.UID", data, 4); + size_t i = 0; + for (; i < datalen / 16; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16); + } + if (datalen % 16) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16)); + } break; } case jsfT5555: { @@ -503,7 +519,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf)); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } @@ -517,7 +532,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.Protection2", data + (15 * 4), 4); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } @@ -530,7 +544,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } @@ -544,7 +557,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4); for (size_t i = 0; i < (datalen / 4); i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); } @@ -564,8 +576,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, memcpy(vdata, data + (14 + atslen), 2 * 64 * 17); for (size_t i = 0; i < datalen; i++) { - char path[PATH_MAX_LENGTH] = {0}; - if (vdata[0][i][0]) { snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i); JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN); @@ -591,31 +601,27 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, memcpy(dvdata, &data[14 + datslen], 4 * 0xE * (24 + 1)); for (int i = 0; i < (int)datalen; i++) { - char path[PATH_MAX_LENGTH] = {0}; if (dvdata[0][i][0]) { snprintf(path, sizeof(path), "$.DES.%d.Key", i); - JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], 8); + JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN); } if (dvdata[1][i][0]) { snprintf(path, sizeof(path), "$.3DES.%d.Key", i); - JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], 16); + JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN); } if (dvdata[2][i][0]) { snprintf(path, sizeof(path), "$.AES.%d.Key", i); - JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], 16); + JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN); } if (dvdata[3][i][0]) { snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i); - JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], 24); + JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN); } } break; } - case jsfFido: { - break; - } case jsfCustom: { (*callback)(root); break; @@ -626,8 +632,8 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, JsonSaveBufAsHexCompact(root, "$.Card.UID", tag->uid, sizeof(tag->uid)); JsonSaveBufAsHexCompact(root, "$.Card.H0R1", tag->HR01, sizeof(tag->HR01)); JsonSaveBufAsHexCompact(root, "$.Card.Size", (uint8_t *) & (tag->size), 2); + for (size_t i = 0; i < TOPAZ_STATIC_MEMORY / 8; i++) { - char path[PATH_MAX_LENGTH] = {0}; snprintf(path, sizeof(path), "$.blocks.%zu", i); JsonSaveBufAsHexCompact(root, path, &tag->data_blocks[i][0], TOPAZ_BLOCK_SIZE); } @@ -638,24 +644,67 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, break; } + case jsfLto: { + JsonSaveStr(root, "FileType", "lto"); + for (size_t i = 0; i < datalen / 32; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 32], 32); + } + break; + } + case jsfCryptorf: { + JsonSaveStr(root, "FileType", "cryptorf"); + for (size_t i = 0; i < datalen / 8; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 8], 8); + } + break; + } + case jsfNDEF: { + JsonSaveStr(root, "FileType", "ndef"); + JsonSaveInt(root, "Ndef.Size", datalen); + size_t i = 0; + for (; i < datalen / 16; i++) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16); + } + if (datalen % 16) { + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16)); + } + break; + } + // no action + case jsfFido: + break; + // depricated + case jsfCardMemory: + case jsf14b: + case jsf15: + case jsfLegic: default: break; } - int res = json_dump_file(root, fileName, JSON_INDENT(2)); - if (res) { - PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName); + char *fn = newfilenamemcopyEx(preferredName, ".json", e_save_path); + if (fn == NULL) { + return PM3_EMALLOC; + } + + if (json_dump_file(root, fn, JSON_INDENT(2))) { + PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fn); retval = 200; + free(fn); goto out; } if (verbose) { - PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName); + PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fn); } + free(fn); out: json_decref(root); - free(fileName); return retval; } int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) { @@ -1083,56 +1132,56 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - typedef union UDATA { - void *v; - uint8_t *bytes; - mfu_dump_t *mfu; - topaz_tag_t *topaz; - } UDATA; - UDATA udata = (UDATA)data; char ctype[100] = {0}; JsonLoadStr(root, "$.FileType", ctype); - if (!strcmp(ctype, "raw")) { - JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen); + // Proxmark3 settings file. No + if (!strcmp(ctype, "settings")) { + goto out; } - if (!strcmp(ctype, "mfcard")) { + udata_t udata = (udata_t)data; + size_t len = 0; + char blocks[PATH_MAX_LENGTH] = {0}; + + if (!strcmp(ctype, "raw")) { + JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen); + goto out; + } + + // depricated mfcard + if (!strcmp(ctype, "mfcard") || !strcmp(ctype, "mfc v2")) { size_t sptr = 0; - for (int i = 0; i < 256; i++) { - char blocks[30] = {0}; - snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + for (int i = 0; i < maxdatalen; i++) { - size_t len = 0; - uint8_t block[16]; - JsonLoadBufAsHex(root, blocks, block, 16, &len); - if (!len) - break; - - if (sptr + 16 > maxdatalen) { + if (sptr + MFBLOCK_SIZE > maxdatalen) { retval = PM3_EMALLOC; goto out; } - memcpy(&udata.bytes[sptr], block, 16); + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + uint8_t block[MFBLOCK_SIZE]; + JsonLoadBufAsHex(root, blocks, block, MFBLOCK_SIZE, &len); + if (!len) + break; + + memcpy(&udata.bytes[sptr], block, MFBLOCK_SIZE); sptr += len; } *datalen = sptr; + goto out; } if (!strcmp(ctype, "fudan")) { size_t sptr = 0; - for (int i = 0; i < 256; i++) { + for (int i = 0; i < maxdatalen; i++) { if (sptr + 4 > maxdatalen) { retval = PM3_EMALLOC; goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); if (!len) break; @@ -1141,6 +1190,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz } *datalen = sptr; + goto out; } if (!strcmp(ctype, "mfu")) { @@ -1164,10 +1214,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.mfu->data[sptr], MFU_BLOCK_SIZE, &len); if (!len) break; @@ -1179,6 +1226,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz --udata.mfu->pages; *datalen += sptr; + goto out; } if (!strcmp(ctype, "hitag")) { @@ -1189,10 +1237,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); if (!len) break; @@ -1201,27 +1246,26 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz } *datalen = sptr; + goto out; } if (!strcmp(ctype, "iclass")) { size_t sptr = 0; - for (size_t i = 0; i < (maxdatalen / 8); i++) { - if (sptr + 8 > maxdatalen) { + for (size_t i = 0; i < (maxdatalen / PICOPASS_BLOCK_SIZE); i++) { + if (sptr + PICOPASS_BLOCK_SIZE > maxdatalen) { retval = PM3_EMALLOC; goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); - - size_t len = 0; - JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], PICOPASS_BLOCK_SIZE, &len); if (!len) break; sptr += len; } *datalen = sptr; + goto out; } if (!strcmp(ctype, "t55x7")) { @@ -1232,10 +1276,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); if (!len) break; @@ -1243,6 +1284,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz sptr += len; } *datalen = sptr; + goto out; } if (!strcmp(ctype, "EM4X50")) { @@ -1253,10 +1295,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); if (!len) break; @@ -1264,14 +1303,80 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz sptr += len; } *datalen = sptr; + goto out; } + // depricated if (!strcmp(ctype, "15693")) { JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen); + goto out; } + // handles ISO15693 w blocksize of 4 bytes. + if (!strcmp(ctype, "15693 v2")) { + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 4); i++) { + if (sptr + 4 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + // handles ISO15693 w blocksize of 8 bytes. + if (!strcmp(ctype, "15693 v3")) { + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 8); i++) { + if (sptr + 8 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + if (!strcmp(ctype, "legic v2")) { + size_t sptr = 0; + for (int i = 0; i < 64; i++) { + if (sptr + 16 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + // depricated if (!strcmp(ctype, "legic")) { JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen); + goto out; } if (!strcmp(ctype, "topaz")) { @@ -1288,22 +1393,19 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } - char blocks[30] = {0}; snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); - - size_t len = 0; JsonLoadBufAsHex(root, blocks, &udata.topaz->data_blocks[sptr][0], TOPAZ_BLOCK_SIZE, &len); if (!len) break; sptr += len; - // ICEMAN todo: add dynamic memory. // uint16_z Size // uint8_t *dynamic_memory; } *datalen += sptr; + goto out; } if (!strcmp(ctype, "mfpkeys")) { @@ -1327,7 +1429,6 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN); - char blocks[40] = {0}; snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyA", i); JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen); @@ -1337,8 +1438,143 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz sptr += (2 * AES_KEY_LEN); } *datalen += sptr; + goto out; } + if (!strcmp(ctype, "mfdes")) { + JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen); + JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen); + uint8_t atslen = udata.bytes[13]; + if (atslen > 0) { + JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen); + } + +// size_t sptr = (14 + atslen); +// uint8_t dvdata[4][0xE][24 + 1] = {{{0}}}; + + /* + for (int i = 0; i < (int)datalen; i++) { + char path[PATH_MAX_LENGTH] = {0}; + + if (dvdata[0][i][0]) { + snprintf(path, sizeof(path), "$.DES.%d.Key", i); + JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN); + } + + if (dvdata[1][i][0]) { + snprintf(path, sizeof(path), "$.3DES.%d.Key", i); + JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN); + } + if (dvdata[2][i][0]) { + snprintf(path, sizeof(path), "$.AES.%d.Key", i); + JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN); + } + if (dvdata[3][i][0]) { + snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i); + JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN); + } + } + */ +// memcpy(&data[14 + atslen], dvdata, 4 * 0xE * (24 + 1)); + + goto out; + } + + if (!strcmp(ctype, "14b v2")) { + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 4); i++) { + if (sptr + 4 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + if (!strcmp(ctype, "lto")) { + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 32); i++) { + if (sptr + 32 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 32, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + if (!strcmp(ctype, "cryptorf")) { + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 8); i++) { + if (sptr + 8 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + if (!strcmp(ctype, "ndef")) { + + json_error_t up_error = {0}; + int i1 = 0; + size_t ndefsize = 0; + if (json_unpack_ex(root, &up_error, 0, "{s:i}", "Ndef.Size", &i1) == 0) { + ndefsize = i1; + } + + size_t sptr = 0; + for (int i = 0; i < (maxdatalen / 16); i++) { + if (sptr + 16 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len); + if (!len) + break; + + sptr += len; + } + + *datalen = sptr; + goto out; + } + + // unidentified file format + if (verbose) { + PrintAndLogEx(FAILED, "Unidentified file format `" _YELLOW_("%s") "`", path); + } + retval = PM3_EFILE; + out: if (callback != NULL) { @@ -2082,17 +2318,20 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) { - int res = 0; + int res = PM3_SUCCESS; DumpFileType_t dftype = getfiletype(fn); switch (dftype) { case BIN: { - res = loadFile_safe(fn, ".bin", pdump, dumplen); + loadFile_safe(fn, ".bin", pdump, dumplen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "File IO failed"); + } break; } case EML: { res = loadFileEML_safe(fn, pdump, dumplen); - if (res == PM3_ESOFT) { - PrintAndLogEx(WARNING, "file IO failed"); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "File IO failed"); } break; } @@ -2103,8 +2342,9 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl return PM3_EMALLOC; } res = loadFileJSON(fn, *pdump, maxdumplen, dumplen, NULL); - if (res == PM3_SUCCESS) + if (res == PM3_SUCCESS) { return res; + } free(*pdump); @@ -2116,7 +2356,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl break; } case DICTIONARY: { - PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed"); + PrintAndLogEx(ERR, "Only BIN/EML/JSON formats allowed"); return PM3_EINVARG; } case MCT: { @@ -2128,15 +2368,49 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl return res; } -int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize) { - +int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) { + if (fn == NULL || strlen(fn) == 0) { + return PM3_EINVARG; + } if (d == NULL || n == 0) { PrintAndLogEx(INFO, "No data to save, skipping..."); return PM3_EINVARG; } - saveFile(fn, ".bin", d, n); - saveFileEML(fn, d, n, blocksize); saveFileJSON(fn, jsft, d, n, NULL); return PM3_SUCCESS; } + +int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) { + + if (fn == NULL || d == NULL || n == 0) { + PrintAndLogEx(INFO, "No data to save, skipping..."); + return PM3_EINVARG; + } + saveFile(fn, ".bin", d, n); + + iso14a_mf_extdump_t jd = {0}; + jd.card_info.ats_len = 0; + + // Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA + if ((d[0] ^ d[1] ^ d[2] ^ d[3]) == d[4] && (d[6] & 0xC0) == 0) { + jd.card_info.uidlen = 4; + memcpy(jd.card_info.uid, d, jd.card_info.uidlen); + jd.card_info.sak = d[5]; + memcpy(jd.card_info.atqa, &d[6], sizeof(jd.card_info.atqa)); + } + // Check for 7 bytes UID: double size uid bits in ATQA + else if ((d[8] & 0xC0) == 0x40) { + jd.card_info.uidlen = 7; + memcpy(jd.card_info.uid, d, jd.card_info.uidlen); + jd.card_info.sak = d[7]; + memcpy(jd.card_info.atqa, &d[8], sizeof(jd.card_info.atqa)); + } else { + PrintAndLogEx(WARNING, "Invalid dump. UID/SAK/ATQA not found"); + } + jd.dump = d; + jd.dumplen = n; + saveFileJSON(fn, jsfMfc_v2, (uint8_t *)&jd, sizeof(jd), NULL); + return PM3_SUCCESS; +} + diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 81cb13e05..98ecc466d 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -29,15 +29,32 @@ #include "mifare/mifarehost.h" #include "cmdhfmfu.h" +#include "protocols.h" // iclass defines +#include "cmdhftopaz.h" // TOPAZ defines +#include "mifare/mifaredefault.h" // MFP / AES defines + +typedef union { + void *v; + uint8_t *bytes; + mfu_dump_t *mfu; + topaz_tag_t *topaz; + iso14a_mf_extdump_t *mfc; +} udata_t; + typedef enum { jsfRaw, jsfCardMemory, + jsfMfc_v2, jsfMfuMemory, jsfHitag, jsfIclass, jsf14b, + jsf14b_v2, jsf15, + jsf15_v2, + jsf15_v3, jsfLegic, + jsfLegic_v2, jsfT55x7, jsfT5555, jsfMfPlusKeys, @@ -49,6 +66,9 @@ typedef enum { jsfFido, jsfFudan, jsfTopaz, + jsfLto, + jsfCryptorf, + jsfNDEF, } JSONFileType; typedef enum { @@ -276,18 +296,33 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl /** STUB - * @brief Utility function to save data to three file files (BIN/EML/JSON). + * @brief Utility function to save data to three file files (BIN/JSON). * It also tries to save according to user preferences set dump folder paths. * E.g. dumpdata.bin - * E.g. dumpdata.eml * E.g. dumpdata.json - + * * @param fn * @param d The binary data to write to the file * @param n the length of the data * @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc) - * @param blocksize * @return PM3_SUCCESS if OK */ -int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize); +int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft); + +/** STUB + * @brief Utility function to save data to three file files (BIN/JSON). + * It also tries to save according to user preferences set dump folder paths. + * E.g. dumpdata.bin + * E.g. dumpdata.json + * + * This function is dedicated for MIFARE CLASSIC dumps. Checking for 4 or 7 byte UID in indata. + * Saves the corrected data in the json file + * + * @param fn + * @param d The binary data to write to the file + * @param n the length of the data + * @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc) + * @return PM3_SUCCESS if OK + */ +int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft); #endif // FILEUTILS_H diff --git a/client/src/nfc/ndef.c b/client/src/nfc/ndef.c index e0bc83c14..50dec1b35 100644 --- a/client/src/nfc/ndef.c +++ b/client/src/nfc/ndef.c @@ -1278,3 +1278,33 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) { } return PM3_SUCCESS; } + + +int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen) { + + size_t idx = 0; + while (idx < ndeflen) { + + if (ndef[idx] == 0x00 || + ndef[idx] == 0x01 || + ndef[idx] == 0x02 || + ndef[idx] == 0x03 || + ndef[idx] == 0xFD) { + idx++; + idx += ndefTLVGetLength(&ndef[idx], &idx); + continue; + } + + if (ndef[idx] == 0xFE) { + idx++; + break; + } + + // invalid NDEF + *outlen = 0; + return PM3_ESOFT; + } + + *outlen = idx; + return PM3_SUCCESS; +} \ No newline at end of file diff --git a/client/src/nfc/ndef.h b/client/src/nfc/ndef.h index 643bb70a7..31967c61a 100644 --- a/client/src/nfc/ndef.h +++ b/client/src/nfc/ndef.h @@ -76,5 +76,5 @@ typedef struct { int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose); int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen, bool verbose); - +int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen); #endif // _NDEF_H_ diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index dca08b6aa..e7e1d0cd3 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -24,7 +24,7 @@ //----------------------------------------------------------------------------- // iCLASS / PICOPASS //----------------------------------------------------------------------------- - +#define PICOPASS_BLOCK_SIZE 8 // iCLASS reader flags #define FLAG_ICLASS_READER_INIT 0x01