diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 8677ff8ab..f8dacd6be 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -683,8 +683,29 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); } } - PrintAndLogEx(NORMAL, ""); + + if (cardtype == DESFIRE_LIGHT) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Desfire Light info")); + if (DesfireSelect(&dctx, ISWIsoID, 0xdf01, NULL) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, " Card have " _GREEN_("default (0xdf01)") " iso id for application"); + + if (DesfireCheckAuthCmd(ISWIsoID, 0xdf01, 0, MFDES_AUTHENTICATE_EV2F, false)) { + PrintAndLogEx(SUCCESS, " Card in the " _GREEN_("AES") " mode"); + } else if (DesfireCheckAuthCmd(ISWIsoID, 0xdf01, 0, MFDES_AUTHENTICATE_EV2F, true)) { + PrintAndLogEx(SUCCESS, " Card in the " _GREEN_("LRP") " mode"); + } + } else { + PrintAndLogEx(SUCCESS, " Card have " _RED_("not a default") " iso id for application"); + } + + if (DesfireCheckAuthCmd(ISWIsoID, 0x3f00, 1, MFDES_AUTHENTICATE_EV2F, true)) { + PrintAndLogEx(SUCCESS, " Card have " _GREEN_("LRP") " key in the MF/key1"); + } + } + + PrintAndLogEx(NORMAL, ""); iso14a_card_select_t card; res = SelectCard14443A_4(true, false, &card); @@ -1294,7 +1315,7 @@ static int CmdHF14ADesList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf mfdes", "des"); } -static int DesfireAuthCheck(DesfireContext_t *dctx, uint32_t appid, DesfireSecureChannel secureChannel, uint8_t *key) { +static int DesfireAuthCheck(DesfireContext_t *dctx, DesfireISOSelectWay way, uint32_t appID, DesfireSecureChannel secureChannel, uint8_t *key) { DesfireSetKeyNoClear(dctx, dctx->keyNum, dctx->keyType, key); int res = DesfireAuthenticate(dctx, secureChannel, false); @@ -1303,7 +1324,7 @@ static int DesfireAuthCheck(DesfireContext_t *dctx, uint32_t appid, DesfireSecur return PM3_SUCCESS; } else if (res < 7) { DropField(); - res = DesfireSelectAIDHex(dctx, appid, false, 0); + res = DesfireSelect(dctx, way, appID, NULL); if (res != PM3_SUCCESS) { return -10; } @@ -1320,7 +1341,8 @@ static int CmdHF14aDesDetect(const char *Cmd) { "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)"); + "hf mfdes detect --aid 123456 -n 2 --save -> detect key 2 from app 123456 and if succeed - save params to defaults (`default` command)\n" + "hf mfdes detect --appisoid df01 --save -> detect key 0 and save to defaults with card in the LRP mode"); void *argtable[] = { arg_param_begin, @@ -1335,6 +1357,7 @@ static int CmdHF14aDesDetect(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, "dict", "", "File with keys dictionary"), arg_lit0(NULL, "save", "save found key and parameters to defaults"), arg_param_end @@ -1346,8 +1369,9 @@ static int CmdHF14aDesDetect(const char *Cmd) { DesfireContext_t 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; @@ -1355,26 +1379,27 @@ static int CmdHF14aDesDetect(const char *Cmd) { 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)) { + if (CLIParamStrToBuf(arg_get_str(ctx, 13), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { PrintAndLogEx(FAILED, "File name too long or invalid."); CLIParserFree(ctx); return PM3_EINVARG; } - bool save = arg_get_lit(ctx, 13); + bool save = arg_get_lit(ctx, 14); SetAPDULogging(APDULogging); CLIParserFree(ctx); // no auth and fill KDF if needs - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose); + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, true, verbose); if (res != PM3_SUCCESS) { DropField(); - PrintAndLogEx(FAILED, "Select AID 0x%06x " _RED_("failed") ". Result: %d", appid, res); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } bool keytypes[4] = {0}; + bool uselrp = false; uint8_t data[250] = {0}; size_t datalen = 0; @@ -1398,7 +1423,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { } else { // if fail - check auth commands AuthCommandsChk_t authCmdCheck = {0}; - DesfireCheckAuthCommands(appid, NULL, 0, &authCmdCheck); + DesfireCheckAuthCommands(selectway, id, NULL, 0, &authCmdCheck); if (authCmdCheck.checked) { if (authCmdCheck.auth) { keytypes[T_DES] = true; @@ -1411,28 +1436,35 @@ static int CmdHF14aDesDetect(const char *Cmd) { if (authCmdCheck.authAES || authCmdCheck.authEV2) { keytypes[T_AES] = true; } + if (authCmdCheck.authLRP) { + keytypes[T_AES] = true; + uselrp = true; + securechann = DACLRP; + } } else { // if nothing helps - we check DES only keytypes[T_DES] = true; } - res = DesfireSelectAIDHex(&dctx, appid, false, 0); + res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, true, verbose); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + DropField(); + PrintAndLogEx(FAILED, "Select or authentication %s " _RED_("failed") ". Result [%d] %s", DesfireWayIDStr(selectway, id), res, DesfireAuthErrorToStr(res)); return res; } } if (verbose) { - if (appid == 0) + if (DesfireMFSelected(selectway, id)) 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", + PrintAndLogEx(INFO, "Check: %s key num: %d (0x%02x)", DesfireWayIDStr(selectway, id), dctx.keyNum, dctx.keyNum); + PrintAndLogEx(INFO, "keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s LRP: %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") + keytypes[T_AES] ? _GREEN_("YES") : _RED_("NO"), + uselrp ? _GREEN_("YES") : _RED_("NO") ); } @@ -1455,7 +1487,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { if (ktype == T_3K3DES) memcpy(&key[16], key, 8); - res = DesfireAuthCheck(&dctx, appid, securechann, key); + res = DesfireAuthCheck(&dctx, selectway, id, securechann, key); if (res == PM3_SUCCESS) { found = true; break; // all the params already in the dctx @@ -1490,7 +1522,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { break; for (int i = 0; i < keyListLen; i++) { - res = DesfireAuthCheck(&dctx, appid, securechann, &keyList[i * keylen]); + res = DesfireAuthCheck(&dctx, selectway, id, securechann, &keyList[i * keylen]); if (res == PM3_SUCCESS) { found = true; break; // all the params already in the dctx @@ -1523,12 +1555,13 @@ static int CmdHF14aDesDetect(const char *Cmd) { } if (found) { - if (appid == 0) + if (DesfireMFSelected(selectway, id)) 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, "Found key for: %s key num: %d (0x%02x)", DesfireWayIDStr(selectway, id), dctx.keyNum, dctx.keyNum); - PrintAndLogEx(INFO, "key " _GREEN_("%s") " [%d]: " _GREEN_("%s"), + PrintAndLogEx(INFO, "channel " _GREEN_("%s") " key " _GREEN_("%s") " [%d]: " _GREEN_("%s"), + CLIGetOptionListStr(DesfireSecureChannelOpts, securechann), CLIGetOptionListStr(DesfireAlgoOpts, dctx.keyType), desfire_get_key_length(dctx.keyType), sprint_hex(dctx.key, desfire_get_key_length(dctx.keyType))); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 181d12cd5..a001d3b8b 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1571,7 +1571,7 @@ int DesfireAuthenticate(DesfireContext_t *dctx, DesfireSecureChannel secureChann return 100; } -static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd) { +bool DesfireCheckAuthCmd(DesfireISOSelectWay way, uint32_t appID, uint8_t keyNum, uint8_t authcmd, bool checklrp) { size_t recv_len = 0; uint8_t respcode = 0; uint8_t recv_data[256] = {0}; @@ -1579,45 +1579,36 @@ static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd DesfireContext_t dctx = {0}; dctx.keyNum = keyNum; dctx.commMode = DCMPlain; - dctx.cmdSet = DCCNative; + dctx.cmdSet = DCCNativeISO; // if cant select - return false - int res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + int res = DesfireSelect(&dctx, way, appID, NULL); if (res != PM3_SUCCESS) return false; - uint8_t data[] = {keyNum, 0x00}; - res = DesfireExchangeEx(false, &dctx, authcmd, data, (authcmd == MFDES_AUTHENTICATE_EV2F) ? 2 : 1, &respcode, recv_data, &recv_len, false, 0); + uint8_t data[] = {keyNum, 0x01, (checklrp) ? 0x02 : 0x00}; + uint8_t datalen = (authcmd == MFDES_AUTHENTICATE_EV2F) ? 3 : 1; + res = DesfireExchangeEx(false, &dctx, authcmd, data, datalen, &respcode, recv_data, &recv_len, false, 0); DropField(); - return (res == PM3_SUCCESS && respcode == 0xaf); + + if (checklrp) + return (res == PM3_SUCCESS && respcode == 0xaf && recv_len == 17 && recv_data[0] == 0x01); + else + return (res == PM3_SUCCESS && respcode == 0xaf); } -static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorithm keytype) { +static bool DesfireCheckISOAuthCmd(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorithm keytype) { DesfireContext_t dctx = {0}; dctx.keyNum = keyNum; dctx.commMode = DCMPlain; dctx.cmdSet = DCCISO; - bool app_level = (appAID != 0x000000); - int res = 0; - if (dfname == NULL || strnlen(dfname, 16) == 0) { - if (appAID == 0x000000) { - res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, NULL, NULL); - if (res != PM3_SUCCESS) - return false; - } else { - res = DesfireSelectAIDHex(&dctx, appAID, false, 0); - if (res != PM3_SUCCESS) - return false; - } - } else { - res = DesfireISOSelectDF(&dctx, dfname, NULL, NULL); - if (res != PM3_SUCCESS) - return false; - app_level = true; - } + int res = DesfireSelect(&dctx, way, appID, dfname); + if (res != PM3_SUCCESS) + return false; + bool app_level = !DesfireMFSelected(way, appID); uint8_t rndlen = DesfireGetRndLenForKey(keytype); uint8_t piccrnd[64] = {0}; @@ -1637,24 +1628,26 @@ static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum return (sw == 0x9000 || sw == 0x6982); } -void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) { +void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) { memset(authCmdCheck, 0, sizeof(AuthCommandsChk_t)); - authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE); - authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO); - authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); - authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F); - authCmdCheck->authISONative = DesfireCheckISOAuthCmd(appAID, dfname, keyNum, T_DES); + authCmdCheck->auth = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE, false); + authCmdCheck->authISO = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_ISO, false); + authCmdCheck->authAES = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_AES, false); + authCmdCheck->authEV2 = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_EV2F, false); + authCmdCheck->authISONative = DesfireCheckISOAuthCmd(way, appID, dfname, keyNum, T_DES); + authCmdCheck->authLRP = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_EV2F, true); authCmdCheck->checked = true; } void DesfireCheckAuthCommandsPrint(AuthCommandsChk_t *authCmdCheck) { - PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", + PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s auth lrp: %s", authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"), - authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO") + authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authLRP ? _GREEN_("YES") : _RED_("NO") ); } @@ -1688,7 +1681,7 @@ int DesfireFillPICCInfo(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, bool deepm // field on-off zone if (deepmode) - DesfireCheckAuthCommands(0x000000, NULL, 0, &PICCInfo->authCmdCheck); + DesfireCheckAuthCommands(ISW6bAID, 0x000000, NULL, 0, &PICCInfo->authCmdCheck); return PM3_SUCCESS; } @@ -1770,7 +1763,7 @@ int DesfireFillAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS ap // field on-off zone if (fillAppSettings && PICCInfo->appCount > 0 && deepmode) { for (int i = 0; i < PICCInfo->appCount; i++) { - DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); + DesfireCheckAuthCommands(ISW6bAID, appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); } } @@ -2955,18 +2948,31 @@ int DesfireSelectEx(DesfireContext_t *ctx, bool fieldon, DesfireISOSelectWay way size_t resplen = 0; if (way == ISWMF || (way == ISWDFName && dfname == NULL)) { - return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen); + return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, NULL, 0, resp, &resplen); } else if (way == ISW6bAID) { + if (id == 0x000000 && fieldon) + return DesfireAnticollision(false); + + DesfireCommandSet cmdset = ctx->cmdSet; + int res; + + // if we try to select 6b AID via ISO channel - we can only switch the channel via the over channel because there is no equivalent command in the iso commands + if (ctx->cmdSet == DCCISO) + ctx->cmdSet = DCCNativeISO; + if (fieldon) - return DesfireSelectAIDHex(ctx, id, false, 0); + res = DesfireSelectAIDHex(ctx, id, false, 0); else - return DesfireSelectAIDHexNoFieldOn(ctx, id); + res = DesfireSelectAIDHexNoFieldOn(ctx, id); + + ctx->cmdSet = cmdset; + return res; } else if (way == ISWIsoID) { uint8_t data[2] = {0}; Uint2byteToMemBe(data, id); return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, data, 2, resp, &resplen); } else if (way == ISWDFName) { - return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen); + return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, NULL, 0, resp, &resplen); } return PM3_ESOFT; } diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 1df4cfedb..5cdcb3c26 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -98,6 +98,7 @@ typedef struct { bool authAES; bool authEV2; bool authISONative; + bool authLRP; } AuthCommandsChk_t; typedef struct { @@ -183,7 +184,9 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s int DesfireSelectAndAuthenticateAppW(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, DesfireISOSelectWay way, uint32_t id, bool noauth, bool verbose); int DesfireSelectAndAuthenticateISO(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, bool selectfile, uint16_t isofileid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool verbose); -void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck); + +bool DesfireCheckAuthCmd(DesfireISOSelectWay way, uint32_t appID, uint8_t keyNum, uint8_t authcmd, bool checklrp); +void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck); void DesfireCheckAuthCommandsPrint(AuthCommandsChk_t *authCmdCheck); int DesfireFormatPICC(DesfireContext_t *dctx);