Merge pull request #1483 from merlokk/lrp_detect

hf mfdes detect with lrp mode and hf mfdes info updates
This commit is contained in:
Oleg Moiseenko 2021-08-25 14:24:35 +03:00 committed by GitHub
commit 143d0140db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 62 deletions

View file

@ -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", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2/lrp>", "Secure channel: d40/ev1/ev2/lrp"),
arg_str0(NULL, "aid", "<app id hex>", "Application ID (3 hex bytes, big endian)"),
arg_str0(NULL, "appisoid", "<isoid hex>", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."),
arg_str0(NULL, "dict", "<file>", "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)));

View file

@ -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;
}

View file

@ -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);