From 88c16d2868cbfdef00cedb20faf3d8ddb4c398ea Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 19 Aug 2021 20:10:50 +0300 Subject: [PATCH 01/17] read2 commands --- client/src/mifare/desfiresecurechan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 8a92df73a..39640f685 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -167,10 +167,15 @@ static const CmdHeaderLengthsS CmdHeaderLengths[] = { {MFDES_CHANGE_FILE_SETTINGS, 1}, {MFDES_CREATE_TRANS_MAC_FILE, 5}, {MFDES_READ_DATA, 7}, + {MFDES_READ_DATA2, 7}, {MFDES_WRITE_DATA, 7}, + {MFDES_WRITE_DATA2, 7}, {MFDES_READ_RECORDS, 7}, + {MFDES_READ_RECORDS2, 7}, {MFDES_WRITE_RECORD, 7}, + {MFDES_WRITE_RECORD2, 7}, {MFDES_UPDATE_RECORD, 10}, + {MFDES_UPDATE_RECORD2, 10}, }; static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { From a7b132a6204c252ac3426ce6e51bf8f2674a517d Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 19 Aug 2021 20:11:10 +0300 Subject: [PATCH 02/17] read pm3 command --- client/src/cmdhfmfdes.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 44e325c43..5208d305a 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4662,8 +4662,9 @@ 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, 0, &securechann, DCMMACed, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -4693,13 +4694,6 @@ static int CmdHF14ADesReadData(const char *Cmd) { return PM3_EINVARG; } - uint32_t appisoid = 0x0000; - bool isoidpresent = false; - if (CLIGetUint32Hex(ctx, 17, 0x0000, &appisoid, &isoidpresent, 2, "Application ISO ID (for EF) must have 2 bytes length")) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - uint32_t fileisoid = 0x0000; bool fileisoidpresent = false; if (CLIGetUint32Hex(ctx, 18, 0x0000, &fileisoid, &fileisoidpresent, 2, "File ISO ID (for DF) must have 2 bytes length")) { @@ -4715,18 +4709,11 @@ static int CmdHF14ADesReadData(const char *Cmd) { return PM3_EINVARG; } - 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, true, fileisoid, noauth, verbose); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } + res = DesfireSelectAndAuthenticateW(&dctx, securechann, selectway, id, noauth, true, fileisoid, verbose); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); + return res; } if (dctx.cmdSet != DCCISO) From 9d6567edceb9a612869ecff3d525b6e9d8a4acc2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 17:36:43 +0300 Subject: [PATCH 03/17] plain read works --- client/src/cmdhfmfdes.c | 8 ++++++-- client/src/mifare/desfirecore.c | 10 +++++----- client/src/mifare/desfirecrypto.c | 3 +-- client/src/mifare/desfirecrypto.h | 3 +-- client/src/mifare/desfiresecurechan.c | 5 +++++ 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 5208d305a..a221ed267 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4461,6 +4461,9 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet int res = 0; // length of record for record file size_t reclen = 0; + + // iso chaining works in the lrp mode + dctx->isoChaining = (dctx->secureChannel == DACLRP); // get file settings if (filetype == RFTAuto) { @@ -4502,7 +4505,7 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet if (fsettings.fileCommMode != 0 && noauth) PrintAndLogEx(WARNING, "File needs communication mode `%s` but there is no authentication", CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)); - if ((fsettings.rAccess < 0x0e && fsettings.rAccess != dctx->keyNum) || (fsettings.rwAccess < 0x0e && fsettings.rwAccess != dctx->keyNum)) + if ((fsettings.rAccess < 0x0e && fsettings.rAccess != dctx->keyNum) && (fsettings.rwAccess < 0x0e && fsettings.rwAccess != dctx->keyNum)) PrintAndLogEx(WARNING, "File needs to be authenticated with key 0x%02x or 0x%02x but current authentication key is 0x%02x", fsettings.rAccess, fsettings.rwAccess, dctx->keyNum); if (fsettings.rAccess == 0x0f && fsettings.rwAccess == 0x0f) @@ -4630,7 +4633,8 @@ static int CmdHF14ADesReadData(const char *Cmd) { "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\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"); + "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\n" + "hf mfdes read --appisoid df01 --fid 00 -s lrp -t aes -> read via lrp"); void *argtable[] = { arg_param_begin, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 2f8b33006..767c977a0 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2083,7 +2083,7 @@ int DesfireReadFile(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_ Uint3byteToMemLe(&data[1], offset); Uint3byteToMemLe(&data[4], len); - return DesfireCommand(dctx, MFDES_READ_DATA, data, 7, resp, resplen, -1); + return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_DATA2 : MFDES_READ_DATA, data, 7, resp, resplen, -1); } int DesfireWriteFile(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data) { @@ -2093,7 +2093,7 @@ int DesfireWriteFile(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32 Uint3byteToMemLe(&xdata[4], len); memcpy(&xdata[7], data, len); - return DesfireCommandTxData(dctx, MFDES_WRITE_DATA, xdata, 7 + len); + return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_WRITE_DATA2 : MFDES_WRITE_DATA, xdata, 7 + len); } int DesfireValueFileOperations(DesfireContext *dctx, uint8_t fid, uint8_t operation, uint32_t *value) { @@ -2119,7 +2119,7 @@ int DesfireReadRecords(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint Uint3byteToMemLe(&data[1], recnum); Uint3byteToMemLe(&data[4], reccount); - return DesfireCommand(dctx, MFDES_READ_RECORDS, data, 7, resp, resplen, -1); + return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_RECORDS2 : MFDES_READ_RECORDS, data, 7, resp, resplen, -1); } int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data) { @@ -2129,7 +2129,7 @@ int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint Uint3byteToMemLe(&xdata[4], len); memcpy(&xdata[7], data, len); - return DesfireCommandTxData(dctx, MFDES_WRITE_RECORD, xdata, 7 + len); + return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_WRITE_RECORD2 : MFDES_WRITE_RECORD, xdata, 7 + len); } int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data) { @@ -2140,7 +2140,7 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin Uint3byteToMemLe(&xdata[7], len); memcpy(&xdata[10], data, len); - return DesfireCommandTxData(dctx, MFDES_UPDATE_RECORD, xdata, 10 + len); + return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_UPDATE_RECORD2 : MFDES_UPDATE_RECORD, xdata, 10 + len); } static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 500486486..fee29f340 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -37,12 +37,11 @@ void DesfireClearContext(DesfireContext *ctx) { ctx->keyType = T_DES; memset(ctx->key, 0, sizeof(ctx->key)); - LRPClearContext(&ctx->lrpCtx); - ctx->secureChannel = DACNone; ctx->cmdSet = DCCNative; ctx->commMode = DCMNone; + ctx->isoChaining = false; ctx->appSelected = false; ctx->selectedAID = 0; diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 7d19a5c28..78d0ceee5 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -78,8 +78,6 @@ typedef struct DesfireContextS { uint8_t key[DESFIRE_MAX_KEY_SIZE]; uint8_t masterKey[DESFIRE_MAX_KEY_SIZE]; // source for kdf - LRPContext lrpCtx; - // KDF finction uint8_t kdfAlgo; uint8_t kdfInputLen; @@ -89,6 +87,7 @@ typedef struct DesfireContextS { DesfireCommandSet cmdSet; // native/nativeiso/iso DesfireCommunicationMode commMode; // plain/mac/enc + bool isoChaining; bool appSelected; // for iso auth uint32_t selectedAID; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 39640f685..746beaebf 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -25,11 +25,16 @@ static const uint8_t CommandsCanUseAnyChannel[] = { MFDES_S_ADDITIONAL_FRAME, MFDES_READ_DATA, + MFDES_READ_DATA2, MFDES_WRITE_DATA, + MFDES_WRITE_DATA2, MFDES_GET_VALUE, MFDES_READ_RECORDS, + MFDES_READ_RECORDS2, MFDES_WRITE_RECORD, + MFDES_WRITE_RECORD2, MFDES_UPDATE_RECORD, + MFDES_UPDATE_RECORD2, }; static bool CommandCanUseAnyChannel(uint8_t cmd) { From 32ad6ef9454289e3b459a94509ad76dc9c0ec4a8 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:25:15 +0300 Subject: [PATCH 04/17] lrp write works --- client/src/cmdhfmfdes.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a221ed267..28c60d69b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4834,8 +4834,9 @@ static int CmdHF14ADesWriteData(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, 0, &securechann, DCMPlain, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -4873,13 +4874,6 @@ static int CmdHF14ADesWriteData(const char *Cmd) { int updaterecno = arg_get_int_def(ctx, 19, -1); - uint32_t appisoid = 0x0000; - bool isoidpresent = false; - if (CLIGetUint32Hex(ctx, 20, 0x0000, &appisoid, &isoidpresent, 2, "Application ISO ID (for EF) must have 2 bytes length")) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - uint32_t fileisoid = 0x0000; bool fileisoidpresent = false; if (CLIGetUint32Hex(ctx, 21, 0x0000, &fileisoid, &fileisoidpresent, 2, "File ISO ID (for DF) must have 2 bytes length")) { @@ -4917,18 +4911,11 @@ static int CmdHF14ADesWriteData(const char *Cmd) { if (trkeylen > 0) DesfireGetCardUID(&dctx); - 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, true, fileisoid, noauth, verbose); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } + res = DesfireSelectAndAuthenticateW(&dctx, securechann, selectway, id, noauth, true, fileisoid, verbose); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); + return res; } // ISO command set @@ -4990,6 +4977,12 @@ static int CmdHF14ADesWriteData(const char *Cmd) { if (fsettings.fileCommMode != 0 && noauth) PrintAndLogEx(WARNING, "File needs communication mode `%s` but there is no authentication", CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)); + if ((fsettings.rAccess < 0x0e && fsettings.rAccess != dctx.keyNum) && (fsettings.rwAccess < 0x0e && fsettings.rwAccess != dctx.keyNum)) + PrintAndLogEx(WARNING, "File needs to be authenticated with key 0x%02x or 0x%02x but current authentication key is 0x%02x", fsettings.rAccess, fsettings.rwAccess, dctx.keyNum); + + if (fsettings.rAccess == 0x0f && fsettings.rwAccess == 0x0f) + PrintAndLogEx(WARNING, "File access denied. All read access rights is 0x0f."); + if (verbose) PrintAndLogEx(INFO, "Got file type: %s. Option: %s. comm mode: %s", GetDesfireFileType(fsettings.fileType), @@ -5032,6 +5025,9 @@ static int CmdHF14ADesWriteData(const char *Cmd) { PrintAndLogEx(WARNING, "Desfire CommitReaderID command " _RED_("error") ". Result: %d", res); } + // iso chaining works in the lrp mode + dctx.isoChaining = (dctx.secureChannel == DACLRP); + // write if (op == RFTData) { res = DesfireWriteFile(&dctx, fnum, offset, datalen, data); From f3b368ebb6f623a8933b86a41f65dcd632a86aec Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:48:24 +0300 Subject: [PATCH 05/17] value operations plain get works --- client/src/cmdhfmfdes.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 28c60d69b..e1cd364b7 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4153,6 +4153,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), arg_str0(NULL, "fid", "", "File ID (1 hex byte)"), arg_str0("o", "op", "", "Operation: get(default)/credit/limcredit(limited credit)/debit/clear. Operation clear: get-getopt-debit to min value"), arg_str0("d", "data", "", "Value for operation (HEX 4 bytes)"), @@ -4163,31 +4164,32 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 15); + bool noauth = arg_get_lit(ctx, 16); DesfireContext dctx; int securechann = defaultSecureChannel; - uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t fileid = 1; - if (CLIGetUint32Hex(ctx, 12, 1, &fileid, NULL, 1, "File ID must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 1, &fileid, NULL, 1, "File ID must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } int op = MFDES_GET_VALUE; - if (CLIGetOptionList(arg_get_str(ctx, 13), DesfireValueFileOperOpts, &op)) { + if (CLIGetOptionList(arg_get_str(ctx, 14), DesfireValueFileOperOpts, &op)) { CLIParserFree(ctx); return PM3_ESOFT; } uint32_t value = 0; - if (CLIGetUint32Hex(ctx, 14, 0, &value, NULL, 4, "Value must have 4 byte length")) { + if (CLIGetUint32Hex(ctx, 15, 0, &value, NULL, 4, "Value must have 4 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -4195,14 +4197,19 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + // iso chaining works in the lrp mode + dctx.isoChaining = (dctx.secureChannel == DACLRP); + + // select + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } if (verbose) - PrintAndLogEx(INFO, "app %06x file %02x operation: %s value: 0x%08x", appid, fileid, CLIGetOptionListStr(DesfireValueFileOperOpts, op), value); + PrintAndLogEx(INFO, "%s file %02x operation: %s value: 0x%08x", DesfireWayIDStr(selectway, id), fileid, CLIGetOptionListStr(DesfireValueFileOperOpts, op), value); if (op != 0xff) { res = DesfireValueFileOperations(&dctx, fileid, op, &value); @@ -4215,6 +4222,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { if (op == MFDES_GET_VALUE) { PrintAndLogEx(SUCCESS, "Value: " _GREEN_("%d (0x%08x)"), value, value); } else { + DesfireSetCommMode(&dctx, DCMMACed); res = DesfireCommitTransaction(&dctx, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire CommitTransaction command " _RED_("error") ". Result: %d", res); @@ -4271,6 +4279,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Value debited"); + DesfireSetCommMode(&dctx, DCMMACed); res = DesfireCommitTransaction(&dctx, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire CommitTransaction command " _RED_("error") ". Result: %d", res); From 534201b6d1b3bf00fedbe56626ec6b63a124b1b7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:53:56 +0300 Subject: [PATCH 06/17] lrp delete file works. value operations in the plain mode works too --- client/src/cmdhfmfdes.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e1cd364b7..95c734c8b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4065,7 +4065,8 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes deletefile", "Delete file from application. Master key needs to be provided or flag --no-auth set (depend on cards settings).", - "hf mfdes deletefile --aid 123456 --fid 01 -> delete file for: app=123456, file=01 with defaults from `default` command"); + "hf mfdes deletefile --aid 123456 --fid 01 -> delete file for: app=123456, file=01 with defaults from `default` command\n" + "hf mfdes deletefile --appisoid df01 --fid 0f -s lrp -t aes -> delete file for lrp channel"); void *argtable[] = { arg_param_begin, @@ -4080,6 +4081,7 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), arg_str0(NULL, "fid", "", "File ID (1 hex byte)"), arg_lit0(NULL, "no-auth", "execute without authentication"), arg_param_end @@ -4088,19 +4090,20 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 13); + bool noauth = arg_get_lit(ctx, 14); DesfireContext dctx; int securechann = defaultSecureChannel; - uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t fnum = 1; - if (CLIGetUint32Hex(ctx, 12, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -4113,9 +4116,10 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { return PM3_EINVARG; } - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } @@ -4126,7 +4130,7 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "File %02x in the app %06x deleted " _GREEN_("successfully"), fnum, appid); + PrintAndLogEx(SUCCESS, "File %02x in the %s deleted " _GREEN_("successfully"), fnum, DesfireWayIDStr(selectway, id)); DropField(); return PM3_SUCCESS; From 6516cfd6655305e09b89c9fc47722d0accb148c5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:25:44 +0300 Subject: [PATCH 07/17] create transaction mac file 1-byte command sketch --- client/src/cmdhfmfdes.c | 45 ++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 95c734c8b..0830561dc 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3952,7 +3952,8 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { "\n" "hf mfdes createmacfile --aid 123456 --fid 01 --rawrights 0FF0 --mackey 00112233445566778899aabbccddeeff --mackeyver 01 -> create transaction mac file with parameters. Rights from default. Authentication with defaults from `default` command\n" "hf mfdes createmacfile --aid 123456 --fid 01 --amode plain --rrights free --wrights deny --rwrights free --chrights key0 --mackey 00112233445566778899aabbccddeeff -> create file app=123456, file=01, with key, and mentioned rights with defaults from `default` command\n" - "hf mfdes createmacfile -n 0 -t des -k 0000000000000000 -f none --aid 123456 --fid 01 -> execute with default factory setup. key and keyver == 0x00..00"); + "hf mfdes createmacfile -n 0 -t des -k 0000000000000000 -f none --aid 123456 --fid 01 -> execute with default factory setup. key and keyver == 0x00..00\n" + "hf mfdes createmacfile --appisoid df01 --fid 0f -s lrp -t aes --defparams -> create transaction mac file via lrp channel with length of command 01 (Desfire Light)"); void *argtable[] = { arg_param_begin, @@ -3967,6 +3968,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), arg_str0(NULL, "fid", "", "File ID (1 hex byte)"), arg_str0(NULL, "amode", "", "File access mode: plain/mac/encrypt"), arg_str0(NULL, "rawrights", "", "Access rights for file (HEX 2 byte) R/W/RW/Chg, 0x0 - 0xD Key, 0xE Free, 0xF Denied"), @@ -3977,26 +3979,29 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { arg_lit0(NULL, "no-auth", "execute without authentication"), arg_str0(NULL, "mackey", "", "AES-128 key for MAC (16 hex bytes, big endian). Default 0x00..00"), arg_str0(NULL, "mackeyver", "", "AES key version for MAC (1 hex byte). Default 0x00"), + arg_lit0(NULL, "defparams", "do not provide key and etc (Desfire Light)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 19); + bool noauth = arg_get_lit(ctx, 20); + bool defparams = arg_get_lit(ctx, 23); uint8_t filetype = 0x05; // transaction mac file DesfireContext dctx; int securechann = defaultSecureChannel; - uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMEncrypted, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } - if (appid == 0x000000) { + if (DesfireMFSelected(selectway, id)) { PrintAndLogEx(ERR, "Can't create files at card level."); CLIParserFree(ctx); return PM3_EINVARG; @@ -4005,7 +4010,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { uint8_t data[250] = {0}; size_t datalen = 0; - res = DesfireCreateFileParameters(ctx, 12, 0, 13, 14, 15, 16, 17, 18, data, &datalen); + res = DesfireCreateFileParameters(ctx, 13, 0, 14, 15, 16, 17, 18, 19, data, &datalen); if (res) { CLIParserFree(ctx); return res; @@ -4013,7 +4018,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { uint8_t sdata[250] = {0}; int sdatalen = sizeof(sdata); - CLIGetHexWithReturn(ctx, 20, sdata, &sdatalen); + CLIGetHexWithReturn(ctx, 21, sdata, &sdatalen); if (sdatalen != 0 && sdatalen != 16) { PrintAndLogEx(ERR, "AES-128 key must be 16 bytes instead of %d.", sdatalen); CLIParserFree(ctx); @@ -4021,7 +4026,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { } uint32_t keyver = 0x00; - if (CLIGetUint32Hex(ctx, 21, 0x00, &keyver, NULL, 1, "Key version must have 1 bytes length")) { + if (CLIGetUint32Hex(ctx, 22, 0x00, &keyver, NULL, 1, "Key version must have 1 bytes length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -4037,25 +4042,37 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { data[datalen] = keyver & 0xff; datalen++; - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } + // data contains file id only + if (defparams) + datalen = 1; + if (verbose) - PrintAndLogEx(INFO, "App: %06x. File num: 0x%02x type: 0x%02x data[%zu]: %s", appid, data[0], filetype, datalen, sprint_hex(data, datalen)); - DesfirePrintCreateFileSettings(filetype, data, datalen); + PrintAndLogEx(INFO, "%s. File num: 0x%02x type: 0x%02x data[%zu]: %s", DesfireWayIDStr(selectway, id), data[0], filetype, datalen, sprint_hex(data, datalen)); + + if (defparams) { + PrintAndLogEx(INFO, "---- " _CYAN_("Create file settings") " ----"); + PrintAndLogEx(SUCCESS, "File type : transaction mac"); + PrintAndLogEx(SUCCESS, "File number : 0x%02x (%d)", data[0], data[0]); + PrintAndLogEx(SUCCESS, "Default settings : true"); + } else { + DesfirePrintCreateFileSettings(filetype, data, datalen); + } - - res = DesfireCreateFile(&dctx, filetype, data, datalen, true); + res = DesfireCreateFile(&dctx, filetype, data, datalen, !defparams); // cant check length if there is 1 byte data in the command if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire CreateFile command " _RED_("error") ". Result: %d", res); DropField(); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "%s file %02x in the app %06x created " _GREEN_("successfully"), GetDesfireFileType(filetype), data[0], appid); + PrintAndLogEx(SUCCESS, "%s file %02x in the %s created " _GREEN_("successfully"), GetDesfireFileType(filetype), data[0], DesfireWayIDStr(selectway, id)); DropField(); return PM3_SUCCESS; From e3a7b4ad1f9874f6a94ed3e66cf59371026ef5b5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:46:21 +0300 Subject: [PATCH 08/17] fix header length behavior --- client/src/mifare/desfiresecurechan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 746beaebf..01430070e 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -157,6 +157,7 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_GET_UID, DACLRP, DCCNative, DCMEncrypted}, {MFDES_CHANGE_FILE_SETTINGS, DACLRP, DCCNative, DCMEncrypted}, {MFDES_CHANGE_CONFIGURATION, DACLRP, DCCNative, DCMEncrypted}, + {MFDES_CREATE_TRANS_MAC_FILE, DACLRP, DCCNative, DCMEncrypted}, {MFDES_CHANGE_KEY, DACLRP, DCCNative, DCMEncryptedPlain}, }; @@ -261,6 +262,8 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = srcdatalen; uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + if (srcdatalen < hdrlen) + hdrlen = srcdatalen; if (ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) { if (srcdatalen == 0) @@ -317,6 +320,8 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = srcdatalen; uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + if (srcdatalen < hdrlen) + hdrlen = srcdatalen; // we calc MAC anyway // if encypted channel and no data - we only calc MAC @@ -371,6 +376,8 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = srcdatalen; uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + if (srcdatalen < hdrlen) + hdrlen = srcdatalen; if (ctx->commMode == DCMMACed) { uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; @@ -408,6 +415,8 @@ static void DesfireSecureChannelEncodeLRP(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = srcdatalen; uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + if (srcdatalen < hdrlen) + hdrlen = srcdatalen; if (ctx->commMode == DCMMACed) { uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; From f47b6f05d041f6a64d20294608ee9ec3b1eae8d3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:47:06 +0300 Subject: [PATCH 09/17] fix mode --- client/src/cmdhfmfdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 0830561dc..a63d4761b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3995,7 +3995,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; From b6118cbde9efd677ddfd136283991e708cf31831 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 20:00:13 +0300 Subject: [PATCH 10/17] add iso chaining options --- 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 a63d4761b..f1748f731 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4219,7 +4219,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { CLIParserFree(ctx); // iso chaining works in the lrp mode - dctx.isoChaining = (dctx.secureChannel == DACLRP); + dctx.isoChaining |= (dctx.secureChannel == DACLRP); // select res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); @@ -4493,7 +4493,7 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet size_t reclen = 0; // iso chaining works in the lrp mode - dctx->isoChaining = (dctx->secureChannel == DACLRP); + dctx->isoChaining |= (dctx->secureChannel == DACLRP); // get file settings if (filetype == RFTAuto) { @@ -4686,6 +4686,7 @@ static int CmdHF14ADesReadData(const char *Cmd) { 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)."), arg_str0(NULL, "fileisoid", "", "File ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), + arg_lit0(NULL, "isochain", "use iso chaining commands. Switched on by default if secure channel = lrp"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -4735,6 +4736,8 @@ static int CmdHF14ADesReadData(const char *Cmd) { return PM3_EINVARG; } + dctx.isoChaining = arg_get_lit(ctx, 19); + SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -5056,7 +5059,7 @@ static int CmdHF14ADesWriteData(const char *Cmd) { } // iso chaining works in the lrp mode - dctx.isoChaining = (dctx.secureChannel == DACLRP); + dctx.isoChaining |= (dctx.secureChannel == DACLRP); // write if (op == RFTData) { From 9d1519083275b70f2d6069c7b05506c612726cc8 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 20:05:01 +0300 Subject: [PATCH 11/17] some help --- client/src/cmdhfmfdes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f1748f731..379e96502 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4664,7 +4664,8 @@ static int CmdHF14ADesReadData(const char *Cmd) { "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\n" - "hf mfdes read --appisoid df01 --fid 00 -s lrp -t aes -> read via lrp"); + "hf mfdes read --appisoid df01 --fid 00 -s lrp -t aes -> read via lrp channel\n" + "hf mfdes read --appisoid df01 --fid 00 -s ev2 -t aes --isochain -> read Desfire Light via ev2 channel"); void *argtable[] = { arg_param_begin, From 1b0ffac58984ce1d6b3585fd090fd75b5da7265f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 22:57:07 +0300 Subject: [PATCH 12/17] createmacfile works, print lrp transaction counter --- client/src/cmdhfmfdes.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 379e96502..40ee8f032 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3953,7 +3953,8 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { "hf mfdes createmacfile --aid 123456 --fid 01 --rawrights 0FF0 --mackey 00112233445566778899aabbccddeeff --mackeyver 01 -> create transaction mac file with parameters. Rights from default. Authentication with defaults from `default` command\n" "hf mfdes createmacfile --aid 123456 --fid 01 --amode plain --rrights free --wrights deny --rwrights free --chrights key0 --mackey 00112233445566778899aabbccddeeff -> create file app=123456, file=01, with key, and mentioned rights with defaults from `default` command\n" "hf mfdes createmacfile -n 0 -t des -k 0000000000000000 -f none --aid 123456 --fid 01 -> execute with default factory setup. key and keyver == 0x00..00\n" - "hf mfdes createmacfile --appisoid df01 --fid 0f -s lrp -t aes --defparams -> create transaction mac file via lrp channel with length of command 01 (Desfire Light)"); + "hf mfdes createmacfile --appisoid df01 --fid 0f -s lrp -t aes --rawrights 0FF0 --mackey 00112233445566778899aabbccddeeff --mackeyver 01 -> create transaction mac file via lrp channel\n" + "hf mfdes createmacfile --appisoid df01 --fid 0f -s lrp -t aes --rawrights 0F10 --mackey 00112233445566778899aabbccddeeff --mackeyver 01 -> create transaction mac file via lrp channel with CommitReaderID command enable"); void *argtable[] = { arg_param_begin, @@ -3979,7 +3980,6 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { arg_lit0(NULL, "no-auth", "execute without authentication"), arg_str0(NULL, "mackey", "", "AES-128 key for MAC (16 hex bytes, big endian). Default 0x00..00"), arg_str0(NULL, "mackeyver", "", "AES key version for MAC (1 hex byte). Default 0x00"), - arg_lit0(NULL, "defparams", "do not provide key and etc (Desfire Light)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3987,7 +3987,6 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); bool noauth = arg_get_lit(ctx, 20); - bool defparams = arg_get_lit(ctx, 23); uint8_t filetype = 0x05; // transaction mac file @@ -4049,23 +4048,12 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { return res; } - // data contains file id only - if (defparams) - datalen = 1; - if (verbose) PrintAndLogEx(INFO, "%s. File num: 0x%02x type: 0x%02x data[%zu]: %s", DesfireWayIDStr(selectway, id), data[0], filetype, datalen, sprint_hex(data, datalen)); - if (defparams) { - PrintAndLogEx(INFO, "---- " _CYAN_("Create file settings") " ----"); - PrintAndLogEx(SUCCESS, "File type : transaction mac"); - PrintAndLogEx(SUCCESS, "File number : 0x%02x (%d)", data[0], data[0]); - PrintAndLogEx(SUCCESS, "Default settings : true"); - } else { - DesfirePrintCreateFileSettings(filetype, data, datalen); - } + DesfirePrintCreateFileSettings(filetype, data, datalen); - res = DesfireCreateFile(&dctx, filetype, data, datalen, !defparams); // cant check length if there is 1 byte data in the command + res = DesfireCreateFile(&dctx, filetype, data, datalen, true); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire CreateFile command " _RED_("error") ". Result: %d", res); DropField(); @@ -4636,9 +4624,17 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet PrintAndLogEx(WARNING, "Read wrong %zu bytes from file 0x%02x offset %u", resplen, fnum, offset); print_buffer_with_offset(resp, resplen, offset, true); } else { - uint32_t cnt = MemLeToUint4byte(&resp[0]); - transactionCounter = cnt; - PrintAndLogEx(SUCCESS, "Transaction counter: %d (0x%08x)", cnt, cnt); + if (dctx->secureChannel != DACLRP) { + uint32_t cnt = MemLeToUint4byte(&resp[0]); + transactionCounter = cnt; + PrintAndLogEx(SUCCESS, "Transaction counter: %d (0x%08x)", cnt, cnt); + } else { + uint32_t actTMC = MemLeToUint2byte(&resp[0]); + uint32_t sessTMC = MemLeToUint2byte(&resp[2]); + transactionCounter = actTMC; + PrintAndLogEx(SUCCESS, "Session tr counter : %d (0x%08x)", sessTMC, sessTMC); + PrintAndLogEx(SUCCESS, "Actual tr counter : %d (0x%08x)", actTMC, actTMC); + } PrintAndLogEx(SUCCESS, "Transaction MAC : %s", sprint_hex(&resp[4], 8)); } } else { From 87c05faffd9255f056255ee43ff0da8d461dcb4f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 23:02:52 +0300 Subject: [PATCH 13/17] add link --- client/src/cmdhfmfdes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 40ee8f032..1b5d003ae 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4629,6 +4629,8 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet transactionCounter = cnt; PrintAndLogEx(SUCCESS, "Transaction counter: %d (0x%08x)", cnt, cnt); } else { + // For composing TMC the two subparts are concatenated as follows: actTMC || sesTMC. Both subparts are represented LSB first. + // MF2DLHX0.pdf, 10.3.2.1 Transaction MAC Counter, page 41 uint32_t actTMC = MemLeToUint2byte(&resp[0]); uint32_t sessTMC = MemLeToUint2byte(&resp[2]); transactionCounter = actTMC; From f17dfa4e59d05c450e14f2b0f2dca6abb58f3a5e Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 23:49:53 +0300 Subject: [PATCH 14/17] fix text. read/write/value commands works --- client/src/cmdhfmfdes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 1b5d003ae..5b09192d1 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4662,8 +4662,8 @@ static int CmdHF14ADesReadData(const char *Cmd) { "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\n" - "hf mfdes read --appisoid df01 --fid 00 -s lrp -t aes -> read via lrp channel\n" - "hf mfdes read --appisoid df01 --fid 00 -s ev2 -t aes --isochain -> read Desfire Light via ev2 channel"); + "hf mfdes read --appisoid df01 --fid 00 -s lrp -t aes --length 000010 -> read via lrp channel\n" + "hf mfdes read --appisoid df01 --fid 00 -s ev2 -t aes --length 000010 --isochain -> read Desfire Light via ev2 channel"); void *argtable[] = { arg_param_begin, From 10561e99695c196f4b9d75213fe69ca1bfb7b46a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 20 Aug 2021 23:59:11 +0300 Subject: [PATCH 15/17] move transaction counter --- client/src/cmdhfmfdes.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 5b09192d1..2e4ddf173 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4624,16 +4624,15 @@ static int DesfileReadFileAndPrint(DesfireContext *dctx, uint8_t fnum, int filet PrintAndLogEx(WARNING, "Read wrong %zu bytes from file 0x%02x offset %u", resplen, fnum, offset); print_buffer_with_offset(resp, resplen, offset, true); } else { + uint32_t cnt = MemLeToUint4byte(&resp[0]); + transactionCounter = cnt; if (dctx->secureChannel != DACLRP) { - uint32_t cnt = MemLeToUint4byte(&resp[0]); - transactionCounter = cnt; PrintAndLogEx(SUCCESS, "Transaction counter: %d (0x%08x)", cnt, cnt); } else { // For composing TMC the two subparts are concatenated as follows: actTMC || sesTMC. Both subparts are represented LSB first. // MF2DLHX0.pdf, 10.3.2.1 Transaction MAC Counter, page 41 uint32_t actTMC = MemLeToUint2byte(&resp[0]); uint32_t sessTMC = MemLeToUint2byte(&resp[2]); - transactionCounter = actTMC; PrintAndLogEx(SUCCESS, "Session tr counter : %d (0x%08x)", sessTMC, sessTMC); PrintAndLogEx(SUCCESS, "Actual tr counter : %d (0x%08x)", actTMC, actTMC); } From 09b4c3eed1a8fd91bb06267a52b7e87592941a10 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 21 Aug 2021 00:05:04 +0300 Subject: [PATCH 16/17] rename --- client/src/cmdhfmfdes.c | 2 +- client/src/mifare/desfirecrypto.c | 2 +- client/src/mifare/desfirecrypto.h | 2 +- client/src/mifare/desfiretest.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2e4ddf173..31dd64750 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5043,7 +5043,7 @@ static int CmdHF14ADesWriteData(const char *Cmd) { uint8_t sessionkey[16] = {0}; uint8_t uid[7] = {0}; memcpy(uid, dctx.uid, MAX(dctx.uidlen, 7)); - DesfireGenTransSessionKey(trkey, transactionCounter, uid, false, sessionkey); + DesfireGenTransSessionKeyEV2(trkey, transactionCounter, uid, false, sessionkey); aes_decode(NULL, sessionkey, resp, resp, CRYPTO_AES_BLOCK_SIZE); PrintAndLogEx(INFO, "Prev reader id [%zu]: %s", resplen, sprint_hex(resp, resplen)); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index fee29f340..db898db1d 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -649,7 +649,7 @@ int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t d // https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf // page 42 -void DesfireGenTransSessionKey(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey) { +void DesfireGenTransSessionKeyEV2(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey) { uint8_t xiv[CRYPTO_AES_BLOCK_SIZE] = {0}; if (forMAC) { diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 78d0ceee5..9ed9ef5a5 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -141,7 +141,7 @@ void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], Desfire 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 DesfireGenTransSessionKey(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey); +void DesfireGenTransSessionKeyEV2(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey); int DesfireLRPCalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac); diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index a4ff117b0..75f819dc3 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -462,11 +462,11 @@ static bool TestTransSessionKeys(void) { uint32_t trCntr = 8; uint8_t sessionkey[16] = {0}; - DesfireGenTransSessionKey(key, trCntr, uid, true, sessionkey); + DesfireGenTransSessionKeyEV2(key, trCntr, uid, true, sessionkey); uint8_t keymac[] = {0x7C, 0x1A, 0xD2, 0xD9, 0xC5, 0xC0, 0x81, 0x54, 0xA0, 0xA4, 0x91, 0x4B, 0x40, 0x1A, 0x65, 0x98}; res = res && (memcmp(sessionkey, keymac, sizeof(keymac)) == 0); - DesfireGenTransSessionKey(key, trCntr, uid, false, sessionkey); + DesfireGenTransSessionKeyEV2(key, trCntr, uid, false, sessionkey); uint8_t keyenc[] = {0x11, 0x9B, 0x90, 0x2A, 0x07, 0xB1, 0x8A, 0x86, 0x5B, 0x8E, 0x1B, 0x00, 0x60, 0x59, 0x47, 0x84}; res = res && (memcmp(sessionkey, keyenc, sizeof(keyenc)) == 0); From db2c8776c0459feb2cd55355db2b1a8ac573949b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 21 Aug 2021 14:12:49 +0300 Subject: [PATCH 17/17] clear record file works, lrp transaction check code --- client/src/cmdhfmfdes.c | 42 ++++++++++++++++++--------- client/src/mifare/desfirecrypto.c | 35 ++++++++++++++++++++++ client/src/mifare/desfirecrypto.h | 3 ++ client/src/mifare/desfiresecurechan.c | 1 + 4 files changed, 67 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 31dd64750..d7582869d 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4314,7 +4314,8 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes clearrecfile", "Clear record file. Master key needs to be provided or flag --no-auth set (depend on cards settings).", - "hf mfdes clearrecfile --aid 123456 --fid 01 -> clear record file for: app=123456, file=01 with defaults from `default` command"); + "hf mfdes clearrecfile --aid 123456 --fid 01 -> clear record file for: app=123456, file=01 with defaults from `default` command\n" + "hf mfdes clearrecfile --appisoid df01 --fid 01 -s lrp -t aes -n 3 -> clear record file for lrp channel with key number 3"); void *argtable[] = { arg_param_begin, @@ -4329,6 +4330,7 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), arg_str0(NULL, "fid", "", "File ID for clearing (1 hex byte)"), arg_lit0(NULL, "no-auth", "execute without authentication"), arg_param_end @@ -4337,19 +4339,20 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 13); + bool noauth = arg_get_lit(ctx, 14); DesfireContext dctx; int securechann = defaultSecureChannel; - uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t fnum = 1; - if (CLIGetUint32Hex(ctx, 12, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -4362,9 +4365,10 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { return PM3_EINVARG; } - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, noauth, verbose); + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } @@ -4374,8 +4378,22 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { DropField(); return PM3_ESOFT; } + + if (verbose) + PrintAndLogEx(INFO, "File cleared"); + + DesfireSetCommMode(&dctx, DCMMACed); + res = DesfireCommitTransaction(&dctx, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire CommitTransaction command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } - PrintAndLogEx(SUCCESS, "File %02x in the app %06x cleared " _GREEN_("successfully"), fnum, appid); + if (verbose) + PrintAndLogEx(INFO, "Transaction commited"); + + PrintAndLogEx(SUCCESS, "File %02x in the %s cleared " _GREEN_("successfully"), fnum, DesfireWayIDStr(selectway, id)); DropField(); return PM3_SUCCESS; @@ -5040,13 +5058,9 @@ static int CmdHF14ADesWriteData(const char *Cmd) { PrintAndLogEx(INFO, "Prev reader id encoded [%zu]: %s", resplen, sprint_hex(resp, resplen)); if (trkeylen > 0) { - uint8_t sessionkey[16] = {0}; - uint8_t uid[7] = {0}; - memcpy(uid, dctx.uid, MAX(dctx.uidlen, 7)); - DesfireGenTransSessionKeyEV2(trkey, transactionCounter, uid, false, sessionkey); - - aes_decode(NULL, sessionkey, resp, resp, CRYPTO_AES_BLOCK_SIZE); - PrintAndLogEx(INFO, "Prev reader id [%zu]: %s", resplen, sprint_hex(resp, resplen)); + uint8_t prevReaderID[CRYPTO_AES_BLOCK_SIZE] = {0}; + DesfireDecodePrevReaderID(&dctx, trkey, transactionCounter, resp, prevReaderID); + PrintAndLogEx(INFO, "Prev reader id: %s", resplen, sprint_hex(prevReaderID, CRYPTO_AES_BLOCK_SIZE)); } readeridpushed = true; diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index db898db1d..9a37f107a 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -667,6 +667,41 @@ void DesfireGenTransSessionKeyEV2(uint8_t *key, uint32_t trCntr, uint8_t *uid, b DesfireCryptoCMACEx(&ctx, DCOMainKey, xiv, 16, 0, sessionkey); } +// https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf +// page 43 +void DesfireGenTransSessionKeyLRP(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey) { + uint8_t data[CRYPTO_AES_BLOCK_SIZE] = {0}; + + data[1] = 0x01; + data[3] = 0x80; + Uint4byteToMemLe(&data[4], trCntr + 0x00010001); + memcpy(&data[8], uid, 7); + if (forMAC) { + data[15] = 0x5a; + } else { + data[15] = 0xa5; + } + + LRPContext lctx = {0}; + LRPSetKey(&lctx, key, 0, true); + LRPCMAC(&lctx, data, sizeof(data), sessionkey); +} + +void DesfireDecodePrevReaderID(DesfireContext *ctx, uint8_t *key, uint32_t trCntr, uint8_t *encPrevReaderID, uint8_t *prevReaderID) { + uint8_t sessionkey[16] = {0}; + uint8_t uid[7] = {0}; + memcpy(uid, ctx->uid, MAX(ctx->uidlen, 7)); + + if (ctx->secureChannel == DACEV2) { + DesfireGenTransSessionKeyEV2(key, trCntr, uid, false, sessionkey); + + aes_decode(NULL, sessionkey, encPrevReaderID, prevReaderID, CRYPTO_AES_BLOCK_SIZE); + } else if (ctx->secureChannel == DACLRP) { + DesfireGenTransSessionKeyLRP(key, trCntr, uid, false, sessionkey); + + } +} + int DesfireLRPCalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) { uint8_t mdata[1050] = {0}; size_t mdatalen = 0; diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 9ed9ef5a5..cd16dc954 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -141,7 +141,10 @@ void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], Desfire 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 DesfireGenTransSessionKeyEV2(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey); +void DesfireGenTransSessionKeyLRP(uint8_t *key, uint32_t trCntr, uint8_t *uid, bool forMAC, uint8_t *sessionkey); +void DesfireDecodePrevReaderID(DesfireContext *ctx, uint8_t *key, uint32_t trCntr, uint8_t *encPrevReaderID, uint8_t *prevReaderID); int DesfireLRPCalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 01430070e..a26dbe312 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -153,6 +153,7 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_GET_ISOFILE_IDS, DACLRP, DCCNative, DCMMACed}, {MFDES_GET_FILE_SETTINGS, DACLRP, DCCNative, DCMMACed}, {MFDES_GET_KEY_VERSION, DACLRP, DCCNative, DCMMACed}, + {MFDES_CLEAR_RECORD_FILE, DACLRP, DCCNative, DCMMACed}, {MFDES_GET_UID, DACLRP, DCCNative, DCMEncrypted}, {MFDES_CHANGE_FILE_SETTINGS, DACLRP, DCCNative, DCMEncrypted},