Simplify hf mfp dump: remove key probing, load-and-read only

Restructure hf mfp dump to match hf mf dump pattern: load keys
from files, read sectors, save. Remove all key probing/checking
logic (use hf mfp chk and hf mf chk separately for key discovery).
Use MF_KEY_A/MF_KEY_B defines instead of magic numbers.
Replace custom JSON parser with existing loadFileJSON infrastructure.
This commit is contained in:
Tomas Nilsson
2026-03-08 18:35:11 +01:00
parent 7bdd677e36
commit 03d6da87e2
+59 -331
View File
@@ -38,8 +38,6 @@
#include "mifare/mifarehost.h" // mf_read_sector (SL1 CRYPTO1)
#include "cmdtrace.h"
#include "crypto/originality.h"
#include "jansson.h"
#include "preferences.h" // getDeviceDebugLevel, setDeviceDebugLevel
static const uint8_t mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0x9006, 0x9007, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
@@ -1905,41 +1903,37 @@ static int CmdHFMFPChk(const char *Cmd) {
static int mfp_load_keys_from_json(const char *filename, uint8_t foundKeys[2][64][AES_KEY_LEN + 1]) {
json_t *root = NULL;
int res = loadFileJSONroot(filename, (void **)&root, true);
// loadFileJSON handles "mfpkeys" file type via loadFileJSONex.
// Buffer layout: UID(7) + pad(3) + SAK(1) + ATQA(2) + ATSlen(1) + ATS(atslen)
// then flat keys: KeyA0(16) KeyB0(16) KeyA1(16) KeyB1(16) ...
uint8_t data[14 + 256 + (2 * 64 * AES_KEY_LEN)];
memset(data, 0, sizeof(data));
size_t datalen = 0;
int res = loadFileJSON(filename, data, sizeof(data), &datalen, NULL);
if (res != PM3_SUCCESS) {
return res;
}
// check file type
json_t *jtype = json_object_get(root, "FileType");
if (!jtype || !json_is_string(jtype) || strcmp(json_string_value(jtype), "mfpkeys") != 0) {
PrintAndLogEx(ERR, "Key file is not a MIFARE Plus key file");
json_decref(root);
return PM3_EFILE;
}
char path[64];
uint8_t tmpkey[AES_KEY_LEN];
size_t tmplen = 0;
uint8_t atslen = data[13];
size_t key_offset = 14 + atslen;
for (int i = 0; i < 64; i++) {
snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", i);
tmplen = 0;
if (JsonLoadBufAsHex(root, path, tmpkey, AES_KEY_LEN, &tmplen) == 0 && tmplen == AES_KEY_LEN) {
foundKeys[0][i][0] = 1;
memcpy(&foundKeys[0][i][1], tmpkey, AES_KEY_LEN);
}
size_t off = key_offset + (i * 2 * AES_KEY_LEN);
uint8_t *ka = data + off;
uint8_t *kb = data + off + AES_KEY_LEN;
snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", i);
tmplen = 0;
if (JsonLoadBufAsHex(root, path, tmpkey, AES_KEY_LEN, &tmplen) == 0 && tmplen == AES_KEY_LEN) {
foundKeys[1][i][0] = 1;
memcpy(&foundKeys[1][i][1], tmpkey, AES_KEY_LEN);
// check if key is non-zero (present in JSON)
if (memcmp(ka, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", AES_KEY_LEN) != 0) {
foundKeys[MF_KEY_A][i][0] = 1;
memcpy(&foundKeys[MF_KEY_A][i][1], ka, AES_KEY_LEN);
}
if (memcmp(kb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", AES_KEY_LEN) != 0) {
foundKeys[MF_KEY_B][i][0] = 1;
memcpy(&foundKeys[MF_KEY_B][i][1], kb, AES_KEY_LEN);
}
}
json_decref(root);
return PM3_SUCCESS;
}
@@ -1961,13 +1955,13 @@ static int mfp_load_mfc_keys_from_bin(const char *filename, uint8_t mfcFoundKeys
}
for (uint8_t s = 0; s < numSectors && s * MIFARE_KEY_SIZE < alen; s++) {
mfcFoundKeys[0][s][0] = 1;
memcpy(&mfcFoundKeys[0][s][1], keyA + s * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE);
mfcFoundKeys[MF_KEY_A][s][0] = 1;
memcpy(&mfcFoundKeys[MF_KEY_A][s][1], keyA + s * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE);
}
for (uint8_t s = 0; s < numSectors && s * MIFARE_KEY_SIZE < blen; s++) {
mfcFoundKeys[1][s][0] = 1;
memcpy(&mfcFoundKeys[1][s][1], keyB + s * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE);
mfcFoundKeys[MF_KEY_B][s][0] = 1;
memcpy(&mfcFoundKeys[MF_KEY_B][s][1], keyB + s * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE);
}
free(keyA);
@@ -1984,92 +1978,25 @@ static int mfp_read_sector_sl1(uint8_t sectorNo, uint8_t keyType, const uint8_t
return res;
}
// Build a list of default MFC 6-byte keys for SL1 probing
static int mfp_load_mfc_default_keys(uint8_t **pkeyBlock, uint32_t *pkeycnt) {
size_t numDefaults = ARRAYLEN(g_mifare_default_keys);
*pkeyBlock = calloc(numDefaults, MIFARE_KEY_SIZE);
if (*pkeyBlock == NULL) {
return PM3_EMALLOC;
}
for (size_t i = 0; i < numDefaults; i++) {
num_to_bytes(g_mifare_default_keys[i], MIFARE_KEY_SIZE, *pkeyBlock + i * MIFARE_KEY_SIZE);
}
*pkeycnt = numDefaults;
return PM3_SUCCESS;
}
// Try to find an MFC (CRYPTO1) key for a sector by attempting to read it.
// Uses mf_read_sector which has a proper timeout, unlike mf_check_keys
// which can hang in firmware if the card doesn't respond to ISO 14443-3.
// Returns true if a working key was found.
// Try MFC (CRYPTO1) keys on a sector using mf_read_sector.
// Returns true if a working key was found (stored in mfcFoundKeys).
// Bails out early if the card doesn't respond to ISO 14443-3 select
// (PM3_ETIMEOUT), which means the sector is SL3-only.
static bool mfp_sl1_try_keys(uint8_t sectorNo, uint8_t *keys, uint32_t keycnt,
uint8_t mfcFoundKeys[2][64][MIFARE_KEY_SIZE + 1], bool verbose) {
uint8_t dummy[16 * 16] = {0};
for (uint8_t kt = 0; kt < 2; kt++) {
if (mfcFoundKeys[kt][sectorNo][0]) {
continue;
}
for (uint32_t i = 0; i < keycnt; i++) {
uint8_t *trykey = keys + i * MIFARE_KEY_SIZE;
int res = mf_read_sector(sectorNo, kt, trykey, dummy);
if (res == PM3_SUCCESS) {
mfcFoundKeys[kt][sectorNo][0] = 1;
memcpy(&mfcFoundKeys[kt][sectorNo][1], trykey, MIFARE_KEY_SIZE);
if (verbose) {
PrintAndLogEx(INFO, "SL1 key found: sector %u key%s [ " _GREEN_("%s") " ]",
sectorNo, (kt == 0) ? "A" : "B",
sprint_hex_inrow(trykey, MIFARE_KEY_SIZE));
} else {
PrintAndLogEx(NORMAL, "+" NOLF);
}
return true;
}
// Timeout means card doesn't respond to ISO 14443-3 select at all.
// This sector is SL3-only; no point trying more CRYPTO1 keys.
if (res == PM3_ETIMEOUT) {
if (verbose) {
PrintAndLogEx(DEBUG, "Sector %u not responding to ISO 14443-3, skipping MFC probe", sectorNo);
}
return false;
}
}
}
return false;
}
static int CmdHFMFPDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp dump",
"Dump MIFARE Plus tag to file (bin/json)\n"
"Supports both SL3 (AES) and SL1 (CRYPTO1) sectors.\n"
"Automatically detects sector security level.\n"
"Reads sectors using keys from `hf mfp chk --dump` (AES/SL3)\n"
"and/or `hf mf chk` key file (CRYPTO1/SL1) for mixed-mode cards.\n"
"If no <name> given, UID will be used as filename",
"hf mfp dump\n"
"hf mfp dump --keys hf-mfp-01020304-key.json\n"
"hf mfp dump -k ffffffffffffffffffffffffffffffff\n"
"hf mfp dump --dict mfp_default_keys\n"
"hf mfp dump --keys hf-mfp-01020304-key.json --mfc-keys hf-mf-01020304-key.bin\n"
"hf mfp dump --keys hf-mfp-01020304-key.json --mfc-dict mfc_default_keys\n");
"hf mfp dump -k ffffffffffffffffffffffffffffffff\n");
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_str0(NULL, "keys", "<fn>", "AES key file from `hf mfp chk --dump` (JSON)"),
arg_str0("k", "key", "<hex>", "AES key for all sectors (16 hex bytes)"),
arg_str0(NULL, "dict", "<fn>", "AES dictionary file"),
arg_str0(NULL, "mfc-keys", "<fn>", "MFC key file for SL1 sectors (.bin from `hf mf chk`)"),
arg_str0(NULL, "mfc-dict", "<fn>", "MFC dictionary file for SL1 sectors"),
arg_lit0(NULL, "ns", "No save to file"),
arg_lit0("v", "verbose", "Verbose output"),
arg_lit0(NULL, "no-default", "Skip default key probing for unknown sectors"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -2086,21 +2013,12 @@ static int CmdHFMFPDump(const char *Cmd) {
uint8_t userkey[AES_KEY_LEN] = {0};
CLIGetHexWithReturn(ctx, 3, userkey, &userkeylen);
int dictfnlen = 0;
char dict_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)dict_fn, FILE_PATH_SIZE, &dictfnlen);
int mfckeyfnlen = 0;
char mfc_key_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)mfc_key_fn, FILE_PATH_SIZE, &mfckeyfnlen);
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)mfc_key_fn, FILE_PATH_SIZE, &mfckeyfnlen);
int mfcdictfnlen = 0;
char mfc_dict_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)mfc_dict_fn, FILE_PATH_SIZE, &mfcdictfnlen);
bool nosave = arg_get_lit(ctx, 7);
bool verbose = arg_get_lit(ctx, 8);
bool no_default = arg_get_lit(ctx, 9);
bool nosave = arg_get_lit(ctx, 5);
bool verbose = arg_get_lit(ctx, 6);
CLIParserFree(ctx);
@@ -2137,7 +2055,7 @@ static int CmdHFMFPDump(const char *Cmd) {
PrintAndLogEx(NORMAL, "");
// ========================================
// Phase 0: Key file loading (no card interaction yet)
// Load keys
// ========================================
// AES keys: aesFoundKeys[keytype][sector][0]=found, [1..16]=key
@@ -2148,7 +2066,7 @@ static int CmdHFMFPDump(const char *Cmd) {
uint8_t mfcFoundKeys[2][64][MIFARE_KEY_SIZE + 1];
memset(mfcFoundKeys, 0, sizeof(mfcFoundKeys));
// 0a. Load AES keys from JSON key file (from hf mfp chk --dump)
// Load AES keys from JSON key file (from hf mfp chk --dump)
if (keyfnlen > 0) {
res = mfp_load_keys_from_json(key_fn, aesFoundKeys);
if (res != PM3_SUCCESS) {
@@ -2156,18 +2074,18 @@ static int CmdHFMFPDump(const char *Cmd) {
} else {
int cnt = 0;
for (uint8_t s = 0; s < numSectors; s++) {
if (aesFoundKeys[0][s][0]) cnt++;
if (aesFoundKeys[1][s][0]) cnt++;
if (aesFoundKeys[MF_KEY_A][s][0]) cnt++;
if (aesFoundKeys[MF_KEY_B][s][0]) cnt++;
}
PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%d") " AES keys from key file", cnt);
}
}
// 0b. Apply user-supplied AES key to all slots that don't have one yet
// Apply user-supplied AES key to all slots that don't have one yet
if (userkeylen == AES_KEY_LEN) {
int applied = 0;
for (uint8_t s = 0; s < numSectors; s++) {
for (uint8_t kt = 0; kt < 2; kt++) {
for (uint8_t kt = MF_KEY_A; kt <= MF_KEY_B; kt++) {
if (aesFoundKeys[kt][s][0] == 0) {
aesFoundKeys[kt][s][0] = 1;
memcpy(&aesFoundKeys[kt][s][1], userkey, AES_KEY_LEN);
@@ -2178,7 +2096,7 @@ static int CmdHFMFPDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Applied user AES key to " _GREEN_("%d") " key slots", applied);
}
// 0c. Load MFC keys from binary key file (from hf mf chk/autopwn)
// Load MFC keys from binary key file (from hf mf chk)
if (mfckeyfnlen > 0) {
res = mfp_load_mfc_keys_from_bin(mfc_key_fn, mfcFoundKeys, numSectors);
if (res != PM3_SUCCESS) {
@@ -2186,218 +2104,29 @@ static int CmdHFMFPDump(const char *Cmd) {
} else {
int cnt = 0;
for (uint8_t s = 0; s < numSectors; s++) {
if (mfcFoundKeys[0][s][0]) cnt++;
if (mfcFoundKeys[1][s][0]) cnt++;
if (mfcFoundKeys[MF_KEY_A][s][0]) cnt++;
if (mfcFoundKeys[MF_KEY_B][s][0]) cnt++;
}
PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%d") " MFC (CRYPTO1) keys from key file", cnt);
}
}
// 0d. Build combined MFC probe key list (dictionary + defaults)
uint8_t *mfcProbeKeys = NULL;
uint32_t mfcProbeKeyCnt = 0;
if (!no_default) {
uint8_t *dict_keys = NULL;
uint32_t dict_cnt = 0;
if (mfcdictfnlen > 0) {
loadFileDICTIONARY_safe(mfc_dict_fn, (void **)&dict_keys, MIFARE_KEY_SIZE, &dict_cnt);
}
uint8_t *def_keys = NULL;
uint32_t def_cnt = 0;
mfp_load_mfc_default_keys(&def_keys, &def_cnt);
uint32_t total = dict_cnt + def_cnt;
if (total > 0) {
mfcProbeKeys = calloc(total, MIFARE_KEY_SIZE);
if (mfcProbeKeys) {
if (dict_cnt > 0) {
memcpy(mfcProbeKeys, dict_keys, dict_cnt * MIFARE_KEY_SIZE);
}
if (def_cnt > 0) {
memcpy(mfcProbeKeys + dict_cnt * MIFARE_KEY_SIZE, def_keys, def_cnt * MIFARE_KEY_SIZE);
}
mfcProbeKeyCnt = total;
}
}
free(dict_keys);
free(def_keys);
}
// ========================================
// Phase 1: Classify sectors as SL3 or SL1
// Read sectors with loaded keys
// ========================================
// Try one MFC key (FFFFFFFFFFFF) on each sector to determine SL.
// mf_read_sector returns:
// PM3_SUCCESS -> SL1 confirmed, key found
// PM3_EUNDEF -> SL1 confirmed (card responded to ISO 14443-3 auth), wrong key
// PM3_ETIMEOUT -> SL3 (card doesn't respond to ISO 14443-3)
// Suppress firmware debug messages during classification and key probing.
// The many auth attempts produce a flood of "Auth error" / "Can't select card"
// messages from the firmware that interfere with other tools reading stdout.
uint8_t dbg_curr = DBG_NONE;
if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) {
free(mfcProbeKeys);
return PM3_EFAILED;
}
setDeviceDebugLevel(DBG_NONE, false);
// Determine SL for each sector based on which keys are available
uint8_t sectorSL[64];
memset(sectorSL, MFP_SL_UNKNOWN, sizeof(sectorSL));
// Sectors with pre-loaded keys already have a known SL
for (uint8_t s = 0; s < numSectors; s++) {
if (aesFoundKeys[0][s][0] || aesFoundKeys[1][s][0]) {
if (aesFoundKeys[MF_KEY_A][s][0] || aesFoundKeys[MF_KEY_B][s][0]) {
sectorSL[s] = MFP_SL_3;
}
if (mfcFoundKeys[0][s][0] || mfcFoundKeys[1][s][0]) {
if (mfcFoundKeys[MF_KEY_A][s][0] || mfcFoundKeys[MF_KEY_B][s][0]) {
sectorSL[s] = MFP_SL_1;
}
}
// Probe unclassified sectors with FFFFFFFFFFFF (CRYPTO1)
{
uint8_t probe_key[MIFARE_KEY_SIZE];
memset(probe_key, 0xFF, MIFARE_KEY_SIZE);
uint8_t dummy[16 * 16] = {0};
PrintAndLogEx(INFO, "Classifying sector security levels...");
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] != MFP_SL_UNKNOWN) {
continue;
}
DropField();
res = mf_read_sector(s, 0, probe_key, dummy);
if (res == PM3_SUCCESS) {
// FFFFFFFFFFFF worked -> SL1 with default key
sectorSL[s] = MFP_SL_1;
mfcFoundKeys[0][s][0] = 1;
memcpy(&mfcFoundKeys[0][s][1], probe_key, MIFARE_KEY_SIZE);
} else if (res == PM3_EUNDEF) {
// Card responded to ISO 14443-3 but wrong key -> SL1
sectorSL[s] = MFP_SL_1;
} else {
// Timeout or other error -> SL3
sectorSL[s] = MFP_SL_3;
}
}
DropField();
int pre_sl3 = 0, pre_sl1 = 0;
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_3) pre_sl3++;
else if (sectorSL[s] == MFP_SL_1) pre_sl1++;
}
PrintAndLogEx(SUCCESS, "Sector classification: " _GREEN_("%d") " SL3, " _YELLOW_("%d") " SL1",
pre_sl3, pre_sl1);
}
// ========================================
// Phase 2: AES key probing (SL3 sectors only)
// ========================================
// plus_key_check skips sectors where foundKeys[][sector][0] is set,
// so we mark SL1 sectors with a dummy key to exclude them.
{
// Save and temporarily mark SL1 sectors so plus_key_check skips them
uint8_t sl1_backup[2][64];
memset(sl1_backup, 0, sizeof(sl1_backup));
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_1) {
for (uint8_t kt = 0; kt < 2; kt++) {
sl1_backup[kt][s] = aesFoundKeys[kt][s][0];
if (aesFoundKeys[kt][s][0] == 0) {
// Mark as "found" with dummy so plus_key_check skips it
aesFoundKeys[kt][s][0] = 0xFF;
}
}
}
}
bool need_aes_probe = false;
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_3 &&
(aesFoundKeys[0][s][0] == 0 || aesFoundKeys[1][s][0] == 0)) {
need_aes_probe = true;
break;
}
}
if (need_aes_probe && !no_default) {
uint8_t *key_block = NULL;
uint32_t keycnt = 0;
res = mfp_load_keys(&key_block, &keycnt, NULL, 0, dict_fn, dictfnlen, card.uid, true);
if (res == PM3_SUCCESS && keycnt > 0) {
int sl3_unknown = 0;
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_3 &&
(aesFoundKeys[0][s][0] == 0 || aesFoundKeys[1][s][0] == 0)) {
sl3_unknown++;
}
}
PrintAndLogEx(INFO, "Probing " _YELLOW_("%u") " AES keys against %d SL3 sectors...", keycnt, sl3_unknown);
uint8_t end_sector = numSectors - 1;
res = plus_key_check(0, end_sector, 0, 1, key_block, keycnt, aesFoundKeys, verbose, true);
if (res == PM3_EOPABORTED) {
PrintAndLogEx(WARNING, "\nAborted");
}
PrintAndLogEx(NORMAL, "");
}
free(key_block);
}
// Restore SL1 sector dummy markers
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_1) {
for (uint8_t kt = 0; kt < 2; kt++) {
if (aesFoundKeys[kt][s][0] == 0xFF) {
aesFoundKeys[kt][s][0] = sl1_backup[kt][s];
}
}
}
}
}
// ========================================
// Phase 3: MFC key probing (SL1 sectors only)
// ========================================
if (mfcProbeKeyCnt > 0 && mfcProbeKeys != NULL) {
int sl1_need_keys = 0;
for (uint8_t s = 0; s < numSectors; s++) {
if (sectorSL[s] == MFP_SL_1 &&
(mfcFoundKeys[0][s][0] == 0 || mfcFoundKeys[1][s][0] == 0)) {
sl1_need_keys++;
}
}
if (sl1_need_keys > 0) {
PrintAndLogEx(INFO, "Probing " _YELLOW_("%u") " MFC keys against %d SL1 sectors...", mfcProbeKeyCnt, sl1_need_keys);
for (uint8_t s = 0; s < numSectors; s++) {
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard");
break;
}
if (sectorSL[s] != MFP_SL_1) {
continue;
}
if (mfcFoundKeys[0][s][0] && mfcFoundKeys[1][s][0]) {
continue;
}
mfp_sl1_try_keys(s, mfcProbeKeys, mfcProbeKeyCnt, mfcFoundKeys, verbose);
}
PrintAndLogEx(NORMAL, "");
}
}
// Restore firmware debug level before reading
setDeviceDebugLevel(dbg_curr, false);
// ========================================
// Phase 4: Read sectors with found keys
// ========================================
uint16_t totalBlocks = 0;
for (uint8_t s = 0; s < numSectors; s++) {
totalBlocks += mfNumBlocksPerSector(s);
@@ -2406,7 +2135,7 @@ static int CmdHFMFPDump(const char *Cmd) {
uint8_t *carddata = calloc(totalBlocks * MFBLOCK_SIZE, sizeof(uint8_t));
if (carddata == NULL) {
PrintAndLogEx(ERR, "Failed to allocate memory");
free(mfcProbeKeys);
return PM3_EMALLOC;
}
@@ -2432,7 +2161,7 @@ static int CmdHFMFPDump(const char *Cmd) {
if (sectorSL[s] == MFP_SL_3) {
// --- Try SL3 (AES) ---
for (uint8_t kt = 0; kt < 2 && !readOK; kt++) {
for (uint8_t kt = MF_KEY_A; kt <= MF_KEY_B && !readOK; kt++) {
if (aesFoundKeys[kt][s][0] == 0) {
continue;
}
@@ -2446,13 +2175,13 @@ static int CmdHFMFPDump(const char *Cmd) {
sectorsRead++;
sl3Count++;
} else if (verbose) {
PrintAndLogEx(DEBUG, "Sector %u SL3 key%s failed: %d", s, (kt == 0) ? "A" : "B", res);
PrintAndLogEx(DEBUG, "Sector %u SL3 key%s failed: %d", s, (kt == MF_KEY_A) ? "A" : "B", res);
}
}
} else if (sectorSL[s] == MFP_SL_1) {
// --- Try SL1 (CRYPTO1) ---
DropField();
for (uint8_t kt = 0; kt < 2 && !readOK; kt++) {
for (uint8_t kt = MF_KEY_A; kt <= MF_KEY_B && !readOK; kt++) {
if (mfcFoundKeys[kt][s][0] == 0) {
continue;
}
@@ -2466,7 +2195,7 @@ static int CmdHFMFPDump(const char *Cmd) {
sectorsRead++;
sl1Count++;
} else if (verbose) {
PrintAndLogEx(DEBUG, "Sector %u SL1 key%s failed: %d", s, (kt == 0) ? "A" : "B", res);
PrintAndLogEx(DEBUG, "Sector %u SL1 key%s failed: %d", s, (kt == MF_KEY_A) ? "A" : "B", res);
}
}
}
@@ -2500,26 +2229,26 @@ static int CmdHFMFPDump(const char *Cmd) {
switch (sectorSL[s]) {
case MFP_SL_3:
slStr = _GREEN_("3 ");
if (aesFoundKeys[0][s][0]) {
snprintf(strA, sizeof(strA), _GREEN_("%s"), sprint_hex_inrow(&aesFoundKeys[0][s][1], AES_KEY_LEN));
if (aesFoundKeys[MF_KEY_A][s][0]) {
snprintf(strA, sizeof(strA), _GREEN_("%s"), sprint_hex_inrow(&aesFoundKeys[MF_KEY_A][s][1], AES_KEY_LEN));
} else {
snprintf(strA, sizeof(strA), _RED_("%s"), "--------------------------------");
}
if (aesFoundKeys[1][s][0]) {
snprintf(strB, sizeof(strB), _GREEN_("%s"), sprint_hex_inrow(&aesFoundKeys[1][s][1], AES_KEY_LEN));
if (aesFoundKeys[MF_KEY_B][s][0]) {
snprintf(strB, sizeof(strB), _GREEN_("%s"), sprint_hex_inrow(&aesFoundKeys[MF_KEY_B][s][1], AES_KEY_LEN));
} else {
snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------");
}
break;
case MFP_SL_1:
slStr = _YELLOW_("1 ");
if (mfcFoundKeys[0][s][0]) {
snprintf(strA, sizeof(strA), _GREEN_("%s") " ", sprint_hex_inrow(&mfcFoundKeys[0][s][1], MIFARE_KEY_SIZE));
if (mfcFoundKeys[MF_KEY_A][s][0]) {
snprintf(strA, sizeof(strA), _GREEN_("%s") " ", sprint_hex_inrow(&mfcFoundKeys[MF_KEY_A][s][1], MIFARE_KEY_SIZE));
} else {
snprintf(strA, sizeof(strA), _RED_("%s"), "--------------------------------");
}
if (mfcFoundKeys[1][s][0]) {
snprintf(strB, sizeof(strB), _GREEN_("%s") " ", sprint_hex_inrow(&mfcFoundKeys[1][s][1], MIFARE_KEY_SIZE));
if (mfcFoundKeys[MF_KEY_B][s][0]) {
snprintf(strB, sizeof(strB), _GREEN_("%s") " ", sprint_hex_inrow(&mfcFoundKeys[MF_KEY_B][s][1], MIFARE_KEY_SIZE));
} else {
snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------");
}
@@ -2555,7 +2284,7 @@ static int CmdHFMFPDump(const char *Cmd) {
if (nosave) {
PrintAndLogEx(INFO, "Called with no-save option");
free(carddata);
free(mfcProbeKeys);
return PM3_SUCCESS;
}
@@ -2570,7 +2299,7 @@ static int CmdHFMFPDump(const char *Cmd) {
if (fptr == NULL) {
PrintAndLogEx(ERR, "Failed to allocate memory");
free(carddata);
free(mfcProbeKeys);
return PM3_EMALLOC;
}
strcpy(fptr, "hf-mfp-");
@@ -2587,7 +2316,6 @@ static int CmdHFMFPDump(const char *Cmd) {
}
free(carddata);
free(mfcProbeKeys);
return PM3_SUCCESS;
}