From 8319953ad76cbdcc2eeb6b184f4786b959f8fd37 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 19:41:25 +0300 Subject: [PATCH 01/12] commands sketches and `iso select` command --- client/src/iso7816/apduinfo.h | 2 + client/src/mifare/desfirecore.c | 134 ++++++++++++++++++++++++++++++-- client/src/mifare/desfirecore.h | 5 ++ 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/client/src/iso7816/apduinfo.h b/client/src/iso7816/apduinfo.h index a1528801a..f206ecbdd 100644 --- a/client/src/iso7816/apduinfo.h +++ b/client/src/iso7816/apduinfo.h @@ -19,6 +19,8 @@ #define APDUCODE_TYPE_ERROR 3 #define APDUCODE_TYPE_SECURITY 4 +#define APDU_INCLUDE_LE_00 0x100 + typedef struct { const char *ID; const uint8_t Type; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 147850852..07279f6cf 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -277,6 +277,34 @@ void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) { data[2] = (aid >> 16) & 0xff; } +static uint8_t DesfireKeyToISOKey(DesfireCryptoAlgorythm keytype) { + switch (keytype) { + case T_DES: + return 0x02; + case T_3DES: + return 0x02; + case T_3K3DES: + return 0x04; + case T_AES: + return 0x09; + } + return 0x00; +} + +static uint8_t DesfireGetRndLenForKey(DesfireCryptoAlgorythm keytype) { + switch (keytype) { + case T_DES: + return 0x08; + case T_3DES: + return 0x08; + case T_3K3DES: + return 0x10; + case T_AES: + return 0x10; + } + return 0x00; +} + void DesfirePrintContext(DesfireContext *ctx) { PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s", ctx->keyNum, @@ -311,7 +339,7 @@ void DesfirePrintContext(DesfireContext *ctx) { } } -static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) { +static int DESFIRESendApduEx(bool activate_field, sAPDU apdu, uint16_t le, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) { if (result_len) *result_len = 0; if (sw) *sw = 0; @@ -327,7 +355,7 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin // COMPUTE APDU int datalen = 0; - if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) { // 100 == with Le + if (APDUEncodeS(&apdu, false, le, data, &datalen)) { // 100 == with Le PrintAndLogEx(ERR, "APDU encoding error."); return PM3_EAPDU_ENCODEFAIL; } @@ -370,6 +398,10 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin return PM3_SUCCESS; } +static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) { + return DESFIRESendApduEx(activate_field, apdu, APDU_INCLUDE_LE_00, result, max_result_len, result_len, sw); +} + static int DESFIRESendRaw(bool activate_field, uint8_t *data, size_t datalen, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint8_t *respcode) { *result_len = 0; if (respcode) *respcode = 0xff; @@ -516,7 +548,7 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8 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, size_t splitbysize) { +static int DesfireExchangeISONative(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) @@ -622,6 +654,16 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } +static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) { + uint32_t rlen = 0; + int res = DESFIRESendApduEx(activate_field, apdu, le, resp, 255, &rlen, sw); + + if (res == PM3_SUCCESS) + *resplen = rlen; + + return res; +} + // move data from blockdata [format: ...] to single data block static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t *dstdatalen) { *dstdatalen = 0; @@ -665,7 +707,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin if (ctx->cmdSet == DCCNative) res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); else - res = DesfireExchangeISO(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); + res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); if (splitbysize) { uint8_t sdata[250 * 5] = {0}; @@ -1201,7 +1243,53 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec return PM3_SUCCESS; } +static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { + uint8_t rndlen = DesfireGetRndLenForKey(dctx->keyType); + + uint8_t hostrnd[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + uint8_t hostrnd2[] = {0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; + + uint8_t piccrnd[64]; + size_t xlen = 0; + int res = DesfireISOGetChallenge(dctx, dctx->keyType, piccrnd, &xlen); + if (res != PM3_SUCCESS) + return 301; + + if (xlen != rndlen) + return 302; + + uint8_t both[32] = {0}; + memcpy(both, hostrnd, rndlen); + memcpy(&both[rndlen], piccrnd, rndlen); + + // encode + + // external authenticate + res = DesfireISOExternalAuth(dctx, dctx->keyNum, dctx->keyType); + if (res != PM3_SUCCESS) + return 302; + + // internal authenticate + uint8_t rnddata[64] = {0}; + xlen = 0; + res = DesfireISOInternalAuth(dctx, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen); + if (res != PM3_SUCCESS) + return 303; + + if (xlen != rndlen) + return 304; + + // decode rnddata + + // check + + return PM3_SUCCESS; +} + int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { + if (dctx->cmdSet == DCCISO) + return DesfireAuthenticateISO(dctx, secureChannel, verbose); + if (secureChannel == DACd40 || secureChannel == DACEV1) return DesfireAuthenticateEV1(dctx, secureChannel, verbose); @@ -1382,7 +1470,6 @@ int DesfireFillFileList(DesfireContext *dctx, FileListS FileList, size_t *filesc return res; } - int DesfireCreateFile(DesfireContext *dctx, uint8_t ftype, uint8_t *fdata, size_t fdatalen, bool checklen) { const DesfireCreateFileCommandsS *rcmd = GetDesfireFileCmdRec(ftype); if (rcmd == NULL) @@ -2087,3 +2174,40 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para return res; } + +int DesfireISOSelect(DesfireContext *dctx, bool sel_by_df_name, uint8_t *id, uint8_t idlen, uint8_t *resp, size_t *resplen) { + sAPDU apdu = {0}; + apdu.CLA = 0x00; + apdu.INS = ISO7816_SELECT_FILE; + apdu.P1 = (sel_by_df_name) ? 0x04 : 0x00; + apdu.P2 = 0x00; + apdu.Lc = idlen; + apdu.data = id; + + uint16_t sw = 0; + int res = DesfireExchangeISO(true, dctx, apdu, APDU_INCLUDE_LE_00, resp, resplen, &sw); + + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; +} + +int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen) { + DesfireGetRndLenForKey(keytype); + + return PM3_SUCCESS; +} + +int DesfireISOExternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype) { + + DesfireKeyToISOKey(keytype); + + return PM3_SUCCESS; +} + +int DesfireISOInternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen) { + + return PM3_SUCCESS; +} + diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index f845bf334..16d4be8d3 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -167,4 +167,9 @@ int DesfireReadRecords(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data); int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data); +int DesfireISOSelect(DesfireContext *dctx, bool sel_by_df_name, uint8_t *id, uint8_t idlen, uint8_t *resp, size_t *resplen); +int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); +int DesfireISOExternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype); +int DesfireISOInternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); + #endif // __DESFIRECORE_H From cefad274871e5aa2a7bc32e3308f2ba764e53666 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 20:10:21 +0300 Subject: [PATCH 02/12] app select works --- client/src/cmdhfmfdes.c | 34 +++++++++++++++++++++++++++------ client/src/mifare/desfirecore.c | 8 ++++---- client/src/mifare/desfirecore.h | 2 +- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f8d00fd7e..325afe0f5 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3053,6 +3053,7 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { 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 of application for some parameters (3 hex bytes, big endian)"), + arg_str0(NULL, "dfname", "", "Application DF Name (string, max 16 chars). Selects application via ISO SELECT command"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3068,18 +3069,39 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { CLIParserFree(ctx); return res; } + + uint8_t dfname[32] = {0}; + int dfnamelen = 16; + CLIGetStrWithReturn(ctx, 12, dfname, &dfnamelen); SetAPDULogging(APDULogging); CLIParserFree(ctx); - res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose); - if (res != PM3_SUCCESS) { - DropField(); - PrintAndLogEx(FAILED, "Select application 0x%06x " _RED_("failed") " ", appid); - return res; + if (dfnamelen > 0) { // dctx.cmdSet == DCCISO ? + uint8_t resp[250] = {0}; + size_t resplen = 0; + res = DesfireISOSelect(&dctx, (char *)dfname, resp, &resplen); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "ISO Select application " _RED_("failed")); + return res; + } + + if (resplen > 0) + PrintAndLogEx(FAILED, "Application " _CYAN_("FCI template") " [%zu]%s", resplen, sprint_hex(resp, resplen)); + + PrintAndLogEx(SUCCESS, "Application `%s` selected " _GREEN_("succesfully") " ", (char *)dfname); + } else { + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose); + if (res != PM3_SUCCESS) { + DropField(); + PrintAndLogEx(FAILED, "Select application 0x%06x " _RED_("failed") " ", appid); + return res; + } + + PrintAndLogEx(SUCCESS, "Application 0x%06x selected " _GREEN_("succesfully") " ", appid); } - PrintAndLogEx(SUCCESS, "Application 0x%06x selected " _GREEN_("succesfully") " ", appid); DropField(); return res; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 07279f6cf..e3b4be02e 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2175,14 +2175,14 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para return res; } -int DesfireISOSelect(DesfireContext *dctx, bool sel_by_df_name, uint8_t *id, uint8_t idlen, uint8_t *resp, size_t *resplen) { +int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { sAPDU apdu = {0}; apdu.CLA = 0x00; apdu.INS = ISO7816_SELECT_FILE; - apdu.P1 = (sel_by_df_name) ? 0x04 : 0x00; + apdu.P1 = 0x04; apdu.P2 = 0x00; - apdu.Lc = idlen; - apdu.data = id; + apdu.Lc = strnlen(dfname, 16); + apdu.data = (uint8_t *)dfname; uint16_t sw = 0; int res = DesfireExchangeISO(true, dctx, apdu, APDU_INCLUDE_LE_00, resp, resplen, &sw); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 16d4be8d3..2f1edfe13 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -167,7 +167,7 @@ int DesfireReadRecords(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data); int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data); -int DesfireISOSelect(DesfireContext *dctx, bool sel_by_df_name, uint8_t *id, uint8_t idlen, uint8_t *resp, size_t *resplen); +int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); int DesfireISOExternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype); int DesfireISOInternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); From b8ce6676ef5a59abe18b56e225c47305dc668c29 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 20:13:33 +0300 Subject: [PATCH 03/12] select empty app --- 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 325afe0f5..a709a4dd2 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3077,13 +3077,13 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - if (dfnamelen > 0) { // dctx.cmdSet == DCCISO ? + if (dctx.cmdSet == DCCISO || dfnamelen > 0) { uint8_t resp[250] = {0}; size_t resplen = 0; res = DesfireISOSelect(&dctx, (char *)dfname, resp, &resplen); if (res != PM3_SUCCESS) { DropField(); - PrintAndLogEx(FAILED, "ISO Select application " _RED_("failed")); + PrintAndLogEx(FAILED, "ISO Select application `%s` " _RED_("failed"), (char *)dfname); return res; } From d80656ef53a5f9d4af18b2c482a5ec61e2ebd3ad Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 20:23:52 +0300 Subject: [PATCH 04/12] select command refactoring --- client/src/cmdhfmfdes.c | 1 - client/src/mifare/desfirecore.c | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index a709a4dd2..d134447a3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3102,7 +3102,6 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { PrintAndLogEx(SUCCESS, "Application 0x%06x selected " _GREEN_("succesfully") " ", appid); } - DropField(); return res; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index e3b4be02e..9952bba64 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2176,17 +2176,8 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para } int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { - sAPDU apdu = {0}; - apdu.CLA = 0x00; - apdu.INS = ISO7816_SELECT_FILE; - apdu.P1 = 0x04; - apdu.P2 = 0x00; - apdu.Lc = strnlen(dfname, 16); - apdu.data = (uint8_t *)dfname; - uint16_t sw = 0; - int res = DesfireExchangeISO(true, dctx, apdu, APDU_INCLUDE_LE_00, resp, resplen, &sw); - + int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, 0x04, 0x00, strnlen(dfname, 16), (uint8_t *)dfname}, APDU_INCLUDE_LE_00, resp, resplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) return PM3_ESOFT; From dd74ec95230d0e222cf6a5b76157b4e9bbecf43d Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 00:05:39 +0300 Subject: [PATCH 05/12] ev1 gen session keys --- client/src/mifare/desfirecrypto.c | 29 +++++++++++++++++++++++++++++ client/src/mifare/desfirecrypto.h | 1 + 2 files changed, 30 insertions(+) diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 73913c449..a8ddcdf46 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -389,6 +389,35 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode) { return fmode; } +void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key) { + switch (keytype) { + case T_DES: + memcpy(key, rnda, 4); + memcpy(key + 4, rndb, 4); + break; + case T_3DES: + memcpy(key, rnda, 4); + memcpy(key + 4, rndb, 4); + memcpy(key + 8, rnda + 4, 4); + memcpy(key + 12, rndb + 4, 4); + break; + case T_3K3DES: + memcpy(key, rnda, 4); + memcpy(key + 4, rndb, 4); + memcpy(key + 8, rnda + 6, 4); + memcpy(key + 12, rndb + 6, 4); + memcpy(key + 16, rnda + 12, 4); + memcpy(key + 20, rndb + 12, 4); + break; + case T_AES: + memcpy(key, rnda, 4); + memcpy(key + 4, rndb, 4); + memcpy(key + 8, rnda + 12, 4); + memcpy(key + 12, rndb + 12, 4); + break; + } +} + // https://www.nxp.com/docs/en/application-note/AN12343.pdf // page 35 void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey) { diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 2ba28bc46..49e18edfa 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -108,6 +108,7 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key); DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); +void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key); 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); From c4a20a3df73aed7e7bd1c8fa8f8e19c526b43e85 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 00:06:21 +0300 Subject: [PATCH 06/12] iso authenticate works for aes and application level --- client/src/mifare/desfirecore.c | 96 +++++++++++++++++++++++++++------ client/src/mifare/desfirecore.h | 4 +- 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 9952bba64..26ab50304 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -261,6 +261,22 @@ const char *DesfireAuthErrorToStr(int error) { return "Can't select application."; case 201: return "Authentication retured no error but channel not authenticated."; + case 301: + return "ISO Get challenge error."; + case 302: + return "ISO Get challenge returned wrong length."; + case 303: + return "Crypto encode piccrnd1 error."; + case 304: + return "External authenticate error."; + case 305: + return "Internal authenticate error."; + case 306: + return "Internal authenticate returned wrong length."; + case 307: + return "Crypto decode piccrnd2 error."; + case 308: + return "Random numbers dont match. Authentication failed."; default: break; } @@ -797,6 +813,14 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) { if (verbose) DesfirePrintContext(dctx); + + bool isosw = false; + if (dctx->cmdSet == DCCISO) { + dctx->cmdSet = DCCNativeISO; + isosw = true; + if (verbose) + PrintAndLogEx(INFO, "Switch to " _CYAN_("native") " for select"); + } int res = DesfireSelectAIDHex(dctx, aid, false, 0); if (res != PM3_SUCCESS) { @@ -805,6 +829,9 @@ int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel se } if (verbose) PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid); + + if (isosw) + dctx->cmdSet = DCCISO; if (!noauth) { res = DesfireAuthenticate(dctx, secureChannel, verbose); @@ -1263,31 +1290,47 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec memcpy(&both[rndlen], piccrnd, rndlen); // encode + uint8_t IV[16] = {0}; + if (aes_encode(IV, dctx->key, both, both, rndlen * 2)) + return 303; // external authenticate - res = DesfireISOExternalAuth(dctx, dctx->keyNum, dctx->keyType); + res = DesfireISOExternalAuth(dctx, true, dctx->keyNum, dctx->keyType, both); if (res != PM3_SUCCESS) - return 302; + return 304; // internal authenticate uint8_t rnddata[64] = {0}; xlen = 0; - res = DesfireISOInternalAuth(dctx, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen); + res = DesfireISOInternalAuth(dctx, true, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen); if (res != PM3_SUCCESS) - return 303; + return 305; - if (xlen != rndlen) - return 304; + if (xlen != rndlen * 2) + return 306; // decode rnddata + uint8_t piccrnd2[64] = {0}; + if (aes_decode(IV, dctx->key, rnddata, piccrnd2, rndlen * 2)) + return 307; // check + if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0) + return 308; + DesfireGenSessionKeyEV1(hostrnd, piccrnd2, dctx->keyType, dctx->sessionKeyEnc); + DesfireClearIV(dctx); + memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)); + dctx->secureChannel = secureChannel; + + if (verbose) + PrintAndLogEx(INFO, "session key: %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType))); + return PM3_SUCCESS; } int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { - if (dctx->cmdSet == DCCISO) + if (dctx->cmdSet == DCCISO && secureChannel != DACEV2) return DesfireAuthenticateISO(dctx, secureChannel, verbose); if (secureChannel == DACd40 || secureChannel == DACEV1) @@ -2185,20 +2228,39 @@ int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t * } int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen) { - DesfireGetRndLenForKey(keytype); - - return PM3_SUCCESS; -} - -int DesfireISOExternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype) { + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; - DesfireKeyToISOKey(keytype); + return res; +} + +int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data) { + uint8_t p1 = DesfireKeyToISOKey(keytype); + uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum; - return PM3_SUCCESS; + uint8_t resp[250] = {0}; + size_t resplen = 0; + + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; } -int DesfireISOInternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen) { +int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen) { + uint8_t keylen = DesfireGetRndLenForKey(keytype); + uint8_t p1 = DesfireKeyToISOKey(keytype); + uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum; - return PM3_SUCCESS; + uint16_t sw = 0; + int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw); + if (res == PM3_SUCCESS && sw != 0x9000) + return PM3_ESOFT; + + return res; } diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 2f1edfe13..c7bd24507 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -169,7 +169,7 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); -int DesfireISOExternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype); -int DesfireISOInternalAuth(DesfireContext *dctx, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); +int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data); +int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); #endif // __DESFIRECORE_H From 5484cdb517c30bc399d2f9110b62f3588ba8be0a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 00:08:07 +0300 Subject: [PATCH 07/12] remove todo --- client/src/cmdhfmfdes.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index d134447a3..e6026d4ed 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -6348,12 +6348,9 @@ int CmdHFMFDes(const char *Cmd) { ISO/IEC 7816 Cmds ----------------- - 'A4' Select 'B0' Read Binary 'D6' Update Binary 'B2' Read Records 'E2' Append Records - '84' Get Challenge - '88' Internal Authenticate - '82' External Authenticate + */ From 72585aae8ae0ae2d7d52b65067b7c4dd1ed72f50 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 10:47:19 +0300 Subject: [PATCH 08/12] iso select refactoring --- client/src/cmdhfmfdes.c | 10 ++++++++-- client/src/mifare/desfirecore.c | 15 +++++++++++++-- client/src/mifare/desfirecore.h | 12 +++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e6026d4ed..63e691aa3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3080,7 +3080,10 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { if (dctx.cmdSet == DCCISO || dfnamelen > 0) { uint8_t resp[250] = {0}; size_t resplen = 0; - res = DesfireISOSelect(&dctx, (char *)dfname, resp, &resplen); + if (dfnamelen > 0) + res = DesfireISOSelectDF(&dctx, (char *)dfname, resp, &resplen); + else + res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, resp, &resplen); if (res != PM3_SUCCESS) { DropField(); PrintAndLogEx(FAILED, "ISO Select application `%s` " _RED_("failed"), (char *)dfname); @@ -3090,7 +3093,10 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { if (resplen > 0) PrintAndLogEx(FAILED, "Application " _CYAN_("FCI template") " [%zu]%s", resplen, sprint_hex(resp, resplen)); - PrintAndLogEx(SUCCESS, "Application `%s` selected " _GREEN_("succesfully") " ", (char *)dfname); + if (dfnamelen > 0) + PrintAndLogEx(SUCCESS, "Application `%s` selected " _GREEN_("succesfully"), (char *)dfname); + else + PrintAndLogEx(SUCCESS, "PICC MF selected " _GREEN_("succesfully")); } else { res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose); if (res != PM3_SUCCESS) { diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 26ab50304..8ee78813d 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -2218,15 +2218,26 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para return res; } -int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { +int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) { + uint8_t xresp[250] = {0}; + size_t xresplen = 0; uint16_t sw = 0; - int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, 0x04, 0x00, strnlen(dfname, 16), (uint8_t *)dfname}, APDU_INCLUDE_LE_00, resp, resplen, &sw); + int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw); if (res == PM3_SUCCESS && sw != 0x9000) return PM3_ESOFT; + if (resp != NULL && resplen != NULL) { + *resplen = xresplen; + memcpy(resp, xresp, xresplen); + } + return res; } +int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { + return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen); +} + int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen) { uint16_t sw = 0; int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index c7bd24507..655995e5b 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -21,6 +21,15 @@ #define DESFIRE_TX_FRAME_MAX_LEN 54 +enum DesfireISOSelectControlEnum { + ISSMFDFEF = 0x00, + ISSChildDF = 0x01, + ISSEFByFileID = 0x02, + ISSParentDF = 0x03, + ISSDFName = 0x04 +}; +typedef enum DesfireISOSelectControlEnum DesfireISOSelectControl; + typedef struct { const uint8_t id; const char *text; @@ -167,7 +176,8 @@ int DesfireReadRecords(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data); int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data); -int DesfireISOSelect(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); +int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); +int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen); int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data); int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); From de566068b7d745260db34718027994e9253961a2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 10:54:03 +0300 Subject: [PATCH 09/12] clear session after select --- client/src/mifare/desfirecore.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 8ee78813d..d4e498d0a 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -775,6 +775,9 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { return PM3_SUCCESS; } + + DesfireClearSession(ctx); + return res; } @@ -2231,6 +2234,8 @@ int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t memcpy(resp, xresp, xresplen); } + DesfireClearSession(dctx); + return res; } From e4eff3c40f8ce4c7a485615da69cb4833c4c724f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 10:55:21 +0300 Subject: [PATCH 10/12] fix --- client/src/mifare/desfirecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index d4e498d0a..872ea481c 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -773,11 +773,11 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { if (respcode != MFDES_S_OPERATION_OK) return PM3_EAPDU_FAIL; + DesfireClearSession(ctx); + return PM3_SUCCESS; } - DesfireClearSession(ctx); - return res; } From 91f000ad333ad4fe511d2d506e254f1ee0f7e61f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 11:58:33 +0300 Subject: [PATCH 11/12] iso channel auth with des/2dea/3tdea/aes works --- client/src/mifare/desfirecore.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 872ea481c..d24cd99d5 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1293,9 +1293,8 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec memcpy(&both[rndlen], piccrnd, rndlen); // encode - uint8_t IV[16] = {0}; - if (aes_encode(IV, dctx->key, both, both, rndlen * 2)) - return 303; + DesfireClearIV(dctx); + DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303 // external authenticate res = DesfireISOExternalAuth(dctx, true, dctx->keyNum, dctx->keyType, both); @@ -1314,8 +1313,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec // decode rnddata uint8_t piccrnd2[64] = {0}; - if (aes_decode(IV, dctx->key, rnddata, piccrnd2, rndlen * 2)) - return 307; + DesfireCryptoEncDec(dctx, false, rnddata, rndlen * 2, piccrnd2, false); // error 307 // check if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0) From 84d89b248071499311b5b26b4bae10c685a45713 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 31 Jul 2021 12:36:49 +0300 Subject: [PATCH 12/12] iso auth works for app and picc level --- client/src/mifare/desfirecore.c | 6 ++++-- client/src/mifare/desfirecrypto.c | 2 ++ client/src/mifare/desfirecrypto.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index d24cd99d5..51ad6172d 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -774,6 +774,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { return PM3_EAPDU_FAIL; DesfireClearSession(ctx); + ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00); return PM3_SUCCESS; } @@ -1297,14 +1298,14 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303 // external authenticate - res = DesfireISOExternalAuth(dctx, true, dctx->keyNum, dctx->keyType, both); + res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both); if (res != PM3_SUCCESS) return 304; // internal authenticate uint8_t rnddata[64] = {0}; xlen = 0; - res = DesfireISOInternalAuth(dctx, true, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen); + res = DesfireISOInternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen); if (res != PM3_SUCCESS) return 305; @@ -2233,6 +2234,7 @@ int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t } DesfireClearSession(dctx); + dctx->appSelected = !( (cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0) ); return res; } diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index a8ddcdf46..e1670ada2 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -41,6 +41,8 @@ void DesfireClearContext(DesfireContext *ctx) { ctx->secureChannel = DACNone; ctx->cmdSet = DCCNative; ctx->commMode = DCMNone; + + ctx->appSelected = false; ctx->kdfAlgo = 0; ctx->kdfInputLen = 0; diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 49e18edfa..b24b8a3ac 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -75,6 +75,8 @@ typedef struct DesfireContextS { DesfireSecureChannel secureChannel; // none/d40/ev1/ev2 DesfireCommandSet cmdSet; // native/nativeiso/iso DesfireCommunicationMode commMode; // plain/mac/enc + + bool appSelected; // for iso auth uint8_t IV[DESFIRE_MAX_KEY_SIZE]; uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];