From 0d00f567779f1f531e7f838cd3c64026511e48f7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 13:11:17 +0300 Subject: [PATCH] CmdHF14ADesGetAppNames works --- client/src/cmdhfmfdes.c | 150 +++++++++++++++++++++++++++++++- client/src/mifare/desfirecore.c | 31 ++++--- client/src/mifare/desfirecore.h | 2 +- 3 files changed, 167 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c8721433b..384e67049 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5080,7 +5080,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { }; int commchann = DCCNativeISO; - CLIGetOptionListWithReturn(ctx, 8, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); + CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); const CLIParserOption authc_opts[] = { @@ -5090,7 +5090,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { }; int authchann = DACEV1; - CLIGetOptionListWithReturn(ctx, 9, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); + CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); SetAPDULogging(APDULogging); @@ -5142,8 +5142,152 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { return PM3_SUCCESS; } -// {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, static int CmdHF14ADesGetAppNames(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes getappnames", + "Get Application IDs, ISO IDs and DF names from card. Master key needs to be provided.", + "hf mfdes getappnames -n 0 -t des -k 0000000000000000 -f none -> execute with default factory setup"); + + 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", "", "Commpunicaton mode: plain/mac/encrypt"), + arg_str0("c", "commc", "", "Commpunicaton channel: native/niso/iso"), + arg_str0("u", "authc", "", "Authentication channel: d40/ev1/ev2"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId + + + const CLIParserOption algo_opts[] = { + {T_DES, "des"}, + {T_3DES, "2tdea"}, + {T_3K3DES, "3tdea"}, + {T_AES, "aes"}, + }; + + int ares = T_DES; + CLIGetOptionListWithReturn(ctx, 4, algo_opts, ARRAY_LENGTH(algo_opts), &ares); + PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares)); + + int keylen = 0; + uint8_t key[200] = {0}; + CLIGetHexWithReturn(ctx, 5, key, &keylen); + if (keylen == 0) { + keylen = key_size(ares); + //memcpy(key, defaultkey, key_size(ares)); + } + if (keylen != key_size(ares)) { + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares), key_size(ares), keylen); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + const CLIParserOption kdf_opts[] = { + {MFDES_KDF_ALGO_NONE, "none"}, + {MFDES_KDF_ALGO_AN10922, "an10922"}, + {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, + }; + + int kres = MFDES_KDF_ALGO_NONE; + CLIGetOptionListWithReturn(ctx, 6, kdf_opts, ARRAY_LENGTH(kdf_opts), &kres); + PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kres)); + + int kdfInputLen = 0; + uint8_t kdfInput[50] = {0}; + CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); + + const CLIParserOption cmode_opts[] = { + {DCMPlain, "plain"}, + {DCMMACed, "mac"}, + {DCMEncrypted, "encrypt"}, + }; + + int commmode = DCMPlain; + CLIGetOptionListWithReturn(ctx, 8, cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); + + const CLIParserOption commc_opts[] = { + {DCCNative, "native"}, + {DCCNativeISO, "niso"}, + {DCCISO, "iso"}, + }; + + int commchann = DCCNativeISO; + CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); + + const CLIParserOption authc_opts[] = { + {DACd40, "d40"}, + {DACEV1, "ev1"}, + {DACEV2, "ev2"}, + }; + + int authchann = DACEV1; + CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); + PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); + + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + + DesfireContext dctx; + DesfireSetKey(&dctx, keyNum, ares, key); + DesfireSetCommandChannel(&dctx, commchann); + + + int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + DropField(); + return PM3_ESOFT; + } + + res = DesfireAuthenticate(&dctx, authchann); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (DesfireIsAuthenticated(&dctx)) { + if (verbose) + PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); + } else { + return PM3_ESOFT; + } + + uint8_t buf[APDU_RES_LEN] = {0}; + size_t buflen = 0; + + // result bytes: 3, 2, 1-16. total record size = 24 + res = DesfireGetDFList(&dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire DesfireGetDFList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (buflen > 0) { + PrintAndLogEx(INFO, "----------------------- " _CYAN_("File list") " -----------------------"); + for (int i = 0; i < buflen; i++) + PrintAndLogEx(INFO, "AID: %06x ISO file id: %02x%02x ISO DF name[%d]: %s", + DesfireAIDByteToUint(&buf[i * 24]), + buf[i * 24 + 3], buf[i * 24 + 4], + strlen((char *)&buf[i * 24 + 5]), + &buf[i * 24 + 5]); + } + + DropField(); return PM3_SUCCESS; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index de71db69f..18aa09265 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -256,20 +256,17 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin return PM3_SUCCESS; } -static int DesfireExchangeNative(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) { +static int DesfireExchangeNative(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) { return PM3_SUCCESS; } -static int DesfireExchangeISO(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) { +static int DesfireExchangeISO(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) { if (resplen) *resplen = 0; if (respcode) *respcode = 0xff; - // TODO !!! - size_t splitbysize = 0; - uint16_t sw = 0; uint8_t buf[255 * 5] = {0x00}; uint32_t buflen = 0; @@ -342,15 +339,15 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } -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) { +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 res = PM3_SUCCESS; switch(ctx->cmdChannel) { case DCCNative: - res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); + res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); break; case DCCNativeISO: - res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); + res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); break; case DCCISO: return PM3_EAPDU_FAIL; @@ -361,7 +358,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin } int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen) { - return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true); + return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true, 0); } int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { @@ -376,7 +373,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { size_t resplen = 0; uint8_t respcode = 0; - int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true); + 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) return PM3_ECARDEXCHANGE; @@ -472,7 +469,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { uint8_t recv_data[256] = {0}; // Let's send our auth command - int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false); + int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 1; } @@ -585,7 +582,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { bothlen = 32; } - res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false); + res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 7; } @@ -661,3 +658,13 @@ int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { return PM3_EAPDU_FAIL; return PM3_SUCCESS; } + +int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { + uint8_t respcode = 0xff; + int res = DesfireExchangeEx(false, dctx, MFDES_GET_DF_NAMES, NULL, 0, &respcode, resp, resplen, true, 24); + if (res != PM3_SUCCESS) + return res; + if (respcode != MFDES_S_OPERATION_OK) + return PM3_EAPDU_FAIL; + return PM3_SUCCESS; +} diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index bffcda7bd..a0b31babb 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -77,7 +77,7 @@ uint32_t DesfireAIDByteToUint(uint8_t *data); void DesfireAIDUintToByte(uint32_t aid, uint8_t *data); 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); +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 DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);