From c2fd7790f012d169f3e24a8faf9ffe73849883c7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 19:50:35 +0300 Subject: [PATCH 01/80] lsfiles table format --- client/src/cmdhfmfdes.c | 26 +++++------ client/src/mifare/desfirecore.c | 83 ++++++++++++++++++++++++++++----- client/src/mifare/desfirecore.h | 2 + 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 63e691aa3..14bd2c400 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6164,19 +6164,18 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { return res; } - PrintAndLogEx(INFO, "---------------------------- " _CYAN_("File list") " -----------------------(r w rw ch)-----"); - for (int i = 0; i < filescount; i++) { - PrintAndLogEx(SUCCESS, "ID: " _GREEN_("%02x ") NOLF, FileList[i].fileNum); - if (isopresent) { - if (FileList[i].fileISONum != 0) - PrintAndLogEx(NORMAL, "ISO ID: " _CYAN_("%04x ") NOLF, FileList[i].fileISONum); - else - PrintAndLogEx(NORMAL, "ISO ID: " _YELLOW_("n/a ") NOLF); - } + PrintAndLogEx(INFO, "------------------------------------------ " _CYAN_("File list") " -----------------------------------------------------"); + for (int i = 0; i < filescount; i++) + DesfirePrintFileSettingsTable((i == 0), FileList[i].fileNum, isopresent, FileList[i].fileISONum, &FileList[i].fileSettings); - DesfirePrintFileSettingsOneLine(&FileList[i].fileSettings); - } + DropField(); + return PM3_SUCCESS; +} +static int CmdHF14ADesLsApp(const char *Cmd) { + + + DropField(); return PM3_SUCCESS; } @@ -6311,12 +6310,13 @@ static command_t CommandTable[] = { {"getkeysettings", CmdHF14ADesGetKeySettings, IfPm3Iso14443a, "Get Key Settings"}, {"getkeyversions", CmdHF14ADesGetKeyVersions, IfPm3Iso14443a, "Get Key Versions"}, {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, + {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, + {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, + {"lsapp", CmdHF14ADesLsApp, IfPm3Iso14443a, "Show all files list"}, {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, {"createapp", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application"}, {"deleteapp", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application"}, {"selectapp", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, - {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, - {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"getfileids", CmdHF14ADesGetFileIDs, IfPm3Iso14443a, "Get File IDs list"}, {"getfileisoids", CmdHF14ADesGetFileISOIDs, IfPm3Iso14443a, "Get File ISO IDs list"}, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 51ad6172d..443c623d5 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1701,6 +1701,7 @@ void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool static const char *DesfireUnknownStr = "unknown"; static const char *DesfireDisabledStr = "disabled"; static const char *DesfireFreeStr = "free"; +static const char *DesfireNAStr = "n/a"; static const DesfireCreateFileCommandsS DesfireFileCommands[] = { {0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true}, {0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true}, @@ -1771,6 +1772,32 @@ const char *GetDesfireAccessRightStr(uint8_t right) { return DesfireUnknownStr; } +const char *AccessRightShortStr[] = { + "key0", + "key1", + "key2", + "key3", + "key4", + "key5", + "key6", + "key7", + "key8", + "key9", + "keyA", + "keyB", + "keyC", + "keyD", + "free", + "deny" +}; + +const char *GetDesfireAccessRightShortStr(uint8_t right) { + if (right > 0x0f) + return DesfireNAStr; + + return AccessRightShortStr[right]; +} + void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch) { mode[0] = (ch & 0x0f) | ((rw << 4) & 0xf0); mode[1] = (w & 0x0f) | ((r << 4) & 0xf0); @@ -1863,10 +1890,7 @@ void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsett } } -void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { - PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); - PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); - +static void DesfirePrintShortFileTypeSettings(FileSettingsS *fsettings) { switch (fsettings->fileType) { case 0x00: case 0x01: { @@ -1874,13 +1898,13 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { break; } case 0x02: { - PrintAndLogEx(NORMAL, "[%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF, + PrintAndLogEx(NORMAL, "value [%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF, fsettings->lowerLimit, fsettings->upperLimit, fsettings->limitedCredit, fsettings->value, fsettings->value); break; } case 0x03: case 0x04: { - PrintAndLogEx(NORMAL, "%d/%d record size: %d [0x%x]b " NOLF, + PrintAndLogEx(NORMAL, "record count %d/%d size: %d [0x%x]b " NOLF, fsettings->curRecordCount, fsettings->maxRecordCount, fsettings->recordSize, fsettings->recordSize); break; } @@ -1891,13 +1915,50 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { default: { break; } - } + } +} + +void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { + PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); + PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); + + DesfirePrintShortFileTypeSettings(fsettings); PrintAndLogEx(NORMAL, "(%s %s %s %s)", - GetDesfireAccessRightStr(fsettings->rAccess), - GetDesfireAccessRightStr(fsettings->wAccess), - GetDesfireAccessRightStr(fsettings->rwAccess), - GetDesfireAccessRightStr(fsettings->chAccess)); + GetDesfireAccessRightShortStr(fsettings->rAccess), + GetDesfireAccessRightShortStr(fsettings->wAccess), + GetDesfireAccessRightShortStr(fsettings->rwAccess), + GetDesfireAccessRightShortStr(fsettings->chAccess)); +} + +void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings) { + if (printheader) { + PrintAndLogEx(SUCCESS, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings "); + PrintAndLogEx(SUCCESS, "----------------------------------------------------------------------------------------------------------"); + } + PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id); + if (isoidavail) { + if (isoid != 0) + PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid); + else + PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF); + } else { + PrintAndLogEx(NORMAL, " |" NOLF); + } + + PrintAndLogEx(NORMAL, "0x%02x " _CYAN_("%-13s") " |" NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); + PrintAndLogEx(NORMAL, " %-5s |" NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); + + PrintAndLogEx(NORMAL, "%04x, %-4s %-4s %-4s %-4s |" NOLF, + fsettings->rawAccessRights, + GetDesfireAccessRightShortStr(fsettings->rAccess), + GetDesfireAccessRightShortStr(fsettings->wAccess), + GetDesfireAccessRightShortStr(fsettings->rwAccess), + GetDesfireAccessRightShortStr(fsettings->chAccess)); + + PrintAndLogEx(NORMAL, " " NOLF); + DesfirePrintShortFileTypeSettings(fsettings); + PrintAndLogEx(NORMAL, ""); } void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 655995e5b..e41b4b6df 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -147,6 +147,7 @@ int DesfireGetFileISOIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsettings); void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings); +void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings); void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings); int DesfireGetFileSettings(DesfireContext *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen); int DesfireGetFileSettingsStruct(DesfireContext *dctx, uint8_t fileid, FileSettingsS *fsettings); @@ -154,6 +155,7 @@ int DesfireChangeFileSettings(DesfireContext *dctx, uint8_t *data, size_t datale const DesfireCreateFileCommandsS *GetDesfireFileCmdRec(uint8_t type); const char *GetDesfireAccessRightStr(uint8_t right); +const char *GetDesfireAccessRightShortStr(uint8_t right); void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch); void DesfireDecodeFileAcessMode(uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch); void DesfirePrintAccessRight(uint8_t *data); From c46f227a4cdf836720cc81ff6dbab992a9e04e86 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 20:04:27 +0300 Subject: [PATCH 02/80] lsapp command --- client/src/cmdhfmfdes.c | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 14bd2c400..bcb258ea7 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6173,7 +6173,69 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { } static int CmdHF14ADesLsApp(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes lsapp", + "Show application list. Master key needs to be provided or flag --no-auth set (depend on cards settings).", + "hf mfdes lsapp -> show application list with defaults from `default` command"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Communicaton mode: plain/mac/encrypt"), + arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), + arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), + arg_lit0(NULL, "no-auth", "execute without authentication"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + bool noauth = arg_get_lit(ctx, 11); + + DesfireContext dctx; + int securechann = defaultSecureChannel; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMPlain, NULL); + if (res) { + CLIParserFree(ctx); + return res; + } + + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + uint8_t buf[250] = {0}; + size_t buflen = 0; + + res = DesfireGetAIDList(&dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + for (int i = 0; i < buflen; i += 3) + PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); + + // result bytes: 3, 2, 1-16. total record size = 24 + res = DesfireGetDFList(&dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); + } else if (buflen > 1) { + //for + } DropField(); From 5eefe7d14ca6c3e28abdda8e66ace458e5ee1a57 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 20:33:54 +0300 Subject: [PATCH 03/80] fix split block length bug --- client/src/mifare/desfirecore.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 443c623d5..5b32176b6 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -695,8 +695,13 @@ static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t len = 0; for (int i = 0; i < *blockdatacount; i++) { size_t tlen = len + blockdata[i * blockdatasize]; - if (tlen > dstdatalen) + if (tlen > dstdatalen) { tlen = dstdatalen; + if (tlen >= len) + blockdata[i * blockdatasize] = tlen - len; + else + blockdata[i * blockdatasize] = 0; + } if (len == tlen) { *blockdatacount = i; break; From b12abd8f73549a6c5fc6ab7b2a9c905354adda54 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 20:38:27 +0300 Subject: [PATCH 04/80] clear block data before copy --- client/src/mifare/desfirecore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 5b32176b6..3ab153f78 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -694,6 +694,7 @@ static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, s static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t dstdatalen) { size_t len = 0; for (int i = 0; i < *blockdatacount; i++) { + memset(&blockdata[i * blockdatasize + 1], 0, blockdatasize - 1); size_t tlen = len + blockdata[i * blockdatasize]; if (tlen > dstdatalen) { tlen = dstdatalen; From a36ec293838e11d71b10a124574b47588699b0d8 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 21:47:42 +0300 Subject: [PATCH 05/80] lsapp base works --- client/src/cmdhfmfdes.c | 30 +++++++++++++++++++++++++++--- client/src/mifare/desfirecore.h | 7 +++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index bcb258ea7..6aa42fd78 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6170,6 +6170,14 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { DropField(); return PM3_SUCCESS; +} + +static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) { + for (int i = 0; i < appcount; i++) + if (AppList[i].appNum == appNum) + return i; + + return -1; } static int CmdHF14ADesLsApp(const char *Cmd) { @@ -6201,7 +6209,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMPlain, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMMACed, NULL); if (res) { CLIParserFree(ctx); return res; @@ -6226,17 +6234,33 @@ static int CmdHF14ADesLsApp(const char *Cmd) { return PM3_ESOFT; } + AppListS AppList = {0}; + + size_t appcount = buflen / 3; for (int i = 0; i < buflen; i += 3) - PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); + AppList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]); // result bytes: 3, 2, 1-16. total record size = 24 res = DesfireGetDFList(&dctx, buf, &buflen); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); } else if (buflen > 1) { - //for + for (int i = 0; i < buflen; i++) { + int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), AppList, appcount); + if (indx >= 0) { + AppList[indx].appISONum = MemBeToUint2byte(&buf[i * 24 + 1 + 3]); + memcpy(AppList[indx].appDFName, &buf[i * 24 + 1 + 5], strnlen((char *)&buf[i * 24 + 1 + 5], 16)); + } + } } + PrintAndLogEx(INFO, "-------------- " _CYAN_("Alications list") " --------------"); + PrintAndLogEx(INFO, "Applications count: " _GREEN_("%zu"), appcount); + if (appcount > 0) { + for (int i = 0; i < appcount; i++) { + PrintAndLogEx(INFO, "App num: 0x%02x iso id: 0x%04x name: %s", AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); + } + } DropField(); return PM3_SUCCESS; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index e41b4b6df..b8370b7a5 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -85,6 +85,13 @@ typedef struct { typedef FileListElmS FileListS[32]; +typedef struct { + uint32_t appNum; + uint16_t appISONum; + char appDFName[16]; +} AppListElmS; +typedef AppListElmS AppListS[64]; + typedef enum { RFTAuto, RFTData, From 7d6ff9f7734e6096420b0c16f551dc0235a50224 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Aug 2021 18:28:55 +0300 Subject: [PATCH 06/80] DesfireCheckAuthCommands --- client/src/cmdhfmfdes.c | 23 +++++++++++++++--- client/src/mifare/desfirecore.c | 41 +++++++++++++++++++++++++++++++++ client/src/mifare/desfirecore.h | 11 +++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 6aa42fd78..ed72a6b28 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6176,7 +6176,7 @@ static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) for (int i = 0; i < appcount; i++) if (AppList[i].appNum == appNum) return i; - + return -1; } @@ -6227,6 +6227,10 @@ static int CmdHF14ADesLsApp(const char *Cmd) { uint8_t buf[250] = {0}; size_t buflen = 0; + uint32_t freemem = 0; + DesfireGetFreeMem(&dctx, &freemem); + + res = DesfireGetAIDList(&dctx, buf, &buflen); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); @@ -6253,12 +6257,25 @@ static int CmdHF14ADesLsApp(const char *Cmd) { } } } - + + AuthCommandsChk authCmdCheck0 = {0}; + DesfireCheckAuthCommands(0x000000, 0, &authCmdCheck0); + if (appcount > 0) { + for (int i = 0; i < appcount; i++) { + DesfireCheckAuthCommands(AppList[i].appNum, 0, &AppList[i].authCmdCheck); + } + } + PrintAndLogEx(INFO, "-------------- " _CYAN_("Alications list") " --------------"); - PrintAndLogEx(INFO, "Applications count: " _GREEN_("%zu"), appcount); + PrintAndLogEx(INFO, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); + PrintAndLogEx(INFO, "PICC level auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&authCmdCheck0); + if (appcount > 0) { for (int i = 0; i < appcount; i++) { PrintAndLogEx(INFO, "App num: 0x%02x iso id: 0x%04x name: %s", AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); + PrintAndLogEx(INFO, "Auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); } } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 3ab153f78..1d087876f 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1350,6 +1350,47 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return 100; } +static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd) { + size_t recv_len = 0; + uint8_t respcode = 0; + uint8_t recv_data[256] = {0}; + + DesfireContext dctx = {0}; + dctx.keyNum = keyNum; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCNative; + + // if cant select - return false + int res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + if (res != PM3_SUCCESS) + return false; + + uint8_t data[] = {keyNum, 0x00}; + res = DesfireExchangeEx(false, &dctx, authcmd, data, (authcmd == MFDES_AUTHENTICATE_EV2F) ? 2 : 1, &respcode, recv_data, &recv_len, false, 0); + DropField(); + return (res == PM3_SUCCESS && respcode == 0xaf); +} + +void DesfireCheckAuthCommands(uint32_t appAID, uint8_t keyNum, AuthCommandsChk *authCmdCheck) { + memset(authCmdCheck, 0, sizeof(AuthCommandsChk)); + + authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE); + authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO); + authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); + authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F); + +} + +void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { + PrintAndLogEx(NORMAL, "auth:%s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", + authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO") + ); +} + static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { if (resplen) *resplen = 0; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index b8370b7a5..e8236768b 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -85,10 +85,19 @@ typedef struct { typedef FileListElmS FileListS[32]; +typedef struct { + bool auth; + bool authISO; + bool authAES; + bool authEV2; + bool authISONative; +} AuthCommandsChk; + typedef struct { uint32_t appNum; uint16_t appISONum; char appDFName[16]; + AuthCommandsChk authCmdCheck; } AppListElmS; typedef AppListElmS AppListS[64]; @@ -126,6 +135,8 @@ const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose); +void DesfireCheckAuthCommands(uint32_t appAID, uint8_t keyNum, AuthCommandsChk *authCmdCheck); +void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck); int DesfireFormatPICC(DesfireContext *dctx); int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem); From 8402ba3d952425dd808c953e369a24753d729c17 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Aug 2021 19:27:50 +0300 Subject: [PATCH 07/80] add iso native check --- client/src/cmdhfmfdes.c | 4 +-- client/src/mifare/desfirecore.c | 44 +++++++++++++++++++++++++++++++-- client/src/mifare/desfirecore.h | 2 +- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index ed72a6b28..e8ccc6194 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6259,10 +6259,10 @@ static int CmdHF14ADesLsApp(const char *Cmd) { } AuthCommandsChk authCmdCheck0 = {0}; - DesfireCheckAuthCommands(0x000000, 0, &authCmdCheck0); + DesfireCheckAuthCommands(0x000000, NULL, 0, &authCmdCheck0); if (appcount > 0) { for (int i = 0; i < appcount; i++) { - DesfireCheckAuthCommands(AppList[i].appNum, 0, &AppList[i].authCmdCheck); + DesfireCheckAuthCommands(AppList[i].appNum, AppList[i].appDFName, 0, &AppList[i].authCmdCheck); } } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 1d087876f..74aa44e94 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1371,14 +1371,54 @@ static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd return (res == PM3_SUCCESS && respcode == 0xaf); } -void DesfireCheckAuthCommands(uint32_t appAID, uint8_t keyNum, AuthCommandsChk *authCmdCheck) { +static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorythm keytype) { + + DesfireContext dctx = {0}; + dctx.keyNum = keyNum; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCISO; + + bool app_level = (appAID != 0x000000); + int res = 0; + // if cant select - return false + if (dfname == NULL || strnlen(dfname, 16) == 0) { + res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + if (res != PM3_SUCCESS) + return false; + } else { + res = DesfireISOSelectDF(&dctx, dfname, NULL, NULL); + if (res != PM3_SUCCESS) + return false; + app_level = true; + } + + uint8_t rndlen = DesfireGetRndLenForKey(keytype); + + uint8_t piccrnd[64] = {0}; + size_t xlen = 0; + res = DesfireISOGetChallenge(&dctx, keytype, piccrnd, &xlen); + if (res != PM3_SUCCESS || xlen != rndlen) + return false; + + uint8_t resp[250] = {0}; + size_t resplen = 0; + + uint16_t sw = 0; + uint8_t p1 = DesfireKeyToISOKey(keytype); + uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum; + res = DesfireExchangeISO(false, &dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw); + DropField(); + return (sw == 0x9000 || sw == 0x6982); +} + +void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck) { memset(authCmdCheck, 0, sizeof(AuthCommandsChk)); authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE); authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO); authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F); - + authCmdCheck->authISONative = DesfireCheckISOAuthCmd(appAID, dfname, keyNum, T_DES); } void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index e8236768b..f7b97a161 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -135,7 +135,7 @@ const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose); -void DesfireCheckAuthCommands(uint32_t appAID, uint8_t keyNum, AuthCommandsChk *authCmdCheck); +void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck); void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck); int DesfireFormatPICC(DesfireContext *dctx); From 508e89a7a9a9ba26f41bf1a7a2cc91ed8d1fa759 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Aug 2021 22:56:03 +0300 Subject: [PATCH 08/80] iso check correctly select MF --- client/src/mifare/desfirecore.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 74aa44e94..42921ad4d 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1379,12 +1379,17 @@ static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum dctx.cmdSet = DCCISO; bool app_level = (appAID != 0x000000); - int res = 0; - // if cant select - return false + int res = 0; if (dfname == NULL || strnlen(dfname, 16) == 0) { - res = DesfireSelectAIDHex(&dctx, appAID, false, 0); - if (res != PM3_SUCCESS) - return false; + if (appAID == 0x000000) { + res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, NULL, NULL); + if (res != PM3_SUCCESS) + return false; + } else { + res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + if (res != PM3_SUCCESS) + return false; + } } else { res = DesfireISOSelectDF(&dctx, dfname, NULL, NULL); if (res != PM3_SUCCESS) From 784ebe2e3d4c19627a7246491da9d6aa3c86b32d Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Aug 2021 23:23:17 +0300 Subject: [PATCH 09/80] picc getkeysettings --- client/src/cmdhfmfdes.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e8ccc6194..de32a335b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6258,24 +6258,38 @@ static int CmdHF14ADesLsApp(const char *Cmd) { } } + uint8_t keysettings0 = 0; + uint8_t numkeys0 = 0; + res = DesfireGetKeySettings(&dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + keysettings0 = buf[0]; + numkeys0 = buf[1]; + } + AuthCommandsChk authCmdCheck0 = {0}; DesfireCheckAuthCommands(0x000000, NULL, 0, &authCmdCheck0); + if (appcount > 0) { for (int i = 0; i < appcount; i++) { DesfireCheckAuthCommands(AppList[i].appNum, AppList[i].appDFName, 0, &AppList[i].authCmdCheck); } } - PrintAndLogEx(INFO, "-------------- " _CYAN_("Alications list") " --------------"); + PrintAndLogEx(INFO, "------------------- " _CYAN_("PICC level") " ------------------"); PrintAndLogEx(INFO, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); PrintAndLogEx(INFO, "PICC level auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&authCmdCheck0); + if (numkeys0 > 0) + PrintKeySettings(keysettings0, numkeys0, false, true); if (appcount > 0) { + PrintAndLogEx(INFO, "-------------- " _CYAN_("Alications list") " --------------"); + for (int i = 0; i < appcount; i++) { PrintAndLogEx(INFO, "App num: 0x%02x iso id: 0x%04x name: %s", AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); PrintAndLogEx(INFO, "Auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); + PrintAndLogEx(INFO, ""); } } From a2eca79ed955f0fea9098814a0b4d4a6fe02e34c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 13:38:16 +0300 Subject: [PATCH 10/80] lsapp: get key settins for all app --- client/src/cmdhfmfdes.c | 35 +++++++++++++++++------ client/src/mifare/desfirecore.c | 46 ++++++------------------------- client/src/mifare/desfirecore.h | 7 ++++- client/src/mifare/desfirecrypto.c | 44 +++++++++++++++++++++++++++++ client/src/mifare/desfirecrypto.h | 4 +++ 5 files changed, 89 insertions(+), 47 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index de32a335b..a3183b014 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6265,7 +6265,21 @@ static int CmdHF14ADesLsApp(const char *Cmd) { keysettings0 = buf[0]; numkeys0 = buf[1]; } - + + if (appcount > 0) { + for (int i = 0; i < appcount; i++) { + DesfireGetKeySettings(&dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + AppList[i].keySettings = buf[0]; + AppList[i].numKeysRaw = buf[1]; + AppList[i].numberOfKeys = AppList[i].numKeysRaw & 0x1f; + AppList[i].isoFileIDEnabled = ((AppList[i].numKeysRaw & 0x20) != 0); + AppList[i].keyType = DesfireKeyTypeToAlgo(AppList[i].numKeysRaw >> 6); + } + } + } + + // field on-off zone AuthCommandsChk authCmdCheck0 = {0}; DesfireCheckAuthCommands(0x000000, NULL, 0, &authCmdCheck0); @@ -6275,21 +6289,26 @@ static int CmdHF14ADesLsApp(const char *Cmd) { } } - PrintAndLogEx(INFO, "------------------- " _CYAN_("PICC level") " ------------------"); - PrintAndLogEx(INFO, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); - PrintAndLogEx(INFO, "PICC level auth commands: " NOLF); + // print zone + PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("PICC level") " ------------------"); + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); + PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&authCmdCheck0); if (numkeys0 > 0) PrintKeySettings(keysettings0, numkeys0, false, true); if (appcount > 0) { - PrintAndLogEx(INFO, "-------------- " _CYAN_("Alications list") " --------------"); + PrintAndLogEx(SUCCESS, ""); + PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); for (int i = 0; i < appcount; i++) { - PrintAndLogEx(INFO, "App num: 0x%02x iso id: 0x%04x name: %s", AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); - PrintAndLogEx(INFO, "Auth commands: " NOLF); + PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); + PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); - PrintAndLogEx(INFO, ""); + PrintAndLogEx(SUCCESS, ""); + if (AppList[i].numberOfKeys > 0) { + PrintKeySettings(AppList[i].keySettings, AppList[i].numKeysRaw, true, true); + } } } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 42921ad4d..319b22af4 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1427,7 +1427,7 @@ void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, Aut } void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { - PrintAndLogEx(NORMAL, "auth:%s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", + PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), @@ -1702,42 +1702,12 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin return DesfireCommandTxData(dctx, MFDES_UPDATE_RECORD, xdata, 10 + len); } -uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) { - switch (keyType) { - case T_DES: - return 0x00; - case T_3DES: - return 0x00; - case T_3K3DES: - return 0x01; - case T_AES: - return 0x02; - } - return 0; -} -static void PrintKeyType(uint8_t keytype) { - switch (keytype) { - case 00: - PrintAndLogEx(SUCCESS, "Key: 2TDEA"); - break; - case 01: - PrintAndLogEx(SUCCESS, "Key: 3TDEA"); - break; - case 02: - PrintAndLogEx(SUCCESS, "Key: AES"); - break; - default: - PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keytype); - break; - } -} - static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { PrintAndLogEx(SUCCESS, "PICC level rights:"); - PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); if (print2ndbyte) @@ -1768,14 +1738,14 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print break; } - PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); if (print2ndbyte) { - PrintKeyType(numkeys >> 6); + DesfirePrintCardKeyType(numkeys >> 6); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); if (numkeys & 0x20) PrintAndLogEx(SUCCESS, "iso file id: enabled"); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index f7b97a161..9d3ad04e6 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -98,6 +98,12 @@ typedef struct { uint16_t appISONum; char appDFName[16]; AuthCommandsChk authCmdCheck; + + uint8_t keySettings; + uint8_t numKeysRaw; + bool isoFileIDEnabled; // from numKeysRaw + uint8_t numberOfKeys; // from numKeysRaw + DesfireCryptoAlgorythm keyType; // from numKeysRaw } AppListElmS; typedef AppListElmS AppListS[64]; @@ -151,7 +157,6 @@ int DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *data, size_t len, uint8_ int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len); void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte); -uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType); int DesfireChangeKeyCmd(DesfireContext *dctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen); int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newkeynum, DesfireCryptoAlgorythm newkeytype, uint32_t newkeyver, uint8_t *newkey, DesfireCryptoAlgorythm oldkeytype, uint8_t *oldkey, bool verbose); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index e1670ada2..a83ce2e19 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -353,6 +353,50 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key) { return version; } +DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType) { + switch (keyType) { + case 00: + return T_3DES; + case 01: + return T_3K3DES; + case 02: + return T_AES; + default: + return T_3DES; // unknown.... + } +} + +uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) { + switch (keyType) { + case T_DES: + return 0x00; + case T_3DES: + return 0x00; + case T_3K3DES: + return 0x01; + case T_AES: + return 0x02; + } + return 0; +} + +void DesfirePrintCardKeyType(uint8_t keyType) { + switch (keyType) { + case 00: + PrintAndLogEx(SUCCESS, "Key: 2TDEA"); + break; + case 01: + PrintAndLogEx(SUCCESS, "Key: 3TDEA"); + break; + case 02: + PrintAndLogEx(SUCCESS, "Key: AES"); + break; + default: + PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keyType); + break; + } +} + DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode) { DesfireCommunicationMode mode = DCMNone; switch (file_comm_mode & 0x03) { diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index b24b8a3ac..8670022a2 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -107,6 +107,10 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); uint8_t DesfireDESKeyGetVersion(uint8_t *key); +DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType); +uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType); +void DesfirePrintCardKeyType(uint8_t keyType); + DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); From 5b03b9870b70d54624d15e1f158a54a45145f661 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 16:17:16 +0300 Subject: [PATCH 11/80] add AID functions and select app wo field on --- client/src/cmdhfmfdes.c | 16 ++++++++++++++++ client/src/mifare/desfirecore.c | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a3183b014..a5137dd10 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6268,6 +6268,10 @@ static int CmdHF14ADesLsApp(const char *Cmd) { if (appcount > 0) { for (int i = 0; i < appcount; i++) { + res = DesfireSelectAIDHexNoFieldOn(&dctx, AppList[i].appNum); + if (res != PM3_SUCCESS) + continue; + DesfireGetKeySettings(&dctx, buf, &buflen); if (res == PM3_SUCCESS && buflen >= 2) { AppList[i].keySettings = buf[0]; @@ -6303,6 +6307,18 @@ static int CmdHF14ADesLsApp(const char *Cmd) { for (int i = 0; i < appcount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); + + uint8_t aid[3] = {0}; + DesfireAIDUintToByte(AppList[i].appNum, aid); + if ((aid[2] >> 4) == 0xF) { + uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); + PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); + PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); + MADDFDecodeAndPrint(short_aid); + } else { + AIDDFDecodeAndPrint(aid); + } + PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); PrintAndLogEx(SUCCESS, ""); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 319b22af4..8460f05af 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -770,6 +770,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { size_t resplen = 0; uint8_t respcode = 0; + ctx->secureChannel = DACNone; int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true, 0); if (res == PM3_SUCCESS) { if (resplen != 0) @@ -806,6 +807,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { size_t resplen = 0; uint8_t respcode = 0; + ctx->secureChannel = DACNone; int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0); if (res == PM3_SUCCESS) { if (resplen != 0) @@ -815,6 +817,9 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { if (respcode != MFDES_S_OPERATION_OK) return PM3_EAPDU_FAIL; + DesfireClearSession(ctx); + ctx->appSelected = (aid != 0x000000); + return PM3_SUCCESS; } return res; From fd138bdd043eb26228bedec1400f3479da5bdaf4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 16:41:49 +0300 Subject: [PATCH 12/80] move aiddesfire to mifare folder and refactoring --- client/CMakeLists.txt | 2 +- client/Makefile | 2 +- client/src/aiddesfire.c | 133 ----------- client/src/cmdhfmfdes.c | 222 +----------------- client/src/mifare/aiddesfire.c | 329 +++++++++++++++++++++++++++ client/src/{ => mifare}/aiddesfire.h | 1 + client/src/mifare/desfirecore.c | 16 ++ client/src/mifare/desfirecore.h | 1 + 8 files changed, 353 insertions(+), 353 deletions(-) delete mode 100644 client/src/aiddesfire.c create mode 100644 client/src/mifare/aiddesfire.c rename client/src/{ => mifare}/aiddesfire.h (91%) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 21ebf9efd..64dd713a3 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -222,6 +222,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/loclass/hash1_brute.c ${PM3_ROOT}/client/src/loclass/ikeys.c ${PM3_ROOT}/client/src/mifare/mad.c + ${PM3_ROOT}/client/src/mifare/aiddesfire.c ${PM3_ROOT}/client/src/mifare/mfkey.c ${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifaredefault.c @@ -236,7 +237,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/image.ui - ${PM3_ROOT}/client/src/aiddesfire.c ${PM3_ROOT}/client/src/aidsearch.c ${PM3_ROOT}/client/src/cmdanalyse.c ${PM3_ROOT}/client/src/cmdcrc.c diff --git a/client/Makefile b/client/Makefile index 51f7cb2df..bcdfb7140 100644 --- a/client/Makefile +++ b/client/Makefile @@ -474,7 +474,7 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@ # enumerations # ################ -SRCS = aiddesfire.c \ +SRCS = mifare/aiddesfire.c \ aidsearch.c \ cmdanalyse.c \ cmdcrc.c \ diff --git a/client/src/aiddesfire.c b/client/src/aiddesfire.c deleted file mode 100644 index b628ea072..000000000 --- a/client/src/aiddesfire.c +++ /dev/null @@ -1,133 +0,0 @@ -//----------------------------------------------------------------------------- -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// AID DESFire functions -//----------------------------------------------------------------------------- - -#include "aiddesfire.h" -#include "pm3_cmd.h" -#include "fileutils.h" -#include "jansson.h" - -static json_t *df_known_aids = NULL; - -static int open_aiddf_file(json_t **root, bool verbose) { - - char *path; - int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true); - if (res != PM3_SUCCESS) { - return PM3_EFILE; - } - - int retval = PM3_SUCCESS; - json_error_t error; - - *root = json_load_file(path, 0, &error); - if (!*root) { - PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text); - retval = PM3_ESOFT; - goto out; - } - - if (!json_is_array(*root)) { - PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path); - retval = PM3_ESOFT; - goto out; - } - - if (verbose) - PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root)); -out: - free(path); - return retval; -} - -static int close_aiddf_file(json_t *root) { - json_decref(root); - return PM3_SUCCESS; -} - -static const char *aiddf_json_get_str(json_t *data, const char *name) { - - json_t *jstr = json_object_get(data, name); - if (jstr == NULL) - return NULL; - - if (!json_is_string(jstr)) { - PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); - return NULL; - } - - const char *cstr = json_string_value(jstr); - if (strlen(cstr) == 0) - return NULL; - - return cstr; -} - -static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { - char laid[7] = {0}; - sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase - - json_t *elm = NULL; - - for (uint32_t idx = 0; idx < json_array_size(root); idx++) { - json_t *data = json_array_get(root, idx); - if (!json_is_object(data)) { - PrintAndLogEx(ERR, "data [%d] is not an object\n", idx); - continue; - } - const char *faid = aiddf_json_get_str(data, "AID"); - char lfaid[strlen(faid) + 1]; - strcpy(lfaid, faid); - str_lower(lfaid); - if (strcmp(laid, lfaid) == 0) { - elm = data; - break; - } - } - - if (elm == NULL) { - PrintAndLogEx(INFO, fmt, " (unknown)"); - return PM3_ENODATA; - } - const char *vaid = aiddf_json_get_str(elm, "AID"); - const char *vendor = aiddf_json_get_str(elm, "Vendor"); - const char *country = aiddf_json_get_str(elm, "Country"); - const char *name = aiddf_json_get_str(elm, "Name"); - const char *description = aiddf_json_get_str(elm, "Description"); - const char *type = aiddf_json_get_str(elm, "Type"); - - if (name && vendor) { - char result[5 + strlen(name) + strlen(vendor)]; - sprintf(result, " %s [%s]", name, vendor); - PrintAndLogEx(INFO, fmt, result); - } - - if (verbose) { - PrintAndLogEx(SUCCESS, " AID: %s", vaid); - if (name) - PrintAndLogEx(SUCCESS, " Name: %s", name); - if (description) - PrintAndLogEx(SUCCESS, " Description: %s", description); - if (type) - PrintAndLogEx(SUCCESS, " Type: %s", type); - if (vendor) - PrintAndLogEx(SUCCESS, " Vendor: %s", vendor); - if (country) - PrintAndLogEx(SUCCESS, " Country: %s", country); - } - return PM3_SUCCESS; -} - -int AIDDFDecodeAndPrint(uint8_t aid[3]) { - open_aiddf_file(&df_known_aids, false); - - char fmt[80]; - sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s"); - print_aiddf_description(df_known_aids, aid, fmt, false); - close_aiddf_file(df_known_aids); - return PM3_SUCCESS; -} diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a5137dd10..5a57b3c07 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -38,7 +38,7 @@ #include "nfc/ndef.h" // NDEF #include "mifare/mad.h" #include "generator.h" -#include "aiddesfire.h" +#include "mifare/aiddesfire.h" #include "util.h" #define MAX_KEY_LEN 24 @@ -146,202 +146,6 @@ typedef enum { MFDES_VALUE_FILE } MFDES_FILE_TYPE_T; -// NXP Appnote AN10787 - Application Directory (MAD) -typedef enum { - CL_ADMIN = 0, - CL_MISC1, - CL_MISC2, - CL_MISC3, - CL_MISC4, - CL_MISC5, - CL_MISC6, - CL_MISC7, - CL_AIRLINES = 8, - CL_FERRY, - CL_RAIL, - CL_MISC, - CL_TRANSPORT, - CL_SECURITY = 0x14, - CL_CITYTRAFFIC = 0x18, - CL_CZECH_RAIL, - CL_BUS, - CL_MMT, - CL_TAXI = 0x28, - CL_TOLL = 0x30, - CL_GENERIC_TRANS, - CL_COMPANY_SERVICES = 0x38, - CL_CITYCARD = 0x40, - CL_ACCESS_CONTROL_1 = 0x47, - CL_ACCESS_CONTROL_2, - CL_VIGIK = 0x49, - CL_NED_DEFENCE = 0x4A, - CL_BOSCH_TELECOM = 0x4B, - CL_EU = 0x4C, - CL_SKI_TICKET = 0x50, - CL_SOAA = 0x55, - CL_ACCESS2 = 0x56, - CL_FOOD = 0x60, - CL_NONFOOD = 0x68, - CL_HOTEL = 0x70, - CL_LOYALTY = 0x71, - CL_AIRPORT = 0x75, - CL_CAR_RENTAL = 0x78, - CL_NED_GOV = 0x79, - CL_ADMIN2 = 0x80, - CL_PURSE = 0x88, - CL_TV = 0x90, - CL_CRUISESHIP = 0x91, - CL_IOPTA = 0x95, - CL_METERING = 0x97, - CL_TELEPHONE = 0x98, - CL_HEALTH = 0xA0, - CL_WAREHOUSE = 0xA8, - CL_BANKING = 0xB8, - CL_ENTERTAIN = 0xC0, - CL_PARKING = 0xC8, - CL_FLEET = 0xC9, - CL_FUEL = 0xD0, - CL_INFO = 0xD8, - CL_PRESS = 0xE0, - CL_NFC = 0xE1, - CL_COMPUTER = 0xE8, - CL_MAIL = 0xF0, - CL_AMISC = 0xF8, - CL_AMISC1 = 0xF9, - CL_AMISC2 = 0xFA, - CL_AMISC3 = 0xFB, - CL_AMISC4 = 0xFC, - CL_AMISC5 = 0xFD, - CL_AMISC6 = 0xFE, - CL_AMISC7 = 0xFF, -} aidcluster_h; - -static const char *cluster_to_text(uint8_t cluster) { - switch (cluster) { - case CL_ADMIN: - return "card administration"; - case CL_MISC1: - case CL_MISC2: - case CL_MISC3: - case CL_MISC4: - case CL_MISC5: - case CL_MISC6: - case CL_MISC7: - return "miscellaneous applications"; - case CL_AIRLINES: - return "airlines"; - case CL_FERRY: - return "ferry traffic"; - case CL_RAIL: - return "railway services"; - case CL_MISC: - return "miscellaneous applications"; - case CL_TRANSPORT: - return "transport"; - case CL_SECURITY: - return "security solutions"; - case CL_CITYTRAFFIC: - return "city traffic"; - case CL_CZECH_RAIL: - return "Czech Railways"; - case CL_BUS: - return "bus services"; - case CL_MMT: - return "multi modal transit"; - case CL_TAXI: - return "taxi"; - case CL_TOLL: - return "road toll"; - case CL_GENERIC_TRANS: - return "generic transport"; - case CL_COMPANY_SERVICES: - return "company services"; - case CL_CITYCARD: - return "city card services"; - case CL_ACCESS_CONTROL_1: - case CL_ACCESS_CONTROL_2: - return "access control & security"; - case CL_VIGIK: - return "VIGIK"; - case CL_NED_DEFENCE: - return "Ministry of Defence, Netherlands"; - case CL_BOSCH_TELECOM: - return "Bosch Telecom, Germany"; - case CL_EU: - return "European Union Institutions"; - case CL_SKI_TICKET: - return "ski ticketing"; - case CL_SOAA: - return "SOAA standard for offline access standard"; - case CL_ACCESS2: - return "access control & security"; - case CL_FOOD: - return "food"; - case CL_NONFOOD: - return "non-food trade"; - case CL_HOTEL: - return "hotel"; - case CL_LOYALTY: - return "loyalty"; - case CL_AIRPORT: - return "airport services"; - case CL_CAR_RENTAL: - return "car rental"; - case CL_NED_GOV: - return "Dutch government"; - case CL_ADMIN2: - return "administration services"; - case CL_PURSE: - return "electronic purse"; - case CL_TV: - return "television"; - case CL_CRUISESHIP: - return "cruise ship"; - case CL_IOPTA: - return "IOPTA"; - case CL_METERING: - return "metering"; - case CL_TELEPHONE: - return "telephone"; - case CL_HEALTH: - return "health services"; - case CL_WAREHOUSE: - return "warehouse"; - case CL_BANKING: - return "banking"; - case CL_ENTERTAIN: - return "entertainment & sports"; - case CL_PARKING: - return "car parking"; - case CL_FLEET: - return "fleet management"; - case CL_FUEL: - return "fuel, gasoline"; - case CL_INFO: - return "info services"; - case CL_PRESS: - return "press"; - case CL_NFC: - return "NFC Forum"; - case CL_COMPUTER: - return "computer"; - case CL_MAIL: - return "mail"; - case CL_AMISC: - case CL_AMISC1: - case CL_AMISC2: - case CL_AMISC3: - case CL_AMISC4: - case CL_AMISC5: - case CL_AMISC6: - case CL_AMISC7: - return "miscellaneous applications"; - default: - break; - } - return "reserved"; -} - typedef enum { DESFIRE_UNKNOWN = 0, DESFIRE_MF3ICD40, @@ -2125,7 +1929,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { if ((aid[2] >> 4) == 0xF) { uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); + PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8)); MADDFDecodeAndPrint(short_aid); } else { AIDDFDecodeAndPrint(aid); @@ -6308,16 +6112,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { for (int i = 0; i < appcount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); - uint8_t aid[3] = {0}; - DesfireAIDUintToByte(AppList[i].appNum, aid); - if ((aid[2] >> 4) == 0xF) { - uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); - PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); - MADDFDecodeAndPrint(short_aid); - } else { - AIDDFDecodeAndPrint(aid); - } + DesfirePrintAIDFunctions(AppList[i].appNum); PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); @@ -6390,16 +6185,7 @@ static int CmdHF14ADesDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Application " _CYAN_("%06x") " have " _GREEN_("%zu") " files", appid, filescount); - uint8_t aid[3] = {0}; - DesfireAIDUintToByte(appid, aid); - if ((aid[2] >> 4) == 0xF) { - uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); - PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); - MADDFDecodeAndPrint(short_aid); - } else { - AIDDFDecodeAndPrint(aid); - } + DesfirePrintAIDFunctions(appid); if (filescount == 0) { PrintAndLogEx(INFO, "There is no files in the application %06x", appid); diff --git a/client/src/mifare/aiddesfire.c b/client/src/mifare/aiddesfire.c new file mode 100644 index 000000000..0957fe6b3 --- /dev/null +++ b/client/src/mifare/aiddesfire.c @@ -0,0 +1,329 @@ +//----------------------------------------------------------------------------- +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// AID DESFire functions +//----------------------------------------------------------------------------- + +#include "aiddesfire.h" +#include "pm3_cmd.h" +#include "fileutils.h" +#include "jansson.h" + +// NXP Appnote AN10787 - Application Directory (MAD) +typedef enum { + CL_ADMIN = 0, + CL_MISC1, + CL_MISC2, + CL_MISC3, + CL_MISC4, + CL_MISC5, + CL_MISC6, + CL_MISC7, + CL_AIRLINES = 8, + CL_FERRY, + CL_RAIL, + CL_MISC, + CL_TRANSPORT, + CL_SECURITY = 0x14, + CL_CITYTRAFFIC = 0x18, + CL_CZECH_RAIL, + CL_BUS, + CL_MMT, + CL_TAXI = 0x28, + CL_TOLL = 0x30, + CL_GENERIC_TRANS, + CL_COMPANY_SERVICES = 0x38, + CL_CITYCARD = 0x40, + CL_ACCESS_CONTROL_1 = 0x47, + CL_ACCESS_CONTROL_2, + CL_VIGIK = 0x49, + CL_NED_DEFENCE = 0x4A, + CL_BOSCH_TELECOM = 0x4B, + CL_EU = 0x4C, + CL_SKI_TICKET = 0x50, + CL_SOAA = 0x55, + CL_ACCESS2 = 0x56, + CL_FOOD = 0x60, + CL_NONFOOD = 0x68, + CL_HOTEL = 0x70, + CL_LOYALTY = 0x71, + CL_AIRPORT = 0x75, + CL_CAR_RENTAL = 0x78, + CL_NED_GOV = 0x79, + CL_ADMIN2 = 0x80, + CL_PURSE = 0x88, + CL_TV = 0x90, + CL_CRUISESHIP = 0x91, + CL_IOPTA = 0x95, + CL_METERING = 0x97, + CL_TELEPHONE = 0x98, + CL_HEALTH = 0xA0, + CL_WAREHOUSE = 0xA8, + CL_BANKING = 0xB8, + CL_ENTERTAIN = 0xC0, + CL_PARKING = 0xC8, + CL_FLEET = 0xC9, + CL_FUEL = 0xD0, + CL_INFO = 0xD8, + CL_PRESS = 0xE0, + CL_NFC = 0xE1, + CL_COMPUTER = 0xE8, + CL_MAIL = 0xF0, + CL_AMISC = 0xF8, + CL_AMISC1 = 0xF9, + CL_AMISC2 = 0xFA, + CL_AMISC3 = 0xFB, + CL_AMISC4 = 0xFC, + CL_AMISC5 = 0xFD, + CL_AMISC6 = 0xFE, + CL_AMISC7 = 0xFF, +} aidcluster_h; + +const char *nxp_cluster_to_text(uint8_t cluster) { + switch (cluster) { + case CL_ADMIN: + return "card administration"; + case CL_MISC1: + case CL_MISC2: + case CL_MISC3: + case CL_MISC4: + case CL_MISC5: + case CL_MISC6: + case CL_MISC7: + return "miscellaneous applications"; + case CL_AIRLINES: + return "airlines"; + case CL_FERRY: + return "ferry traffic"; + case CL_RAIL: + return "railway services"; + case CL_MISC: + return "miscellaneous applications"; + case CL_TRANSPORT: + return "transport"; + case CL_SECURITY: + return "security solutions"; + case CL_CITYTRAFFIC: + return "city traffic"; + case CL_CZECH_RAIL: + return "Czech Railways"; + case CL_BUS: + return "bus services"; + case CL_MMT: + return "multi modal transit"; + case CL_TAXI: + return "taxi"; + case CL_TOLL: + return "road toll"; + case CL_GENERIC_TRANS: + return "generic transport"; + case CL_COMPANY_SERVICES: + return "company services"; + case CL_CITYCARD: + return "city card services"; + case CL_ACCESS_CONTROL_1: + case CL_ACCESS_CONTROL_2: + return "access control & security"; + case CL_VIGIK: + return "VIGIK"; + case CL_NED_DEFENCE: + return "Ministry of Defence, Netherlands"; + case CL_BOSCH_TELECOM: + return "Bosch Telecom, Germany"; + case CL_EU: + return "European Union Institutions"; + case CL_SKI_TICKET: + return "ski ticketing"; + case CL_SOAA: + return "SOAA standard for offline access standard"; + case CL_ACCESS2: + return "access control & security"; + case CL_FOOD: + return "food"; + case CL_NONFOOD: + return "non-food trade"; + case CL_HOTEL: + return "hotel"; + case CL_LOYALTY: + return "loyalty"; + case CL_AIRPORT: + return "airport services"; + case CL_CAR_RENTAL: + return "car rental"; + case CL_NED_GOV: + return "Dutch government"; + case CL_ADMIN2: + return "administration services"; + case CL_PURSE: + return "electronic purse"; + case CL_TV: + return "television"; + case CL_CRUISESHIP: + return "cruise ship"; + case CL_IOPTA: + return "IOPTA"; + case CL_METERING: + return "metering"; + case CL_TELEPHONE: + return "telephone"; + case CL_HEALTH: + return "health services"; + case CL_WAREHOUSE: + return "warehouse"; + case CL_BANKING: + return "banking"; + case CL_ENTERTAIN: + return "entertainment & sports"; + case CL_PARKING: + return "car parking"; + case CL_FLEET: + return "fleet management"; + case CL_FUEL: + return "fuel, gasoline"; + case CL_INFO: + return "info services"; + case CL_PRESS: + return "press"; + case CL_NFC: + return "NFC Forum"; + case CL_COMPUTER: + return "computer"; + case CL_MAIL: + return "mail"; + case CL_AMISC: + case CL_AMISC1: + case CL_AMISC2: + case CL_AMISC3: + case CL_AMISC4: + case CL_AMISC5: + case CL_AMISC6: + case CL_AMISC7: + return "miscellaneous applications"; + default: + break; + } + return "reserved"; +} + +static json_t *df_known_aids = NULL; + +static int open_aiddf_file(json_t **root, bool verbose) { + + char *path; + int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true); + if (res != PM3_SUCCESS) { + return PM3_EFILE; + } + + int retval = PM3_SUCCESS; + json_error_t error; + + *root = json_load_file(path, 0, &error); + if (!*root) { + PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text); + retval = PM3_ESOFT; + goto out; + } + + if (!json_is_array(*root)) { + PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path); + retval = PM3_ESOFT; + goto out; + } + + if (verbose) + PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root)); +out: + free(path); + return retval; +} + +static int close_aiddf_file(json_t *root) { + json_decref(root); + return PM3_SUCCESS; +} + +static const char *aiddf_json_get_str(json_t *data, const char *name) { + + json_t *jstr = json_object_get(data, name); + if (jstr == NULL) + return NULL; + + if (!json_is_string(jstr)) { + PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); + return NULL; + } + + const char *cstr = json_string_value(jstr); + if (strlen(cstr) == 0) + return NULL; + + return cstr; +} + +static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { + char laid[7] = {0}; + sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase + + json_t *elm = NULL; + + for (uint32_t idx = 0; idx < json_array_size(root); idx++) { + json_t *data = json_array_get(root, idx); + if (!json_is_object(data)) { + PrintAndLogEx(ERR, "data [%d] is not an object\n", idx); + continue; + } + const char *faid = aiddf_json_get_str(data, "AID"); + char lfaid[strlen(faid) + 1]; + strcpy(lfaid, faid); + str_lower(lfaid); + if (strcmp(laid, lfaid) == 0) { + elm = data; + break; + } + } + + if (elm == NULL) { + PrintAndLogEx(INFO, fmt, " (unknown)"); + return PM3_ENODATA; + } + const char *vaid = aiddf_json_get_str(elm, "AID"); + const char *vendor = aiddf_json_get_str(elm, "Vendor"); + const char *country = aiddf_json_get_str(elm, "Country"); + const char *name = aiddf_json_get_str(elm, "Name"); + const char *description = aiddf_json_get_str(elm, "Description"); + const char *type = aiddf_json_get_str(elm, "Type"); + + if (name && vendor) { + char result[5 + strlen(name) + strlen(vendor)]; + sprintf(result, " %s [%s]", name, vendor); + PrintAndLogEx(INFO, fmt, result); + } + + if (verbose) { + PrintAndLogEx(SUCCESS, " AID: %s", vaid); + if (name) + PrintAndLogEx(SUCCESS, " Name: %s", name); + if (description) + PrintAndLogEx(SUCCESS, " Description: %s", description); + if (type) + PrintAndLogEx(SUCCESS, " Type: %s", type); + if (vendor) + PrintAndLogEx(SUCCESS, " Vendor: %s", vendor); + if (country) + PrintAndLogEx(SUCCESS, " Country: %s", country); + } + return PM3_SUCCESS; +} + +int AIDDFDecodeAndPrint(uint8_t aid[3]) { + open_aiddf_file(&df_known_aids, false); + + char fmt[80]; + sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s"); + print_aiddf_description(df_known_aids, aid, fmt, false); + close_aiddf_file(df_known_aids); + return PM3_SUCCESS; +} diff --git a/client/src/aiddesfire.h b/client/src/mifare/aiddesfire.h similarity index 91% rename from client/src/aiddesfire.h rename to client/src/mifare/aiddesfire.h index bb67dab83..c09f6e971 100644 --- a/client/src/aiddesfire.h +++ b/client/src/mifare/aiddesfire.h @@ -11,6 +11,7 @@ #include "common.h" +const char *nxp_cluster_to_text(uint8_t cluster); int AIDDFDecodeAndPrint(uint8_t aid[3]); #endif // _AIDDESFIRE_H_ diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 8460f05af..52984f9ff 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -32,6 +32,8 @@ #include "util_posix.h" // msleep #include "mifare/desfire_crypto.h" #include "desfiresecurechan.h" +#include "mifare/mad.h" +#include "mifare/aiddesfire.h" const CLIParserOption DesfireAlgoOpts[] = { {T_DES, "des"}, @@ -825,6 +827,20 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { return res; } +void DesfirePrintAIDFunctions(uint32_t appid) { + uint8_t aid[3] = {0}; + DesfireAIDUintToByte(appid, aid); + if ((aid[2] >> 4) == 0xF) { + uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); + PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); + PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8)); + MADDFDecodeAndPrint(short_aid); + } else { + AIDDFDecodeAndPrint(aid); + } +} + + int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) { if (verbose) DesfirePrintContext(dctx); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 9d3ad04e6..2e3fab97d 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -136,6 +136,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); +void DesfirePrintAIDFunctions(uint32_t appid); const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); From d27c340ab0b9091c339a378ed38934c45440fdf5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 17:03:50 +0300 Subject: [PATCH 13/80] add get key versions to lsapp --- client/src/cmdhfmfdes.c | 30 ++++++++++++++++++++++++++++-- client/src/mifare/desfirecore.h | 2 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 5a57b3c07..53c9ececd 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6064,10 +6064,18 @@ static int CmdHF14ADesLsApp(const char *Cmd) { uint8_t keysettings0 = 0; uint8_t numkeys0 = 0; + uint8_t keyVer0 = 0; res = DesfireGetKeySettings(&dctx, buf, &buflen); if (res == PM3_SUCCESS && buflen >= 2) { keysettings0 = buf[0]; numkeys0 = buf[1]; + if ((numkeys0 & 0x1f) > 0) { + uint8_t keyNum0 = numkeys0 & 0x1f; + res = DesfireGetKeyVersion(&dctx, &keyNum0, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + keyVer0 = buf[0]; + } + } } if (appcount > 0) { @@ -6083,6 +6091,14 @@ static int CmdHF14ADesLsApp(const char *Cmd) { AppList[i].numberOfKeys = AppList[i].numKeysRaw & 0x1f; AppList[i].isoFileIDEnabled = ((AppList[i].numKeysRaw & 0x20) != 0); AppList[i].keyType = DesfireKeyTypeToAlgo(AppList[i].numKeysRaw >> 6); + + if (AppList[i].numberOfKeys > 0) + for (uint8_t keyn = 0; keyn < AppList[i].numberOfKeys; keyn++) { + res = DesfireGetKeyVersion(&dctx, &keyn, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + AppList[i].keyVersions[keyn] = buf[0]; + } + } } } } @@ -6102,11 +6118,13 @@ static int CmdHF14ADesLsApp(const char *Cmd) { PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&authCmdCheck0); - if (numkeys0 > 0) + if (numkeys0 > 0) { PrintKeySettings(keysettings0, numkeys0, false, true); + PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", keyVer0, keyVer0); + } if (appcount > 0) { - PrintAndLogEx(SUCCESS, ""); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); for (int i = 0; i < appcount; i++) { @@ -6119,6 +6137,14 @@ static int CmdHF14ADesLsApp(const char *Cmd) { PrintAndLogEx(SUCCESS, ""); if (AppList[i].numberOfKeys > 0) { PrintKeySettings(AppList[i].keySettings, AppList[i].numKeysRaw, true, true); + + if (AppList[i].numberOfKeys > 0) { + PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, AppList[i].numberOfKeys - 1); + for (uint8_t keyn = 0; keyn < AppList[i].numberOfKeys; keyn++) { + PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", AppList[i].keyVersions[keyn]); + } + PrintAndLogEx(NORMAL, "\n"); + } } } } diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 2e3fab97d..0f8da7392 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -104,6 +104,8 @@ typedef struct { bool isoFileIDEnabled; // from numKeysRaw uint8_t numberOfKeys; // from numKeysRaw DesfireCryptoAlgorythm keyType; // from numKeysRaw + + uint8_t keyVersions[16]; } AppListElmS; typedef AppListElmS AppListS[64]; From ed310ed432470b62093befd7c46158b3ec8d1926 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 17:49:04 +0300 Subject: [PATCH 14/80] DesfireFillAppList refactoring --- client/src/cmdhfmfdes.c | 109 +++----------------------------- client/src/mifare/desfirecore.c | 107 +++++++++++++++++++++++++++++++ client/src/mifare/desfirecore.h | 14 ++++ 3 files changed, 131 insertions(+), 99 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 53c9ececd..3d1ddbc3c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5976,14 +5976,6 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { return PM3_SUCCESS; } -static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) { - for (int i = 0; i < appcount; i++) - if (AppList[i].appNum == appNum) - return i; - - return -1; -} - static int CmdHF14ADesLsApp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes lsapp", @@ -6013,7 +6005,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMMACed, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMPlain, NULL); if (res) { CLIParserFree(ctx); return res; @@ -6028,106 +6020,25 @@ static int CmdHF14ADesLsApp(const char *Cmd) { return res; } - uint8_t buf[250] = {0}; - size_t buflen = 0; - - uint32_t freemem = 0; - DesfireGetFreeMem(&dctx, &freemem); - - - res = DesfireGetAIDList(&dctx, buf, &buflen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); - DropField(); - return PM3_ESOFT; - } - + PICCInfoS PICCInfo = {0}; AppListS AppList = {0}; - - size_t appcount = buflen / 3; - for (int i = 0; i < buflen; i += 3) - AppList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]); - - // result bytes: 3, 2, 1-16. total record size = 24 - res = DesfireGetDFList(&dctx, buf, &buflen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); - } else if (buflen > 1) { - for (int i = 0; i < buflen; i++) { - int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), AppList, appcount); - if (indx >= 0) { - AppList[indx].appISONum = MemBeToUint2byte(&buf[i * 24 + 1 + 3]); - memcpy(AppList[indx].appDFName, &buf[i * 24 + 1 + 5], strnlen((char *)&buf[i * 24 + 1 + 5], 16)); - } - } - } - - uint8_t keysettings0 = 0; - uint8_t numkeys0 = 0; - uint8_t keyVer0 = 0; - res = DesfireGetKeySettings(&dctx, buf, &buflen); - if (res == PM3_SUCCESS && buflen >= 2) { - keysettings0 = buf[0]; - numkeys0 = buf[1]; - if ((numkeys0 & 0x1f) > 0) { - uint8_t keyNum0 = numkeys0 & 0x1f; - res = DesfireGetKeyVersion(&dctx, &keyNum0, 1, buf, &buflen); - if (res == PM3_SUCCESS && buflen > 0) { - keyVer0 = buf[0]; - } - } - } - - if (appcount > 0) { - for (int i = 0; i < appcount; i++) { - res = DesfireSelectAIDHexNoFieldOn(&dctx, AppList[i].appNum); - if (res != PM3_SUCCESS) - continue; - - DesfireGetKeySettings(&dctx, buf, &buflen); - if (res == PM3_SUCCESS && buflen >= 2) { - AppList[i].keySettings = buf[0]; - AppList[i].numKeysRaw = buf[1]; - AppList[i].numberOfKeys = AppList[i].numKeysRaw & 0x1f; - AppList[i].isoFileIDEnabled = ((AppList[i].numKeysRaw & 0x20) != 0); - AppList[i].keyType = DesfireKeyTypeToAlgo(AppList[i].numKeysRaw >> 6); - - if (AppList[i].numberOfKeys > 0) - for (uint8_t keyn = 0; keyn < AppList[i].numberOfKeys; keyn++) { - res = DesfireGetKeyVersion(&dctx, &keyn, 1, buf, &buflen); - if (res == PM3_SUCCESS && buflen > 0) { - AppList[i].keyVersions[keyn] = buf[0]; - } - } - } - } - } - - // field on-off zone - AuthCommandsChk authCmdCheck0 = {0}; - DesfireCheckAuthCommands(0x000000, NULL, 0, &authCmdCheck0); - - if (appcount > 0) { - for (int i = 0; i < appcount; i++) { - DesfireCheckAuthCommands(AppList[i].appNum, AppList[i].appDFName, 0, &AppList[i].authCmdCheck); - } - } + DesfireFillAppList(&dctx, &PICCInfo, AppList, true); // print zone PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("PICC level") " ------------------"); - PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), appcount, freemem); + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), PICCInfo.appCount, PICCInfo.freemem); PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); - DesfireCheckAuthCommandsPrint(&authCmdCheck0); - if (numkeys0 > 0) { - PrintKeySettings(keysettings0, numkeys0, false, true); - PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", keyVer0, keyVer0); + DesfireCheckAuthCommandsPrint(&PICCInfo.authCmdCheck); + if (PICCInfo.numberOfKeys > 0) { + PrintKeySettings(PICCInfo.keySettings, PICCInfo.numKeysRaw, false, true); + PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo.keyVersion0, PICCInfo.keyVersion0); } - if (appcount > 0) { + if (PICCInfo.appCount > 0) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); - for (int i = 0; i < appcount; i++) { + for (int i = 0; i < PICCInfo.appCount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); DesfirePrintAIDFunctions(AppList[i].appNum); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 52984f9ff..a3a806293 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1457,6 +1457,113 @@ void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { ); } +int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode) { + uint8_t buf[250] = {0}; + size_t buflen = 0; + + uint32_t freemem = 0; + int res = DesfireGetFreeMem(dctx, &freemem); + if (res == PM3_SUCCESS) + PICCInfo->freemem = freemem; + + PICCInfo->keySettings = 0; + PICCInfo->numKeysRaw = 0; + PICCInfo->keyVersion0 = 0; + res = DesfireGetKeySettings(dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + PICCInfo->keySettings = buf[0]; + PICCInfo->numKeysRaw = buf[1]; + PICCInfo->numberOfKeys = PICCInfo->numKeysRaw & 0x1f; + if (PICCInfo->numKeysRaw > 0) { + uint8_t keyNum0 = 0; + res = DesfireGetKeyVersion(dctx, &keyNum0, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + PICCInfo->keyVersion0 = buf[0]; + } + } + } + + // field on-off zone + if (deepmode) + DesfireCheckAuthCommands(0x000000, NULL, 0, &PICCInfo->authCmdCheck); + + return PM3_SUCCESS; +} + +static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) { + for (int i = 0; i < appcount; i++) + if (AppList[i].appNum == appNum) + return i; + + return -1; +} + +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode) { + uint8_t buf[250] = {0}; + size_t buflen = 0; + + DesfireFillPICCInfo(dctx, PICCInfo, deepmode); + + int res = DesfireGetAIDList(dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + PICCInfo->appCount = buflen / 3; + for (int i = 0; i < buflen; i += 3) + appList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]); + + // result bytes: 3, 2, 1-16. total record size = 24 + res = DesfireGetDFList(dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); + } else if (buflen > 1) { + for (int i = 0; i < buflen; i++) { + int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), appList, PICCInfo->appCount); + if (indx >= 0) { + appList[indx].appISONum = MemBeToUint2byte(&buf[i * 24 + 1 + 3]); + memcpy(appList[indx].appDFName, &buf[i * 24 + 1 + 5], strnlen((char *)&buf[i * 24 + 1 + 5], 16)); + } + } + } + + if (PICCInfo->appCount > 0) { + for (int i = 0; i < PICCInfo->appCount; i++) { + res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum); + if (res != PM3_SUCCESS) + continue; + + DesfireGetKeySettings(dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + appList[i].keySettings = buf[0]; + appList[i].numKeysRaw = buf[1]; + appList[i].numberOfKeys = appList[i].numKeysRaw & 0x1f; + appList[i].isoFileIDEnabled = ((appList[i].numKeysRaw & 0x20) != 0); + appList[i].keyType = DesfireKeyTypeToAlgo(appList[i].numKeysRaw >> 6); + + if (appList[i].numberOfKeys > 0) + for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { + res = DesfireGetKeyVersion(dctx, &keyn, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + appList[i].keyVersions[keyn] = buf[0]; + } + } + } + } + } + + // field on-off zone + if (PICCInfo->appCount > 0 && deepmode) { + for (int i = 0; i < PICCInfo->appCount; i++) { + DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); + } + } + + return PM3_SUCCESS; +} + static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { if (resplen) *resplen = 0; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 0f8da7392..d63d6582a 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -109,6 +109,18 @@ typedef struct { } AppListElmS; typedef AppListElmS AppListS[64]; +typedef struct { + size_t appCount; + uint32_t freemem; + AuthCommandsChk authCmdCheck; + + uint8_t keySettings; + uint8_t numKeysRaw; + uint8_t numberOfKeys; // from numKeysRaw + + uint8_t keyVersion0; +} PICCInfoS; + typedef enum { RFTAuto, RFTData, @@ -152,6 +164,8 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem); int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); +int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode); +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode); int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen); int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid); From 0951b3117525f08008a0ffa31ccba746d24c887b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 18:13:45 +0300 Subject: [PATCH 15/80] print refactoring --- client/src/cmdhfmfdes.c | 43 +++++---------------------- client/src/mifare/desfirecore.c | 52 +++++++++++++++++++++++++++++++-- client/src/mifare/desfirecore.h | 9 +++++- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 3d1ddbc3c..2bb941809 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6014,6 +6014,8 @@ static int CmdHF14ADesLsApp(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); + PrintAndLogEx(INPLACE, _YELLOW_("It may take up to 15 seconds. Processing....")); + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); @@ -6022,43 +6024,14 @@ static int CmdHF14ADesLsApp(const char *Cmd) { PICCInfoS PICCInfo = {0}; AppListS AppList = {0}; - DesfireFillAppList(&dctx, &PICCInfo, AppList, true); + DesfireFillAppList(&dctx, &PICCInfo, AppList, true, false); + + printf("\33[2K\r"); // clear current line before printing + PrintAndLogEx(NORMAL, ""); // print zone - PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("PICC level") " ------------------"); - PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), PICCInfo.appCount, PICCInfo.freemem); - PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); - DesfireCheckAuthCommandsPrint(&PICCInfo.authCmdCheck); - if (PICCInfo.numberOfKeys > 0) { - PrintKeySettings(PICCInfo.keySettings, PICCInfo.numKeysRaw, false, true); - PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo.keyVersion0, PICCInfo.keyVersion0); - } - - if (PICCInfo.appCount > 0) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); - - for (int i = 0; i < PICCInfo.appCount; i++) { - PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), AppList[i].appNum, AppList[i].appISONum, AppList[i].appDFName); - - DesfirePrintAIDFunctions(AppList[i].appNum); - - PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); - DesfireCheckAuthCommandsPrint(&AppList[i].authCmdCheck); - PrintAndLogEx(SUCCESS, ""); - if (AppList[i].numberOfKeys > 0) { - PrintKeySettings(AppList[i].keySettings, AppList[i].numKeysRaw, true, true); - - if (AppList[i].numberOfKeys > 0) { - PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, AppList[i].numberOfKeys - 1); - for (uint8_t keyn = 0; keyn < AppList[i].numberOfKeys; keyn++) { - PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", AppList[i].keyVersions[keyn]); - } - PrintAndLogEx(NORMAL, "\n"); - } - } - } - } + DesfirePrintPICCInfo(&dctx, &PICCInfo); + DesfirePrintAppList(&dctx, &PICCInfo, AppList); DropField(); return PM3_SUCCESS; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index a3a806293..eb9110f84 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1498,12 +1498,10 @@ static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) return -1; } -int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode) { +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles) { uint8_t buf[250] = {0}; size_t buflen = 0; - DesfireFillPICCInfo(dctx, PICCInfo, deepmode); - int res = DesfireGetAIDList(dctx, buf, &buflen); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); @@ -1550,11 +1548,19 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi appList[i].keyVersions[keyn] = buf[0]; } } + + appList[i].filesReaded = false; + if (readFiles) { + res = DesfireFillFileList(dctx, appList[i].fileList, &appList[i].filesCount, &appList[i].isoPresent); + appList[i].filesReaded = (res == PM3_SUCCESS); + } } } } // field on-off zone + DesfireFillPICCInfo(dctx, PICCInfo, deepmode); + if (PICCInfo->appCount > 0 && deepmode) { for (int i = 0; i < PICCInfo->appCount; i++) { DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); @@ -1564,6 +1570,46 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi return PM3_SUCCESS; } +void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) { + PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("PICC level") " ------------------"); + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), PICCInfo->appCount, PICCInfo->freemem); + PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); + if (PICCInfo->numberOfKeys > 0) { + PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true); + PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0); + } +} + +void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList) { + if (PICCInfo->appCount == 0) + return; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); + + for (int i = 0; i < PICCInfo->appCount; i++) { + PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName); + + DesfirePrintAIDFunctions(appList[i].appNum); + + PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck); + PrintAndLogEx(SUCCESS, ""); + if (appList[i].numberOfKeys > 0) { + PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true); + + if (appList[i].numberOfKeys > 0) { + PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1); + for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { + PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]); + } + PrintAndLogEx(NORMAL, "\n"); + } + } + } +} + static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { if (resplen) *resplen = 0; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index d63d6582a..e6f0a15cd 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -106,6 +106,11 @@ typedef struct { DesfireCryptoAlgorythm keyType; // from numKeysRaw uint8_t keyVersions[16]; + + bool filesReaded; + size_t filesCount; + bool isoPresent; + FileListS fileList; } AppListElmS; typedef AppListElmS AppListS[64]; @@ -165,7 +170,9 @@ int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode); -int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode); +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles); +void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo); +void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList); int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen); int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid); From 4f4a14c12471d663866dfa476c2ab5f62cffdc8f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 18:29:15 +0300 Subject: [PATCH 16/80] lsapp get/print file list --- client/src/mifare/desfirecore.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index eb9110f84..a9c102ad5 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1586,7 +1586,7 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app return; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "-------------- " _CYAN_("Alications list") " --------------"); + PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Alications list") " ---------------------------------"); for (int i = 0; i < PICCInfo->appCount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName); @@ -1606,6 +1606,26 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app } PrintAndLogEx(NORMAL, "\n"); } + + if (appList[i].filesReaded) { + PrintAndLogEx(SUCCESS, "Application have " _GREEN_("%zu") " files", appList[i].filesCount); + + if (appList[i].filesCount > 0) { + for (int fnum = 0; fnum < appList[i].filesCount; fnum++) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("File %02x") " ----------------------------------", appList[i].fileList[fnum].fileNum); + PrintAndLogEx(SUCCESS, "File ID : " _GREEN_("%02x"), appList[i].fileList[fnum].fileNum); + if (appList[i].isoPresent) { + if (appList[i].fileList[fnum].fileISONum != 0) + PrintAndLogEx(SUCCESS, "File ISO ID : %04x", appList[i].fileList[fnum].fileISONum); + else + PrintAndLogEx(SUCCESS, "File ISO ID : " _YELLOW_("n/a")); + } + DesfirePrintFileSettingsExtended(&appList[i].fileList[fnum].fileSettings); + } + } + PrintAndLogEx(NORMAL, ""); + } } } } From ddd0e3c868f72e0f03fe9a09488028684784d722 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 18:50:29 +0300 Subject: [PATCH 17/80] add checked auth commands flag, remove old code --- client/src/cmdhfmfdes.c | 285 ++------------------------------ client/src/mifare/desfirecore.c | 17 +- client/src/mifare/desfirecore.h | 1 + 3 files changed, 27 insertions(+), 276 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2bb941809..7a517bc1d 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1294,33 +1294,6 @@ static int handler_desfire_appids(uint8_t *dest, uint32_t *app_ids_len) { return res; } -// --- GET DF NAMES -static int handler_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) { - - if (g_debugMode > 1) { - if (dest == NULL) PrintAndLogEx(ERR, "DEST = NULL"); - if (dfname_count == NULL) PrintAndLogEx(ERR, "DFNAME_COUNT = NULL"); - } - - if (dest == NULL || dfname_count == NULL) - return PM3_EINVARG; - - *dfname_count = 0; - sAPDU apdu = {0x90, MFDES_GET_DF_NAMES, 0x00, 0x00, 0x00, NULL}; //0x6d - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true); - if (res != PM3_SUCCESS) { - return res; - } - - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - *dfname_count = recv_len; - return res; -} - static int handler_desfire_select_application(uint8_t *aid) { if (g_debugMode > 1) { if (aid == NULL) { @@ -1739,238 +1712,6 @@ static int CmdHF14ADesInfo(const char *Cmd) { return PM3_SUCCESS; } -static void DecodeFileType(uint8_t filetype) { - switch (filetype) { - case 0x00: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Standard Data File", filetype); - break; - case 0x01: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Backup Data File", filetype); - break; - case 0x02: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Value Files with Backup", filetype); - break; - case 0x03: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Linear Record Files with Backup", filetype); - break; - case 0x04: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Cyclic Record Files with Backup", filetype); - break; - default: - PrintAndLogEx(INFO, " File Type: 0x%02X", filetype); - break; - } -} - -static void DecodeComSet(uint8_t comset) { - switch (comset) { - case 0x00: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain", comset); - break; - case 0x01: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain + MAC", comset); - break; - case 0x03: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Enciphered", comset); - break; - default: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X", comset); - break; - } -} - -static char *DecodeAccessValue(uint8_t value) { - - char *car = (char *)calloc(255, sizeof(char)); - if (car == NULL) - return NULL; - - switch (value) { - case 0xE: - strcat(car, "(Free Access)"); - break; - case 0xF: - strcat(car, "(Denied Access)"); - break; - default: - snprintf(car, 255, "(Access Key: %d)", value); - break; - } - return car; -} - -static void DecodeAccessRights(uint16_t accrights) { - int change_access_rights = accrights & 0xF; - int read_write_access = (accrights >> 4) & 0xF; - int write_access = (accrights >> 8) & 0xF; - int read_access = (accrights >> 12) & 0xF; - char *car = DecodeAccessValue(change_access_rights); - if (car == NULL) return; - - char *rwa = DecodeAccessValue(read_write_access); - if (rwa == NULL) { - free(car); - return; - } - - char *wa = DecodeAccessValue(write_access); - if (wa == NULL) { - free(car); - free(rwa); - return; - } - - char *ra = DecodeAccessValue(read_access); - if (ra == NULL) { - free(car); - free(rwa); - free(wa); - return; - } - - PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra); - free(car); - free(rwa); - free(wa); - free(ra); -} - -static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) { - uint8_t filetype = src[0]; - uint8_t comset = src[1]; - - uint16_t accrights = (src[3] << 8) + src[2]; - if (src_len == 1 + 1 + 2 + 3 + maclen) { - int filesize = (src[6] << 16) + (src[5] << 8) + src[4]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Filesize: %d (0x%X)", filesize, filesize); - return PM3_SUCCESS; - } else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) { - int lowerlimit = (src[7] << 24) + (src[6] << 16) + (src[5] << 8) + src[4]; - int upperlimit = (src[11] << 24) + (src[10] << 16) + (src[9] << 8) + src[8]; - int limitcredvalue = (src[15] << 24) + (src[14] << 16) + (src[13] << 8) + src[12]; - uint8_t limited_credit_enabled = src[17]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Lower limit: %d (0x%X) - Upper limit: %d (0x%X) - limited credit value: %d (0x%X) - limited credit enabled: %d", lowerlimit, lowerlimit, upperlimit, upperlimit, limitcredvalue, limitcredvalue, limited_credit_enabled); - return PM3_SUCCESS; - } else if (src_len == 1 + 1 + 2 + 3 + 3 + 3 + maclen) { - uint32_t recordsize = (src[6] << 16) + (src[5] << 8) + src[4]; - uint32_t maxrecords = (src[9] << 16) + (src[8] << 8) + src[7]; - uint32_t currentrecord = (src[12] << 16) + (src[11] << 8) + src[10]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Record size: %d (0x%X) - MaxNumberRecords: %d (0x%X) - Current Number Records: %d (0x%X)", recordsize, recordsize, maxrecords, maxrecords, currentrecord, currentrecord); - return PM3_SUCCESS; - } - return PM3_ESOFT; -} - -static int CmdHF14ADesEnumApplications(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes enum", - "Enumerate all AID's on MIFARE DESfire tag", - "hf mfdes enum"); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - DropFieldDesfire(); - - uint8_t aid[3] = {0}; - uint8_t app_ids[78] = {0}; - uint32_t app_ids_len = 0; - - uint8_t file_ids[33] = {0}; - uint32_t file_ids_len = 0; - - dfname_t dfnames[255]; - uint8_t dfname_count = 0; - - if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Can't get list of applications on tag"); - DropFieldDesfire(); - return PM3_ESOFT; - } - - if (handler_desfire_dfnames(dfnames, &dfname_count) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_("Can't get DF Names")); - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-- MIFARE DESFire Enumerate applications --------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's'); - - for (uint32_t i = 0; i < app_ids_len; i += 3) { - - aid[0] = app_ids[i]; - aid[1] = app_ids[i + 1]; - aid[2] = app_ids[i + 2]; - - PrintAndLogEx(NORMAL, ""); - - if (memcmp(aid, "\x00\x00\x00", 3) == 0) { - // CARD MASTER KEY - PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); - } else { - PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); - } - - PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]); - if ((aid[2] >> 4) == 0xF) { - uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); - PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8)); - MADDFDecodeAndPrint(short_aid); - } else { - AIDDFDecodeAndPrint(aid); - } - for (uint8_t m = 0; m < dfname_count; m++) { - if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) { - PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name); - } - } - - int res = getKeySettings(aid); - if (res != PM3_SUCCESS) continue; - - res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) continue; - - res = handler_desfire_fileids(file_ids, &file_ids_len); - if (res != PM3_SUCCESS) continue; - - PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's'); - for (int j = (int)file_ids_len - 1; j >= 0; j--) { - PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[j], file_ids[j]); - - uint8_t filesettings[20] = {0}; - uint32_t fileset_len = 0; - uint32_t maclen = 0; // To be implemented - - res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len); - if (res != PM3_SUCCESS) continue; - - if (DecodeFileSettings(filesettings, fileset_len, maclen) != PM3_SUCCESS) { - PrintAndLogEx(INFO, " Settings [%u] %s", fileset_len, sprint_hex(filesettings, fileset_len)); - } - } - - } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - DropFieldDesfire(); - return PM3_SUCCESS; -} - static void DesFill2bPattern( uint8_t deskeyList[MAX_KEYS_LIST_LEN][8], uint32_t *deskeyListLen, uint8_t aeskeyList[MAX_KEYS_LIST_LEN][16], uint32_t *aeskeyListLen, @@ -5980,7 +5721,8 @@ static int CmdHF14ADesLsApp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes lsapp", "Show application list. Master key needs to be provided or flag --no-auth set (depend on cards settings).", - "hf mfdes lsapp -> show application list with defaults from `default` command"); + "hf mfdes lsapp -> show application list with defaults from `default` command\n" + "hf mfdes lsapp --files -> show application list and show each file type/settings/etc for each application"); void *argtable[] = { arg_param_begin, @@ -5995,6 +5737,8 @@ static int CmdHF14ADesLsApp(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), arg_lit0(NULL, "no-auth", "execute without authentication"), + arg_lit0(NULL, "no-deep", "not to check authentication commands that avail for any application"), + arg_lit0(NULL, "files", "scan files and print file settings for each application"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -6002,6 +5746,8 @@ static int CmdHF14ADesLsApp(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); bool noauth = arg_get_lit(ctx, 11); + bool nodeep = arg_get_lit(ctx, 12); + bool scanfiles = arg_get_lit(ctx, 13); DesfireContext dctx; int securechann = defaultSecureChannel; @@ -6024,7 +5770,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { PICCInfoS PICCInfo = {0}; AppListS AppList = {0}; - DesfireFillAppList(&dctx, &PICCInfo, AppList, true, false); + DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles); printf("\33[2K\r"); // clear current line before printing PrintAndLogEx(NORMAL, ""); @@ -6143,7 +5889,6 @@ static command_t CommandTable[] = { {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "MIFARE DesFire Authentication"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "[old]Check keys"}, - {"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "[old]Tries enumerate all applications"}, {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"freemem", CmdHF14ADesGetFreeMem, IfPm3Iso14443a, "Get free memory size"}, {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get uid from card"}, @@ -6152,19 +5897,19 @@ static command_t CommandTable[] = { {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"}, // {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, + {"lsapp", CmdHF14ADesLsApp, IfPm3Iso14443a, "Show all applications with files list"}, + {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, + {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, + {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, + {"createapp", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application"}, + {"deleteapp", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application"}, + {"selectapp", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, {"-----------", CmdHelp, IfPm3Iso14443a, "------------------------ " _CYAN_("Keys") " -----------------------"}, {"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"}, {"chkeysettings", CmdHF14ADesChKeySettings, IfPm3Iso14443a, "Change Key Settings"}, {"getkeysettings", CmdHF14ADesGetKeySettings, IfPm3Iso14443a, "Get Key Settings"}, {"getkeyversions", CmdHF14ADesGetKeyVersions, IfPm3Iso14443a, "Get Key Versions"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, - {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, - {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, - {"lsapp", CmdHF14ADesLsApp, IfPm3Iso14443a, "Show all files list"}, - {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, - {"createapp", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application"}, - {"deleteapp", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application"}, - {"selectapp", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"getfileids", CmdHF14ADesGetFileIDs, IfPm3Iso14443a, "Get File IDs list"}, {"getfileisoids", CmdHF14ADesGetFileISOIDs, IfPm3Iso14443a, "Get File ISO IDs list"}, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index a9c102ad5..05331f383 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1445,6 +1445,7 @@ void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, Aut authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F); authCmdCheck->authISONative = DesfireCheckISOAuthCmd(appAID, dfname, keyNum, T_DES); + authCmdCheck->checked = true; } void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { @@ -1571,10 +1572,11 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) { - PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("PICC level") " ------------------"); + PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------"); PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), PICCInfo->appCount, PICCInfo->freemem); PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); - DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); + if (PICCInfo->authCmdCheck.checked) + DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); if (PICCInfo->numberOfKeys > 0) { PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true); PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0); @@ -1586,16 +1588,19 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app return; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Alications list") " ---------------------------------"); + PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------"); for (int i = 0; i < PICCInfo->appCount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName); DesfirePrintAIDFunctions(appList[i].appNum); - PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); - DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck); - PrintAndLogEx(SUCCESS, ""); + if (PICCInfo->authCmdCheck.checked) { + PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck); + PrintAndLogEx(SUCCESS, ""); + } + if (appList[i].numberOfKeys > 0) { PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index e6f0a15cd..2100a521a 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -86,6 +86,7 @@ typedef struct { typedef FileListElmS FileListS[32]; typedef struct { + bool checked; bool auth; bool authISO; bool authAES; From 05a212721fffe3b6bc0edb72b17a66b8151c4098 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 18:58:00 +0300 Subject: [PATCH 18/80] remove old tests --- client/src/cmdhfmfdes.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 7a517bc1d..b65af9dac 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2394,29 +2394,6 @@ static int CmdHF14aDesMAD(const char *Cmd) { } */ -/*static int CmdTest(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - uint8_t IV[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t key[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - uint8_t encRndB[8] = {0x1A, 0xBE, 0x10, 0x8D, 0x09, 0xE0, 0x18, 0x13}; - uint8_t RndB[8] = {0}; - uint8_t RndA[8] = {0x6E, 0x6A, 0xEB, 0x86, 0x6E, 0x6A, 0xEB, 0x86}; - tdes_nxp_receive(encRndB, RndB, 8, key, IV, 2); - uint8_t rotRndB[8] = {0}; - memcpy(rotRndB, RndB, 8); - rol(rotRndB, 8); - uint8_t tmp[16] = {0x00}; - uint8_t both[16] = {0x00}; - memcpy(tmp, RndA, 8); - memcpy(tmp + 8, rotRndB, 8); - PrintAndLogEx(INFO, "3keyenc: %s", sprint_hex(tmp, 16)); - PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(IV, 8)); - tdes_nxp_send(tmp, both, 16, key, IV, 2); - PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(both, 16)); - return PM3_SUCCESS; -} -*/ static uint8_t defaultKeyNum = 0; static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES; static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; From f70558c0089aec9097e2ee28d3453368ed306f5a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 23:05:25 +0300 Subject: [PATCH 19/80] readsig command --- client/src/mifare/desfirecore.c | 20 ++++++++++++++++++++ client/src/mifare/desfirecore.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 05331f383..00328bef1 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1688,6 +1688,26 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem) { return res; } +int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen) { + *resplen = 0; + + uint8_t xresp[257] = {0}; + size_t xresplen = 0; + uint8_t respcode = 0xff; + + int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen); + if (res != PM3_SUCCESS) + return res; + + if (respcode != 0x90) + return PM3_EAPDU_FAIL; + + memcpy(resp, xresp, xresplen); + *resplen = xresplen; + + return PM3_SUCCESS; +} + int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1); } diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 2100a521a..4d53e96f2 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -153,6 +153,8 @@ void DesfirePrintContext(DesfireContext *ctx); int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize); +int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen); + int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); From 6ae54d58936401431af6f42a5ea5ff8f73d9e00c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 23:39:23 +0300 Subject: [PATCH 20/80] add n/a value for freemem --- client/src/mifare/desfirecore.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 00328bef1..438125051 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1466,6 +1466,8 @@ int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode int res = DesfireGetFreeMem(dctx, &freemem); if (res == PM3_SUCCESS) PICCInfo->freemem = freemem; + else + PICCInfo->freemem = 0xffffffff; PICCInfo->keySettings = 0; PICCInfo->numKeysRaw = 0; @@ -1573,7 +1575,10 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) { PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------"); - PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d"), PICCInfo->appCount, PICCInfo->freemem); + if (PICCInfo->freemem == 0xffffffff) + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount); + else + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem); PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); if (PICCInfo->authCmdCheck.checked) DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); From c84aa8cb40575e9d929039b76de6f2de76f65de7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 2 Aug 2021 23:40:02 +0300 Subject: [PATCH 21/80] info command --- client/src/cmdhfmfdes.c | 354 +++------------------------------------- 1 file changed, 24 insertions(+), 330 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index b65af9dac..3f0bcbeeb 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -720,87 +720,6 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp return PM3_SUCCESS; } -// -- test if card supports 0x0A -static int test_desfire_authenticate(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// -- test if card supports 0x1A -static int test_desfire_authenticate_iso(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// -- test if card supports 0xAA -static int test_desfire_authenticate_aes(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// --- GET FREE MEM -static int desfire_print_freemem(uint32_t free_mem) { - PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem); - return PM3_SUCCESS; -} - -static int handler_desfire_freemem(uint32_t *free_mem) { - if (free_mem == NULL) return PM3_EINVARG; - - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, data}; // 0x6E - *free_mem = 0; - uint32_t recv_len = 0; - uint16_t sw = 0; - uint8_t fmem[4] = {0}; - - size_t plen = apdu.Lc; - uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND); - apdu.Lc = (uint8_t)plen; - apdu.data = p; - - int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS) - return res; - - size_t dlen = recv_len; - p = mifare_cryto_postprocess_data(tag, apdu.data, &dlen, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); - (void)p; - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - *free_mem = le24toh(fmem); - return res; -} - /*static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) { if (new_key == NULL || old_key == NULL) { @@ -1093,155 +1012,6 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat return PM3_SUCCESS; } -static int handler_desfire_signature(uint8_t *signature, size_t *signature_len) { - - if (signature == NULL) { - PrintAndLogEx(DEBUG, "SIGNATURE=NULL"); - return PM3_EINVARG; - } - if (signature_len == NULL) { - PrintAndLogEx(DEBUG, "SIGNATURE_LEN=NULL"); - return PM3_EINVARG; - } - - uint8_t c[] = {0x00}; - sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, sizeof(c), c}; // 0x3C - - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true); - if (res == PM3_SUCCESS) { - if (recv_len != 56) { - *signature_len = 0; - res = PM3_ESOFT; - } else { - *signature_len = recv_len; - } - } - DropFieldDesfire(); - return res; -} - -// --- KEY VERSION -static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) { - PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version); - return PM3_SUCCESS; -} - -static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { - if (num_versions == NULL) { - PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL"); - return PM3_EINVARG; - } - sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS) - return res; - - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - return res; -} - -// --- KEY SETTING Application Master Key -static int desfire_print_amk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { - PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings); - // 2 MSB denotes - const char *str = " Max key number and type : %d, " _YELLOW_("%s"); - - if (algo == MFDES_ALGO_DES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES"); - else if (algo == MFDES_ALGO_AES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES"); - else if (algo == MFDES_ALGO_3K3DES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES"); - - //PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(SUCCESS, " Changekey Access rights"); - - // Access rights. - uint8_t rights = ((key_settings >> 4) & 0x0F); - switch (rights) { - case 0x0: - PrintAndLogEx(SUCCESS, " -- AMK authentication is necessary to change any key (default)"); - break; - case 0xE: - PrintAndLogEx(SUCCESS, " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key"); - break; - case 0xF: - PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen"); - break; - default: - PrintAndLogEx(SUCCESS, - " -- Authentication with the specified key is necessary to change any key.\n" - "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n" - "For keys other then the master or change key, an authentication with the same key is needed." - ); - break; - } - - PrintAndLogEx(SUCCESS, " [%c...] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, " [.%c..] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [...%c] AMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); - return PM3_SUCCESS; -} - -// --- KEY SETTING PICC Master Key (CMK) -static int desfire_print_piccmk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { - //PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings")); - // number of Master keys (0x01) - PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); - const char *str = " Operation of PICC master key : " _YELLOW_("%s"); - - if (algo == MFDES_ALGO_DES) - PrintAndLogEx(SUCCESS, str, "(3)DES"); - else if (algo == MFDES_ALGO_AES) - PrintAndLogEx(SUCCESS, str, "AES"); - else if (algo == MFDES_ALGO_3K3DES) - PrintAndLogEx(SUCCESS, str, "3K3DES"); - - uint8_t cmk_num_versions = 0; - if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions); - } - - PrintAndLogEx(INFO, " ----------------------------------------------------------"); - - // Authentication tests - int res = test_desfire_authenticate(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_iso(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_aes(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, " Key setting: 0x%02X [%c%c%c%c]", - key_settings, - (key_settings & (1 << 3)) ? '1' : '0', - (key_settings & (1 << 2)) ? '1' : '0', - (key_settings & (1 << 1)) ? '1' : '0', - (key_settings & (1 << 0)) ? '1' : '0' - ); - - PrintAndLogEx(SUCCESS, " [%c...] CMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, " [.%c..] CMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with CMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, " [...%c] CMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); - return PM3_SUCCESS; -} - static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_keys) { if (key_settings == NULL) { PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL"); @@ -1322,28 +1092,6 @@ static int handler_desfire_select_application(uint8_t *aid) { return PM3_SUCCESS; } -static int key_setting_to_algo(uint8_t aid[3], uint8_t *key_setting, mifare_des_authalgo_t *algo, uint8_t *num_keys) { - int res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - *num_keys = 0; - res = handler_desfire_getkeysettings(key_setting, num_keys); - if (res == PM3_SUCCESS) { - switch (*num_keys >> 6) { - case 0: - *algo = MFDES_ALGO_DES; - break; - case 1: - *algo = MFDES_ALGO_3K3DES; - break; - case 2: - *algo = MFDES_ALGO_AES; - break; - } - } - return res; -} - static int handler_desfire_fileids(uint8_t *dest, uint32_t *file_ids_len) { if (g_debugMode > 1) { if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); @@ -1382,70 +1130,6 @@ static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t return res; } -static int getKeySettings(uint8_t *aid) { - if (aid == NULL) return PM3_EINVARG; - - uint8_t num_keys = 0; - uint8_t key_setting = 0; - int res = 0; - if (memcmp(aid, "\x00\x00\x00", 3) == 0) { - - // CARD MASTER KEY - //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); - - // KEY Settings - AMK - mifare_des_authalgo_t algo = MFDES_ALGO_DES; - res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); - - if (res == PM3_SUCCESS) { - desfire_print_piccmk_keysetting(key_setting, num_keys, algo); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read PICC Master key settings")); - } - - } else { - - // AID - APPLICATION MASTER KEYS - //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); - res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - // KEY Settings - AMK - mifare_des_authalgo_t algo = MFDES_ALGO_DES; - res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); - if (res == PM3_SUCCESS) { - desfire_print_amk_keysetting(key_setting, num_keys, algo); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); - } - - // KEY VERSION - AMK - uint8_t num_version = 0; - if (handler_desfire_keyversion(0, &num_version) == PM3_SUCCESS) { - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, " Application keys"); - desfire_print_keyversion(0, num_version); - } else { - PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys"); - } - - // From 0x01 to numOfKeys. We already got 0x00. (AMK) - num_keys &= 0x3F; - if (num_keys > 1) { - for (uint8_t i = 0x01; i < num_keys; ++i) { - if (handler_desfire_keyversion(i, &num_version) == PM3_SUCCESS) { - desfire_print_keyversion(i, num_version); - } else { - PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i); - } - } - } - } - - DropFieldDesfire(); - return PM3_SUCCESS; -} - static void swap24(uint8_t *data) { if (data == NULL) return; uint8_t tmp = data[0]; @@ -1632,35 +1316,45 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (major == 0 && minor == 2) PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); - + + DesfireContext dctx = {0}; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCNative; + res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (res != PM3_SUCCESS) + return res; + if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3 || cardtype == NTAG413DNA) { // Signature originality check - uint8_t signature[56] = {0}; + uint8_t signature[250] = {0}; // must be 56 size_t signature_len = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); - if (handler_desfire_signature(signature, &signature_len) == PM3_SUCCESS) { - desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype); + res = DesfireReadSignature(&dctx, 0x00, signature, &signature_len); + if (res == PM3_SUCCESS) { + if (signature_len == 56) + desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype); + else + PrintAndLogEx(WARNING, "--- GetSignature returned wrong signature length: %zu", signature_len); } else { PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd"); } } - - // Master Key settings - uint8_t master_aid[3] = {0x00, 0x00, 0x00}; - getKeySettings(master_aid); + + PICCInfoS PICCInfo = {0}; + DesfireFillPICCInfo(&dctx, &PICCInfo, true); + DesfirePrintPICCInfo(&dctx, &PICCInfo); if (cardtype != DESFIRE_LIGHT) { // Free memory on card PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Free memory")); - uint32_t free_mem = 0; - if (handler_desfire_freemem(&free_mem) == PM3_SUCCESS) { - desfire_print_freemem(free_mem); + if (PICCInfo.freemem != 0xffffffff) { + PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), PICCInfo.freemem); } else { PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); } @@ -5863,14 +5557,14 @@ static int CmdHF14ADesTest(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"}, + {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"}, + {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get uid from card"}, {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "MIFARE DesFire Authentication"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "[old]Check keys"}, - {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"freemem", CmdHF14ADesGetFreeMem, IfPm3Iso14443a, "Get free memory size"}, - {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get uid from card"}, {"setconfig", CmdHF14ADesSetConfiguration, IfPm3Iso14443a, "Set card configuration"}, - {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "[old]Tag information"}, + {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"}, // {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"}, From 857d67d7332a698b8c2cb4537143e8084a2a80f5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 00:19:11 +0300 Subject: [PATCH 22/80] some fixes in info command --- client/src/cmdhfmfdes.c | 21 ++++++++++++++------- client/src/mifare/desfirecore.c | 4 +++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 3f0bcbeeb..1b3d42862 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1255,7 +1255,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - DropFieldDesfire(); + DropField(); mfdes_info_res_t info; int res = mfdes_get_info(&info); @@ -1270,8 +1270,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "---------------------------------- " _CYAN_("Tag Information") " ----------------------------------"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen)); PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5)); PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]); @@ -1296,7 +1295,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionSW[6], false)); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities")); + PrintAndLogEx(INFO, "--------------------------------- " _CYAN_("Card capabilities") " ---------------------------------"); uint8_t major = info.versionSW[3]; uint8_t minor = info.versionSW[4]; if (major == 0 && minor == 4) @@ -1324,6 +1323,15 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (res != PM3_SUCCESS) return res; + PICCInfoS PICCInfo = {0}; + + uint8_t buf[250] = {0}; + size_t buflen = 0; + res = DesfireGetAIDList(&dctx, buf, &buflen); + if (res == PM3_SUCCESS) { + PICCInfo.appCount = buflen / 3; + } + if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3 || @@ -1345,7 +1353,6 @@ static int CmdHF14ADesInfo(const char *Cmd) { } } - PICCInfoS PICCInfo = {0}; DesfireFillPICCInfo(&dctx, &PICCInfo, true); DesfirePrintPICCInfo(&dctx, &PICCInfo); @@ -1358,8 +1365,8 @@ static int CmdHF14ADesInfo(const char *Cmd) { } else { PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); } + PrintAndLogEx(NORMAL, ""); iso14a_card_select_t card; @@ -1402,7 +1409,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { */ - DropFieldDesfire(); + DropField(); return PM3_SUCCESS; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 438125051..01f4b2b2b 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1934,8 +1934,10 @@ static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool prin PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); - if (print2ndbyte) + if (print2ndbyte) { + DesfirePrintCardKeyType(numkeys >> 6); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); + } } static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { From 4e7603d2d7f335f64ceb5fa0313de6e2ad240f84 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 12:23:44 +0300 Subject: [PATCH 23/80] lsapp field on/off fix --- client/src/mifare/desfirecore.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 01f4b2b2b..22bca2196 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1530,9 +1530,15 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } } + // field on-off zone + DesfireFillPICCInfo(dctx, PICCInfo, deepmode); + if (PICCInfo->appCount > 0) { for (int i = 0; i < PICCInfo->appCount; i++) { - res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum); + if (i == 0) + res = DesfireSelectAIDHex(dctx, appList[i].appNum, false, 0); + else + res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum); if (res != PM3_SUCCESS) continue; @@ -1562,8 +1568,6 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } // field on-off zone - DesfireFillPICCInfo(dctx, PICCInfo, deepmode); - if (PICCInfo->appCount > 0 && deepmode) { for (int i = 0; i < PICCInfo->appCount; i++) { DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); From 7e4ad7a3f971b421a760f4e30719fe1987a3b4c6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 13:22:41 +0300 Subject: [PATCH 24/80] info improvements --- client/src/cmdhfmfdes.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 1b3d42862..7dc1d201c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1325,11 +1325,11 @@ static int CmdHF14ADesInfo(const char *Cmd) { PICCInfoS PICCInfo = {0}; - uint8_t buf[250] = {0}; - size_t buflen = 0; - res = DesfireGetAIDList(&dctx, buf, &buflen); + uint8_t aidbuf[250] = {0}; + size_t aidbuflen = 0; + res = DesfireGetAIDList(&dctx, aidbuf, &aidbuflen); if (res == PM3_SUCCESS) { - PICCInfo.appCount = buflen / 3; + PICCInfo.appCount = aidbuflen / 3; } if (cardtype == DESFIRE_EV2 || @@ -1353,6 +1353,15 @@ static int CmdHF14ADesInfo(const char *Cmd) { } } + if (aidbuflen > 2) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list")); + PrintAndLogEx(SUCCESS, "AIDs: " NOLF); + for (int i = 0; i < aidbuflen; i += 3) + PrintAndLogEx(NORMAL, "%s %06x" NOLF, (i == 0) ? "" : ",", DesfireAIDByteToUint(&aidbuf[i])); + PrintAndLogEx(NORMAL, "\n"); + } + DesfireFillPICCInfo(&dctx, &PICCInfo, true); DesfirePrintPICCInfo(&dctx, &PICCInfo); From 4cc8483711f320b3cc0dc4f717e86843fc2ad52a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 14:43:16 +0300 Subject: [PATCH 25/80] add to `select` : select MF via iso and select EF by ISO ID via ISO --- client/src/cmdhfmfdes.c | 50 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e93531403..2751255dd 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3038,7 +3038,10 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes selectapp", "Select application on the card. It selects app if it is a valid one or returns an error.", - "hf mfdes selectapp --aid 123456 -> select application 123456"); + "hf mfdes selectapp --aid 123456 -> select application 123456\n" + "hf mfdes selectapp --mf -> select master file (PICC level)\n" + "hf mfdes selectapp --dfname aid123456 -> select application aid123456 by DF name\n" + "hf mfdes selectapp --isoid 1111 -> select application 1111 by ISO ID"); void *argtable[] = { arg_param_begin, @@ -3054,6 +3057,8 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), arg_str0(NULL, "aid", "", "Application ID of application for some parameters (3 hex bytes, big endian)"), arg_str0(NULL, "dfname", "", "Application DF Name (string, max 16 chars). Selects application via ISO SELECT command"), + arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), + arg_lit0(NULL, "mf", "Select MF (master file) via ISO channel"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3074,12 +3079,49 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { int dfnamelen = 16; CLIGetStrWithReturn(ctx, 12, dfname, &dfnamelen); + uint32_t isoid = 0x0000; + res = arg_get_u32_hexstr_def_nlen(ctx, 13, 0x0000, &isoid, 2, true); + bool idsoidpresent = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "ISO ID for EF or DF must have 2 bytes length"); + return PM3_EINVARG; + } + + bool selectmf = arg_get_lit(ctx, 14); + SetAPDULogging(APDULogging); CLIParserFree(ctx); - if (dctx.cmdSet == DCCISO || dfnamelen > 0) { - uint8_t resp[250] = {0}; - size_t resplen = 0; + uint8_t resp[250] = {0}; + size_t resplen = 0; + + if (selectmf) { + res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, resp, &resplen); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "ISO Select MF " _RED_("failed")); + return res; + } + + if (resplen > 0) + PrintAndLogEx(FAILED, "Application " _CYAN_("FCI template") " [%zu]%s", resplen, sprint_hex(resp, resplen)); + + PrintAndLogEx(SUCCESS, "PICC MF selected " _GREEN_("succesfully")); + } else if (idsoidpresent) { + uint8_t data[2] = {0}; + Uint2byteToMemLe(data, isoid); + res = DesfireISOSelect(&dctx, ISSMFDFEF, data, 2, resp, &resplen); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "ISO Select DF 0x%04x " _RED_("failed"), isoid); + return res; + } + + if (resplen > 0) + PrintAndLogEx(FAILED, "Application " _CYAN_("FCI template") " [%zu]%s", resplen, sprint_hex(resp, resplen)); + + PrintAndLogEx(SUCCESS, "PICC DF 0x%04x selected " _GREEN_("succesfully"), isoid); + } else if (dctx.cmdSet == DCCISO || dfnamelen > 0) { if (dfnamelen > 0) res = DesfireISOSelectDF(&dctx, (char *)dfname, resp, &resplen); else From e65c2dc91548fa2f400d94f0a852abdf6cfc5ec3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 14:59:27 +0300 Subject: [PATCH 26/80] add change keys command samples --- client/src/cmdhfmfdes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e93531403..79766114c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3370,7 +3370,13 @@ static int CmdHF14ADesChangeKey(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes changekey", "Change PICC/Application key. Needs to provide keynum/key for a valid authentication (may get from default parameters).", - "hf mfdes changekey --aid 123456 -> execute with default factory setup"); + "Change crypto algorithm for PICC key is possible, but for APP keys crypto algorithm is set by createapp command and can't be changed wo application delete\n" + "\n" + "hf mfdes changekey --aid 123456 -> execute with default factory setup. change des key 0 in the app 123456 from 00..00 to 00..00\n" + "hf mfdes changekey -t des --newalgo aes --newkey 11223344556677889900112233445566 --newver a5 -> change card master key to AES one\n" + "hf mfdes changekey --aid 123456 -t aes --key 00000000000000000000000000000000 --newkey 11223344556677889900112233445566 -> change app master key\n" + "hf mfdes changekey --aid 123456 -t des -n 0 --newkeyno 1 --oldkey 5555555555555555 --newkey 1122334455667788 -> change key 1 with auth from key 0\n" + "hf mfdes changekey --aid 123456 -t 3tdea --newkey 112233445566778899001122334455667788990011223344-> change 3tdea key 0 from default 00..00 to provided"); void *argtable[] = { arg_param_begin, From e7414e127d44746c14bceb7f07ea95f5ca6f9778 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 17:41:55 +0300 Subject: [PATCH 27/80] test --- client/src/mifare/desfiretest.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index c08d7600d..aa9ffebad 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -269,6 +269,40 @@ static bool TestEV2IVEncode(void) { return res; } +static bool TestEV2MAC(void) { + bool res = true; + + uint8_t key[] = {0x93, 0x66, 0xFA, 0x19, 0x5E, 0xB5, 0x66, 0xF5, 0xBD, 0x2B, 0xAD, 0x40, 0x20, 0xB8, 0x30, 0x02}; + uint8_t ti[] = {0xE2, 0xD3, 0xAF, 0x69}; + uint8_t cmd = 8D; + uint8_t cmddata = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22} + uint8_t macres[] = {0x68, 0xF2, 0xC2, 0x8C, 0x57, 0x5A, 0x16, 0x28}; + + DesfireContext ctx = {0}; + ctx.keyType = T_AES; + memcpy(ctx.sessionKeyMAC, key, 16); + memcpy(ctx.TI, ti, 4); + ctx.cmdCntr = 0; + + uint8_t mac[16] = {0}; + DesfireEV2CalcCMAC(&ctx, cmd, cmddata, sizeof(cmddata), mac); + res = res && (memcmp(mac, macres, sizeof(macres)) == 0); + + memset(mac, 0, sizeof(mac)); + uint8_t macres2[] = {0x08, 0x20, 0xF6, 0x88, 0x98, 0xC2, 0xA7, 0xF1}; + uint8_t rc = 0; + ctx.cmdCntr++; + DesfireEV2CalcCMAC(&ctx, rc, NULL, 0, mac); + res = res && (memcmp(mac, macres2, sizeof(macres2)) == 0); + + if (res) + PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail")); + + return res; + bool DesfireTest(bool verbose) { bool res = true; @@ -281,6 +315,7 @@ bool DesfireTest(bool verbose) { res = res && TestCMACDES(); res = res && TestEV2SessionKeys(); res = res && TestEV2IVEncode(); + res = res && TestEV2MAC(); PrintAndLogEx(INFO, "---------------------------"); if (res) From fa309476988bfdc3cd616764d29e1ad91c48f177 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 17:55:28 +0300 Subject: [PATCH 28/80] mac calc --- client/src/mifare/desfirecrypto.c | 13 +++++++++++++ client/src/mifare/desfirecrypto.h | 1 + 2 files changed, 14 insertions(+) diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index ba82cdae0..7501de141 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -474,6 +474,19 @@ void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv) { memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE); } +int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) { + uint8_t mdata[1050] = {0}; + size_t mdatalen = 0; + + mdata[0] = cmd; + Uint2byteToMemLe(&mdata[1], ctx->cmdCntr); + memcpy(&mdata[3], ctx->TI, 4); + if (data != NULL && datalen > 0) + memcpy(&mdata[7], data, datalen); + mdatalen = 1 + 2 + 4 + datalen; + + return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen); +} void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) { crc32_ex(data, len, crc); diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index a336f9e3f..2de188981 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -113,6 +113,7 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key); void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey); void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv); +int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac); void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc); void desfire_crc32_append(uint8_t *data, const size_t len); From 22c2b4601075a2321eae9ea26f95398599876be3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 18:03:17 +0300 Subject: [PATCH 29/80] add tests --- client/src/mifare/desfiretest.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index aa9ffebad..350cad4f8 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -269,26 +269,31 @@ static bool TestEV2IVEncode(void) { return res; } +// https://www.nxp.com/docs/en/application-note/AN12343.pdf +// page 54 static bool TestEV2MAC(void) { bool res = true; uint8_t key[] = {0x93, 0x66, 0xFA, 0x19, 0x5E, 0xB5, 0x66, 0xF5, 0xBD, 0x2B, 0xAD, 0x40, 0x20, 0xB8, 0x30, 0x02}; uint8_t ti[] = {0xE2, 0xD3, 0xAF, 0x69}; - uint8_t cmd = 8D; - uint8_t cmddata = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22} + uint8_t cmd = 0x8D; + uint8_t cmddata[] = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; uint8_t macres[] = {0x68, 0xF2, 0xC2, 0x8C, 0x57, 0x5A, 0x16, 0x28}; + // init DesfireContext ctx = {0}; ctx.keyType = T_AES; memcpy(ctx.sessionKeyMAC, key, 16); memcpy(ctx.TI, ti, 4); ctx.cmdCntr = 0; + // tx 1 uint8_t mac[16] = {0}; DesfireEV2CalcCMAC(&ctx, cmd, cmddata, sizeof(cmddata), mac); res = res && (memcmp(mac, macres, sizeof(macres)) == 0); + // rx 1 memset(mac, 0, sizeof(mac)); uint8_t macres2[] = {0x08, 0x20, 0xF6, 0x88, 0x98, 0xC2, 0xA7, 0xF1}; uint8_t rc = 0; @@ -296,12 +301,31 @@ static bool TestEV2MAC(void) { DesfireEV2CalcCMAC(&ctx, rc, NULL, 0, mac); res = res && (memcmp(mac, macres2, sizeof(macres2)) == 0); + // tx 2 + memset(mac, 0, sizeof(mac)); + cmd = 0xAD; + uint8_t cmddata3[] = {0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}; + uint8_t macres3[] = {0x0D, 0x9B, 0xE1, 0x91, 0xD5, 0x96, 0x08, 0x34}; + DesfireEV2CalcCMAC(&ctx, cmd, cmddata3, sizeof(cmddata3), mac); + res = res && (memcmp(mac, macres3, sizeof(macres3)) == 0); + + // rx 2 + rc = 0; + ctx.cmdCntr++; + uint8_t cmddata4[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t macres4[] = {0xA4, 0x9A, 0x44, 0x22, 0x2D, 0x92, 0x66, 0x66}; + DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac); + res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0); + if (res) PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("passed")); else PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail")); return res; +} bool DesfireTest(bool verbose) { bool res = true; From 58e8693b49d25910dbea9b7fbe2b3c3f30933af2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 18:33:06 +0300 Subject: [PATCH 30/80] ev2 tx channel sketch --- client/src/mifare/desfiresecurechan.c | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 73aba69a6..c0ee5273f 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -244,9 +244,47 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint } static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + uint8_t data[1050] = {0}; + size_t rlen = 0; + memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; + uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + + if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) { + + if (srcdatalen > hdrlen && ctx->commMode == DCMMACed) { + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireEV2CalcCMAC(ctx, cmd, data, srcdatalen, cmac); + + memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); + *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); + } + } else if (ctx->commMode == DCMEncrypted) { + //uint8_t iv[CRYPTO_AES_BLOCK_SIZE] = {0}; + DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx + + rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); + memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); + data[hdrlen] = 0x80; // padding + + dstdata[0] = cmd; + memcpy(&dstdata[1], srcdata, hdrlen); + DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[1 + hdrlen], true); + + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireEV2CalcCMAC(ctx, cmd, &dstdata[1], hdrlen + rlen, cmac); + + memcpy(&dstdata[ + hdrlen + rlen], cmac, DesfireGetMACLength(ctx)); + + *dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx); + } else if (ctx->commMode == DCMEncryptedPlain) { + if (srcdatalen <= hdrlen) + return; + + // TODO !!! + } } void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { From 8d84e967169672eab582d869831408fd96072fda Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 18:49:52 +0300 Subject: [PATCH 31/80] ev2 rx channel sketch --- client/src/mifare/desfiresecurechan.c | 48 ++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index c0ee5273f..bd732e6a8 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -262,7 +262,6 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } } else if (ctx->commMode == DCMEncrypted) { - //uint8_t iv[CRYPTO_AES_BLOCK_SIZE] = {0}; DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); @@ -415,6 +414,53 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + + // if comm mode = plain --> response with MAC + // if request is not zero length --> response MAC + if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) { + if (srcdatalen < DesfireGetMACLength(ctx)) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + return; + } + + memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx)); + *dstdatalen = srcdatalen - DesfireGetMACLength(ctx); + + DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac); + if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { + PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + } + } else if (ctx->commMode == DCMEncrypted) { + if (srcdatalen < desfire_get_key_block_length(ctx->keyType) + DesfireGetMACLength(ctx)) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + return; + } + + *dstdatalen = srcdatalen - DesfireGetMACLength(ctx); + DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac); + if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { + PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + } + + DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx + + DesfireCryptoEncDec(ctx, true, srcdata, *dstdatalen, dstdata, false); + PrintAndLogEx(INFO, "decoded[%d]: %s", *dstdatalen, sprint_hex(dstdata, *dstdatalen)); + + size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen); + if (puredatalen != 0) { + *dstdatalen = puredatalen; + } else { + PrintAndLogEx(WARNING, "Padding search error."); + } + } } void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { From fd5afbdfac4bbdea4c64cb3df84b66ea462e42b0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 18:58:39 +0300 Subject: [PATCH 32/80] encode fix --- client/src/mifare/desfiresecurechan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index bd732e6a8..2314f7df5 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -254,7 +254,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) { - if (srcdatalen > hdrlen && ctx->commMode == DCMMACed) { + if (ctx->commMode == DCMMACed || ctx->commMode == DCMEncrypted) { uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; DesfireEV2CalcCMAC(ctx, cmd, data, srcdatalen, cmac); From 645985a1f90045387183d34058f131505e1dbd1a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 3 Aug 2021 19:08:30 +0300 Subject: [PATCH 33/80] check mode in ev2 like ev1 --- client/src/mifare/desfirecore.c | 2 +- client/src/mifare/desfiresecurechan.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index e60093317..869be3d0e 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -347,7 +347,7 @@ void DesfirePrintContext(DesfireContext *ctx) { desfire_get_key_block_length(ctx->keyType), sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType))); if (ctx->secureChannel == DACEV2) { - PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%08x", + PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%04x", sprint_hex(ctx->TI, 4), ctx->cmdCntr); } diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 2314f7df5..1fc5ed78a 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -256,7 +256,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint if (ctx->commMode == DCMMACed || ctx->commMode == DCMEncrypted) { uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; - DesfireEV2CalcCMAC(ctx, cmd, data, srcdatalen, cmac); + DesfireEV2CalcCMAC(ctx, cmd, srcdata, srcdatalen, cmac); memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); @@ -515,6 +515,15 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De break; } + // ev2 like ev1 + if (secureChannel == DACEV2 && + AllowedChannelModes[i].secureChannel == DACEV1 && + (AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) && + AllowedChannelModes[i].commMode == commMode) { + + found = true; + break; + } } if (!found) From fc8e3e8851bfb11b037de3afc838d97f108056fd Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 14:58:07 +0300 Subject: [PATCH 34/80] fix ev2 auth. ev2/enc/nodata works --- client/src/mifare/desfirecore.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 869be3d0e..1a1890b11 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1153,6 +1153,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0}; uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; + uint8_t rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA' uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB' uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') @@ -1201,8 +1202,6 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); rol(rotRndB, CRYPTO_AES_BLOCK_SIZE); - uint8_t encRndA[16] = {0x00}; - // - Encrypt our response uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE); @@ -1232,20 +1231,21 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec } // Part 4 - memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE); - uint8_t data[32] = {0}; if (aes_decode(IV, key, recv_data, data, recv_len)) return 10; - rol(RndA, CRYPTO_AES_BLOCK_SIZE); + // rotate rndA to check + memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE); + rol(rotRndA, CRYPTO_AES_BLOCK_SIZE); + uint8_t *recRndA = (firstauth) ? &data[4] : data; - if (memcmp(RndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { + if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); - PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); } return 11; } From 51b197c3a60adc091b7aff6363d1fece4ae8c128 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 15:26:40 +0300 Subject: [PATCH 35/80] ev2 encrypted channel tx works --- client/src/mifare/desfirecore.c | 4 ++-- client/src/mifare/desfirecrypto.c | 19 +++++++++++-------- client/src/mifare/desfirecrypto.h | 9 +++++++-- client/src/mifare/desfiresecurechan.c | 25 +++++++++++++------------ 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 1a1890b11..454616643 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1295,7 +1295,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec // encode DesfireClearIV(dctx); - DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303 + DesfireCryptoEncDec(dctx, DCOMainKey, both, rndlen * 2, both, true); // error 303 // external authenticate res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both); @@ -1314,7 +1314,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec // decode rnddata uint8_t piccrnd2[64] = {0}; - DesfireCryptoEncDec(dctx, false, rnddata, rndlen * 2, piccrnd2, false); // error 307 + DesfireCryptoEncDec(dctx, DCOMainKey, rnddata, rndlen * 2, piccrnd2, false); // error 307 // check if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0) diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 7501de141..95dc95b0e 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -217,7 +217,7 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm memcpy(dstdata, edata, block_size); } -void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) { +void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) { uint8_t data[1024] = {0}; uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; @@ -234,10 +234,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s size_t offset = 0; while (offset < srcdatalen) { - if (use_session_key) + if (key_type == DCOSessionKeyMac) { DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); - else + } else if (key_type == DCOSessionKeyEnc) { + DesfireCryptoEncDecSingleBlock(ctx->sessionKeyEnc, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); + } else { DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); + } offset += block_size; } @@ -250,13 +253,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s memcpy(dstdata, data, srcdatalen); } -void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { +void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { bool dir_to_send = encode; bool xencode = encode; if (ctx->secureChannel == DACd40) xencode = false; - DesfireCryptoEncDecEx(ctx, use_session_key, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); + DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); } static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) { @@ -269,7 +272,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_ uint8_t ivect[kbs]; memset(ivect, 0, kbs); - DesfireCryptoEncDecEx(ctx, true, l, kbs, l, true, true, ivect); + DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect); bool txor = false; @@ -314,7 +317,7 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t * bin_xor(buffer + len - kbs, sk1, kbs); } - DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true); + DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true); if (cmac != NULL) memcpy(cmac, ctx->IV, kbs); @@ -484,7 +487,7 @@ int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t d if (data != NULL && datalen > 0) memcpy(&mdata[7], data, datalen); mdatalen = 1 + 2 + 4 + datalen; - + return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen); } diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 2de188981..dfc9a0685 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -61,6 +61,11 @@ typedef enum { DCMEncryptedPlain } DesfireCommunicationMode; +typedef enum { + DCOMainKey, + DCOSessionKeyMac, + DCOSessionKeyEnc +} DesfireCryptoOpKeyType; typedef struct DesfireContextS { uint8_t keyNum; @@ -100,8 +105,8 @@ size_t DesfireGetMACLength(DesfireContext *ctx); size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen); -void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode); -void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv); +void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode); +void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv); void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac); void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 1fc5ed78a..0f6ad2bd4 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -166,7 +166,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); uint8_t mac[32] = {0}; - DesfireCryptoEncDecEx(ctx, true, data, srcmaclen, NULL, true, true, mac); + DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac); memcpy(dstdata, srcdata, srcdatalen); memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); @@ -181,7 +181,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint memcpy(dstdata, srcdata, hdrlen); //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2)); - DesfireCryptoEncDec(ctx, true, data, rlen - hdrlen, &dstdata[hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen - hdrlen, &dstdata[hdrlen], true); *dstdatalen = rlen; } else if (ctx->commMode == DCMEncryptedPlain) { @@ -191,7 +191,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; memcpy(data, srcdata, srcdatalen); memcpy(dstdata, srcdata, hdrlen); - DesfireCryptoEncDec(ctx, true, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true); *dstdatalen = rlen; ctx->commMode = DCMEncrypted; } @@ -227,7 +227,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint desfire_crc32_append(data, srcdatalen + 1); memcpy(dstdata, srcdata, hdrlen); - DesfireCryptoEncDec(ctx, true, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true); *dstdatalen = hdrlen + rlen; } else if (ctx->commMode == DCMEncryptedPlain) { @@ -237,7 +237,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint memcpy(dstdata, srcdata, hdrlen); memcpy(data, &srcdata[hdrlen], srcdatalen); rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); - DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[hdrlen], true); *dstdatalen = hdrlen + rlen; ctx->commMode = DCMEncrypted; } @@ -270,7 +270,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint dstdata[0] = cmd; memcpy(&dstdata[1], srcdata, hdrlen); - DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[1 + hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[1 + hdrlen], true); uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; DesfireEV2CalcCMAC(ctx, cmd, &dstdata[1], hdrlen + rlen, cmac); @@ -321,7 +321,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, uint8_t mac[16] = {0}; rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType)); memcpy(data, srcdata, srcdatalen - maclen); - DesfireCryptoEncDecEx(ctx, true, data, rlen, NULL, true, true, mac); + DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, rlen, NULL, true, true, mac); if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) { *dstdatalen = srcdatalen - maclen; @@ -340,7 +340,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, return; } - DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2); @@ -392,7 +392,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, return; } - DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4); @@ -447,12 +447,13 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + } else { + //PrintAndLogEx(INFO, "Received MAC OK"); } - DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx + DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx - DesfireCryptoEncDec(ctx, true, srcdata, *dstdatalen, dstdata, false); - PrintAndLogEx(INFO, "decoded[%d]: %s", *dstdatalen, sprint_hex(dstdata, *dstdatalen)); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, *dstdatalen, dstdata, false); size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen); if (puredatalen != 0) { From 3baf5955781de0b3d58e08efa97feafa6050f690 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 15:48:20 +0300 Subject: [PATCH 36/80] make style --- client/src/cmdhfmfdes.c | 28 +++---- client/src/mifare/desfirecore.c | 94 +++++++++++----------- client/src/mifare/desfirecore.h | 10 +-- client/src/mifare/desfirecrypto.c | 2 +- client/src/mifare/desfiresecurechan.c | 4 +- client/src/mifare/desfiretest.c | 16 ++-- doc/commands.json | 107 ++++++++++++++++---------- doc/commands.md | 20 ++--- 8 files changed, 154 insertions(+), 127 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index ceb29fca4..11cff911c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1315,23 +1315,23 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (major == 0 && minor == 2) PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); - + DesfireContext dctx = {0}; dctx.commMode = DCMPlain; dctx.cmdSet = DCCNative; res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); if (res != PM3_SUCCESS) return res; - + PICCInfoS PICCInfo = {0}; - + uint8_t aidbuf[250] = {0}; size_t aidbuflen = 0; res = DesfireGetAIDList(&dctx, aidbuf, &aidbuflen); if (res == PM3_SUCCESS) { PICCInfo.appCount = aidbuflen / 3; - } - + } + if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3 || @@ -1352,16 +1352,16 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd"); } } - + if (aidbuflen > 2) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list")); PrintAndLogEx(SUCCESS, "AIDs: " NOLF); for (int i = 0; i < aidbuflen; i += 3) - PrintAndLogEx(NORMAL, "%s %06x" NOLF, (i == 0) ? "" : ",", DesfireAIDByteToUint(&aidbuf[i])); + PrintAndLogEx(NORMAL, "%s %06x" NOLF, (i == 0) ? "" : ",", DesfireAIDByteToUint(&aidbuf[i])); PrintAndLogEx(NORMAL, "\n"); } - + DesfireFillPICCInfo(&dctx, &PICCInfo, true); DesfirePrintPICCInfo(&dctx, &PICCInfo); @@ -5450,7 +5450,7 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { DropField(); return PM3_SUCCESS; -} +} static int CmdHF14ADesLsApp(const char *Cmd) { CLIParserContext *ctx; @@ -5494,26 +5494,26 @@ static int CmdHF14ADesLsApp(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - + PrintAndLogEx(INPLACE, _YELLOW_("It may take up to 15 seconds. Processing....")); - + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); return res; } - + PICCInfoS PICCInfo = {0}; AppListS AppList = {0}; DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles); printf("\33[2K\r"); // clear current line before printing PrintAndLogEx(NORMAL, ""); - + // print zone DesfirePrintPICCInfo(&dctx, &PICCInfo); DesfirePrintAppList(&dctx, &PICCInfo, AppList); - + DropField(); return PM3_SUCCESS; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index ddfa07685..b75ec45bd 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1266,7 +1266,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec // rotate rndA to check memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE); rol(rotRndA, CRYPTO_AES_BLOCK_SIZE); - + uint8_t *recRndA = (firstauth) ? &data[4] : data; if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { @@ -1375,7 +1375,7 @@ static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd size_t recv_len = 0; uint8_t respcode = 0; uint8_t recv_data[256] = {0}; - + DesfireContext dctx = {0}; dctx.keyNum = keyNum; dctx.commMode = DCMPlain; @@ -1393,14 +1393,14 @@ static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd } static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorythm keytype) { - + DesfireContext dctx = {0}; dctx.keyNum = keyNum; dctx.commMode = DCMPlain; dctx.cmdSet = DCCISO; bool app_level = (appAID != 0x000000); - int res = 0; + int res = 0; if (dfname == NULL || strnlen(dfname, 16) == 0) { if (appAID == 0x000000) { res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, NULL, NULL); @@ -1417,21 +1417,21 @@ static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum return false; app_level = true; } - + uint8_t rndlen = DesfireGetRndLenForKey(keytype); - + uint8_t piccrnd[64] = {0}; size_t xlen = 0; res = DesfireISOGetChallenge(&dctx, keytype, piccrnd, &xlen); if (res != PM3_SUCCESS || xlen != rndlen) return false; - + uint8_t resp[250] = {0}; size_t resplen = 0; - + uint16_t sw = 0; uint8_t p1 = DesfireKeyToISOKey(keytype); - uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum; + uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum; res = DesfireExchangeISO(false, &dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw); DropField(); return (sw == 0x9000 || sw == 0x6982); @@ -1439,7 +1439,7 @@ static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck) { memset(authCmdCheck, 0, sizeof(AuthCommandsChk)); - + authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE); authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO); authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); @@ -1450,12 +1450,12 @@ void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, Aut void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", - authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), - authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), - authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), - authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"), - authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO") - ); + authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO") + ); } int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode) { @@ -1468,7 +1468,7 @@ int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode PICCInfo->freemem = freemem; else PICCInfo->freemem = 0xffffffff; - + PICCInfo->keySettings = 0; PICCInfo->numKeysRaw = 0; PICCInfo->keyVersion0 = 0; @@ -1489,14 +1489,14 @@ int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode // field on-off zone if (deepmode) DesfireCheckAuthCommands(0x000000, NULL, 0, &PICCInfo->authCmdCheck); - + return PM3_SUCCESS; } static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) { - for (int i = 0; i < appcount; i++) - if (AppList[i].appNum == appNum) - return i; + for (int i = 0; i < appcount; i++) + if (AppList[i].appNum == appNum) + return i; return -1; } @@ -1510,12 +1510,12 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); DropField(); return PM3_ESOFT; - } - + } + PICCInfo->appCount = buflen / 3; for (int i = 0; i < buflen; i += 3) appList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]); - + // result bytes: 3, 2, 1-16. total record size = 24 res = DesfireGetDFList(dctx, buf, &buflen); if (res != PM3_SUCCESS) { @@ -1549,7 +1549,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi appList[i].numberOfKeys = appList[i].numKeysRaw & 0x1f; appList[i].isoFileIDEnabled = ((appList[i].numKeysRaw & 0x20) != 0); appList[i].keyType = DesfireKeyTypeToAlgo(appList[i].numKeysRaw >> 6); - + if (appList[i].numberOfKeys > 0) for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { res = DesfireGetKeyVersion(dctx, &keyn, 1, buf, &buflen); @@ -1557,7 +1557,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi appList[i].keyVersions[keyn] = buf[0]; } } - + appList[i].filesReaded = false; if (readFiles) { res = DesfireFillFileList(dctx, appList[i].fileList, &appList[i].filesCount, &appList[i].isoPresent); @@ -1598,7 +1598,7 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------"); - + for (int i = 0; i < PICCInfo->appCount; i++) { PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName); @@ -1609,10 +1609,10 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck); PrintAndLogEx(SUCCESS, ""); } - + if (appList[i].numberOfKeys > 0) { PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true); - + if (appList[i].numberOfKeys > 0) { PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1); for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { @@ -1620,7 +1620,7 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app } PrintAndLogEx(NORMAL, "\n"); } - + if (appList[i].filesReaded) { PrintAndLogEx(SUCCESS, "Application have " _GREEN_("%zu") " files", appList[i].filesCount); @@ -1641,7 +1641,7 @@ void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS app PrintAndLogEx(NORMAL, ""); } } - } + } } static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { @@ -1699,18 +1699,18 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem) { int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen) { *resplen = 0; - + uint8_t xresp[257] = {0}; size_t xresplen = 0; uint8_t respcode = 0xff; - + int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen); if (res != PM3_SUCCESS) return res; - + if (respcode != 0x90) return PM3_EAPDU_FAIL; - + memcpy(resp, xresp, xresplen); *resplen = xresplen; @@ -2080,7 +2080,7 @@ const char *AccessRightShortStr[] = { "keyC", "keyD", "free", - "deny" + "deny" }; const char *GetDesfireAccessRightShortStr(uint8_t right) { @@ -2207,7 +2207,7 @@ static void DesfirePrintShortFileTypeSettings(FileSettingsS *fsettings) { default: { break; } - } + } } void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { @@ -2228,15 +2228,15 @@ void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail PrintAndLogEx(SUCCESS, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings "); PrintAndLogEx(SUCCESS, "----------------------------------------------------------------------------------------------------------"); } - PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id); - if (isoidavail) { - if (isoid != 0) - PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid); - else - PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF); - } else { - PrintAndLogEx(NORMAL, " |" NOLF); - } + PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id); + if (isoidavail) { + if (isoid != 0) + PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid); + else + PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF); + } else { + PrintAndLogEx(NORMAL, " |" NOLF); + } PrintAndLogEx(NORMAL, "0x%02x " _CYAN_("%-13s") " |" NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); PrintAndLogEx(NORMAL, " %-5s |" NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); @@ -2247,7 +2247,7 @@ void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail GetDesfireAccessRightShortStr(fsettings->wAccess), GetDesfireAccessRightShortStr(fsettings->rwAccess), GetDesfireAccessRightShortStr(fsettings->chAccess)); - + PrintAndLogEx(NORMAL, " " NOLF); DesfirePrintShortFileTypeSettings(fsettings); PrintAndLogEx(NORMAL, ""); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 4f849e135..3bf6f581b 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -99,15 +99,15 @@ typedef struct { uint16_t appISONum; char appDFName[16]; AuthCommandsChk authCmdCheck; - + uint8_t keySettings; uint8_t numKeysRaw; bool isoFileIDEnabled; // from numKeysRaw uint8_t numberOfKeys; // from numKeysRaw DesfireCryptoAlgorythm keyType; // from numKeysRaw - + uint8_t keyVersions[16]; - + bool filesReaded; size_t filesCount; bool isoPresent; @@ -119,11 +119,11 @@ typedef struct { size_t appCount; uint32_t freemem; AuthCommandsChk authCmdCheck; - + uint8_t keySettings; uint8_t numKeysRaw; uint8_t numberOfKeys; // from numKeysRaw - + uint8_t keyVersion0; } PICCInfoS; diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index edc2452f6..8feecd39c 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -524,7 +524,7 @@ void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv) { int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) { uint8_t mdata[1050] = {0}; size_t mdatalen = 0; - + mdata[0] = cmd; Uint2byteToMemLe(&mdata[1], ctx->cmdCntr); memcpy(&mdata[3], ctx->TI, 4); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 0f6ad2bd4..475772ad8 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -263,7 +263,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint } } else if (ctx->commMode == DCMEncrypted) { DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx - + rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); data[hdrlen] = 0x80; // padding @@ -281,7 +281,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint } else if (ctx->commMode == DCMEncryptedPlain) { if (srcdatalen <= hdrlen) return; - + // TODO !!! } } diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index 350cad4f8..9972a6793 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -277,8 +277,9 @@ static bool TestEV2MAC(void) { uint8_t key[] = {0x93, 0x66, 0xFA, 0x19, 0x5E, 0xB5, 0x66, 0xF5, 0xBD, 0x2B, 0xAD, 0x40, 0x20, 0xB8, 0x30, 0x02}; uint8_t ti[] = {0xE2, 0xD3, 0xAF, 0x69}; uint8_t cmd = 0x8D; - uint8_t cmddata[] = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; + uint8_t cmddata[] = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 + }; uint8_t macres[] = {0x68, 0xF2, 0xC2, 0x8C, 0x57, 0x5A, 0x16, 0x28}; // init @@ -300,7 +301,7 @@ static bool TestEV2MAC(void) { ctx.cmdCntr++; DesfireEV2CalcCMAC(&ctx, rc, NULL, 0, mac); res = res && (memcmp(mac, macres2, sizeof(macres2)) == 0); - + // tx 2 memset(mac, 0, sizeof(mac)); cmd = 0xAD; @@ -312,13 +313,14 @@ static bool TestEV2MAC(void) { // rx 2 rc = 0; ctx.cmdCntr++; - uint8_t cmddata4[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t cmddata4[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; uint8_t macres4[] = {0xA4, 0x9A, 0x44, 0x22, 0x2D, 0x92, 0x66, 0x66}; DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac); res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0); - + if (res) PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("passed")); else diff --git a/doc/commands.json b/doc/commands.json index 103ead0b0..dc7c4e06d 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -973,7 +973,7 @@ }, "help": { "command": "help", - "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210731.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", + "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210804.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", "notes": [ "auto" ], @@ -3990,7 +3990,13 @@ "command": "hf mfdes changekey", "description": "change picc/application key. needs to provide keynum/key for a valid authentication (may get from default parameters).", "notes": [ - "hf mfdes changekey --aid 123456 -> execute with default factory setup" + "change crypto algorithm for picc key is possible, but for app keys crypto algorithm is set by createapp command and can't be changed wo application delete", + "", + "hf mfdes changekey --aid 123456 -> execute with default factory setup. change des key 0 in the app 123456 from 00..00 to 00..00", + "hf mfdes changekey -t des --newalgo aes --newkey 11223344556677889900112233445566 --newver a5 -> change card master key to aes one", + "hf mfdes changekey --aid 123456 -t aes --key 00000000000000000000000000000000 --newkey 11223344556677889900112233445566 -> change app master key", + "hf mfdes changekey --aid 123456 -t des -n 0 --newkeyno 1 --oldkey 5555555555555555 --newkey 1122334455667788 -> change key 1 with auth from key 0", + "hf mfdes changekey --aid 123456 -t 3tdea --newkey 11223344556677889900112233445566778899001122334 -> change 3tdea key 0 from default 00..00 to provided" ], "offline": false, "options": [ @@ -4342,6 +4348,26 @@ ], "usage": "hf mfdes createvaluefile [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--fid ] [--amode ] [--rawrights ] [--rrights ] [--wrights ] [--rwrights ] [--chrights ] [--no-auth] [--lower ] [--upper ] [--value ] [--lcredit ]" }, + "hf mfdes default": { + "command": "hf mfdes default", + "description": "set default parameters for access to desfire card.", + "notes": [ + "hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --keyno key number", + "-t, --algo crypt algo: des, 2tdea, 3tdea, aes", + "-k, --key key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", + "-f, --kdf key derivation function (kdf): none, an10922, gallagher", + "-i, --kdfi kdf input (hex 1-31 bytes)", + "-m, --cmode communicaton mode: plain/mac/encrypt", + "-c, --ccset communicaton command set: native/niso/iso", + "-s, --schann secure channel: d40/ev1/ev2" + ], + "usage": "hf mfdes default [-h] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ]" + }, "hf mfdes deleteapp": { "command": "hf mfdes deleteapp", "description": "delete application by its 3-byte aid. master key needs to be provided.", @@ -4414,18 +4440,6 @@ ], "usage": "hf mfdes dump [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--no-auth]" }, - "hf mfdes enum": { - "command": "hf mfdes enum", - "description": "enumerate all aid's on mifare desfire tag", - "notes": [ - "hf mfdes enum" - ], - "offline": false, - "options": [ - "-h, --help this help" - ], - "usage": "hf mfdes enum [-h]" - }, "hf mfdes formatpicc": { "command": "hf mfdes formatpicc", "description": "format card. can be done only if enabled in the configuration. master key needs to be provided.", @@ -4669,31 +4683,11 @@ }, "hf mfdes help": { "command": "hf mfdes help", - "description": "help this help list list desfire (iso 14443a) history test test crypto --------------------------------------------------------------------------------------- hf mfdes default available offline: no set default parameters for access to desfire card.", - "notes": [ - "hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters" - ], - "offline": true, - "options": [ - "-h, --help this help", - "-n, --keyno key number", - "-t, --algo crypt algo: des, 2tdea, 3tdea, aes", - "-k, --key key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", - "-f, --kdf key derivation function (kdf): none, an10922, gallagher", - "-i, --kdfi kdf input (hex 1-31 bytes)", - "-m, --cmode communicaton mode: plain/mac/encrypt", - "-c, --ccset communicaton command set: native/niso/iso", - "-s, --schann secure channel: d40/ev1/ev2" - ], - "usage": "hf mfdes default [-h] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ]" - }, - "hf mfdes info": { - "command": "hf mfdes info", - "description": "get info from mifare desfire tags", + "description": "help this help list list desfire (iso 14443a) history test test crypto --------------------------------------------------------------------------------------- hf mfdes info available offline: no get info from mifare desfire tags", "notes": [ "hf mfdes info" ], - "offline": false, + "offline": true, "options": [ "-h, --help this help" ], @@ -4720,6 +4714,32 @@ ], "usage": "hf mfdes list [-h1fcrux] [--dict ]..." }, + "hf mfdes lsapp": { + "command": "hf mfdes lsapp", + "description": "show application list. master key needs to be provided or flag --no-auth set (depend on cards settings).", + "notes": [ + "hf mfdes lsapp -> show application list with defaults from `default` command", + "hf mfdes lsapp --files -> show application list and show each file type/settings/etc for each application" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyno key number", + "-t, --algo crypt algo: des, 2tdea, 3tdea, aes", + "-k, --key key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", + "-f, --kdf key derivation function (kdf): none, an10922, gallagher", + "-i, --kdfi kdf input (hex 1-31 bytes)", + "-m, --cmode communicaton mode: plain/mac/encrypt", + "-c, --ccset communicaton command set: native/niso/iso", + "-s, --schann secure channel: d40/ev1/ev2", + "--no-auth execute without authentication", + "--no-deep not to check authentication commands that avail for any application", + "--files scan files and print file settings for each application" + ], + "usage": "hf mfdes lsapp [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--no-auth] [--no-deep] [--files]" + }, "hf mfdes lsfiles": { "command": "hf mfdes lsfiles", "description": "show file list. master key needs to be provided or flag --no-auth set (depend on cards settings).", @@ -4777,7 +4797,10 @@ "command": "hf mfdes selectapp", "description": "select application on the card. it selects app if it is a valid one or returns an error.", "notes": [ - "hf mfdes selectapp --aid 123456 -> select application 123456" + "hf mfdes selectapp --aid 123456 -> select application 123456", + "hf mfdes selectapp --mf -> select master file (picc level)", + "hf mfdes selectapp --dfname aid123456 -> select application aid123456 by df name", + "hf mfdes selectapp --isoid 1111 -> select application 1111 by iso id" ], "offline": false, "options": [ @@ -4793,9 +4816,11 @@ "-c, --ccset communicaton command set: native/niso/iso", "-s, --schann secure channel: d40/ev1/ev2", "--aid application id of application for some parameters (3 hex bytes, big endian)", - "--dfname application df name (string, max 16 chars). selects application via iso select command" + "--dfname application df name (string, max 16 chars). selects application via iso select command", + "--isoid application iso id (iso df id) (2 hex bytes, big endian)", + "--mf select mf (master file) via iso channel" ], - "usage": "hf mfdes selectapp [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--dfname ]" + "usage": "hf mfdes selectapp [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--dfname ] [--isoid ] [--mf]" }, "hf mfdes setconfig": { "command": "hf mfdes setconfig", @@ -4825,7 +4850,7 @@ }, "hf mfdes test": { "command": "hf mfdes test", - "description": "[=] ------ desfire tests ------ [!] no space for crc. pos: 1 [=] crc16............. passed [!] no space for crc. pos: 2 [=] crc32............. passed [=] cmac 3tdea........ passed [=] cmac 2tdea........ passed [=] cmac des.......... passed [=] ev2 session keys.. passed [=] ev2 iv calc....... passed [=] --------------------------- [+] tests [ ok ] ======================================================================================= hf seos { seos rfids... } --------------------------------------------------------------------------------------- hf seos help available offline: yes help this help list list seos history --------------------------------------------------------------------------------------- hf seos info available offline: no get info from seos tags", + "description": "[=] ------ desfire tests ------ [!] no space for crc. pos: 1 [=] crc16............. passed [!] no space for crc. pos: 2 [=] crc32............. passed [=] cmac 3tdea........ passed [=] cmac 2tdea........ passed [=] cmac des.......... passed [=] ev2 session keys.. passed [=] ev2 iv calc....... passed [=] ev2 mac calc...... passed [=] --------------------------- [+] tests [ ok ] ======================================================================================= hf seos { seos rfids... } --------------------------------------------------------------------------------------- hf seos help available offline: yes help this help list list seos history --------------------------------------------------------------------------------------- hf seos info available offline: no get info from seos tags", "notes": [ "hf seos info" ], @@ -9839,6 +9864,6 @@ "metadata": { "commands_extracted": 587, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2021-07-31T13:44:52" + "extracted_on": "2021-08-04T12:46:55" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 830fab232..a5dbcfb3e 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -503,26 +503,26 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf mfdes help `|Y |`This help` +|`hf mfdes info `|N |`Tag information` +|`hf mfdes getuid `|N |`Get uid from card` |`hf mfdes default `|N |`Set defaults for all the commands` |`hf mfdes auth `|N |`MIFARE DesFire Authentication` |`hf mfdes chk `|N |`[old]Check keys` -|`hf mfdes enum `|N |`[old]Tries enumerate all applications` -|`hf mfdes formatpicc `|N |`Format PICC` |`hf mfdes freemem `|N |`Get free memory size` -|`hf mfdes getuid `|N |`Get uid from card` |`hf mfdes setconfig `|N |`Set card configuration` -|`hf mfdes info `|N |`[old]Tag information` +|`hf mfdes formatpicc `|N |`Format PICC` |`hf mfdes list `|Y |`List DESFire (ISO 14443A) history` -|`hf mfdes changekey `|N |`Change Key` -|`hf mfdes chkeysettings `|N |`Change Key Settings` -|`hf mfdes getkeysettings`|N |`Get Key Settings` -|`hf mfdes getkeyversions`|N |`Get Key Versions` +|`hf mfdes lsapp `|N |`Show all applications with files list` +|`hf mfdes getaids `|N |`Get Application IDs list` +|`hf mfdes getappnames `|N |`Get Applications list` |`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce` |`hf mfdes createapp `|N |`Create Application` |`hf mfdes deleteapp `|N |`Delete Application` |`hf mfdes selectapp `|N |`Select Application ID` -|`hf mfdes getaids `|N |`Get Application IDs list` -|`hf mfdes getappnames `|N |`Get Applications list` +|`hf mfdes changekey `|N |`Change Key` +|`hf mfdes chkeysettings `|N |`Change Key Settings` +|`hf mfdes getkeysettings`|N |`Get Key Settings` +|`hf mfdes getkeyversions`|N |`Get Key Versions` |`hf mfdes getfileids `|N |`Get File IDs list` |`hf mfdes getfileisoids `|N |`Get File ISO IDs list` |`hf mfdes lsfiles `|N |`Show all files list` From 5abf00b2b83ef5edf2c59b0aadaacb817118d108 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:04:05 +0300 Subject: [PATCH 37/80] get uid command --- client/src/cmdhfmfdes.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 11cff911c..238e7719c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3092,7 +3092,24 @@ static int CmdHF14ADesGetUID(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Desfire UID[%zu]: %s", buflen, sprint_hex(buf, buflen)); + if (verbose) + PrintAndLogEx(SUCCESS, "received data[%zu]: %s", buflen, sprint_hex(buf, buflen)); + + if (buflen > 0) { + if (buf[0] != 0) { + PrintAndLogEx(SUCCESS, "Desfire UID[%zu]: " _GREEN_("%s"), buflen, sprint_hex(buf, buflen)); + } else { + if (buf[1] == 0x04) { + PrintAndLogEx(SUCCESS, "Desfire UID4: " _GREEN_("%s"), sprint_hex(&buf[2], 4)); + } else if (buf[1] == 0x0a) { + PrintAndLogEx(SUCCESS, "Desfire UID10: " _GREEN_("%s"), sprint_hex(&buf[2], 10)); + } else { + PrintAndLogEx(WARNING, "Card returned wrong uid length: %d (0x%02x)", buf[1], buf[1]); + } + } + } else { + PrintAndLogEx(WARNING, "Card returned no data"); + } DropField(); return PM3_SUCCESS; From ee22a824ce6ee0048245298b2ebba0be5fb02b6c Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 3 Aug 2021 23:22:19 +0200 Subject: [PATCH 38/80] Add support for Electra demodulation --- CHANGELOG.md | 1 + armsrc/Standalone/lf_icehid.c | 5 +- armsrc/lfops.c | 65 ++++++++++++++++--------- client/src/cmddata.c | 5 +- client/src/cmdlfem410x.c | 58 ++++++++++++++-------- client/src/cmdlfem410x.h | 2 +- common/lfdemod.c | 91 ++++++++++++++++++++++++++--------- 7 files changed, 158 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c3781798..41d6b5eec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ 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] + - Added support to demodulate Electra tags and column parity check for EM410x (@doegox) - Fix demod plot for various demodulations (@doegox) - Fix `lf t55xx detect/rdbl/dump` - to override if user set `lf config` and use default values during operation (@iceman1001) - Added `hf iclass encode --wiegand/--fc/--cn` - direct fmt/fc/cn support (@bettse) diff --git a/armsrc/Standalone/lf_icehid.c b/armsrc/Standalone/lf_icehid.c index 0b1e6cbfe..01b164afd 100644 --- a/armsrc/Standalone/lf_icehid.c +++ b/armsrc/Standalone/lf_icehid.c @@ -96,8 +96,9 @@ static uint32_t IceEM410xdemod(void) { return PM3_ESOFT; } - errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); - if (errCnt != 1) { + int type = Em410xDecode(dest, &size, &idx, &hi, &lo); + // Did we find a Short EM or a Long EM? + if ((type & (0x1 | 0x2)) == 0) { BigBuf_free(); return PM3_ESOFT; } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 10ee379cd..5c42ab564 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1476,31 +1476,52 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) { WDT_HIT(); - errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); - if (errCnt == 1) { - if (size == 128) { - Dbprintf("EM XL TAG ID: " _GREEN_("%06x%08x%08x") " - ( %05d_%03d_%08d )", - hi, - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); + int type = Em410xDecode(dest, &size, &idx, &hi, &lo); + if (type & 0x1) { + Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d )", + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); + } + if (type & 0x2) { + Dbprintf("EM XL TAG ID: " _GREEN_("%06x%08x%08x") " - ( %05d_%03d_%08d )", + hi, + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); + } + if (type & 0x4) { + uint64_t data = (lo << 20) >> 20; + // Convert back to Short ID + uint64_t id = ((uint64_t)hi << 16 ) | (lo >> 48); + if ((data & 0xFFFFFFFF) == 0) { + Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) Electra "_GREEN_("%i"), + (uint32_t)(id >> 32), + (uint32_t)id, + (uint32_t)(id & 0xFFFF), + (uint32_t)((id >> 16LL) & 0xFF), + (uint32_t)(id & 0xFFFFFF), + (uint32_t)(data >> 32)); } else { - Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d )", - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); - } - - if (findone) { - *high = hi; - *low = lo; - break; + Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) on 128b frame with data "_GREEN_("%03x%08x"), + (uint32_t)(id >> 32), + (uint32_t)id, + (uint32_t)(id & 0xFFFF), + (uint32_t)((id >> 16LL) & 0xFF), + (uint32_t)(id & 0xFFFFFF), + (uint32_t)(data >> 32), + (uint32_t)data); } } + if ((type > 0) && findone) { + *high = hi; + *low = lo; + break; + } hi = lo = size = idx = 0; clk = invert = 0; } diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 32e2600de..2e8ba515c 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -592,10 +592,11 @@ static int Cmdmandecoderaw(const char *Cmd) { uint64_t id = 0; uint32_t hi = 0; size_t idx = 0; - if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) { + int res = Em410xDecode(bits, &size, &idx, &hi, &id); + if (res > 0) { //need to adjust to set bitstream back to manchester encoded data //setDemodBuff(bits, size, idx); - printEM410x(hi, id, false); + printEM410x(hi, id, false, res); } } setDemodBuff(bits, size, 0); diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index 5619b9a15..2b5295593 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -100,35 +100,55 @@ static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock, uint8_t gap } //print 64 bit EM410x ID in multiple formats -void printEM410x(uint32_t hi, uint64_t id, bool verbose) { +void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) { if (!id && !hi) return; - uint64_t n = 1; - uint64_t id2lo = 0; - uint8_t m, i; - for (m = 5; m > 0; m--) { - for (i = 0; i < 8; i++) { - id2lo = (id2lo << 1LL) | ((id & (n << (i + ((m - 1) * 8)))) >> (i + ((m - 1) * 8))); - } - } - if (verbose == false) { - - if (hi) { - PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); - } else { + if (type & 0x1) { // Short ID PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); } + if (type & 0x2) { // Long ID + PrintAndLogEx(SUCCESS, "EM 410x XL ID "_GREEN_("%06X%016" PRIX64), hi, id); + } + if (type & 0x4) { // Short Extended ID + uint64_t data = (id << 20) >> 20; + // Convert back to Short ID + id = ((uint64_t)hi << 16 ) | (id >> 48); + if ((data & 0xFFFFFFFF) == 0) { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64)" Electra "_GREEN_("%03" PRIu64), id, data >> 32); + } else { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64)" on 128b frame with data "_GREEN_("%011" PRIX64), id, data); + } + } return; } - if (hi) { + if (type & 0x2) { // Long ID //output 88 bit em id - PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); - PrintAndLogEx(SUCCESS, "EM410x XL ( RF/%d )", g_DemodClock); - } else { + PrintAndLogEx(SUCCESS, "EM 410x XL ID "_GREEN_("%06X%016" PRIX64)" ( RF/%d )", hi, id, g_DemodClock); + } + if (type & 0x4) { // Short Extended ID + PrintAndLogEx(SUCCESS, "EM 410x Short ID found on a 128b frame"); + uint64_t data = (id << 20) >> 20; + PrintAndLogEx(SUCCESS, " Data after ID: "_GREEN_("%011" PRIX64), data); + if ((data & 0xFFFFFFFF) == 0) { + PrintAndLogEx(SUCCESS, " Possibly an Electra (RO), 0x"_GREEN_("%03" PRIX64)" = "_GREEN_("%03" PRIu64), data >> 32, data >> 32); + } + PrintAndLogEx(SUCCESS, " Short ID details:"); + // Convert back to Short ID + id = ((uint64_t)hi << 16 ) | (id >> 48); + } + if (type & (0x4 | 0x1)) { // Short Extended or Short ID //output 40 bit em id + uint64_t n = 1; + uint64_t id2lo = 0; + uint8_t m, i; + for (m = 5; m > 0; m--) { + for (i = 0; i < 8; i++) { + id2lo = (id2lo << 1LL) | ((id & (n << (i + ((m - 1) * 8)))) >> (i + ((m - 1) * 8))); + } + } PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock); PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); @@ -252,7 +272,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) { printDemodBuff(0, false, false, true); } - printEM410x(*hi, *lo, verbose); + printEM410x(*hi, *lo, verbose, ans); g_em410xid = *lo; return PM3_SUCCESS; } diff --git a/client/src/cmdlfem410x.h b/client/src/cmdlfem410x.h index d31812b56..92f2f3fcf 100644 --- a/client/src/cmdlfem410x.h +++ b/client/src/cmdlfem410x.h @@ -16,7 +16,7 @@ int CmdLFEM410X(const char *Cmd); int demodEM410x(bool verbose); -void printEM410x(uint32_t hi, uint64_t id, bool verbose); +void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo); int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose); diff --git a/common/lfdemod.c b/common/lfdemod.c index 3c32834f6..d202d9aa0 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -253,6 +253,55 @@ size_t removeParity(uint8_t *bits, size_t startIdx, uint8_t pLen, uint8_t pType, return bitCnt; } +static size_t removeEm410xParity(uint8_t *bits, size_t startIdx, bool isLong, bool *validShort, bool *validShortExtended, bool *validLong) { + uint32_t parityWd = 0; + size_t bitCnt = 0; + bool validColParity = false; + bool validRowParity = true; + bool validRowParitySkipColP = true; + *validShort = false; + *validShortExtended = false; + *validLong = false; + uint8_t bLen = isLong ? 110 : 55; + uint16_t parityCol[4] = { 0, 0, 0, 0 }; + for (int word = 0; word < bLen; word += 5) { + for (int bit = 0; bit < 5; bit++) { + if (word + bit >= bLen) break; + parityWd = (parityWd << 1) | bits[startIdx + word + bit]; + if ((word <= 50) && (bit < 4)) + parityCol[bit] = (parityCol[bit] << 1) | bits[startIdx + word + bit]; + bits[bitCnt++] = (bits[startIdx + word + bit]); + } + if (word + 5 > bLen) break; + + bitCnt--; // overwrite parity with next data + validRowParity &= parityTest(parityWd, 5, 0) != 0; + if (word == 50) { // column parity nibble on short EM and on Electra + validColParity = parityTest(parityCol[0], 11, 0) != 0; + validColParity &= parityTest(parityCol[1], 11, 0) != 0; + validColParity &= parityTest(parityCol[2], 11, 0) != 0; + validColParity &= parityTest(parityCol[3], 11, 0) != 0; + } else { + validRowParitySkipColP &= parityTest(parityWd, 5, 0) != 0; + } + parityWd = 0; + } + if (!isLong && validRowParitySkipColP && validColParity) { + *validShort = true; + } + if (isLong && validRowParity) { + *validLong = true; + } + if (isLong && validRowParitySkipColP && validColParity) { + *validShortExtended = true; + } + if (*validShort || *validShortExtended || *validLong) { + return bitCnt; + } else { + return 0; + } +} + // by marshmellow // takes a array of binary values, length of bits per parity (includes parity bit), // Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) @@ -2122,7 +2171,6 @@ int Em410xDecode(uint8_t *bits, size_t *size, size_t *start_idx, uint32_t *hi, u if (bits[1] > 1) return -1; if (*size < 64) return -2; - uint8_t fmtlen; *start_idx = 0; // preamble 0111111111 @@ -2131,32 +2179,29 @@ int Em410xDecode(uint8_t *bits, size_t *size, size_t *start_idx, uint32_t *hi, u if (!preambleSearch(bits, preamble, sizeof(preamble), size, start_idx)) return -4; - // (iceman) if the preamble doesn't find two occuriences, this identification fails. - fmtlen = (*size == 128) ? 22 : 10; + bool validShort = false; + bool validShortExtended = false; + bool validLong = false; + *size = removeEm410xParity(bits, *start_idx + sizeof(preamble), *size == 128, &validShort, &validShortExtended, &validLong); - //skip last 4bit parity row for simplicity - *size = removeParity(bits, *start_idx + sizeof(preamble), 5, 0, fmtlen * 5); - - switch (*size) { - case 40: { - // std em410x format - *hi = 0; - *lo = ((uint64_t)(bytebits_to_byte(bits, 8)) << 32) | (bytebits_to_byte(bits + 8, 32)); - break; - } - case 88: { - // long em format - *hi = (bytebits_to_byte(bits, 24)); - *lo = ((uint64_t)(bytebits_to_byte(bits + 24, 32)) << 32) | (bytebits_to_byte(bits + 24 + 32, 32)); - break; - } - default: - return -6; + if (validShort) { + // std em410x format + *hi = 0; + *lo = ((uint64_t)(bytebits_to_byte(bits, 8)) << 32) | (bytebits_to_byte(bits + 8, 32)); + // 1 = Short + return 1; } - return 1; + if (validShortExtended || validLong) { + // store in long em format + *hi = (bytebits_to_byte(bits, 24)); + *lo = ((uint64_t)(bytebits_to_byte(bits + 24, 32)) << 32) | (bytebits_to_byte(bits + 24 + 32, 32)); + // 2 = Long + // 4 = ShortExtended + return ((int)validShortExtended << 2) + ((int)validLong << 1); + } + return -6; } - // loop to get raw HID waveform then FSK demodulate the TAG ID from it int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo, int *waveStartIdx) { //make sure buffer has data From bf59d299196b13f0916cddcc8dac48ad592e8561 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:38:10 +0300 Subject: [PATCH 39/80] ch ev2/encode tx no data, rx with data works (getuid) --- client/src/mifare/desfiresecurechan.c | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 475772ad8..d28209f5f 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -252,25 +252,24 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); - if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) { + if (ctx->commMode == DCMMACed) { + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireEV2CalcCMAC(ctx, cmd, srcdata, srcdatalen, cmac); - if (ctx->commMode == DCMMACed || ctx->commMode == DCMEncrypted) { - uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; - DesfireEV2CalcCMAC(ctx, cmd, srcdata, srcdatalen, cmac); - - memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); - *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); - } + memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); + *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } else if (ctx->commMode == DCMEncrypted) { - DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx - - rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); - memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); - data[hdrlen] = 0x80; // padding - dstdata[0] = cmd; memcpy(&dstdata[1], srcdata, hdrlen); - DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[1 + hdrlen], true); + + if (srcdatalen > hdrlen) { + rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); + memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); + data[hdrlen] = 0x80; // padding + + DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[1 + hdrlen], true); + } uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; DesfireEV2CalcCMAC(ctx, cmd, &dstdata[1], hdrlen + rlen, cmac); @@ -418,7 +417,7 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, // if comm mode = plain --> response with MAC // if request is not zero length --> response MAC - if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) { + if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed) { if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; From c3a5a45d37087f041025d3449f3ae1c4ecceb8b3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:42:39 +0300 Subject: [PATCH 40/80] add rx mac print if OK --- client/src/mifare/desfiresecurechan.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index d28209f5f..1a1c3496f 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -324,6 +324,8 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) { *dstdatalen = srcdatalen - maclen; + if (GetAPDULogging()) + PrintAndLogEx(INFO, "Received MAC OK"); } else { PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); //PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen)); @@ -383,6 +385,9 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + } else { + if (GetAPDULogging()) + PrintAndLogEx(INFO, "Received MAC OK"); } } else if (ctx->commMode == DCMEncrypted) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { @@ -432,6 +437,9 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + } else { + if (GetAPDULogging()) + PrintAndLogEx(INFO, "Received MAC OK"); } } else if (ctx->commMode == DCMEncrypted) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType) + DesfireGetMACLength(ctx)) { @@ -447,7 +455,8 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); } else { - //PrintAndLogEx(INFO, "Received MAC OK"); + if (GetAPDULogging()) + PrintAndLogEx(INFO, "Received MAC OK"); } DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx From a6e39a5ff15553e5822936371b29cf26226745f6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 17:15:32 +0300 Subject: [PATCH 41/80] ev2/encoded works with/wo data on the all directions --- client/src/mifare/desfiresecurechan.c | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 1a1c3496f..56d4b9ece 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -259,22 +259,21 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } else if (ctx->commMode == DCMEncrypted) { - dstdata[0] = cmd; - memcpy(&dstdata[1], srcdata, hdrlen); + memcpy(dstdata, srcdata, hdrlen); if (srcdatalen > hdrlen) { rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType)); memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); - data[hdrlen] = 0x80; // padding + data[srcdatalen - hdrlen] = 0x80; // padding DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx - DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[1 + hdrlen], true); + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[hdrlen], true); } uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; - DesfireEV2CalcCMAC(ctx, cmd, &dstdata[1], hdrlen + rlen, cmac); + DesfireEV2CalcCMAC(ctx, cmd, dstdata, hdrlen + rlen, cmac); - memcpy(&dstdata[ + hdrlen + rlen], cmac, DesfireGetMACLength(ctx)); + memcpy(&dstdata[hdrlen + rlen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx); } else if (ctx->commMode == DCMEncryptedPlain) { @@ -442,7 +441,7 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(INFO, "Received MAC OK"); } } else if (ctx->commMode == DCMEncrypted) { - if (srcdatalen < desfire_get_key_block_length(ctx->keyType) + DesfireGetMACLength(ctx)) { + if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; return; @@ -459,15 +458,16 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(INFO, "Received MAC OK"); } - DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx + if (*dstdatalen >= desfire_get_key_block_length(ctx->keyType)) { + DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx + DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, *dstdatalen, dstdata, false); - DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, *dstdatalen, dstdata, false); - - size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen); - if (puredatalen != 0) { - *dstdatalen = puredatalen; - } else { - PrintAndLogEx(WARNING, "Padding search error."); + size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen); + if (puredatalen != 0) { + *dstdatalen = puredatalen; + } else { + PrintAndLogEx(WARNING, "Padding search error."); + } } } } From be9093db6350de8e197ee6b3081c388aa5c29a3e Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:06:23 +0300 Subject: [PATCH 42/80] fix match iso id and iso file id --- client/src/mifare/desfirecore.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index b75ec45bd..fda847a6d 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1822,8 +1822,7 @@ int DesfireFillFileList(DesfireContext *dctx, FileListS FileList, size_t *filesc isoindx++; } } - if (isoindx > 0) - isoindx--; + if (isoindx * 2 != buflen) PrintAndLogEx(WARNING, "Wrong ISO ID list length. must be %zu but %zu", buflen, isoindx * 2); } else { From 450ec87296966778b74636043d0bde5ec0a6f866 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:07:04 +0300 Subject: [PATCH 43/80] add ev1 mac with and wo data --- client/src/cmdhfmfdes.c | 6 +++--- client/src/mifare/desfiresecurechan.c | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 238e7719c..75a6723e1 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4137,7 +4137,7 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4278,7 +4278,7 @@ static int CmdHF14ADesCreateValueFile(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4411,7 +4411,7 @@ static int CmdHF14ADesCreateRecordFile(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 56d4b9ece..9da027ddd 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -147,6 +147,30 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { return 0; } +static const uint8_t EV1TransmitMAC[] = { + MFDES_WRITE_DATA, + MFDES_CREDIT, + MFDES_LIMITED_CREDIT, + MFDES_DEBIT, + MFDES_WRITE_RECORD, + MFDES_UPDATE_RECORD, + MFDES_COMMIT_READER_ID, + MFDES_INIT_KEY_SETTINGS, + MFDES_ROLL_KEY_SETTINGS, + MFDES_FINALIZE_KEY_SETTINGS, +}; + +static bool DesfireEV1TransmitMAC(DesfireContext *ctx, uint8_t cmd) { + if (ctx->secureChannel != DACEV1) + return true; + + for (int i = 0; i < ARRAY_LENGTH(EV1TransmitMAC); i++) + if (EV1TransmitMAC[i] == cmd) + return true; + + return false; +} + static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { uint8_t data[1024] = {0}; size_t rlen = 0; @@ -216,7 +240,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; - if (srcdatalen > hdrlen && ctx->commMode == DCMMACed) { + if (ctx->commMode == DCMMACed && DesfireEV1TransmitMAC(ctx, cmd)) { memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } From 947830543681eac883e20e6693e3d7bcd14ccd6d Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:46:05 +0300 Subject: [PATCH 44/80] d40 mac calc --- client/src/cmdhfmfdes.c | 8 ++--- client/src/mifare/desfiresecurechan.c | 44 +++++++++++++++++++-------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 75a6723e1..363a2f946 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3804,7 +3804,7 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4709,7 +4709,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4921,7 +4921,7 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet FileSettingsS fsettings; DesfireCommunicationMode commMode = dctx->commMode; - DesfireSetCommMode(dctx, DCMPlain); + DesfireSetCommMode(dctx, DCMMACed); res = DesfireGetFileSettingsStruct(dctx, fnum, &fsettings); DesfireSetCommMode(dctx, commMode); @@ -5105,7 +5105,7 @@ static int CmdHF14ADesReadData(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 9da027ddd..e98e09a20 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -147,7 +147,7 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { return 0; } -static const uint8_t EV1TransmitMAC[] = { +static const uint8_t EV1D40TransmitMAC[] = { MFDES_WRITE_DATA, MFDES_CREDIT, MFDES_LIMITED_CREDIT, @@ -160,12 +160,31 @@ static const uint8_t EV1TransmitMAC[] = { MFDES_FINALIZE_KEY_SETTINGS, }; -static bool DesfireEV1TransmitMAC(DesfireContext *ctx, uint8_t cmd) { - if (ctx->secureChannel != DACEV1) +static bool DesfireEV1D40TransmitMAC(DesfireContext *ctx, uint8_t cmd) { + if (ctx->secureChannel != DACd40 && ctx->secureChannel != DACEV1) return true; - for (int i = 0; i < ARRAY_LENGTH(EV1TransmitMAC); i++) - if (EV1TransmitMAC[i] == cmd) + for (int i = 0; i < ARRAY_LENGTH(EV1D40TransmitMAC); i++) + if (EV1D40TransmitMAC[i] == cmd) + return true; + + return false; +} + +static const uint8_t D40ReceiveMAC[] = { + MFDES_READ_DATA, + MFDES_READ_DATA2, + MFDES_READ_RECORDS, + MFDES_READ_RECORDS2, + MFDES_GET_VALUE, +}; + +static bool DesfireEV1D40ReceiveMAC(DesfireContext *ctx, uint8_t cmd) { + if (ctx->secureChannel != DACd40) + return true; + + for (int i = 0; i < ARRAY_LENGTH(D40ReceiveMAC); i++) + if (D40ReceiveMAC[i] == cmd) return true; return false; @@ -192,9 +211,10 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint uint8_t mac[32] = {0}; DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac); - memcpy(dstdata, srcdata, srcdatalen); - memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); - *dstdatalen = rlen; + if (DesfireEV1D40TransmitMAC(ctx, cmd)) { + memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); + *dstdatalen = rlen; + } } else if (ctx->commMode == DCMEncrypted) { if (srcdatalen <= hdrlen) return; @@ -240,7 +260,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; - if (ctx->commMode == DCMMACed && DesfireEV1TransmitMAC(ctx, cmd)) { + if (ctx->commMode == DCMMACed && DesfireEV1D40TransmitMAC(ctx, cmd)) { memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } @@ -339,7 +359,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, switch (ctx->commMode) { case DCMMACed: { size_t maclen = DesfireGetMACLength(ctx); - if (srcdatalen > maclen) { + if (srcdatalen > maclen && DesfireEV1D40ReceiveMAC(ctx, ctx->lastCommand)) { uint8_t mac[16] = {0}; rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType)); memcpy(data, srcdata, srcdatalen - maclen); @@ -351,8 +371,8 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, PrintAndLogEx(INFO, "Received MAC OK"); } else { PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); - //PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen)); - //PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(mac, maclen)); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen)); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(mac, maclen)); } } break; From df0d5617ac2a078f26c164dfa13b04b80e88807b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:49:36 +0300 Subject: [PATCH 45/80] ev2 plain comes wo mac --- client/src/mifare/desfiresecurechan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index e98e09a20..57306c1c2 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -465,7 +465,7 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, // if comm mode = plain --> response with MAC // if request is not zero length --> response MAC - if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed) { + if (ctx->commMode == DCMMACed) { if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; From 7b79bd375f3ff97fecf47f25c5625cdce9b32777 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 19:12:44 +0300 Subject: [PATCH 46/80] move plain mode to mac mode --- client/src/cmdhfmfdes.c | 18 ++++++------ client/src/mifare/desfiresecurechan.c | 40 ++++++++++++--------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 363a2f946..035e52cea 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2843,7 +2843,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 12, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 12, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -3007,7 +3007,7 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -3342,7 +3342,7 @@ static int CmdHF14ADesGetKeyVersions(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); // DCMMACed + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4632,7 +4632,7 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -4869,7 +4869,7 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -5268,7 +5268,7 @@ static int CmdHF14ADesWriteData(const char *Cmd) { FileSettingsS fsettings; DesfireCommunicationMode commMode = dctx.commMode; - DesfireSetCommMode(&dctx, DCMPlain); + DesfireSetCommMode(&dctx, DCMMACed); res = DesfireGetFileSettingsStruct(&dctx, fnum, &fsettings); DesfireSetCommMode(&dctx, commMode); @@ -5431,7 +5431,7 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; @@ -5503,7 +5503,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMPlain, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, (noauth) ? DCMPlain : DCMMACed, NULL); if (res) { CLIParserFree(ctx); return res; @@ -5566,7 +5566,7 @@ static int CmdHF14ADesDump(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, (noauth) ? DCMPlain : DCMMACed, &appid); if (res) { CLIParserFree(ctx); return res; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 57306c1c2..b33287a00 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -42,26 +42,22 @@ static bool CommandCanUseAnyChannel(uint8_t cmd) { static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_SELECT_APPLICATION, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMPlain}, - {MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_DF_NAMES, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_KEY_SETTINGS, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_KEY_VERSION, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_FREE_MEMORY, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_STD_DATA_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_BACKUP_DATA_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_VALUE_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_LINEAR_RECORD_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_CREATE_CYCLIC_RECORD_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_VALUE, DACd40, DCCNative, DCMPlain}, - {MFDES_CREDIT, DACd40, DCCNative, DCMPlain}, - {MFDES_LIMITED_CREDIT, DACd40, DCCNative, DCMPlain}, - {MFDES_DEBIT, DACd40, DCCNative, DCMPlain}, - {MFDES_COMMIT_TRANSACTION, DACd40, DCCNative, DCMPlain}, - {MFDES_CLEAR_RECORD_FILE, DACd40, DCCNative, DCMPlain}, - {MFDES_GET_FILE_SETTINGS, DACd40, DCCNative, DCMPlain}, - + + {MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMMACed}, + {MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_DF_NAMES, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_KEY_SETTINGS, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_KEY_VERSION, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_FREE_MEMORY, DACd40, DCCNative, DCMMACed}, + {MFDES_CREATE_STD_DATA_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_CREATE_BACKUP_DATA_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_CREATE_VALUE_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_CREATE_LINEAR_RECORD_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_CREATE_CYCLIC_RECORD_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_COMMIT_TRANSACTION, DACd40, DCCNative, DCMMACed}, + {MFDES_CLEAR_RECORD_FILE, DACd40, DCCNative, DCMMACed}, + {MFDES_GET_FILE_SETTINGS, DACd40, DCCNative, DCMMACed}, {MFDES_GET_VALUE, DACd40, DCCNative, DCMMACed}, {MFDES_CREDIT, DACd40, DCCNative, DCMMACed}, {MFDES_DEBIT, DACd40, DCCNative, DCMMACed}, @@ -85,10 +81,10 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_CHANGE_KEY, DACd40, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACd40, DCCNative, DCMEncryptedPlain}, - {MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMPlain}, - {MFDES_GET_FREE_MEMORY, DACEV1, DCCNative, DCMPlain}, {MFDES_SELECT_APPLICATION, DACEV1, DCCNative, DCMPlain}, + {MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMMACed}, + {MFDES_GET_FREE_MEMORY, DACEV1, DCCNative, DCMMACed}, {MFDES_CREATE_APPLICATION, DACEV1, DCCNative, DCMMACed}, {MFDES_DELETE_APPLICATION, DACEV1, DCCNative, DCMMACed}, {MFDES_GET_APPLICATION_IDS, DACEV1, DCCNative, DCMMACed}, From 7e8ffc3e0c0e8f4ac631703dac0d84a95c5d9a23 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 4 Aug 2021 18:17:16 +0200 Subject: [PATCH 47/80] string formatter --- client/src/crypto/asn1dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/crypto/asn1dump.c b/client/src/crypto/asn1dump.c index f09c4284f..fa5216825 100644 --- a/client/src/crypto/asn1dump.c +++ b/client/src/crypto/asn1dump.c @@ -327,7 +327,7 @@ bool asn1_tag_dump(const struct tlv *tlv, int level, bool *candump) { */ PrintAndLogEx(INFO, - "%*s-- %02X [%02ZX] '"_YELLOW_("%s") "'" NOLF + "%*s-- %02X [%02zX] '"_YELLOW_("%s") "'" NOLF , (level * 4) , " " , tlv->tag From d992ce73c3c0acc4d4aea1ab19c5011778a026f5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 4 Aug 2021 18:25:23 +0200 Subject: [PATCH 48/80] re-added the old checksum bits but guarded them as debug prints --- client/src/cmdlfindala.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index 98e90b3ef..38b7c264c 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -198,12 +198,17 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) { parity |= DemodBuffer[34] << 1; // b2 parity |= DemodBuffer[38] << 0; // b1 + uint8_t checksum = 0; + checksum |= DemodBuffer[62] << 1; // b2 + checksum |= DemodBuffer[63] << 0; // b1 + PrintAndLogEx(SUCCESS, "Fmt " _GREEN_("26") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u") " Parity: " _GREEN_("%1d%1d") , fc , csn , parity >> 1 & 0x01 , parity & 0x01 ); + PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01); PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); // This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS From 638838439340e264d6f88ac81cafbd747678cd9f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 19:41:04 +0300 Subject: [PATCH 49/80] cov 354477 --- client/src/cmdhfmfdes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 035e52cea..0dd003987 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2316,6 +2316,7 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { bool idsoidpresent = (res == 1); if (res == 2) { PrintAndLogEx(ERR, "ISO ID for EF or DF must have 2 bytes length"); + CLIParserFree(ctx); return PM3_EINVARG; } From e78c563e454bd9877a8559b2f7f13930cc51f051 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 20:01:11 +0300 Subject: [PATCH 50/80] encode with padding sketch --- client/src/cmdhfmfdes.c | 2 -- client/src/mifare/desfirecore.c | 11 ++++++----- client/src/mifare/desfirecrypto.c | 1 + client/src/mifare/desfirecrypto.h | 1 + client/src/mifare/desfiresecurechan.c | 13 +++++++++++-- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 0dd003987..ee0f3e190 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2628,14 +2628,12 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { return res; } - DesfireSetCommMode(&dctx, DCMEncryptedPlain); res = DesfireSetConfiguration(&dctx, paramid, param, paramlen); if (res == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Set configuration 0x%02x " _GREEN_("ok") " ", paramid); } else { PrintAndLogEx(FAILED, "Set configuration 0x%02x " _RED_("failed") " ", paramid); } - DesfireSetCommMode(&dctx, DCMEncrypted); DropField(); return res; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index fda847a6d..10c4dff42 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2545,7 +2545,7 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para size_t datalen = 1 + paramlen; - // add crc + /*// add crc if (dctx->secureChannel == DACd40) { iso14443a_crc_append(&data[1], datalen - 1); datalen += 2; @@ -2553,11 +2553,12 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para desfire_crc32_append(cdata, datalen + 1); datalen += 4; } - +*/ // dynamic length - if (paramid == 0x02) { - data[datalen] = 0x80; - datalen++; + if (paramid == 0x02 && dctx->commMode == DCMEncrypted) { + dctx->commMode = DCMEncryptedWithPadding; + //data[datalen] = 0x80; + //datalen++; } // send command diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 8feecd39c..366995a06 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -429,6 +429,7 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode) { fmode = 0x01; break; case DCMEncrypted: + case DCMEncryptedWithPadding: case DCMEncryptedPlain: fmode = 0x11; break; diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index f336a2448..9fa379049 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -58,6 +58,7 @@ typedef enum { DCMPlain, DCMMACed, DCMEncrypted, + DCMEncryptedWithPadding, DCMEncryptedPlain } DesfireCommunicationMode; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index b33287a00..383e8fdf9 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -260,16 +260,24 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); } - } else if (ctx->commMode == DCMEncrypted) { - rlen = padded_data_length(srcdatalen + 4 - hdrlen, desfire_get_key_block_length(ctx->keyType)); + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { + uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0; + rlen = padded_data_length(srcdatalen + 4 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType)); data[0] = cmd; + + // crc memcpy(&data[1], srcdata, srcdatalen); desfire_crc32_append(data, srcdatalen + 1); + + // add padding + if (paddinglen > 0) + data[srcdatalen + 1 + 4] = 0x80; memcpy(dstdata, srcdata, hdrlen); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true); *dstdatalen = hdrlen + rlen; + ctx->commMode = DCMEncrypted; } else if (ctx->commMode == DCMEncryptedPlain) { if (srcdatalen <= hdrlen) return; @@ -374,6 +382,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, break; } case DCMEncrypted: + case DCMEncryptedWithPadding: if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; From c125c10e312f0600b69efa059a1782ae43b091cd Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 22:36:38 +0300 Subject: [PATCH 51/80] d40 + padding --- client/src/mifare/desfiresecurechan.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 383e8fdf9..4b042a146 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -211,13 +211,18 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); *dstdatalen = rlen; } - } else if (ctx->commMode == DCMEncrypted) { + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { if (srcdatalen <= hdrlen) return; - - rlen = padded_data_length(srcdatalen + 2 - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; // 2 - crc16 + + uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0; + rlen = padded_data_length(srcdatalen + 2 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; // 2 - crc16 memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); iso14443a_crc_append(data, srcdatalen - hdrlen); + + // add padding + if (paddinglen > 0) + data[srcdatalen + 1 + 2] = 0x80; memcpy(dstdata, srcdata, hdrlen); //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2)); @@ -306,7 +311,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); - } else if (ctx->commMode == DCMEncrypted) { + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { memcpy(dstdata, srcdata, hdrlen); if (srcdatalen > hdrlen) { From 7046675403ff0c7fab152160cf6002c753d512c7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:13:57 +0300 Subject: [PATCH 52/80] d40 fix --- client/src/mifare/desfiresecurechan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 4b042a146..14bc3ab18 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -222,7 +222,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint // add padding if (paddinglen > 0) - data[srcdatalen + 1 + 2] = 0x80; + data[srcdatalen - hdrlen + 2] = 0x80; memcpy(dstdata, srcdata, hdrlen); //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2)); From 2432908e08dbccbdc478072832210cc691f7af68 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:39:25 +0300 Subject: [PATCH 53/80] ev2 enc with padding - ok --- client/src/mifare/desfiresecurechan.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 14bc3ab18..992006c9b 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -329,6 +329,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[hdrlen + rlen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx); + ctx->commMode = DCMEncrypted; } else if (ctx->commMode == DCMEncryptedPlain) { if (srcdatalen <= hdrlen) return; @@ -442,7 +443,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, if (GetAPDULogging()) PrintAndLogEx(INFO, "Received MAC OK"); } - } else if (ctx->commMode == DCMEncrypted) { + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; @@ -473,8 +474,6 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, *dstdatalen = srcdatalen; uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; - // if comm mode = plain --> response with MAC - // if request is not zero length --> response MAC if (ctx->commMode == DCMMACed) { if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); @@ -494,7 +493,7 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, if (GetAPDULogging()) PrintAndLogEx(INFO, "Received MAC OK"); } - } else if (ctx->commMode == DCMEncrypted) { + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; From 91b1026f6d6736c5f59edad57c49f3907634d1bb Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:51:09 +0300 Subject: [PATCH 54/80] remove comments --- client/src/mifare/desfirecore.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 10c4dff42..abce6e7e9 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2544,22 +2544,9 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para memcpy(&data[1], param, paramlen); size_t datalen = 1 + paramlen; - - /*// add crc - if (dctx->secureChannel == DACd40) { - iso14443a_crc_append(&data[1], datalen - 1); - datalen += 2; - } else { - desfire_crc32_append(cdata, datalen + 1); - datalen += 4; - } -*/ // dynamic length - if (paramid == 0x02 && dctx->commMode == DCMEncrypted) { + if (paramid == 0x02 && dctx->commMode == DCMEncrypted) dctx->commMode = DCMEncryptedWithPadding; - //data[datalen] = 0x80; - //datalen++; - } // send command uint8_t resp[257] = {0}; From 09bb3f62a1d1d423bdf98c5fa56eb3f22c9c3047 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 00:01:53 +0300 Subject: [PATCH 55/80] make style --- armsrc/lfops.c | 50 +++++++++++++-------------- client/src/cmdlfem410x.c | 4 +-- client/src/mifare/desfirecore.c | 2 +- client/src/mifare/desfiresecurechan.c | 14 ++++---- doc/commands.json | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 5c42ab564..2f5fb47e4 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1479,42 +1479,42 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) { int type = Em410xDecode(dest, &size, &idx, &hi, &lo); if (type & 0x1) { Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d )", - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); } if (type & 0x2) { Dbprintf("EM XL TAG ID: " _GREEN_("%06x%08x%08x") " - ( %05d_%03d_%08d )", - hi, - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); + hi, + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); } if (type & 0x4) { uint64_t data = (lo << 20) >> 20; // Convert back to Short ID - uint64_t id = ((uint64_t)hi << 16 ) | (lo >> 48); + uint64_t id = ((uint64_t)hi << 16) | (lo >> 48); if ((data & 0xFFFFFFFF) == 0) { Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) Electra "_GREEN_("%i"), - (uint32_t)(id >> 32), - (uint32_t)id, - (uint32_t)(id & 0xFFFF), - (uint32_t)((id >> 16LL) & 0xFF), - (uint32_t)(id & 0xFFFFFF), - (uint32_t)(data >> 32)); + (uint32_t)(id >> 32), + (uint32_t)id, + (uint32_t)(id & 0xFFFF), + (uint32_t)((id >> 16LL) & 0xFF), + (uint32_t)(id & 0xFFFFFF), + (uint32_t)(data >> 32)); } else { Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) on 128b frame with data "_GREEN_("%03x%08x"), - (uint32_t)(id >> 32), - (uint32_t)id, - (uint32_t)(id & 0xFFFF), - (uint32_t)((id >> 16LL) & 0xFF), - (uint32_t)(id & 0xFFFFFF), - (uint32_t)(data >> 32), - (uint32_t)data); + (uint32_t)(id >> 32), + (uint32_t)id, + (uint32_t)(id & 0xFFFF), + (uint32_t)((id >> 16LL) & 0xFF), + (uint32_t)(id & 0xFFFFFF), + (uint32_t)(data >> 32), + (uint32_t)data); } } if ((type > 0) && findone) { diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index 2b5295593..0b45f9d0b 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -114,7 +114,7 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) { if (type & 0x4) { // Short Extended ID uint64_t data = (id << 20) >> 20; // Convert back to Short ID - id = ((uint64_t)hi << 16 ) | (id >> 48); + id = ((uint64_t)hi << 16) | (id >> 48); if ((data & 0xFFFFFFFF) == 0) { PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64)" Electra "_GREEN_("%03" PRIu64), id, data >> 32); } else { @@ -137,7 +137,7 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) { } PrintAndLogEx(SUCCESS, " Short ID details:"); // Convert back to Short ID - id = ((uint64_t)hi << 16 ) | (id >> 48); + id = ((uint64_t)hi << 16) | (id >> 48); } if (type & (0x4 | 0x1)) { // Short Extended or Short ID //output 40 bit em id diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index abce6e7e9..0c146e4a0 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1822,7 +1822,7 @@ int DesfireFillFileList(DesfireContext *dctx, FileListS FileList, size_t *filesc isoindx++; } } - + if (isoindx * 2 != buflen) PrintAndLogEx(WARNING, "Wrong ISO ID list length. must be %zu but %zu", buflen, isoindx * 2); } else { diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 992006c9b..2d91b0ecc 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -42,7 +42,7 @@ static bool CommandCanUseAnyChannel(uint8_t cmd) { static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_SELECT_APPLICATION, DACd40, DCCNative, DCMPlain}, - + {MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMMACed}, {MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMMACed}, {MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMMACed}, @@ -159,7 +159,7 @@ static const uint8_t EV1D40TransmitMAC[] = { static bool DesfireEV1D40TransmitMAC(DesfireContext *ctx, uint8_t cmd) { if (ctx->secureChannel != DACd40 && ctx->secureChannel != DACEV1) return true; - + for (int i = 0; i < ARRAY_LENGTH(EV1D40TransmitMAC); i++) if (EV1D40TransmitMAC[i] == cmd) return true; @@ -178,7 +178,7 @@ static const uint8_t D40ReceiveMAC[] = { static bool DesfireEV1D40ReceiveMAC(DesfireContext *ctx, uint8_t cmd) { if (ctx->secureChannel != DACd40) return true; - + for (int i = 0; i < ARRAY_LENGTH(D40ReceiveMAC); i++) if (D40ReceiveMAC[i] == cmd) return true; @@ -214,12 +214,12 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { if (srcdatalen <= hdrlen) return; - + uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0; rlen = padded_data_length(srcdatalen + 2 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; // 2 - crc16 memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); iso14443a_crc_append(data, srcdatalen - hdrlen); - + // add padding if (paddinglen > 0) data[srcdatalen - hdrlen + 2] = 0x80; @@ -269,11 +269,11 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0; rlen = padded_data_length(srcdatalen + 4 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType)); data[0] = cmd; - + // crc memcpy(&data[1], srcdata, srcdatalen); desfire_crc32_append(data, srcdatalen + 1); - + // add padding if (paddinglen > 0) data[srcdatalen + 1 + 4] = 0x80; diff --git a/doc/commands.json b/doc/commands.json index dc7c4e06d..434296a12 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -9864,6 +9864,6 @@ "metadata": { "commands_extracted": 587, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2021-08-04T12:46:55" + "extracted_on": "2021-08-04T21:00:22" } } \ No newline at end of file From 457483eafef530d15cb0d75b78167345020c3156 Mon Sep 17 00:00:00 2001 From: Ray Lee Date: Thu, 5 Aug 2021 11:03:30 +0800 Subject: [PATCH 56/80] ui improve --- client/src/proxmark3.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index d1507923a..dd0ad9be2 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -127,6 +127,15 @@ static void prompt_compose(char *buf, size_t buflen, const char *promptctx, cons static int check_comm(void) { // If communications thread goes down. Device disconnected then this should hook up PM3 again. if (IsCommunicationThreadDead() && session.pm3_present) { +#ifdef HAVE_READLINE + char* saved_line; + int saved_point; + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_set_prompt(""); + rl_replace_line("", 0); + rl_redisplay(); +#endif PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n"); prompt_dev = PROXPROMPT_DEV_OFFLINE; #ifdef HAVE_READLINE @@ -135,7 +144,10 @@ static int check_comm(void) { char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); rl_set_prompt(prompt_filtered); - rl_forced_update_display(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); #endif CloseProxmark(session.current_device); } From 6e5240056e3de60469761d0aab677eb28473a8ce Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 12:32:08 +0300 Subject: [PATCH 57/80] changekey ev2 works --- client/src/cmdhfmfdes.c | 1 + client/src/mifare/desfirecore.c | 13 ++++++++++--- client/src/mifare/desfiresecurechan.c | 7 +------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index ee0f3e190..8285ec0f3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1255,6 +1255,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); + SetAPDULogging(false); DropField(); mfdes_info_res_t info; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 0c146e4a0..ee34f4cfe 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2510,7 +2510,7 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke iso14443a_crc(nkeybuf, nkeylen, &cdata[cdatalen]); cdatalen += 2; } - } else { + } else if (dctx->secureChannel == DACEV1) { // EV1 Checksum must cover : [] desfire_crc32_append(pckcdata, cdatalen + 2); cdatalen += 4; @@ -2518,12 +2518,19 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]); cdatalen += 4; } + } else if (dctx->secureChannel == DACEV2) { + // EV2 : [] + if (newkeynum != dctx->keyNum) { + desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]); + cdatalen += 4; + } } - + // send command uint8_t resp[257] = {0}; size_t resplen = 0; - int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen, resp, &resplen); + PrintAndLogEx(SUCCESS, "Change key [%d] %s", cdatalen + 1, sprint_hex(&pckcdata[1], cdatalen + 1)); + int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen + 1, resp, &resplen); // check response if (res == 0 && resplen > 0) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 2d91b0ecc..75ddec228 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -311,7 +311,7 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); - } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { + } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding || ctx->commMode == DCMEncryptedPlain) { memcpy(dstdata, srcdata, hdrlen); if (srcdatalen > hdrlen) { @@ -330,11 +330,6 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx); ctx->commMode = DCMEncrypted; - } else if (ctx->commMode == DCMEncryptedPlain) { - if (srcdatalen <= hdrlen) - return; - - // TODO !!! } } From 4f33d201a9d8269fe2d73541f65fa11bef230f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C5=BEe=20Jen=C5=A1terle?= Date: Thu, 5 Aug 2021 15:47:32 +0200 Subject: [PATCH 58/80] Added LEAF identity MAD entry --- client/resources/mad.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/resources/mad.json b/client/resources/mad.json index 8b1c4193c..9d5e7b9c5 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -7875,6 +7875,13 @@ "service_provider": "Atelei Engineering", "system_integrator": "Atelei Engineering" }, + { + "application": "Access control", + "company": "LEAF Identity", + "mad": "0x51CD", + "service_provider": "", + "system_integrator": "" + , { "application": "Access & biometrics application", "company": "Manufacture Francaise des Pneumatiques MICHELIN", From d74b9f8cbe964effce1d64b3c3a8904735d3a78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C5=BEe=20Jen=C5=A1terle?= Date: Thu, 5 Aug 2021 15:51:35 +0200 Subject: [PATCH 59/80] fix json --- client/resources/mad.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/resources/mad.json b/client/resources/mad.json index 9d5e7b9c5..9ea7aeaea 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -7881,7 +7881,7 @@ "mad": "0x51CD", "service_provider": "", "system_integrator": "" - , + }, { "application": "Access & biometrics application", "company": "Manufacture Francaise des Pneumatiques MICHELIN", From 7a6766a2a389e427db1f0c8dee6d453bf7496576 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 18:38:32 +0300 Subject: [PATCH 60/80] setconfig help --- client/src/cmdhfmfdes.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 8285ec0f3..62aae3bb3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2557,8 +2557,20 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes setconfig", "Set card configuration. WARNING! Danger zone! Needs to provide card's master key and works if not blocked by config.", - "hf mfdes setconfig --param 03 --data 0428 -> set parameter 03\n" - "hf mfdes setconfig --param 02 --data 0875778102637264 -> set parameter 02"); + "More about options MF2DLHX0.pdf. Options list:\n" + "00h PICC configuration.\n" + "02h ATS update.\n" + "03h SAK update\n" + "04h Secure Messaging Configuration.\n" + "05h Capability data. (here change for LRP in the Desfire Light)\n" + "06h DF Name renaming\n" + "08h File renaming\n" + "09h Value file configuration\n" + "0Ah Failed authentication counter setting\n" + "0Bh HW configuration\n" + "\n" + "hf mfdes setconfig --param 03 --data 0428 -> set SAK\n" + "hf mfdes setconfig --param 02 --data 0875778102637264 -> set ATS (first byte - length)"); void *argtable[] = { arg_param_begin, From 3945e1e7f423412ebe108cca669c09db102975ad Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 19:06:53 +0300 Subject: [PATCH 61/80] added iso channel checks --- client/src/mifare/desfiresecurechan.c | 49 ++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 75ddec228..d5bc141d0 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -41,6 +41,7 @@ static bool CommandCanUseAnyChannel(uint8_t cmd) { } static const AllowedChannelModesS AllowedChannelModes[] = { + // D40 channel {MFDES_SELECT_APPLICATION, DACd40, DCCNative, DCMPlain}, {MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMMACed}, @@ -81,6 +82,7 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_CHANGE_KEY, DACd40, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACd40, DCCNative, DCMEncryptedPlain}, + // EV1 and EV2 channel {MFDES_SELECT_APPLICATION, DACEV1, DCCNative, DCMPlain}, {MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMMACed}, @@ -114,8 +116,26 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_CHANGE_KEY, DACEV1, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACEV1, DCCNative, DCMEncryptedPlain}, + // EV2 channel separately {MFDES_AUTHENTICATE_EV2F, DACEV2, DCCNative, DCMPlain}, {MFDES_AUTHENTICATE_EV2NF, DACEV2, DCCNative, DCMPlain}, + + // ISO channel + {ISO7816_READ_BINARY, DACd40, DCCISO, DCMPlain}, + {ISO7816_UPDATE_BINARY, DACd40, DCCISO, DCMPlain}, + {ISO7816_READ_RECORDS, DACd40, DCCISO, DCMPlain}, + {ISO7816_APPEND_RECORD, DACd40, DCCISO, DCMPlain}, + + {ISO7816_READ_BINARY, DACd40, DCCISO, DCMMACed}, + {ISO7816_READ_RECORDS, DACd40, DCCISO, DCMMACed}, + + {ISO7816_READ_BINARY, DACEV1, DCCISO, DCMPlain}, + {ISO7816_UPDATE_BINARY, DACEV1, DCCISO, DCMPlain}, + {ISO7816_READ_RECORDS, DACEV1, DCCISO, DCMPlain}, + {ISO7816_APPEND_RECORD, DACEV1, DCCISO, DCMPlain}, + + {ISO7816_READ_BINARY, DACEV1, DCCISO, DCMMACed}, + {ISO7816_READ_RECORDS, DACEV1, DCCISO, DCMMACed}, }; #define CMD_HEADER_LEN_ALL 0xffff @@ -186,6 +206,25 @@ static bool DesfireEV1D40ReceiveMAC(DesfireContext *ctx, uint8_t cmd) { return false; } +static const uint8_t ISOChannelValidCmd[] = { + ISO7816_SELECT_FILE, + ISO7816_READ_BINARY, + ISO7816_UPDATE_BINARY, + ISO7816_READ_RECORDS, + ISO7816_APPEND_RECORD, + ISO7816_GET_CHALLENGE, + ISO7816_EXTERNAL_AUTHENTICATION, + ISO7816_INTERNAL_AUTHENTICATION +}; + +static bool DesfireISOChannelValidCmd(uint8_t cmd) { + for (int i = 0; i < ARRAY_LENGTH(ISOChannelValidCmd); i++) + if (ISOChannelValidCmd[i] == cmd) + return true; + + return false; +} + static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { uint8_t data[1024] = {0}; size_t rlen = 0; @@ -543,13 +582,21 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De PrintAndLogEx(WARNING, "Communication mode can't be NONE. command: %02x", cmd); return false; } - + // no security set if (secureChannel == DACNone) return true; + if (CommandCanUseAnyChannel(cmd)) return true; + // ISO commands + if (cmdSet == DCCISO) { + bool res = DesfireISOChannelValidCmd(cmd); + if (!res) + return false; + } + bool found = false; for (int i = 0; i < ARRAY_LENGTH(AllowedChannelModes); i++) if (AllowedChannelModes[i].cmd == cmd) { From c71f93687d075778ee9fe6b7e64f97e714aed116 Mon Sep 17 00:00:00 2001 From: Anze Jensterle Date: Thu, 5 Aug 2021 18:45:50 +0200 Subject: [PATCH 62/80] Fix DESfire DF search and assignment to AID --- client/src/mifare/desfirecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index ee34f4cfe..95d4a2228 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1520,7 +1520,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi res = DesfireGetDFList(dctx, buf, &buflen); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); - } else if (buflen > 1) { + } else if (buflen > 0) { for (int i = 0; i < buflen; i++) { int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), appList, PICCInfo->appCount); if (indx >= 0) { @@ -1529,7 +1529,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } } } - + // field on-off zone DesfireFillPICCInfo(dctx, PICCInfo, deepmode); From f1c48db6bd1bc364cb8febd6f04464c7b4f3ddc6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 20:03:07 +0300 Subject: [PATCH 63/80] added iso commands and read sketch --- client/src/cmdhfmfdes.c | 10 +++++- client/src/mifare/desfirecore.c | 59 +++++++++++++++++++++++++++++++++ client/src/mifare/desfirecore.h | 5 +++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 62aae3bb3..a74c8ffa7 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4922,6 +4922,11 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { return PM3_SUCCESS; } +static int DesfileReadISOFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filetype, uint32_t offset, uint32_t length, bool noauth, bool verbose) { + + + return PM3_SUCCESS; +} static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filetype, uint32_t offset, uint32_t length, bool noauth, bool verbose) { int res = 0; @@ -5167,7 +5172,10 @@ static int CmdHF14ADesReadData(const char *Cmd) { return res; } - res = DesfileReadFileAndPrint(&dctx, fnum, op, offset, length, noauth, verbose); + if (dctx.cmdSet != DCCISO) + res = DesfileReadFileAndPrint(&dctx, fnum, op, offset, length, noauth, verbose); + else + res = DesfileReadISOFileAndPrint(&dctx, fnum, op, offset, length, noauth, verbose); DropField(); return res; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index ee34f4cfe..88b0c88a8 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2627,3 +2627,62 @@ int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, return res; } +int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen) { + uint8_t p1 = 0; + if (use_file_id) + p1 = 0x80 & (fileid & 0x1f); + else + p1 = (offset >> 8) & 0x7f; + uint8_t p2 = offset & 0xff; + + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, length, resp, resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; +} + +int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen) { + uint8_t p1 = 0; + if (use_file_id) + p1 = 0x80 & (fileid & 0x1f); + else + p1 = (offset >> 8) & 0x7f; + uint8_t p2 = offset & 0xff; + + uint8_t resp[250] = {0}; + size_t resplen = 0; + + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; +} + +int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen) { + uint8_t p2 = ((fileid & 0x1f) << 3) | ((read_all_records) ? 0x05 : 0x04); + + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, length, resp, resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; +} + +int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen) { + uint8_t p2 = ((fileid & 0x1f) << 3); + + uint8_t resp[250] = {0}; + size_t resplen = 0; + + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; +} diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 3bf6f581b..83af91767 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -234,4 +234,9 @@ int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data); int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); +int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen); +int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen); +int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen); +int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen); + #endif // __DESFIRECORE_H From 18e2d55c57f012e26984483f9fff0cdb57eead19 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 5 Aug 2021 20:26:27 +0300 Subject: [PATCH 64/80] remove debug & cov 354623 ) --- client/src/mifare/desfirecore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 88b0c88a8..b5a4e1f44 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2529,7 +2529,6 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke // send command uint8_t resp[257] = {0}; size_t resplen = 0; - PrintAndLogEx(SUCCESS, "Change key [%d] %s", cdatalen + 1, sprint_hex(&pckcdata[1], cdatalen + 1)); int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen + 1, resp, &resplen); // check response From 7c921c1e6e5100992cd1cfcfeb941d7b28a391fe Mon Sep 17 00:00:00 2001 From: Ray Lee Date: Fri, 6 Aug 2021 11:13:15 +0800 Subject: [PATCH 65/80] De-redundancy --- client/src/proxmark3.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index dd0ad9be2..d1f74bcba 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -127,15 +127,6 @@ static void prompt_compose(char *buf, size_t buflen, const char *promptctx, cons static int check_comm(void) { // If communications thread goes down. Device disconnected then this should hook up PM3 again. if (IsCommunicationThreadDead() && session.pm3_present) { -#ifdef HAVE_READLINE - char* saved_line; - int saved_point; - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - rl_set_prompt(""); - rl_replace_line("", 0); - rl_redisplay(); -#endif PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n"); prompt_dev = PROXPROMPT_DEV_OFFLINE; #ifdef HAVE_READLINE @@ -144,10 +135,7 @@ static int check_comm(void) { char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); rl_set_prompt(prompt_filtered); - rl_replace_line(saved_line, 0); - rl_point = saved_point; rl_redisplay(); - free(saved_line); #endif CloseProxmark(session.current_device); } From c27100295a800be92d6488fb3fa9c2c7924f18dd Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 14:52:33 +0300 Subject: [PATCH 66/80] fix iso command data --- client/src/mifare/desfirecore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index b5a4e1f44..17a7e0197 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2629,13 +2629,13 @@ int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen) { uint8_t p1 = 0; if (use_file_id) - p1 = 0x80 & (fileid & 0x1f); + p1 = 0x80 | (fileid & 0x1f); else p1 = (offset >> 8) & 0x7f; uint8_t p2 = offset & 0xff; uint16_t sw = 0; - int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, length, resp, resplen, &sw); + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) return PM3_ESOFT; @@ -2645,7 +2645,7 @@ int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen) { uint8_t p1 = 0; if (use_file_id) - p1 = 0x80 & (fileid & 0x1f); + p1 = 0x80 | (fileid & 0x1f); else p1 = (offset >> 8) & 0x7f; uint8_t p2 = offset & 0xff; @@ -2665,7 +2665,7 @@ int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all uint8_t p2 = ((fileid & 0x1f) << 3) | ((read_all_records) ? 0x05 : 0x04); uint16_t sw = 0; - int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, length, resp, resplen, &sw); + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) return PM3_ESOFT; From 409fb65a3fe3294ce56152c6e8bce1ac4888eae6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 14:52:58 +0300 Subject: [PATCH 67/80] add iso to read command and read bin file --- client/src/cmdhfmfdes.c | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a74c8ffa7..a05324224 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4924,6 +4924,42 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { static int DesfileReadISOFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filetype, uint32_t offset, uint32_t length, bool noauth, bool verbose) { + if (filetype == RFTAuto) { + PrintAndLogEx(ERR, "ISO mode needs to specify file type"); + return PM3_EINVARG; + } + + if (filetype == RFTValue) { + PrintAndLogEx(ERR, "ISO mode can't read Value file type"); + return PM3_EINVARG; + } + + if (filetype == RFTMAC) { + PrintAndLogEx(ERR, "ISO mode can't read Transaction MAC file type"); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "------------------------------- " _CYAN_("File ISO %02x data") " -------------------------------", fnum); + + uint8_t resp[2048] = {0}; + size_t resplen = 0; + int res = 0; + + if (filetype == RFTData) { + res = DesfireISOReadBinary(dctx, true, fnum, offset, length, resp, &resplen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire ISOReadBinary command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (resplen > 0) { + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x offset %u", resplen, fnum, offset); + print_buffer_with_offset(resp, resplen, offset, true); + } else { + PrintAndLogEx(SUCCESS, "Read operation returned no data from file %d", fnum); + } + } return PM3_SUCCESS; } @@ -5090,8 +5126,13 @@ static int CmdHF14ADesReadData(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes read", "Read data from file. Key needs to be provided or flag --no-auth set (depend on file settings).", + "It reads file via all command sets. \n" + "For ISO command set it can be read by specifying full 2-byte iso id or 1-byte short iso id (first byte of the full iso id). ISO id lays in the data in BIG ENDIAN format.\n" + "\n" "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command\n" - "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command"); + "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command\n" + "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0, all the data.\n"); + "hf mfdes read --aid 123456 --isofid 1000 --type data -c iso -> read file via ISO channel: app=123456, iso id=1000, offset=0, all the data."); void *argtable[] = { arg_param_begin, From b2ebbf3ed095f3bb99ae74a188122b532e396919 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 14:56:10 +0300 Subject: [PATCH 68/80] fix. remove todo) --- client/src/cmdhfmfdes.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a05324224..2cf38c5de 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5131,7 +5131,7 @@ static int CmdHF14ADesReadData(const char *Cmd) { "\n" "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command\n" "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command\n" - "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0, all the data.\n"); + "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0, all the data.\n" "hf mfdes read --aid 123456 --isofid 1000 --type data -c iso -> read file via ISO channel: app=123456, iso id=1000, offset=0, all the data."); void *argtable[] = { @@ -5760,7 +5760,6 @@ int CmdHFMFDes(const char *Cmd) { ISO/IEC 7816 Cmds ----------------- - 'B0' Read Binary 'D6' Update Binary 'B2' Read Records 'E2' Append Records From 67bfeeed3a9a110eaff4ed08fa9587d3b8645b12 Mon Sep 17 00:00:00 2001 From: Ray Lee Date: Fri, 6 Aug 2021 22:32:45 +0800 Subject: [PATCH 69/80] add support for Shanghai Feiju NTAG213 --- client/src/cmdhfmfu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 146fd0121..2ed3ce86b 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1269,6 +1269,7 @@ uint32_t GetHF14AMfU_Type(void) { NT2H1001G0DUx 0004040202000B03 NT2H1311TTDUx 0004040203000F03 Micron UL 0034210101000E03 + Feiju NTAG 0053040201000F03 */ if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; } @@ -1281,6 +1282,7 @@ uint32_t GetHF14AMfU_Type(void) { else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = NTAG_210u; break; } else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } + else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } //Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter) else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; } From d7aa4feae80034810697672eb22a4a49a91e7140 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 19:46:49 +0300 Subject: [PATCH 70/80] iso select rework --- client/src/mifare/desfirecore.c | 93 ++++++++++++++++++++++++++++++++- client/src/mifare/desfirecore.h | 14 +++++ 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 17a7e0197..54b486642 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -263,6 +263,10 @@ const char *DesfireAuthErrorToStr(int error) { return "Can't select application."; case 201: return "Authentication retured no error but channel not authenticated."; + case 202: + return "Can't select application by ISO ID."; + case 203: + return "Can't select file by ISO ID."; case 301: return "ISO Get challenge error."; case 302: @@ -886,6 +890,62 @@ int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secu return DesfireSelectAndAuthenticateEx(dctx, secureChannel, aid, false, verbose); } +int DesfireSelectAndAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, uint16_t isofileid, bool noauth, bool verbose) { + if (verbose) + DesfirePrintContext(dctx); + + int res = 0; + if (useaid) { + dctx->cmdSet = DCCNativeISO; + if (verbose) + PrintAndLogEx(INFO, "Select via " _CYAN_("native iso wrapping") " interface"); + + res = DesfireSelectAIDHex(dctx, aid, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + return 200; + } + if (verbose) + PrintAndLogEx(INFO, "App %06x via native iso channel is " _GREEN_("selected"), aid); + + dctx->cmdSet = DCCISO; + } else { + res = DesfireSelectEx(dctx, true, ISWIsoID, isoappid, NULL); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire iso application select " _RED_("error") "."); + return 202; + } + if (verbose) + PrintAndLogEx(INFO, "Application iso id %04x is " _GREEN_("selected"), isoappid); + + res = DesfireSelectEx(dctx, false, ISWIsoID, isofileid, NULL); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire iso file select " _RED_("error") "."); + return 203; + } + + if (verbose) + PrintAndLogEx(INFO, "Application iso id %04x file iso id %04x is " _GREEN_("selected"), isoappid, isofileid); + } + + if (!noauth) { + res = DesfireAuthenticate(dctx, secureChannel, verbose); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res)); + return res; + } + + if (DesfireIsAuthenticated(dctx)) { + if (verbose) + PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated")); + } else { + return 201; + } + } + + return PM3_SUCCESS; +} + static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) // 4 different crypto arg1 DES, 3DES, 3K3DES, AES @@ -2566,11 +2626,11 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para return res; } -int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) { +int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) { uint8_t xresp[250] = {0}; size_t xresplen = 0; uint16_t sw = 0; - int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw); + int res = DesfireExchangeISO(fieldon, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) return PM3_ESOFT; @@ -2585,6 +2645,10 @@ int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t return res; } +int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) { + return DesfireISOSelectEx(dctx, true, cntr, data, datalen, resp, resplen); +} + int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen); } @@ -2685,3 +2749,28 @@ int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, return res; } + +int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname) { + uint8_t resp[250] = {0}; + size_t resplen = 0; + + if (way == ISWMF || (way == ISWDFName && dfname == NULL)) { + return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen); + } else if (way == ISW6bAID) { + if (fieldon) + return DesfireSelectAIDHex(ctx, id, false, 0); + else + return DesfireSelectAIDHexNoFieldOn(ctx, id); + } else if (way == ISWIsoID) { + uint8_t data[2] = {0}; + Uint2byteToMemBe(data, id); + return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, data, 2, resp, &resplen); + } else if (way == ISWDFName) { + return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen); + } + return PM3_ESOFT; +} + +int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname) { + return DesfireSelectEx(ctx, true, way, id, dfname); +} diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 83af91767..a03e489eb 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -30,6 +30,14 @@ enum DesfireISOSelectControlEnum { }; typedef enum DesfireISOSelectControlEnum DesfireISOSelectControl; +enum DesfireISOSelectWayEnum { + ISW6bAID, + ISWMF, + ISWIsoID, + ISWDFName +}; +typedef enum DesfireISOSelectWayEnum DesfireISOSelectWay; + typedef struct { const uint8_t id; const char *text; @@ -160,9 +168,13 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); void DesfirePrintAIDFunctions(uint32_t appid); +int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname); +int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname); + const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose); +int DesfireSelectAndAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, uint16_t isofileid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose); void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck); void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck); @@ -230,6 +242,8 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen); +int DesfireISOSelectFile(DesfireContext *dctx, char *appdfname, uint16_t appid, uint16_t fileid); +int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen); int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data); int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); From 92cb18e7d241c5d5afac60ff4ea87389ad1f8086 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 19:47:12 +0300 Subject: [PATCH 71/80] read binary works --- client/src/cmdhfmfdes.c | 102 +++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2cf38c5de..2d650e617 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4922,7 +4922,7 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { return PM3_SUCCESS; } -static int DesfileReadISOFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filetype, uint32_t offset, uint32_t length, bool noauth, bool verbose) { +static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_file, uint8_t fnum, uint16_t fisoid, int filetype, uint32_t offset, uint32_t length, bool noauth, bool verbose) { if (filetype == RFTAuto) { PrintAndLogEx(ERR, "ISO mode needs to specify file type"); @@ -4939,14 +4939,17 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, uint8_t fnum, int fi return PM3_EINVARG; } - PrintAndLogEx(INFO, "------------------------------- " _CYAN_("File ISO %02x data") " -------------------------------", fnum); + if (select_current_file) + PrintAndLogEx(INFO, "------------------------------- " _CYAN_("File ISO %04x data") " -------------------------------", fisoid); + else + PrintAndLogEx(INFO, "---------------------------- " _CYAN_("File ISO short %02x data") " ----------------------------", fnum); uint8_t resp[2048] = {0}; size_t resplen = 0; int res = 0; if (filetype == RFTData) { - res = DesfireISOReadBinary(dctx, true, fnum, offset, length, resp, &resplen); + res = DesfireISOReadBinary(dctx, !select_current_file, (select_current_file) ? 0x00 : fnum, offset, length, resp, &resplen); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire ISOReadBinary command " _RED_("error") ". Result: %d", res); DropField(); @@ -4954,10 +4957,56 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, uint8_t fnum, int fi } if (resplen > 0) { - PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x offset %u", resplen, fnum, offset); + if (select_current_file) + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%04x offset %u", resplen, fisoid, offset); + else + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x offset %u", resplen, fnum, offset); print_buffer_with_offset(resp, resplen, offset, true); } else { - PrintAndLogEx(SUCCESS, "Read operation returned no data from file %d", fnum); + if (select_current_file) + PrintAndLogEx(SUCCESS, "Read operation returned no data from file %04x", fisoid); + else + PrintAndLogEx(SUCCESS, "Read operation returned no data from file %02x", fnum); + } + } + + if (filetype == RFTRecord) { + size_t reclen = 0; + res = DesfireISOReadRecords(dctx, offset, false, (select_current_file) ? 0x00 : fnum, 0, resp, &resplen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire ISOReadRecords (one record) command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + reclen = resplen - 8; + + if (verbose) + PrintAndLogEx(INFO, "Record length %zu", reclen); + + if (length > 1) { + res = DesfireISOReadRecords(dctx, offset, true, (select_current_file) ? 0x00 : fnum, 0, resp, &resplen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire ISOReadRecords (one record) command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + } + + if (resplen > 0) { + size_t reccount = resplen / reclen; + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x from record %d record count %zu record length %zu", resplen, fnum, offset, reccount, reclen); + if (reccount > 1) + PrintAndLogEx(SUCCESS, "Lastest record at the bottom."); + for (int i = 0; i < reccount; i++) { + if (i != 0) + PrintAndLogEx(SUCCESS, "Record %zu", reccount - (i + offset + 1)); + print_buffer_with_offset(&resp[i * reclen], reclen, offset, (i == 0)); + } + } else { + if (select_current_file) + PrintAndLogEx(SUCCESS, "Read operation returned no data from file %04x", fisoid); + else + PrintAndLogEx(SUCCESS, "Read operation returned no data from file %02x", fnum); } } @@ -5131,8 +5180,9 @@ static int CmdHF14ADesReadData(const char *Cmd) { "\n" "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command\n" "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command\n" - "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0, all the data.\n" - "hf mfdes read --aid 123456 --isofid 1000 --type data -c iso -> read file via ISO channel: app=123456, iso id=1000, offset=0, all the data."); + "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0.\n" + "hf mfdes read --aid 123456 --fileisoid 1000 --type data -c iso -> read file via ISO channel: app=123456, iso id=1000, offset=0. Select via native ISO wrapper\n" + "hf mfdes read --appisoid 0102 --fileisoid 1000 --type data -c iso -> read file via ISO channel: app iso id=0102, iso id=1000, offset=0. Select via ISO commands"); void *argtable[] = { arg_param_begin, @@ -5152,6 +5202,8 @@ static int CmdHF14ADesReadData(const char *Cmd) { arg_str0(NULL, "type", "", "File Type auto/data(Standard/Backup)/value/record(linear/cyclic)/mac). Auto - check file settings and then read. Default: auto"), arg_str0("o", "offset", "", "File Offset (3 hex bytes, big endian). For records - record number (0 - lastest record). Default 0"), arg_str0("l", "length", "", "Length to read (3 hex bytes, big endian -> 000000 = Read all data). For records - records count (0 - all). Default 0."), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), + arg_str0(NULL, "fileisoid", "", "File ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5199,6 +5251,24 @@ static int CmdHF14ADesReadData(const char *Cmd) { return PM3_EINVARG; } + uint32_t appisoid = 0x0000; + res = arg_get_u32_hexstr_def_nlen(ctx, 17, 0x0000, &appisoid, 2, true); + bool isoidpresent = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "Application ISO ID (for EF) must have 2 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint32_t fileisoid = 0x0000; + res = arg_get_u32_hexstr_def_nlen(ctx, 18, 0x0000, &fileisoid, 2, true); + bool fileisoidpresent = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "File ISO ID (for DF) must have 2 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -5207,16 +5277,24 @@ static int CmdHF14ADesReadData(const char *Cmd) { return PM3_EINVARG; } - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); - if (res != PM3_SUCCESS) { - DropField(); - return res; + if (!isoidpresent) { + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + } else { + res = DesfireSelectAndAuthenticateISO(&dctx, securechann, (appid != 0), appid, appisoid, fileisoid, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } } if (dctx.cmdSet != DCCISO) res = DesfileReadFileAndPrint(&dctx, fnum, op, offset, length, noauth, verbose); else - res = DesfileReadISOFileAndPrint(&dctx, fnum, op, offset, length, noauth, verbose); + res = DesfileReadISOFileAndPrint(&dctx, fileisoidpresent, fnum, fileisoid, op, offset, length, noauth, verbose); DropField(); return res; From 130ab34ab6283332fe706990aa27b7d69b5cc16b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:01:13 +0300 Subject: [PATCH 72/80] read record --- client/src/cmdhfmfdes.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2d650e617..9a57a4c77 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4978,12 +4978,12 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_ DropField(); return PM3_ESOFT; } - reclen = resplen - 8; + reclen = resplen; if (verbose) PrintAndLogEx(INFO, "Record length %zu", reclen); - if (length > 1) { + if (length != 1) { res = DesfireISOReadRecords(dctx, offset, true, (select_current_file) ? 0x00 : fnum, 0, resp, &resplen); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire ISOReadRecords (one record) command " _RED_("error") ". Result: %d", res); @@ -5177,12 +5177,15 @@ static int CmdHF14ADesReadData(const char *Cmd) { "Read data from file. Key needs to be provided or flag --no-auth set (depend on file settings).", "It reads file via all command sets. \n" "For ISO command set it can be read by specifying full 2-byte iso id or 1-byte short iso id (first byte of the full iso id). ISO id lays in the data in BIG ENDIAN format.\n" + "ISO record commands: offset - record number (0-current, 1..ff-number, 1-lastest), length - if 0 - all records, if 1 - one\n" "\n" "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command\n" "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command\n" "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via ISO channel: app=123456, short iso id=10, offset=0.\n" "hf mfdes read --aid 123456 --fileisoid 1000 --type data -c iso -> read file via ISO channel: app=123456, iso id=1000, offset=0. Select via native ISO wrapper\n" - "hf mfdes read --appisoid 0102 --fileisoid 1000 --type data -c iso -> read file via ISO channel: app iso id=0102, iso id=1000, offset=0. Select via ISO commands"); + "hf mfdes read --appisoid 0102 --fileisoid 1000 --type data -c iso -> read file via ISO channel: app iso id=0102, iso id=1000, offset=0. Select via ISO commands\n" + "hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000001 -> get one record (number 5) from file 1100 via iso commands\n" + "hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000000 -> get all record (from 5 to 1) from file 1100 via iso commands"); void *argtable[] = { arg_param_begin, From 1b6531f50e71e1470d744b1af0cc36f8062917ff Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:02:49 +0300 Subject: [PATCH 73/80] text fix --- client/src/cmdhfmfdes.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 9a57a4c77..4b0ae7457 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4994,7 +4994,10 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_ if (resplen > 0) { size_t reccount = resplen / reclen; - PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x from record %d record count %zu record length %zu", resplen, fnum, offset, reccount, reclen); + if (select_current_file) + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%04x from record %d record count %zu record length %zu", resplen, fisoid, offset, reccount, reclen); + else + PrintAndLogEx(SUCCESS, "Read %zu bytes from file 0x%02x from record %d record count %zu record length %zu", resplen, fnum, offset, reccount, reclen); if (reccount > 1) PrintAndLogEx(SUCCESS, "Lastest record at the bottom."); for (int i = 0; i < reccount; i++) { From 0d551b3940a120c5b9a20fae08f4ff4728367e60 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:03:49 +0300 Subject: [PATCH 74/80] todo --- client/src/cmdhfmfdes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 4b0ae7457..7d2cf0ce4 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5845,7 +5845,6 @@ int CmdHFMFDes(const char *Cmd) { ISO/IEC 7816 Cmds ----------------- 'D6' Update Binary - 'B2' Read Records 'E2' Append Records */ From d92c8f1bff9f33487b02d04add7cb05ecabc48df Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:27:04 +0300 Subject: [PATCH 75/80] iso mac calculation --- client/src/mifare/desfirecore.c | 5 +-- client/src/mifare/desfiresecurechan.c | 44 +++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 54b486642..6411071d3 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -677,11 +677,12 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext *ctx, ui } static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) { + uint8_t r[1050] = {0}; uint32_t rlen = 0; - int res = DESFIRESendApduEx(activate_field, apdu, le, resp, 255, &rlen, sw); + int res = DESFIRESendApduEx(activate_field, apdu, le, r, 255, &rlen, sw); if (res == PM3_SUCCESS) - *resplen = rlen; + DesfireSecureChannelDecode(ctx, r, rlen, 0, resp, resplen); return res; } diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index d5bc141d0..11067d7fb 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -471,8 +471,8 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac); if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); - PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); - PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx))); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx))); } else { if (GetAPDULogging()) PrintAndLogEx(INFO, "Received MAC OK"); @@ -521,8 +521,8 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac); if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); - PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); - PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx))); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx))); } else { if (GetAPDULogging()) PrintAndLogEx(INFO, "Received MAC OK"); @@ -538,8 +538,8 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac); if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); - PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); - PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx))); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx))); } else { if (GetAPDULogging()) PrintAndLogEx(INFO, "Received MAC OK"); @@ -559,7 +559,39 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, } } +static void DesfireISODecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + uint8_t data[1050] = {0}; + + if (srcdatalen < DesfireGetMACLength(ctx)) + return; + + uint8_t maclen = DesfireGetMACLength(ctx); + if (DesfireIsAuthenticated(ctx)) { + memcpy(data, srcdata, srcdatalen - maclen); + data[*dstdatalen] = 0x00; // respcode + + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireCryptoCMAC(ctx, data, srcdatalen - maclen + 1, cmac); + if (memcmp(&srcdata[srcdatalen - maclen], cmac, maclen) != 0) { + PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); + PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen)); + PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, maclen)); + } else { + *dstdatalen = srcdatalen - maclen; + if (GetAPDULogging()) + PrintAndLogEx(INFO, "Received MAC OK"); + } + } +} + void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + if (ctx->cmdSet == DCCISO) { + DesfireISODecode(ctx, srcdata, srcdatalen, dstdata, dstdatalen); + return; + } + switch (ctx->secureChannel) { case DACd40: DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); From 6c3cac9c63f203c4927ae21c1f55ee9daf0e4660 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:31:12 +0300 Subject: [PATCH 76/80] fix buffer length --- client/src/mifare/desfirecore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 6411071d3..efc499cf0 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -677,12 +677,12 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext *ctx, ui } static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) { - uint8_t r[1050] = {0}; - uint32_t rlen = 0; - int res = DESFIRESendApduEx(activate_field, apdu, le, r, 255, &rlen, sw); + uint8_t data[1050] = {0}; + uint32_t datalen = 0; + int res = DESFIRESendApduEx(activate_field, apdu, le, data, sizeof(data), &datalen, sw); if (res == PM3_SUCCESS) - DesfireSecureChannelDecode(ctx, r, rlen, 0, resp, resplen); + DesfireSecureChannelDecode(ctx, data, datalen, 0, resp, resplen); return res; } From 39be125df31c0bb09feda2735757a489c9262699 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 21:38:13 +0300 Subject: [PATCH 77/80] write binary works --- client/src/cmdhfmfdes.c | 96 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 7d2cf0ce4..3bae080d0 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5306,6 +5306,57 @@ static int CmdHF14ADesReadData(const char *Cmd) { return res; } +static int DesfileWriteISOFile(DesfireContext *dctx, bool select_current_file, uint8_t fnum, uint16_t fisoid, int filetype, uint32_t offset, uint8_t *data, uint32_t datalen, bool verbose) { + + if (filetype == RFTAuto) { + PrintAndLogEx(ERR, "ISO mode needs to specify file type"); + return PM3_EINVARG; + } + + if (filetype == RFTValue) { + PrintAndLogEx(ERR, "ISO mode can't write Value file type"); + return PM3_EINVARG; + } + + if (filetype == RFTMAC) { + PrintAndLogEx(ERR, "ISO mode can't write Transaction MAC file type"); + return PM3_EINVARG; + } + + if (dctx->commMode != DCMPlain) { + PrintAndLogEx(ERR, "ISO mode can write only in plain mode"); + return PM3_EINVARG; + } + + int res = 0; + if (filetype == RFTData) { + res = DesfireISOUpdateBinary(dctx, !select_current_file, (select_current_file) ? 0x00 : fnum, offset, data, datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire ISOUpdateBinary command " _RED_("error") ". Result: %d", res); + return PM3_ESOFT; + } + + if (select_current_file) + PrintAndLogEx(INFO, "Write data file %04x " _GREEN_("success"), fisoid); + else + PrintAndLogEx(INFO, "Write data file %02x " _GREEN_("success"), fnum); + } + + if (filetype == RFTRecord) { + res = DesfireISOAppendRecord(dctx, (select_current_file) ? 0x00 : fnum, data, datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire WriteRecord command " _RED_("error") ". Result: %d", res); + return PM3_ESOFT; + } + if (select_current_file) + PrintAndLogEx(INFO, "Write record to file %04x " _GREEN_("success"), fisoid); + else + PrintAndLogEx(INFO, "Write record to file %02x " _GREEN_("success"), fnum); + } + + return PM3_SUCCESS; +} + static int CmdHF14ADesWriteData(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes write", @@ -5341,6 +5392,8 @@ static int CmdHF14ADesWriteData(const char *Cmd) { arg_lit0(NULL, "debit", "use for value file debit operation instead of credit"), arg_lit0(NULL, "commit", "commit needs for backup file only. For the other file types and in the `auto` mode - command set it automatically."), arg_int0(NULL, "updaterec", "", "Record number for update record command. Updates record instead of write. Lastest record - 0"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), + arg_str0(NULL, "fileisoid", "", "File ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5394,6 +5447,24 @@ static int CmdHF14ADesWriteData(const char *Cmd) { int updaterecno = arg_get_int_def(ctx, 19, -1); + uint32_t appisoid = 0x0000; + res = arg_get_u32_hexstr_def_nlen(ctx, 20, 0x0000, &appisoid, 2, true); + bool isoidpresent = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "Application ISO ID (for EF) must have 2 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint32_t fileisoid = 0x0000; + res = arg_get_u32_hexstr_def_nlen(ctx, 21, 0x0000, &fileisoid, 2, true); + bool fileisoidpresent = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "File ISO ID (for DF) must have 2 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -5402,8 +5473,29 @@ static int CmdHF14ADesWriteData(const char *Cmd) { return PM3_EINVARG; } - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); - if (res != PM3_SUCCESS) { + if (!isoidpresent) { + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + } else { + res = DesfireSelectAndAuthenticateISO(&dctx, securechann, (appid != 0), appid, appisoid, fileisoid, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + } + + // ISO command set + if (dctx.cmdSet == DCCISO) { + if (op == RFTRecord && updaterecno >= 0) { + PrintAndLogEx(ERR, "ISO mode can't update record. Only append."); + DropField(); + return PM3_EINVARG; + } + + res = DesfileWriteISOFile(&dctx, fileisoidpresent, fnum, fileisoid, op, offset, data, datalen, verbose); DropField(); return res; } From 53874fcd240d8c7418d2d906dd4d4182d03605a7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 23:09:27 +0300 Subject: [PATCH 78/80] add help --- client/src/cmdhfmfdes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 3bae080d0..0acea11bf 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5369,7 +5369,9 @@ static int CmdHF14ADesWriteData(const char *Cmd) { "hf mfdes write --aid 123456 --fid 01 -d 01020304 -> write data to record file with `auto` type\n" "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 -> write data to record file\n" "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 --updaterec 0 -> update record in the record file. record 0 - lastest record.\n" - "hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command"); + "hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command\n" + "hf mfdes write --appisoid 1234 --fileisoid 1000 --type data -c iso -d 01020304 -> write data to std/backup file via iso commandset\n" + "hf mfdes write --appisoid 1234 --fileisoid 2000 --type record -c iso -d 01020304 -> aend record to record file via iso commandset"); void *argtable[] = { arg_param_begin, From ac7be1c4f476203544548e7f75afcb64f6e5a359 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 23:10:40 +0300 Subject: [PATCH 79/80] remove todo --- client/src/cmdhfmfdes.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 0acea11bf..8e1ccb5d3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5932,13 +5932,3 @@ int CmdHFMFDes(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } - -/* - ToDo: - - ISO/IEC 7816 Cmds - ----------------- - 'D6' Update Binary - 'E2' Append Records - -*/ From e822cf5b1e7f9b76bbbb32df5e4d8f9bfbf06a2a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 6 Aug 2021 23:45:53 +0300 Subject: [PATCH 80/80] make style --- client/src/cmdhfmfdes.c | 12 +++---- client/src/mifare/desfirecore.c | 12 +++---- client/src/mifare/desfiresecurechan.c | 10 +++--- doc/commands.json | 47 +++++++++++++++++++++------ 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 8e1ccb5d3..3d6aa95c9 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4928,7 +4928,7 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_ PrintAndLogEx(ERR, "ISO mode needs to specify file type"); return PM3_EINVARG; } - + if (filetype == RFTValue) { PrintAndLogEx(ERR, "ISO mode can't read Value file type"); return PM3_EINVARG; @@ -4938,7 +4938,7 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_ PrintAndLogEx(ERR, "ISO mode can't read Transaction MAC file type"); return PM3_EINVARG; } - + if (select_current_file) PrintAndLogEx(INFO, "------------------------------- " _CYAN_("File ISO %04x data") " -------------------------------", fisoid); else @@ -4947,7 +4947,7 @@ static int DesfileReadISOFileAndPrint(DesfireContext *dctx, bool select_current_ uint8_t resp[2048] = {0}; size_t resplen = 0; int res = 0; - + if (filetype == RFTData) { res = DesfireISOReadBinary(dctx, !select_current_file, (select_current_file) ? 0x00 : fnum, offset, length, resp, &resplen); if (res != PM3_SUCCESS) { @@ -5312,7 +5312,7 @@ static int DesfileWriteISOFile(DesfireContext *dctx, bool select_current_file, u PrintAndLogEx(ERR, "ISO mode needs to specify file type"); return PM3_EINVARG; } - + if (filetype == RFTValue) { PrintAndLogEx(ERR, "ISO mode can't write Value file type"); return PM3_EINVARG; @@ -5322,12 +5322,12 @@ static int DesfileWriteISOFile(DesfireContext *dctx, bool select_current_file, u PrintAndLogEx(ERR, "ISO mode can't write Transaction MAC file type"); return PM3_EINVARG; } - + if (dctx->commMode != DCMPlain) { PrintAndLogEx(ERR, "ISO mode can write only in plain mode"); return PM3_EINVARG; } - + int res = 0; if (filetype == RFTData) { res = DesfireISOUpdateBinary(dctx, !select_current_file, (select_current_file) ? 0x00 : fnum, offset, data, datalen); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 364d2780c..0a2edd8e5 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1590,7 +1590,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } } } - + // field on-off zone DesfireFillPICCInfo(dctx, PICCInfo, deepmode); @@ -2586,7 +2586,7 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke cdatalen += 4; } } - + // send command uint8_t resp[257] = {0}; size_t resplen = 0; @@ -2698,7 +2698,7 @@ int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, else p1 = (offset >> 8) & 0x7f; uint8_t p2 = offset & 0xff; - + uint16_t sw = 0; int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) @@ -2717,7 +2717,7 @@ int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t filei uint8_t resp[250] = {0}; size_t resplen = 0; - + uint16_t sw = 0; int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) @@ -2728,7 +2728,7 @@ int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t filei int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen) { uint8_t p2 = ((fileid & 0x1f) << 3) | ((read_all_records) ? 0x05 : 0x04); - + uint16_t sw = 0; int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) @@ -2737,7 +2737,7 @@ int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all return res; } -int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen) { +int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen) { uint8_t p2 = ((fileid & 0x1f) << 3); uint8_t resp[250] = {0}; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 11067d7fb..ced1fd073 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -563,10 +563,10 @@ static void DesfireISODecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcda memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; uint8_t data[1050] = {0}; - + if (srcdatalen < DesfireGetMACLength(ctx)) return; - + uint8_t maclen = DesfireGetMACLength(ctx); if (DesfireIsAuthenticated(ctx)) { memcpy(data, srcdata, srcdatalen - maclen); @@ -591,7 +591,7 @@ void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t sr DesfireISODecode(ctx, srcdata, srcdatalen, dstdata, dstdatalen); return; } - + switch (ctx->secureChannel) { case DACd40: DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); @@ -614,7 +614,7 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De PrintAndLogEx(WARNING, "Communication mode can't be NONE. command: %02x", cmd); return false; } - + // no security set if (secureChannel == DACNone) return true; @@ -626,7 +626,7 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De if (cmdSet == DCCISO) { bool res = DesfireISOChannelValidCmd(cmd); if (!res) - return false; + return false; } bool found = false; diff --git a/doc/commands.json b/doc/commands.json index 434296a12..4c1d8f632 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -973,7 +973,7 @@ }, "help": { "command": "help", - "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210804.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", + "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210806.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", "notes": [ "auto" ], @@ -4768,8 +4768,17 @@ "command": "hf mfdes read", "description": "read data from file. key needs to be provided or flag --no-auth set (depend on file settings).", "notes": [ + "it reads file via all command sets.", + "for iso command set it can be read by specifying full 2-byte iso id or 1-byte short iso id (first byte of the full iso id). iso id lays in the data in big endian format.", + "iso record commands: offset - record number (0-current, 1..ff-number, 1-lastest), length - if 0 - all records, if 1 - one", + "", "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command", - "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command" + "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command", + "hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via iso channel: app=123456, short iso id=10, offset=0.", + "hf mfdes read --aid 123456 --fileisoid 1000 --type data -c iso -> read file via iso channel: app=123456, iso id=1000, offset=0. select via native iso wrapper", + "hf mfdes read --appisoid 0102 --fileisoid 1000 --type data -c iso -> read file via iso channel: app iso id=0102, iso id=1000, offset=0. select via iso commands", + "hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000001 -> get one record (number 5) from file 1100 via iso commands", + "hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000000 -> get all record (from 5 to 1) from file 1100 via iso commands" ], "offline": false, "options": [ @@ -4789,9 +4798,11 @@ "--no-auth execute without authentication", "--type file type auto/data(standard/backup)/value/record(linear/cyclic)/mac). auto - check file settings and then read. default: auto", "-o, --offset file offset (3 hex bytes, big endian). for records - record number (0 - lastest record). default 0", - "-l, --length length to read (3 hex bytes, big endian -> 000000 = read all data). for records - records count (0 - all). default 0." + "-l, --length length to read (3 hex bytes, big endian -> 000000 = read all data). for records - records count (0 - all). default 0.", + "--appisoid application iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands.", + "--fileisoid file iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands." ], - "usage": "hf mfdes read [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--fid ] [--no-auth] [--type ] [-o ] [-l ]" + "usage": "hf mfdes read [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--fid ] [--no-auth] [--type ] [-o ] [-l ] [--appisoid ] [--fileisoid ]" }, "hf mfdes selectapp": { "command": "hf mfdes selectapp", @@ -4826,8 +4837,20 @@ "command": "hf mfdes setconfig", "description": "set card configuration. warning! danger zone! needs to provide card's master key and works if not blocked by config.", "notes": [ - "hf mfdes setconfig --param 03 --data 0428 -> set parameter 03", - "hf mfdes setconfig --param 02 --data 0875778102637264 -> set parameter 02" + "more about options mf2dlhx0.pdf. options list:", + "00h picc configuration.", + "02h ats update.", + "03h sak update", + "04h secure messaging configuration.", + "05h capability data. (here change for lrp in the desfire light)", + "06h df name renaming", + "08h file renaming", + "09h value file configuration", + "0ah failed authentication counter setting", + "0bh hw configuration", + "", + "hf mfdes setconfig --param 03 --data 0428 -> set sak", + "hf mfdes setconfig --param 02 --data 0875778102637264 -> set ats (first byte - length)" ], "offline": false, "options": [ @@ -4901,7 +4924,9 @@ "hf mfdes write --aid 123456 --fid 01 -d 01020304 -> write data to record file with `auto` type", "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 -> write data to record file", "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 --updaterec 0 -> update record in the record file. record 0 - lastest record.", - "hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command" + "hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command", + "hf mfdes write --appisoid 1234 --fileisoid 1000 --type data -c iso -d 01020304 -> write data to std/backup file iso commandset", + "hf mfdes write --appisoid 1234 --fileisoid 2000 --type record -c iso -d 01020304 -> aend record to record file via iso commandset" ], "offline": false, "options": [ @@ -4924,9 +4949,11 @@ "-d, --data data for write (data/record file), credit/debit(value file)", "--debit use for value file debit operation instead of credit", "--commit commit needs for backup file only. for the other file types and in the `auto` mode - command set it automatically.", - "--updaterec record number for update record command. updates record instead of write. lastest record - 0" + "--updaterec record number for update record command. updates record instead of write. lastest record - 0", + "--appisoid application iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands.", + "--fileisoid file iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands." ], - "usage": "hf mfdes write [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--fid ] [--no-auth] [--type ] [-o ] [-d ] [--debit] [--commit] [--updaterec ]" + "usage": "hf mfdes write [-hav] [-n ] [-t ] [-k ] [-f ] [-i ] [-m ] [-c ] [-s ] [--aid ] [--fid ] [--no-auth] [--type ] [-o ] [-d ] [--debit] [--commit] [--updaterec ] [--appisoid ] [--fileisoid ]" }, "hf mfp auth": { "command": "hf mfp auth", @@ -9864,6 +9891,6 @@ "metadata": { "commands_extracted": 587, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2021-08-04T21:00:22" + "extracted_on": "2021-08-06T20:40:15" } } \ No newline at end of file