mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-23 22:55:37 -07:00
mfp changes...
This commit is contained in:
parent
d1b62a5fc2
commit
85d4e99ae9
2 changed files with 204 additions and 94 deletions
|
@ -34,19 +34,12 @@
|
|||
#include "protocols.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include "cmdhfmf.h" // printblock, header
|
||||
#include "cmdtrace.h"
|
||||
|
||||
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
||||
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, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
||||
|
||||
typedef enum {
|
||||
MFP_UNKNOWN = 0,
|
||||
DESFIRE_MF3ICD40,
|
||||
DESFIRE_EV1,
|
||||
DESFIRE_EV2,
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
} nxp_cardtype_t;
|
||||
#define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1))
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -233,9 +226,10 @@ static int get_plus_signature(uint8_t *signature, int *signature_len) {
|
|||
*signature_len = 0;
|
||||
retval = PM3_ESOFT;
|
||||
}
|
||||
mfpSetVerboseMode(false);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// GET VERSION
|
||||
static int plus_print_version(uint8_t *version) {
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7));
|
||||
|
@ -261,12 +255,12 @@ static int plus_print_version(uint8_t *version) {
|
|||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int get_plus_version(uint8_t *version, int *version_len) {
|
||||
|
||||
int resplen = 0, retval = PM3_SUCCESS;
|
||||
mfpSetVerboseMode(false);
|
||||
MFPGetVersion(true, false, version, *version_len, &resplen);
|
||||
mfpSetVerboseMode(false);
|
||||
|
||||
*version_len = resplen;
|
||||
if (resplen != 28) {
|
||||
|
@ -484,16 +478,16 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keyLen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keyLen = 16;
|
||||
}
|
||||
|
||||
if (keyNumLen != 2) {
|
||||
PrintAndLogEx(ERR, "Key number length must be 2 bytes instead of: %d", keyNumLen);
|
||||
PrintAndLogEx(ERR, "Key number length must be 2 bytes. Got %d", keyNumLen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (keyLen != 16) {
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen);
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes. Got %d", keyLen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -507,7 +501,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 3) {
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen);
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -539,17 +533,18 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
bool verbose2 = arg_get_lit(ctx, 1) > 1;
|
||||
|
||||
uint8_t key[256] = {0};
|
||||
int keyLen = 0;
|
||||
CLIGetHexWithReturn(ctx, 2, key, &keyLen);
|
||||
int keylen = 0;
|
||||
CLIGetHexWithReturn(ctx, 2, key, &keylen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (keyLen && keyLen != 16) {
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen);
|
||||
if (keylen && keylen != 16) {
|
||||
PrintAndLogEx(FAILED, "Key length must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (!keyLen)
|
||||
memmove(key, DefaultKey, 16);
|
||||
if (keylen == 0) {
|
||||
memmove(key, mfp_default_key, sizeof(mfp_default_key));
|
||||
}
|
||||
|
||||
uint8_t keyNum[2] = {0};
|
||||
uint8_t data[250] = {0};
|
||||
|
@ -572,15 +567,15 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
mfpSetVerboseMode(verbose);
|
||||
for (int i = 0; i < ARRAYLEN(CardAddresses); i++) {
|
||||
keyNum[0] = CardAddresses[i] >> 8;
|
||||
keyNum[1] = CardAddresses[i] & 0xff;
|
||||
for (int i = 0; i < ARRAYLEN(mfp_card_adresses); i++) {
|
||||
keyNum[0] = mfp_card_adresses[i] >> 8;
|
||||
keyNum[1] = mfp_card_adresses[i] & 0xff;
|
||||
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
|
||||
if (!res && (datalen == 3) && data[0] == 0x09) {
|
||||
PrintAndLogEx(WARNING, "Skipped[%04x]...", CardAddresses[i]);
|
||||
PrintAndLogEx(WARNING, "Skipped[%04x]...", mfp_card_adresses[i]);
|
||||
} else {
|
||||
if (res || (datalen != 3) || data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Write error on address %04x", CardAddresses[i]);
|
||||
PrintAndLogEx(ERR, "Write error on address %04x", mfp_card_adresses[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -597,7 +592,9 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
static int CmdHFMFPCommitPerso(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp commitp",
|
||||
"Executes Commit Perso command. Can be used in SL0 mode only.\nOBS! This command will not be executed if CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
|
||||
"Executes Commit Perso command. Can be used in SL0 mode only.\n"
|
||||
"OBS! This command will not be executed if \n"
|
||||
"CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
|
||||
"hf mfp commitp\n"
|
||||
// "hf mfp commitp --sl 1"
|
||||
);
|
||||
|
@ -625,7 +622,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 3) {
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen);
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -633,7 +630,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Switch level ( " _GREEN_("ok") " )");
|
||||
PrintAndLogEx(INFO, "Switched security level ( " _GREEN_("ok") " )");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -645,7 +642,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp auth",
|
||||
"Executes AES authentication command for Mifare Plus card",
|
||||
"Executes AES authentication command for MIFARE Plus card",
|
||||
"hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
|
||||
"hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data");
|
||||
|
||||
|
@ -664,12 +661,12 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
if (keynlen != 2) {
|
||||
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes long instead of: %d", keynlen);
|
||||
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes. Got %d", keynlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes long instead of: %d", keylen);
|
||||
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -679,7 +676,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
static int CmdHFMFPRdbl(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp rdbl",
|
||||
"Reads several blocks from Mifare Plus card",
|
||||
"Reads blocks from MIFARE Plus card",
|
||||
"hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
|
||||
"hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF");
|
||||
|
||||
|
@ -710,23 +707,23 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (blockn > 255) {
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockn);
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255]. got %d", blockn);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// 3 blocks - wo iso14443-4 chaining
|
||||
if (blocksCount > 3) {
|
||||
PrintAndLogEx(ERR, "blocks count must be less than 3. got: %d", blocksCount);
|
||||
PrintAndLogEx(ERR, "blocks count must be less than 3. Got %d", blocksCount);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -763,7 +760,7 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 1 + blocksCount * 16 + 8 + 2) {
|
||||
PrintAndLogEx(ERR, "Error return length:%d", datalen);
|
||||
PrintAndLogEx(ERR, "Error return length: %d", datalen);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -820,17 +817,17 @@ static int CmdHFMFPRdsc(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (sectorNum > 39) {
|
||||
PrintAndLogEx(ERR, "<sector number> must be in range [0..39] got: %d", sectorNum);
|
||||
PrintAndLogEx(ERR, "<sector number> must be in range [0..39]. Got %d", sectorNum);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -894,7 +891,7 @@ static int CmdHFMFPRdsc(const char *Cmd) {
|
|||
static int CmdHFMFPWrbl(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp wrbl",
|
||||
"Writes one block to Mifare Plus card",
|
||||
"Writes one block to MIFARE Plus card",
|
||||
"hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n"
|
||||
"hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF"
|
||||
);
|
||||
|
@ -928,22 +925,22 @@ static int CmdHFMFPWrbl(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (blockNum > 255) {
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockNum);
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255]. Got %d", blockNum);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (datainlen != 16) {
|
||||
PrintAndLogEx(ERR, "<data> must be 16 bytes long. got: %d", datainlen);
|
||||
PrintAndLogEx(ERR, "<data> must be 16 bytes. Got %d", datainlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -997,11 +994,8 @@ static int CmdHFMFPWrbl(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define AES_KEY_LEN 16
|
||||
#define MAX_KEYS_LIST_LEN 1024
|
||||
|
||||
static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
|
||||
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
|
||||
uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
|
||||
bool verbose) {
|
||||
int res;
|
||||
bool selectCard = true;
|
||||
|
@ -1088,7 +1082,7 @@ static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startK
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
|
||||
static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
|
||||
for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
|
||||
keyList[*keyListLen][0] = (pt >> 8) & 0xff;
|
||||
keyList[*keyListLen][1] = pt & 0xff;
|
||||
|
@ -1097,7 +1091,7 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3
|
|||
memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8);
|
||||
(*keyListLen)++;
|
||||
*startPattern = pt;
|
||||
if (*keyListLen == MAX_KEYS_LIST_LEN)
|
||||
if (*keyListLen == MAX_AES_KEYS_LIST_LEN)
|
||||
break;
|
||||
}
|
||||
(*startPattern)++;
|
||||
|
@ -1111,7 +1105,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
|
||||
"hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
|
||||
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
|
||||
"hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n"
|
||||
"hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n"
|
||||
"hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1125,7 +1119,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
|
||||
arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||
arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||
arg_str0("j", "json", "<fn>", "Json filename to save keys"),
|
||||
arg_lit0(NULL, "dump", "Dump found keys to JSON file"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -1136,7 +1130,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
uint8_t startSector = arg_get_int_def(ctx, 3, 0);
|
||||
uint8_t endSector = arg_get_int_def(ctx, 4, 0);
|
||||
|
||||
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
|
||||
uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
|
||||
uint32_t keyListLen = 0;
|
||||
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
|
||||
|
||||
|
@ -1148,7 +1142,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&keyList[keyListLen], vkey, 16);
|
||||
keyListLen++;
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Specified key must have 16 bytes length.");
|
||||
PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1185,7 +1179,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
if (vpatternlen <= 2) {
|
||||
startPattern = (vpattern[0] << 8) + vpattern[1];
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Pattern must be 2-byte length.");
|
||||
PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1193,17 +1187,8 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
|
||||
}
|
||||
|
||||
uint8_t jsonname[250] = {0};
|
||||
int jsonnamelen = 0;
|
||||
if (CLIParamStrToBuf(arg_get_str(ctx, 10), jsonname, sizeof(jsonname), &jsonnamelen)) {
|
||||
PrintAndLogEx(ERR, "Invalid json name.");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
jsonname[jsonnamelen] = 0;
|
||||
|
||||
bool create_dumpfile = arg_get_lit(ctx, 10);
|
||||
bool verbose = arg_get_lit(ctx, 11);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t startKeyAB = 0;
|
||||
|
@ -1227,8 +1212,9 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
}
|
||||
|
||||
// 2-byte pattern search mode
|
||||
if (pattern2b)
|
||||
if (pattern2b) {
|
||||
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||
}
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
|
@ -1291,19 +1277,30 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
keyListLen = keycnt;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "ICE pos... %zu - %zu", old_pos, endFilePosition);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (verbose == false)
|
||||
|
||||
if (verbose == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
// print result
|
||||
char strA[46 + 1] = {0};
|
||||
char strB[46 + 1] = {0};
|
||||
|
||||
uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
|
||||
bool has_ndef_key = false;
|
||||
bool printedHeader = false;
|
||||
for (uint8_t s = startSector; s <= endSector; s++) {
|
||||
|
||||
if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) ||
|
||||
(memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) {
|
||||
has_ndef_key = true;
|
||||
}
|
||||
|
||||
if (printedHeader == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
|
||||
|
@ -1333,7 +1330,13 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n");
|
||||
|
||||
// save keys to json
|
||||
if ((jsonnamelen > 0) && printedHeader) {
|
||||
if (create_dumpfile && printedHeader) {
|
||||
|
||||
size_t keys_len = (2 * 64 * (AES_KEY_LEN + 1));
|
||||
|
||||
uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len];
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
// Mifare Plus info
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
|
||||
|
||||
|
@ -1344,8 +1347,6 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
|
||||
uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0};
|
||||
uint8_t atslen = 0;
|
||||
if (select_status == 1 || select_status == 2) {
|
||||
memcpy(data, card.uid, card.uidlen);
|
||||
|
@ -1357,9 +1358,16 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&data[14], card.ats, atslen);
|
||||
}
|
||||
|
||||
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t));
|
||||
strcpy(fptr, "hf-mfp-");
|
||||
|
||||
FillFileNameByUID(fptr, card.uid, "-key", card.uidlen);
|
||||
|
||||
// length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
|
||||
memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1));
|
||||
saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64, NULL);
|
||||
memcpy(&data[14 + atslen], foundKeys, keys_len);
|
||||
// 64 here is for how many "rows" there is in the data array. A bit confusing
|
||||
saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
@ -1369,7 +1377,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp mad",
|
||||
"Checks and prints Mifare Application Directory (MAD)",
|
||||
"Checks and prints MIFARE Application Directory (MAD)",
|
||||
"hf mfp mad\n"
|
||||
"hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid");
|
||||
|
||||
|
@ -1411,9 +1419,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------");
|
||||
PrintAndLogEx(INFO, "-----------------------------------------------------");
|
||||
MADPrintHeader();
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "Raw:");
|
||||
|
@ -1427,7 +1433,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
if (haveMAD2) {
|
||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys");
|
||||
PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1505,6 +1511,36 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPNDEFFormat(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp ndefformat",
|
||||
"format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n"
|
||||
"If no <name> given, UID will be used as filename. \n"
|
||||
"It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
|
||||
"\n"
|
||||
"If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
|
||||
"hf mfp ndefformat\n"
|
||||
"hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "keys", "<fn>", "filename of keys"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
int keyfnlen = 0;
|
||||
char keyFilename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -1641,19 +1677,73 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPNDEFWrite(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp ndefwrite",
|
||||
"Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
|
||||
"hf mfp ndefwrite -d 0300FE -> write empty record to tag\n"
|
||||
"hf mfp ndefwrite -f myfilename\n"
|
||||
"hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("d", NULL, "<hex>", "raw NDEF hex bytes"),
|
||||
arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
|
||||
arg_lit0("p", NULL, "fix NDEF record headers / terminator block if missing"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t raw[4096] = {0};
|
||||
int rawlen;
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &rawlen);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
bool fix_msg = arg_get_lit(ctx, 3);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (fix_msg) {
|
||||
PrintAndLogEx(NORMAL, "called with fix NDEF message param");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf mf", "mf");
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about Mifare Plus tag"},
|
||||
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
|
||||
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
|
||||
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
|
||||
{"list", CmdHFMFPList, AlwaysAvailable, "List MIFARE Plus history"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
|
||||
{"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"},
|
||||
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
|
||||
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
|
||||
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
|
||||
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
|
||||
{"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"},
|
||||
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"},
|
||||
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"},
|
||||
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"},
|
||||
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"},
|
||||
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write block to card"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------- " _CYAN_("personalization") " -------------------"},
|
||||
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
|
||||
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
|
||||
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("ndef") " ------------------------"},
|
||||
{"ndefformat", CmdHFMFPNDEFFormat, IfPm3Iso14443a, "Format MIFARE Plus Tag as NFC Tag"},
|
||||
{"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
||||
{"ndefwrite", CmdHFMFPNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,26 @@
|
|||
#define AES_KEY_LEN 16
|
||||
#define MAX_AES_KEYS_LIST_LEN 1024
|
||||
|
||||
typedef enum {
|
||||
MFP_UNKNOWN = 0,
|
||||
DESFIRE_MF3ICD40,
|
||||
DESFIRE_EV1,
|
||||
DESFIRE_EV2,
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
} nxp_cardtype_t;
|
||||
|
||||
typedef struct mfp_key_item {
|
||||
uint8_t a[16];
|
||||
uint8_t b[16];
|
||||
} mfp_key_item_t;
|
||||
|
||||
typedef struct mfp_keys {
|
||||
uint8_t success;
|
||||
mfp_key_item_t *keys;
|
||||
} mfp_keys_t;
|
||||
|
||||
int CmdHFMFP(const char *Cmd);
|
||||
int CmdHFMFPNDEFRead(const char *Cmd);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue