From b5f323672f292c8a87162f4ca2eaac0252372b46 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 11 Aug 2021 15:48:46 +0300 Subject: [PATCH 1/4] detect command and detect type of the key --- client/src/cmdhfmfdes.c | 494 +++++++++++++++++++++++++++------------- 1 file changed, 337 insertions(+), 157 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 52589572c..17259eb58 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -367,6 +367,164 @@ static void swap24(uint8_t *data) { data[2] = tmp; }; +// default parameters +static uint8_t defaultKeyNum = 0; +static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES; +static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; +static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE; +static int defaultKdfInputLen = 0; +static uint8_t defaultKdfInput[50] = {0}; +static DesfireSecureChannel defaultSecureChannel = DACEV1; +static DesfireCommandSet defaultCommSet = DCCNativeISO; +static DesfireCommunicationMode defaultCommMode = DCMPlain; + +static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dctx, + uint8_t keynoid, uint8_t algoid, uint8_t keyid, + uint8_t kdfid, uint8_t kdfiid, + uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid, + uint8_t appid, + int *securechannel, + DesfireCommunicationMode defcommmode, + uint32_t *aid) { + + uint8_t keynum = defaultKeyNum; + int algores = defaultAlgoId; + uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; + memcpy(key, defaultKey, DESFIRE_MAX_KEY_SIZE); + int kdfAlgo = defaultKdfAlgo; + int kdfInputLen = defaultKdfInputLen; + uint8_t kdfInput[50] = {0}; + memcpy(kdfInput, defaultKdfInput, defaultKdfInputLen); + int commmode = defaultCommMode; + if (defcommmode != DCMNone) + commmode = defcommmode; + int commset = defaultCommSet; + int secchann = defaultSecureChannel; + + if (keynoid) { + keynum = arg_get_int_def(ctx, keynoid, keynum); + } + + if (algoid) { + if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores)) + return PM3_ESOFT; + } + + if (keyid) { + int keylen = 0; + uint8_t keydata[200] = {0}; + if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen)) + return PM3_ESOFT; + if (keylen && keylen != desfire_get_key_length(algores)) { + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), desfire_get_key_length(algores), keylen); + return PM3_EINVARG; + } + if (keylen) + memcpy(key, keydata, keylen); + } + + if (kdfid) { + if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo)) + return PM3_ESOFT; + } + + if (kdfiid) { + int datalen = kdfInputLen; + uint8_t data[200] = {0}; + if (CLIParamHexToBuf(arg_get_str(ctx, kdfiid), data, sizeof(data), &datalen)) + return PM3_ESOFT; + if (datalen) { + kdfInputLen = datalen; + memcpy(kdfInput, data, datalen); + } + } + + if (cmodeid) { + if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode)) + return PM3_ESOFT; + } + + if (ccsetid) { + if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset)) + return PM3_ESOFT; + } + + if (schannid) { + + if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann)) + return PM3_ESOFT; + } + + if (appid && aid) { + *aid = 0x000000; + if (CLIGetUint32Hex(ctx, appid, 0x000000, aid, NULL, 3, "AID must have 3 bytes length")) + return PM3_EINVARG; + } + + DesfireSetKey(dctx, keynum, algores, key); + DesfireSetKdf(dctx, kdfAlgo, kdfInput, kdfInputLen); + DesfireSetCommandSet(dctx, commset); + DesfireSetCommMode(dctx, commmode); + if (securechannel) + *securechannel = secchann; + + return PM3_SUCCESS; +} + +static int CmdHF14ADesDefault(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes default", + "Set default parameters for access to desfire card.", + "hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters"); + + void *argtable[] = { + arg_param_begin, + 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_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + DesfireContext dctx; + int securechann = defaultSecureChannel; + int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, &securechann, DCMNone, NULL); + if (res) { + CLIParserFree(ctx); + return res; + } + + CLIParserFree(ctx); + + defaultKeyNum = dctx.keyNum; + defaultAlgoId = dctx.keyType; + memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE); + defaultKdfAlgo = dctx.kdfAlgo; + defaultKdfInputLen = dctx.kdfInputLen; + memcpy(defaultKdfInput, dctx.kdfInput, sizeof(dctx.kdfInput)); + defaultSecureChannel = securechann; + defaultCommSet = dctx.cmdSet; + defaultCommMode = dctx.commMode; + + PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------"); + + PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum); + PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); + PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId))); + PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo)); + PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen)); + PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel)); + PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet)); + PrintAndLogEx(INFO, "Comm mode : %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, defaultCommMode)); + + return PM3_SUCCESS; +} + static int CmdHF14ADesInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes info", @@ -1112,6 +1270,184 @@ static int CmdHF14ADesList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf mfdes", "des"); } +static int CmdHF14aDesDetect(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes detect", + "Detect key type and tries to find one from the list.", + "hf mfdes detect -> detect key 0 from PICC level\n" + "hf mfdes detect -s d40 -> detect key 0 from PICC level via secure channel D40\n" + "hf mfdes detect --dict mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary\n" + "hf mfdes detect --aid 123456 -n 2 --save -> detect key 2 from app 123456 and if succeed - save params to defaults (`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_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "dict", "", "File with keys dictionary"), + arg_lit0(NULL, "save", "save found key and parameters to defaults"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + + DesfireContext dctx; + int securechann = defaultSecureChannel; + uint32_t appid = 0x000000; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid); + 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")) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool save = arg_get_lit(ctx, 13); + + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + + // no auth and fill KDF if needs + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "Select AID 0x%06x " _RED_("failed") ". Result: %d", appid, res); + return res; + } + + bool keytypes[4] = {0}; + /*T_DES = 0x00, + T_3DES = 0x01, //aka 2K3DES + T_3K3DES = 0x02, + T_AES = 0x03 */ + + uint8_t data[250] = {0}; + size_t datalen = 0; + res = DesfireGetKeySettings(&dctx, data, &datalen); + if (res == PM3_SUCCESS && datalen >= 2) { + uint8_t num_keys = data[1]; + switch (num_keys >> 6) { + case 0: + keytypes[T_DES] = true; + keytypes[T_3DES] = true; + break; + case 1: + keytypes[T_3K3DES] = true; + break; + case 2: + keytypes[T_AES] = true; + break; + default: + break; + } + } else { + // if fail - check auth commands + AuthCommandsChk authCmdCheck = {0}; + DesfireCheckAuthCommands(appid, NULL, 0, &authCmdCheck); + if (authCmdCheck.checked) { + if (authCmdCheck.auth) { + keytypes[T_DES] = true; + keytypes[T_3DES] = true; + + if (authCmdCheck.authISO) { + keytypes[T_3K3DES] = true; + } + } + if (authCmdCheck.authAES || authCmdCheck.authEV2) { + keytypes[T_AES] = true; + } + } else { + // if nothing helps - we check DES only + keytypes[T_DES] = true; + } + + res = DesfireSelectAIDHex(&dctx, appid, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + return res; + } + } + + if (verbose) { + PrintAndLogEx(INFO, "Check keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s", + keytypes[T_DES] ? _GREEN_("YES") : _RED_("NO"), + keytypes[T_3DES] ? _GREEN_("YES") : _RED_("NO"), + keytypes[T_3K3DES] ? _GREEN_("YES") : _RED_("NO"), + keytypes[T_AES] ? _GREEN_("YES") : _RED_("NO") + ); + } + + // for key types + for (uint8_t ktype = T_DES; ktype <= T_AES; ktype++) { + + } + +/* + // load keys from file + size_t endFilePosition = 0; + if (dict_filenamelen) { + + res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 8, &deskeyListLen, 0, &endFilePosition, true); + if (res == PM3_SUCCESS && endFilePosition) + PrintAndLogEx(SUCCESS, "First part of des dictionary successfully loaded."); + + // checks + if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) { + for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) { + DesfireSetKeyNoClear(dctx, keyno, T_DES, deskeyList[curkey]); + res = DesfireAuthenticate(dctx, secureChannel, false); + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8)); + foundKeys[0][keyno][0] = 0x01; + *result = true; + memcpy(&foundKeys[0][keyno][1], deskeyList[curkey], 8); + break; + } else if (res < 7) { + badlen = true; + DropField(); + res = DesfireSelectAIDHex(dctx, curaid, false, 0); + if (res != PM3_SUCCESS) { + return res; + } + break; + } + } + if (badlen == true) { + badlen = false; + break; + } + } + } + // load keys from file + uint32_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + if (res == PM3_SUCCESS && endFilePosition) + deskeyListLen = keycnt; +*/ + + DropField(); + + if (save) { + + } + + return PM3_SUCCESS; +} + /* static int CmdHF14aDesNDEFRead(const char *Cmd) { DropFieldDesfire(); @@ -1241,163 +1577,6 @@ static int CmdHF14aDesMAD(const char *Cmd) { } */ -static uint8_t defaultKeyNum = 0; -static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES; -static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; -static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE; -static int defaultKdfInputLen = 0; -static uint8_t defaultKdfInput[50] = {0}; -static DesfireSecureChannel defaultSecureChannel = DACEV1; -static DesfireCommandSet defaultCommSet = DCCNativeISO; -static DesfireCommunicationMode defaultCommMode = DCMPlain; - -static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dctx, - uint8_t keynoid, uint8_t algoid, uint8_t keyid, - uint8_t kdfid, uint8_t kdfiid, - uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid, - uint8_t appid, - int *securechannel, - DesfireCommunicationMode defcommmode, - uint32_t *aid) { - - uint8_t keynum = defaultKeyNum; - int algores = defaultAlgoId; - uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; - memcpy(key, defaultKey, DESFIRE_MAX_KEY_SIZE); - int kdfAlgo = defaultKdfAlgo; - int kdfInputLen = defaultKdfInputLen; - uint8_t kdfInput[50] = {0}; - memcpy(kdfInput, defaultKdfInput, defaultKdfInputLen); - int commmode = defaultCommMode; - if (defcommmode != DCMNone) - commmode = defcommmode; - int commset = defaultCommSet; - int secchann = defaultSecureChannel; - - if (keynoid) { - keynum = arg_get_int_def(ctx, keynoid, keynum); - } - - if (algoid) { - if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores)) - return PM3_ESOFT; - } - - if (keyid) { - int keylen = 0; - uint8_t keydata[200] = {0}; - if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen)) - return PM3_ESOFT; - if (keylen && keylen != desfire_get_key_length(algores)) { - PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), desfire_get_key_length(algores), keylen); - return PM3_EINVARG; - } - if (keylen) - memcpy(key, keydata, keylen); - } - - if (kdfid) { - if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo)) - return PM3_ESOFT; - } - - if (kdfiid) { - int datalen = kdfInputLen; - uint8_t data[200] = {0}; - if (CLIParamHexToBuf(arg_get_str(ctx, kdfiid), data, sizeof(data), &datalen)) - return PM3_ESOFT; - if (datalen) { - kdfInputLen = datalen; - memcpy(kdfInput, data, datalen); - } - } - - if (cmodeid) { - if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode)) - return PM3_ESOFT; - } - - if (ccsetid) { - if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset)) - return PM3_ESOFT; - } - - if (schannid) { - - if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann)) - return PM3_ESOFT; - } - - if (appid && aid) { - *aid = 0x000000; - if (CLIGetUint32Hex(ctx, appid, 0x000000, aid, NULL, 3, "AID must have 3 bytes length")) - return PM3_EINVARG; - } - - DesfireSetKey(dctx, keynum, algores, key); - DesfireSetKdf(dctx, kdfAlgo, kdfInput, kdfInputLen); - DesfireSetCommandSet(dctx, commset); - DesfireSetCommMode(dctx, commmode); - if (securechannel) - *securechannel = secchann; - - return PM3_SUCCESS; -} - -static int CmdHF14ADesDefault(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes default", - "Set default parameters for access to desfire card.", - "hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters"); - - void *argtable[] = { - arg_param_begin, - 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_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - DesfireContext dctx; - int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, &securechann, DCMNone, NULL); - if (res) { - CLIParserFree(ctx); - return res; - } - - CLIParserFree(ctx); - - defaultKeyNum = dctx.keyNum; - defaultAlgoId = dctx.keyType; - memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE); - defaultKdfAlgo = dctx.kdfAlgo; - defaultKdfInputLen = dctx.kdfInputLen; - memcpy(defaultKdfInput, dctx.kdfInput, sizeof(dctx.kdfInput)); - defaultSecureChannel = securechann; - defaultCommSet = dctx.cmdSet; - defaultCommMode = dctx.commMode; - - PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------"); - - PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum); - PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); - PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId))); - PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo)); - PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen)); - PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel)); - PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet)); - PrintAndLogEx(INFO, "Comm mode : %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, defaultCommMode)); - - return PM3_SUCCESS; -} - static int CmdHF14ADesSelectApp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes selectapp", @@ -4951,6 +5130,7 @@ static command_t CommandTable[] = { {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "MIFARE DesFire Authentication"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"}, + {"detect", CmdHF14aDesDetect, IfPm3Iso14443a, "Detect key type and tries to find one from the list"}, {"freemem", CmdHF14ADesGetFreeMem, IfPm3Iso14443a, "Get free memory size"}, {"setconfig", CmdHF14ADesSetConfiguration, IfPm3Iso14443a, "Set card configuration"}, {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, From 2acbd67900e3052c8304e98c776bcfaa2f55b20b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 11 Aug 2021 16:03:01 +0300 Subject: [PATCH 2/4] add a key --- client/src/cmdhfmfdes.c | 6 +++++- client/src/mifare/mifaredefault.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 17259eb58..24a0f0466 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1383,7 +1383,11 @@ static int CmdHF14aDesDetect(const char *Cmd) { } if (verbose) { - PrintAndLogEx(INFO, "Check keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s", + if (appid == 0) + PrintAndLogEx(INFO, "Check PICC key num: %d (0x%02x)", dctx.keyNum, dctx.keyNum); + else + PrintAndLogEx(INFO, "Check app: %06x key num: %d (0x%02x)", appid, dctx.keyNum, dctx.keyNum); + PrintAndLogEx(INFO, "keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s", keytypes[T_DES] ? _GREEN_("YES") : _RED_("NO"), keytypes[T_3DES] ? _GREEN_("YES") : _RED_("NO"), keytypes[T_3K3DES] ? _GREEN_("YES") : _RED_("NO"), diff --git a/client/src/mifare/mifaredefault.c b/client/src/mifare/mifaredefault.c index 8c9a26071..f1a507536 100644 --- a/client/src/mifare/mifaredefault.c +++ b/client/src/mifare/mifaredefault.c @@ -35,6 +35,7 @@ const char *g_mifare_plus_default_keys[] = { "0102030405060708090a0b0c0d0e0f10", "00010203040506070809101112131415", "01020304050607080910111213141516", + "00112233445566778899aabbccddeeff", "404142434445464748494a4b4c4d4e4f", "303132333435363738393a3b3c3d3e3f", }; From 705f7a698fb8954524704f2a2006ce610d448dd6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 11 Aug 2021 20:28:59 +0300 Subject: [PATCH 3/4] works --- client/src/cmdhfmfdes.c | 172 ++++++++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 49 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 24a0f0466..aadda4179 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -36,6 +36,7 @@ #include "fileutils.h" #include "nfc/ndef.h" // NDEF #include "mifare/mad.h" +#include "mifare/mifaredefault.h" #include "generator.h" #include "mifare/aiddesfire.h" #include "util.h" @@ -1270,6 +1271,25 @@ static int CmdHF14ADesList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf mfdes", "des"); } +static int DesfireAuthCheck(DesfireContext *dctx, uint32_t appid, DesfireSecureChannel secureChannel, uint8_t *key) { + DesfireSetKeyNoClear(dctx, dctx->keyNum, dctx->keyType, key); + + int res = DesfireAuthenticate(dctx, secureChannel, false); + if (res == PM3_SUCCESS) { + memcpy(dctx->key, key, desfire_get_key_length(dctx->keyType)); + return PM3_SUCCESS; + } else if (res < 7) { + DropField(); + res = DesfireSelectAIDHex(dctx, appid, false, 0); + if (res != PM3_SUCCESS) { + return -10; + } + return -11; + } + return -1; +} + + static int CmdHF14aDesDetect(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes detect", @@ -1296,7 +1316,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { arg_lit0(NULL, "save", "save found key and parameters to defaults"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIExecWithReturn(ctx, Cmd, argtable, true); bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); @@ -1310,8 +1330,10 @@ static int CmdHF14aDesDetect(const char *Cmd) { return res; } - uint32_t fnum = 1; - if (CLIGetUint32Hex(ctx, 12, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) { + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(ctx, 12), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); CLIParserFree(ctx); return PM3_EINVARG; } @@ -1330,10 +1352,6 @@ static int CmdHF14aDesDetect(const char *Cmd) { } bool keytypes[4] = {0}; - /*T_DES = 0x00, - T_3DES = 0x01, //aka 2K3DES - T_3K3DES = 0x02, - T_AES = 0x03 */ uint8_t data[250] = {0}; size_t datalen = 0; @@ -1396,56 +1414,112 @@ static int CmdHF14aDesDetect(const char *Cmd) { } // for key types + bool found = false; + size_t errcount = 0; for (uint8_t ktype = T_DES; ktype <= T_AES; ktype++) { + if (!keytypes[ktype]) + continue; + dctx.keyType = ktype; + if (verbose) + PrintAndLogEx(INFO, "Scan key type: %s", CLIGetOptionListStr(DesfireAlgoOpts, dctx.keyType)); - } - -/* - // load keys from file - size_t endFilePosition = 0; - if (dict_filenamelen) { - - res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 8, &deskeyListLen, 0, &endFilePosition, true); - if (res == PM3_SUCCESS && endFilePosition) - PrintAndLogEx(SUCCESS, "First part of des dictionary successfully loaded."); - - // checks - if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) { - for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) { - DesfireSetKeyNoClear(dctx, keyno, T_DES, deskeyList[curkey]); - res = DesfireAuthenticate(dctx, secureChannel, false); - if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8)); - foundKeys[0][keyno][0] = 0x01; - *result = true; - memcpy(&foundKeys[0][keyno][1], deskeyList[curkey], 8); - break; - } else if (res < 7) { - badlen = true; - DropField(); - res = DesfireSelectAIDHex(dctx, curaid, false, 0); - if (res != PM3_SUCCESS) { - return res; - } - break; + if (dict_filenamelen == 0) { + // keys from mifaredefault.h + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; + if (hex_to_bytes(g_mifare_plus_default_keys[i], key, 16) != 16) + continue; + if (ktype == T_3K3DES) + memcpy(&key[16], key, 8); + + res = DesfireAuthCheck(&dctx, appid, securechann, key); + if (res == PM3_SUCCESS) { + found = true; + break; // all the params already in the dctx + } + if (res == -10) { + if (verbose) + PrintAndLogEx(ERR, "Can't select AID. There is no connection with card."); + + found = false; + break; // we can't select app after invalid 1st auth stages + } + if (res == -11) { + if (errcount > 10) { + if (verbose) + PrintAndLogEx(ERR, "Too much errors (%zu) from card", errcount); + break; } - } - if (badlen == true) { - badlen = false; - break; - } + errcount++; + } else + errcount = 0; } + } else { + // keys from file + uint8_t keyList[MAX_KEYS_LIST_LEN * MAX_KEY_LEN] = {0}; + uint32_t keyListLen = 0; + size_t keylen = desfire_get_key_length(dctx.keyType); + size_t endFilePosition = 0; + + while (!found) { + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, keylen, &keyListLen, endFilePosition, &endFilePosition, verbose); + PrintAndLogEx(ERR, "--res: %d endFilePosition: %d keyListLen: %d", res, endFilePosition, keyListLen); + if (res != 1 && res != PM3_SUCCESS) + break; + + for (int i = 0; i < keyListLen; i++) { + PrintAndLogEx(ERR, "--key:[%02d] %s", i, sprint_hex(&keyList[i * keylen], keylen)); + + res = DesfireAuthCheck(&dctx, appid, securechann, &keyList[i * keylen]); + if (res == PM3_SUCCESS) { + found = true; + break; // all the params already in the dctx + } + if (res == -10) { + if (verbose) + PrintAndLogEx(ERR, "Can't select AID. There is no connection with card."); + + found = false; + break; // we can't select app after invalid 1st auth stages + } + if (res == -11) { + if (errcount > 10) { + if (verbose) + PrintAndLogEx(ERR, "Too much errors (%zu) from card", errcount); + break; + } + errcount++; + } else + errcount = 0; + } + + if (endFilePosition == 0) + break; + } + } - // load keys from file - uint32_t keycnt = 0; - res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); - if (res == PM3_SUCCESS && endFilePosition) - deskeyListLen = keycnt; -*/ + if (found) + break; + } + + if (found) { + if (appid == 0) + PrintAndLogEx(INFO, _GREEN_("Found") " key num: %d (0x%02x)", dctx.keyNum, dctx.keyNum); + else + PrintAndLogEx(INFO, "Found key for app: %06x key num: %d (0x%02x)", appid, dctx.keyNum, dctx.keyNum); + + PrintAndLogEx(INFO, "key " _GREEN_("%s") " [%d]: " _GREEN_("%s"), + CLIGetOptionListStr(DesfireAlgoOpts, dctx.keyType), + desfire_get_key_length(dctx.keyType), + sprint_hex(dctx.key, desfire_get_key_length(dctx.keyType))); + + } else { + PrintAndLogEx(INFO, "Key " _RED_("not found")); + } DropField(); - if (save) { + if (found && save) { } From 00e3f22ecc79572da4045d66d49535abf1d769b9 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 11 Aug 2021 20:36:22 +0300 Subject: [PATCH 4/4] remove debug and save to default --- client/src/cmdhfmfdes.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index aadda4179..5fc43de19 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1463,13 +1463,10 @@ static int CmdHF14aDesDetect(const char *Cmd) { while (!found) { res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, keylen, &keyListLen, endFilePosition, &endFilePosition, verbose); - PrintAndLogEx(ERR, "--res: %d endFilePosition: %d keyListLen: %d", res, endFilePosition, keyListLen); if (res != 1 && res != PM3_SUCCESS) break; for (int i = 0; i < keyListLen; i++) { - PrintAndLogEx(ERR, "--key:[%02d] %s", i, sprint_hex(&keyList[i * keylen], keylen)); - res = DesfireAuthCheck(&dctx, appid, securechann, &keyList[i * keylen]); if (res == PM3_SUCCESS) { found = true; @@ -1520,7 +1517,25 @@ static int CmdHF14aDesDetect(const char *Cmd) { DropField(); if (found && save) { - + defaultKeyNum = dctx.keyNum; + defaultAlgoId = dctx.keyType; + memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE); + defaultKdfAlgo = dctx.kdfAlgo; + defaultKdfInputLen = dctx.kdfInputLen; + memcpy(defaultKdfInput, dctx.kdfInput, sizeof(dctx.kdfInput)); + defaultSecureChannel = securechann; + defaultCommSet = dctx.cmdSet; + + PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------"); + + PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum); + PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); + PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId))); + PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo)); + PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen)); + PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel)); + PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet)); + PrintAndLogEx(INFO, _GREEN_("Saved")); } return PM3_SUCCESS;