From 2fa6c4643e62e23511ffc5c7a2f2ef52114790d5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 1 Jul 2021 19:53:57 +0300 Subject: [PATCH 01/31] desfire channel sketch --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdhfmfdes.c | 117 ++++++++++++++ client/src/mifare/desfire_crypto.c | 11 ++ client/src/mifare/desfire_crypto.h | 2 + client/src/mifare/desfirecore.c | 236 +++++++++++++++++++++++++++++ client/src/mifare/desfirecore.h | 75 +++++++++ include/protocols.h | 1 + 8 files changed, 444 insertions(+) create mode 100644 client/src/mifare/desfirecore.c create mode 100644 client/src/mifare/desfirecore.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a81682337..0030df688 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -226,6 +226,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/mifarehost.c ${PM3_ROOT}/client/src/nfc/ndef.c ${PM3_ROOT}/client/src/mifare/desfire_crypto.c + ${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui diff --git a/client/Makefile b/client/Makefile index 9ed3feb86..ef8130c7d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -572,6 +572,7 @@ SRCS = aiddesfire.c \ loclass/elite_crack.c \ loclass/ikeys.c \ mifare/desfire_crypto.c \ + mifare/desfirecore.c \ mifare/mad.c \ mifare/mfkey.c \ mifare/mifare4.c \ diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2608a29eb..04079eba3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5116,6 +5116,121 @@ static int CmdHF14aDesMAD(const char *Cmd) { } */ +static int CmdHF14ADesGetAIDs(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes getaids", + "Get Application IDs list from card. Master key needs to be provided.", + "hf mfdes getaids -n 0 -t des -k 0000000000000000 -f none -> execute with default factory setup"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_int0("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_int0("f", "kdf", "", "Key Derivation Function (KDF): None(default), AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + +/* + int aidlength = 0; + uint8_t aid[3] = {0}; + CLIGetHexWithReturn(ctx, 1, aid, &aidlength); + swap24(aid); + uint8_t vkey[16] = {0}; + int vkeylen = 0; + CLIGetHexWithReturn(ctx, 2, vkey, &vkeylen); + + if (vkeylen > 0) { + if (vkeylen == 8) { + memcpy(&deskeyList[deskeyListLen], vkey, 8); + deskeyListLen++; + } else if (vkeylen == 16) { + memcpy(&aeskeyList[aeskeyListLen], vkey, 16); + aeskeyListLen++; + } else if (vkeylen == 24) { + memcpy(&k3kkeyList[k3kkeyListLen], vkey, 16); + k3kkeyListLen++; + } else { + PrintAndLogEx(ERR, "Specified key must have 8, 16 or 24 bytes length."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(ctx, 3), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool pattern1b = arg_get_lit(ctx, 4); + bool pattern2b = arg_get_lit(ctx, 5); + + if (pattern1b && pattern2b) { + PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (dict_filenamelen && (pattern1b || pattern2b)) { + PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint32_t startPattern = 0x0000; + uint8_t vpattern[2]; + int vpatternlen = 0; + CLIGetHexWithReturn(ctx, 6, vpattern, &vpatternlen); + if (vpatternlen > 0) { + if (vpatternlen <= 2) { + startPattern = (vpattern[0] << 8) + vpattern[1]; + } else { + PrintAndLogEx(ERR, "Pattern must be 2-byte length."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (!pattern2b) + PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); + } + + uint8_t jsonname[250] = {0}; + int jsonnamelen = 0; + if (CLIParamStrToBuf(arg_get_str(ctx, 7), jsonname, sizeof(jsonname), &jsonnamelen)) { + PrintAndLogEx(ERR, "Invalid json name."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + jsonname[jsonnamelen] = 0; + + bool verbose = arg_get_lit(ctx, 8); + + // Get KDF input + uint8_t kdfInput[31] = {0}; + int kdfInputLen = 0; + uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0); + CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen); +*/ + CLIParserFree(ctx); + + + + + return PM3_SUCCESS; +} + +// {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, +static int CmdHF14ADesGetAppNames(const char *Cmd) { + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"}, @@ -5134,6 +5249,8 @@ static command_t CommandTable[] = { {"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"}, {"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"}, {"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, + {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, + {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"}, {"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"}, diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index e3e785e6c..1767c9c47 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -51,6 +51,17 @@ static inline void update_key_schedules(desfirekey_t key) { // } } +int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) { + switch (key_type) { + case T_DES: return 8; + case T_3DES: return 16; + case T_3K3DES: return 24; + case T_AES: return 16; + } + return 0; +} + + /******************************************************************************/ void des_encrypt(void *out, const void *in, const void *key) { diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index ecc6fc4a5..9c67b1182 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -60,6 +60,8 @@ enum DESFIRE_CRYPTOALGO { T_AES = 0x03 }; +int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type); + enum DESFIRE_AUTH_SCHEME { AS_LEGACY, AS_NEW diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c new file mode 100644 index 000000000..dbd77e1ca --- /dev/null +++ b/client/src/mifare/desfirecore.c @@ -0,0 +1,236 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2010 Romain Tartiere. +// Copyright (C) 2014 Iceman +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency Desfire core functions +//----------------------------------------------------------------------------- +// Info from here and many other soursec from the internet +// https://github.com/revk/DESFireAES +// https://github.com/step21/desfire_rfid +// https://github.com/patsys/desfire-python/blob/master/Desfire/DESFire.py +//----------------------------------------------------------------------------- + +#include "desfirecore.h" +#include +#include +#include +#include "ui.h" +#include "protocols.h" +#include "cmdhf14a.h" +#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes +#include "iso7816/iso7816core.h" // APDU logging +#include "util_posix.h" // msleep +#include "mifare/desfire_crypto.h" + +void DesfireClearContext(DesfireContext *ctx) { + ctx->keyNum = 0; + ctx->keyType = T_DES; + memset(ctx->key, 0, sizeof(ctx->key)); + + ctx->authChannel = DACNone; + ctx->cmdChannel = DCCNative; + ctx->commMode = DCMNone; + + memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC)); + memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc)); + memset(ctx->lastIV, 0, sizeof(ctx->lastIV)); + ctx->cntrTx = 0; + ctx->cntrRx = 0; + memset(ctx->TI, 0, sizeof(ctx->TI)); +} + +void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) { + DesfireClearContext(ctx); + + ctx->keyNum = keyNum; + ctx->keyType = keyType; + memcpy(ctx->key, key, desfire_get_key_length(keyType)); +} + +static int DESFIRESendApdu(bool activate_field, sAPDU apdu, 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; + + uint16_t isw = 0; + int res = 0; + + if (activate_field) { + DropField(); + msleep(50); + } + + uint8_t data[APDU_RES_LEN] = {0}; + + // COMPUTE APDU + int datalen = 0; + if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) { // 100 == with Le + PrintAndLogEx(ERR, "APDU encoding error."); + return PM3_EAPDU_ENCODEFAIL; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); + + res = ExchangeAPDU14a(data, datalen, activate_field, true, result, max_result_len, (int *)result_len); + if (res != PM3_SUCCESS) { + return res; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len)); + + if (*result_len < 2) { + return PM3_SUCCESS; + } + + *result_len -= 2; + isw = (result[*result_len] << 8) + result[*result_len + 1]; + if (sw) + *sw = isw; + + if (isw != 0x9000 && + isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) && + isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) && + isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) && + isw != DESFIRE_GET_ISO_STATUS(MFDES_S_NO_CHANGES)) { + if (GetAPDULogging()) { + if (isw >> 8 == 0x61) { + PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff); + } else { + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(isw >> 8, isw & 0xff)); + return PM3_EAPDU_FAIL; + } + } + return PM3_EAPDU_FAIL; + } + return PM3_SUCCESS; +} + +static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { + + return PM3_SUCCESS; +} + +static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { + if (resplen) + *resplen = 0; + + // TODO !!! + size_t splitbysize = 0; + + uint16_t sw = 0; + uint8_t buf[255 * 5] = {0x00}; + uint32_t buflen = 0; + uint32_t pos = 0; + uint32_t i = 1; + + sAPDU apdu = {0}; + apdu.CLA = MFDES_NATIVE_ISO7816_WRAP_CLA; //0x90 + apdu.INS = cmd; + apdu.Lc = datalen; + apdu.P1 = 0; + apdu.P2 = 0; + apdu.data = data; + + int res = DESFIRESendApdu(activate_field, apdu, buf, sizeof(buf), &buflen, &sw); + if (res != PM3_SUCCESS) { + //PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw)); + return res; + } + if (resp) + memcpy(resp, buf, buflen); + + pos += buflen; + if (!enable_chaining) { + if (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { + if (resplen) + *resplen = pos; + return PM3_SUCCESS; + } + return res; + } + + while (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { + apdu.CLA = MFDES_NATIVE_ISO7816_WRAP_CLA; //0x90 + apdu.INS = MFDES_ADDITIONAL_FRAME; //0xAF + apdu.Lc = 0; + apdu.P1 = 0; + apdu.P2 = 0; + apdu.data = NULL; + + res = DESFIRESendApdu(false, apdu, buf, sizeof(buf), &buflen, &sw); + if (res != PM3_SUCCESS) { + //PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw)); + return res; + } + + if (resp != NULL) { + if (splitbysize) { + memcpy(&resp[i * splitbysize], buf, buflen); + i += 1; + } else { + memcpy(&resp[pos], buf, buflen); + } + } + pos += buflen; + + if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) break; + } + + if (resplen) + *resplen = (splitbysize) ? i : pos; + return PM3_SUCCESS; +} + +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { + int res = PM3_SUCCESS; + + switch(ctx->cmdChannel) { + case DCCNative: + res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining); + break; + case DCCNativeISO: + res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining); + break; + case DCCISO: + return PM3_EAPDU_FAIL; + break; + } + + return res; +} + +int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) { + return DesfireExchangeEx(false, ctx, cmd, data, datalen, resp, resplen, true); +} + +int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { + if (aid1 == NULL) + return PM3_EINVARG; + + uint8_t data[6] = {0}; + memcpy(data, aid1, 3); + if (aid2 != NULL) + memcpy(&data[3], aid2, 3); + uint8_t resp[257] = {0}; + size_t resplen = 0; + int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, resp, &resplen, true); + if (res == PM3_SUCCESS && resplen != 0) + return PM3_ECARDEXCHANGE; + return res; +} + +int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2) { + uint8_t data[6] = {0}; + // TODO !!!! + data[0] = aid1 & 0xff; + data[1] = (aid1 >> 8) & 0xff; + data[2] = (aid1 >> 16) & 0xff; + return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL); +} + diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h new file mode 100644 index 000000000..12acb7e8c --- /dev/null +++ b/client/src/mifare/desfirecore.h @@ -0,0 +1,75 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2010 Romain Tartiere. +// Copyright (C) 2014 Iceman +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency Desfire core functions +//----------------------------------------------------------------------------- + +#ifndef __DESFIRECORE_H +#define __DESFIRECORE_H + +#include "common.h" +#include "mifare/desfire_crypto.h" +#include "mifare/mifare4.h" + +#define DESF_MAX_KEY_LEN 24 + +#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x ) + +typedef enum { + DACNone, + DACd40, + DACEV1, + DACEV2 +} DesfireAuthChannel; + +typedef enum { + DCCNative, + DCCNativeISO, + DCCISO +} DesfireCommandChannel; + +typedef enum { + DCMNone, + DCMPlain, + DCMMACed, + DCMEncrypted +} DesfireCommunicationMode; + + +typedef struct DesfireContextS { + uint8_t keyNum; + enum DESFIRE_CRYPTOALGO keyType; // des,2tdea,3tdea,aes + uint8_t key[DESF_MAX_KEY_LEN]; + + // KDF finction + // KDF input + + DesfireAuthChannel authChannel; // none/d40/ev1/ev2 + DesfireCommandChannel cmdChannel; // native/nativeiso/iso + DesfireCommunicationMode commMode; // plain/mac/enc + + uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN]; + uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN]; // look at mifare4.h - mf4Session_t + uint8_t lastIV[DESF_MAX_KEY_LEN]; + //mf4Session_t AESSession; + uint16_t cntrTx; // for AES + uint16_t cntrRx; // for AES + uint8_t TI[4]; // for AES +} DesfireContext; + +void DesfireClearContext(DesfireContext *ctx); +void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key); + +int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); +int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); +int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen); +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining); + + +#endif // __DESFIRECORE_H diff --git a/include/protocols.h b/include/protocols.h index 4b3cf763f..66385bcb9 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -459,6 +459,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MFDES_GET_FILE_SETTINGS 0xF5 #define MFDES_FORMAT_PICC 0xFC #define MFDES_VERIFY_PC 0xFD +#define MFDES_NATIVE_ISO7816_WRAP_CLA 0x90 // MIFARE DESFire status & error codes: #define MFDES_S_OPERATION_OK 0x00 From ecfcc21ded5b4669a86b0bd5d0fe8665024b0783 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 1 Jul 2021 20:06:33 +0300 Subject: [PATCH 02/31] select works (somehow) --- client/src/cmdhfmfdes.c | 21 +++++++++++++++++++++ client/src/mifare/desfirecore.c | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 04079eba3..fa22eabaa 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -28,6 +28,7 @@ #include "iso7816/iso7816core.h" // APDU logging #include "util_posix.h" // msleep #include "mifare/desfire_crypto.h" +#include "mifare/desfirecore.h" #include "crapto1/crapto1.h" #include "fileutils.h" #include "mifare/mifaredefault.h" // default keys @@ -5218,11 +5219,31 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0); CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen); */ +// SetAPDULogging(APDULogging); + SetAPDULogging(true); CLIParserFree(ctx); + uint8_t key[24] = {0}; + DesfireContext dctx; + DesfireSetKey(&dctx, 1, T_DES, key); + dctx.cmdChannel = DCCNativeISO; + + + //size_t len = 0; + uint16_t sw = 0; + //uint8_t buf[APDU_RES_LEN] = {0}; + + int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") ". Card returns 0x%02x", sw); + DropField(); + return PM3_ESOFT; + } + + DropField(); return PM3_SUCCESS; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index dbd77e1ca..6116db41e 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -231,6 +231,11 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin data[0] = aid1 & 0xff; data[1] = (aid1 >> 8) & 0xff; data[2] = (aid1 >> 16) & 0xff; + + data[3] = aid2 & 0xff; + data[4] = (aid2 >> 8) & 0xff; + data[5] = (aid2 >> 16) & 0xff; + return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL); } From 73db86bcc7819408f9322ec68178b8ee6634ba89 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 1 Jul 2021 20:32:04 +0300 Subject: [PATCH 03/31] exchange returns result. select works --- client/src/cmdhfmfdes.c | 6 ++--- client/src/mifare/desfirecore.c | 41 ++++++++++++++++++++++++--------- client/src/mifare/desfirecore.h | 4 ++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index fa22eabaa..046187dcb 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5230,12 +5230,12 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { //size_t len = 0; - uint16_t sw = 0; + //uint16_t sw = 0; //uint8_t buf[APDU_RES_LEN] = {0}; int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); - if (res != 0 || sw != 0x9000) { - PrintAndLogEx(ERR, "Desfire select " _RED_("error") ". Card returns 0x%02x", sw); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); DropField(); return PM3_ESOFT; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 6116db41e..3d910a0da 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -111,14 +111,16 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin return PM3_SUCCESS; } -static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { +static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { return PM3_SUCCESS; } -static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { +static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { if (resplen) *resplen = 0; + if (respcode) + *respcode = 0xff; // TODO !!! size_t splitbysize = 0; @@ -142,6 +144,10 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t //PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw)); return res; } + + if (respcode != NULL && ((sw & 0xff00) == 0x9100)) + *respcode = sw & 0xff; + if (resp) memcpy(resp, buf, buflen); @@ -169,6 +175,9 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return res; } + if (respcode != NULL && ((sw & 0xff00) == 0x9100)) + *respcode = sw & 0xff; + if (resp != NULL) { if (splitbysize) { memcpy(&resp[i * splitbysize], buf, buflen); @@ -187,15 +196,15 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } -int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) { +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { int res = PM3_SUCCESS; switch(ctx->cmdChannel) { case DCCNative: - res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining); + res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); break; case DCCNativeISO: - res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining); + res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); break; case DCCISO: return PM3_EAPDU_FAIL; @@ -205,8 +214,8 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin return res; } -int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) { - return DesfireExchangeEx(false, ctx, cmd, data, datalen, resp, resplen, true); +int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen) { + return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true); } int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { @@ -219,15 +228,25 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { memcpy(&data[3], aid2, 3); uint8_t resp[257] = {0}; size_t resplen = 0; - int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, resp, &resplen, true); - if (res == PM3_SUCCESS && resplen != 0) - return PM3_ECARDEXCHANGE; + uint8_t respcode = 0; + + int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true); + if (res == PM3_SUCCESS) { + if (resplen != 0) + return PM3_ECARDEXCHANGE; + + // select operation fail + if (respcode != MFDES_S_OPERATION_OK) + return PM3_EAPDU_FAIL; + + return PM3_SUCCESS; + } return res; } int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2) { uint8_t data[6] = {0}; - // TODO !!!! + data[0] = aid1 & 0xff; data[1] = (aid1 >> 8) & 0xff; data[2] = (aid1 >> 16) & 0xff; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 12acb7e8c..fa212174c 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -68,8 +68,8 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); -int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen); -int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining); +int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining); #endif // __DESFIRECORE_H From b5ee999c73db635644c7a4f9e2be37e82ddb5faf Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 1 Jul 2021 20:47:02 +0300 Subject: [PATCH 04/31] rename GetErrorString -> DesfireGetErrorString --- client/src/cmdhfmfdes.c | 167 +++++--------------------------- client/src/mifare/desfirecore.c | 125 +++++++++++++++++++++++- client/src/mifare/desfirecore.h | 2 + 3 files changed, 148 insertions(+), 146 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 046187dcb..f51bbdd57 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -509,125 +509,6 @@ static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, return PM3_SUCCESS; } -static const char *getstatus(uint16_t *sw) { - if (sw == NULL) return "--> sw argument error. This should never happen !"; - if (((*sw >> 8) & 0xFF) == 0x91) { - switch (*sw & 0xFF) { - case MFDES_E_OUT_OF_EEPROM: - return "Out of Eeprom, insufficient NV-Memory to complete command"; - case MFDES_E_ILLEGAL_COMMAND_CODE: - return "Command code not supported"; - - case MFDES_E_INTEGRITY_ERROR: - return "CRC or MAC does not match data / Padding bytes invalid"; - - case MFDES_E_NO_SUCH_KEY: - return "Invalid key number specified"; - - case MFDES_E_LENGTH: - return "Length of command string invalid"; - - case MFDES_E_PERMISSION_DENIED: - return "Current configuration/status does not allow the requested command"; - - case MFDES_E_PARAMETER_ERROR: - return "Value of the parameter(s) invalid"; - - case MFDES_E_APPLICATION_NOT_FOUND: - return "Requested AID not present on PICC"; - - case MFDES_E_APPL_INTEGRITY: - return "Application integrity error, application will be disabled"; - - case MFDES_E_AUTHENTIFICATION_ERROR: - return "Current authentication status does not allow the requested command"; - - case MFDES_E_BOUNDARY: - return "Attempted to read/write data from/to beyond the file's/record's limit"; - - case MFDES_E_PICC_INTEGRITY: - return "PICC integrity error, PICC will be disabled"; - - case MFDES_E_COMMAND_ABORTED: - return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD"; - - case MFDES_E_PICC_DISABLED: - return "PICC was disabled by an unrecoverable error"; - - case MFDES_E_COUNT: - return "Application count is limited to 28, not addition CreateApplication possible"; - - case MFDES_E_DUPLICATE: - return "Duplicate entry: File/Application/ISO Text does already exist"; - - case MFDES_E_EEPROM: - return "Eeprom error due to loss of power, internal backup/rollback mechanism activated"; - - case MFDES_E_FILE_NOT_FOUND: - return "Specified file number does not exist"; - - case MFDES_E_FILE_INTEGRITY: - return "File integrity error, file will be disabled"; - - default: - return "Unknown error"; - } - } - return "Unknown error"; -} - -static const char *GetErrorString(int res, uint16_t *sw) { - switch (res) { - case PM3_EAPDU_FAIL: - return getstatus(sw); - case PM3_EUNDEF: - return "Undefined error"; - case PM3_EINVARG: - return "Invalid argument(s)"; - case PM3_EDEVNOTSUPP: - return "Operation not supported by device"; - case PM3_ETIMEOUT: - return "Operation timed out"; - case PM3_EOPABORTED: - return "Operation aborted (by user)"; - case PM3_ENOTIMPL: - return "Not (yet) implemented"; - case PM3_ERFTRANS: - return "Error while RF transmission"; - case PM3_EIO: - return "Input / output error"; - case PM3_EOVFLOW: - return "Buffer overflow"; - case PM3_ESOFT: - return "Software error"; - case PM3_EFLASH: - return "Flash error"; - case PM3_EMALLOC: - return "Memory allocation error"; - case PM3_EFILE: - return "File error"; - case PM3_ENOTTY: - return "Generic TTY error"; - case PM3_EINIT: - return "Initialization error"; - case PM3_EWRONGANSWER: - return "Expected a different answer error"; - case PM3_EOUTOFBOUND: - return "Memory out-of-bounds error"; - case PM3_ECARDEXCHANGE: - return "Exchange with card error"; - case PM3_EAPDU_ENCODEFAIL: - return "Failed to create APDU"; - case PM3_ENODATA: - return "No data"; - case PM3_EFATAL: - return "Fatal error"; - default: - break; - } - return ""; -} - static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *recv_len, uint16_t *sw, uint32_t splitbysize, bool readalldata) { if (apdu == NULL) { PrintAndLogEx(DEBUG, "APDU=NULL"); @@ -649,7 +530,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *r uint32_t i = 1; int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw); if (res != PM3_SUCCESS) { - PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw)); + PrintAndLogEx(DEBUG, "%s", DesfireGetErrorString(res, sw)); DropFieldDesfire(); return res; } @@ -674,7 +555,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *r res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw); if (res != PM3_SUCCESS) { - PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw)); + PrintAndLogEx(DEBUG, "%s", DesfireGetErrorString(res, sw)); DropFieldDesfire(); return res; } @@ -1341,7 +1222,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1771,7 +1652,7 @@ static int handler_desfire_select_application(uint8_t *aid) { PrintAndLogEx(WARNING, _RED_(" Can't select AID 0x%X -> %s"), (aid[2] << 16) + (aid[1] << 8) + aid[0], - GetErrorString(res, &sw) + DesfireGetErrorString(res, &sw) ); DropFieldDesfire(); return res; @@ -1814,7 +1695,7 @@ static int handler_desfire_fileids(uint8_t *dest, uint32_t *file_ids_len) { *file_ids_len = 0; int res = send_desfire_cmd(&apdu, false, dest, &recv_len, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't get file ids -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't get file ids -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1833,7 +1714,7 @@ static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t uint16_t sw = 0; int res = send_desfire_cmd(&apdu, false, dest, destlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't get file settings -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't get file settings -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1873,7 +1754,7 @@ static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid free(data); } if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); } return res; @@ -1888,7 +1769,7 @@ static int handler_desfire_deleteapp(const uint8_t *aid) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); } return res; @@ -1906,7 +1787,7 @@ static int handler_desfire_credit(mfdes_value_t *value, uint8_t cs) { int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't credit value -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't credit value -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1925,7 +1806,7 @@ static int handler_desfire_limitedcredit(mfdes_value_t *value, uint8_t cs) { int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't credit limited value -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't credit limited value -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1944,7 +1825,7 @@ static int handler_desfire_debit(mfdes_value_t *value, uint8_t cs) { int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't debit value -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't debit value -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -1982,7 +1863,7 @@ static int handler_desfire_readdata(mfdes_data_t *data, MFDES_FILE_TYPE_T type, uint32_t resplen = 0; int res = send_desfire_cmd(&apdu, false, data->data, &resplen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2014,7 +1895,7 @@ static int handler_desfire_getvalue(mfdes_value_t *value, uint32_t *resplen, uin int res = send_desfire_cmd(&apdu, false, value->value, resplen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2090,7 +1971,7 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type, res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't write data -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't write data -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2099,7 +1980,7 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type, } if (type == MFDES_RECORD_FILE) { if (handler_desfire_commit_transaction() != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2116,7 +1997,7 @@ static int handler_desfire_deletefile(uint8_t file_no) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't delete file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't delete file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2132,13 +2013,13 @@ static int handler_desfire_clear_record_file(uint8_t file_no) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't clear record file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't clear record file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } else { res = handler_desfire_commit_transaction(); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2155,7 +2036,7 @@ static int handler_desfire_create_value_file(mfdes_value_file_t *value) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2172,7 +2053,7 @@ static int handler_desfire_create_std_file(mfdes_file_t *file) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2190,7 +2071,7 @@ static int handler_desfire_create_linearrecordfile(mfdes_linear_t *file) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create linear record file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create linear record file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2210,7 +2091,7 @@ static int handler_desfire_create_cyclicrecordfile(mfdes_linear_t *file) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create cyclic record file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create cyclic record file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -2226,7 +2107,7 @@ static int handler_desfire_create_backup_file(mfdes_file_t *file) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create backup file -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't create backup file -> %s"), DesfireGetErrorString(res, &sw)); DropFieldDesfire(); return res; } @@ -3573,7 +3454,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) { uint32_t recvlen = 0; int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), DesfireGetErrorString(res, &sw)); } else { PrintAndLogEx(INFO, "Card successfully reset"); } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 3d910a0da..b619e2638 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -25,7 +25,126 @@ #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes #include "iso7816/iso7816core.h" // APDU logging #include "util_posix.h" // msleep -#include "mifare/desfire_crypto.h" +#include "mifare/desfire_crypto.h"\ + +static const char *getstatus(uint16_t *sw) { + if (sw == NULL) return "--> sw argument error. This should never happen !"; + if (((*sw >> 8) & 0xFF) == 0x91) { + switch (*sw & 0xFF) { + case MFDES_E_OUT_OF_EEPROM: + return "Out of Eeprom, insufficient NV-Memory to complete command"; + case MFDES_E_ILLEGAL_COMMAND_CODE: + return "Command code not supported"; + + case MFDES_E_INTEGRITY_ERROR: + return "CRC or MAC does not match data / Padding bytes invalid"; + + case MFDES_E_NO_SUCH_KEY: + return "Invalid key number specified"; + + case MFDES_E_LENGTH: + return "Length of command string invalid"; + + case MFDES_E_PERMISSION_DENIED: + return "Current configuration/status does not allow the requested command"; + + case MFDES_E_PARAMETER_ERROR: + return "Value of the parameter(s) invalid"; + + case MFDES_E_APPLICATION_NOT_FOUND: + return "Requested AID not present on PICC"; + + case MFDES_E_APPL_INTEGRITY: + return "Application integrity error, application will be disabled"; + + case MFDES_E_AUTHENTIFICATION_ERROR: + return "Current authentication status does not allow the requested command"; + + case MFDES_E_BOUNDARY: + return "Attempted to read/write data from/to beyond the file's/record's limit"; + + case MFDES_E_PICC_INTEGRITY: + return "PICC integrity error, PICC will be disabled"; + + case MFDES_E_COMMAND_ABORTED: + return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD"; + + case MFDES_E_PICC_DISABLED: + return "PICC was disabled by an unrecoverable error"; + + case MFDES_E_COUNT: + return "Application count is limited to 28, not addition CreateApplication possible"; + + case MFDES_E_DUPLICATE: + return "Duplicate entry: File/Application/ISO Text does already exist"; + + case MFDES_E_EEPROM: + return "Eeprom error due to loss of power, internal backup/rollback mechanism activated"; + + case MFDES_E_FILE_NOT_FOUND: + return "Specified file number does not exist"; + + case MFDES_E_FILE_INTEGRITY: + return "File integrity error, file will be disabled"; + + default: + return "Unknown error"; + } + } + return "Unknown error"; +} + +const char *DesfireGetErrorString(int res, uint16_t *sw) { + switch (res) { + case PM3_EAPDU_FAIL: + return getstatus(sw); + case PM3_EUNDEF: + return "Undefined error"; + case PM3_EINVARG: + return "Invalid argument(s)"; + case PM3_EDEVNOTSUPP: + return "Operation not supported by device"; + case PM3_ETIMEOUT: + return "Operation timed out"; + case PM3_EOPABORTED: + return "Operation aborted (by user)"; + case PM3_ENOTIMPL: + return "Not (yet) implemented"; + case PM3_ERFTRANS: + return "Error while RF transmission"; + case PM3_EIO: + return "Input / output error"; + case PM3_EOVFLOW: + return "Buffer overflow"; + case PM3_ESOFT: + return "Software error"; + case PM3_EFLASH: + return "Flash error"; + case PM3_EMALLOC: + return "Memory allocation error"; + case PM3_EFILE: + return "File error"; + case PM3_ENOTTY: + return "Generic TTY error"; + case PM3_EINIT: + return "Initialization error"; + case PM3_EWRONGANSWER: + return "Expected a different answer error"; + case PM3_EOUTOFBOUND: + return "Memory out-of-bounds error"; + case PM3_ECARDEXCHANGE: + return "Exchange with card error"; + case PM3_EAPDU_ENCODEFAIL: + return "Failed to create APDU"; + case PM3_ENODATA: + return "No data"; + case PM3_EFATAL: + return "Fatal error"; + default: + break; + } + return ""; +} void DesfireClearContext(DesfireContext *ctx) { ctx->keyNum = 0; @@ -141,7 +260,7 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t int res = DESFIRESendApdu(activate_field, apdu, buf, sizeof(buf), &buflen, &sw); if (res != PM3_SUCCESS) { - //PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw)); + PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw)); return res; } @@ -171,7 +290,7 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t res = DESFIRESendApdu(false, apdu, buf, sizeof(buf), &buflen, &sw); if (res != PM3_SUCCESS) { - //PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw)); + PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw)); return res; } diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index fa212174c..2d102fb45 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -66,6 +66,8 @@ typedef struct DesfireContextS { void DesfireClearContext(DesfireContext *ctx); void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key); +const char *DesfireGetErrorString(int res, uint16_t *sw); + int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); From e5d24ff81f8df7fa9d8fdbb460b210922c78541b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 2 Jul 2021 17:37:15 +0300 Subject: [PATCH 05/31] authentication works --- client/src/cmdhfmfdes.c | 16 +- client/src/mifare/desfirecore.c | 301 +++++++++++++++++++++++++++++++- client/src/mifare/desfirecore.h | 15 +- 3 files changed, 319 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f51bbdd57..67674a5df 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5106,8 +5106,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { uint8_t key[24] = {0}; DesfireContext dctx; - DesfireSetKey(&dctx, 1, T_DES, key); - dctx.cmdChannel = DCCNativeISO; + DesfireSetKey(&dctx, 0, T_DES, key); // T_DES T_3DES T_3K3DES T_AES + DesfireSetCommandChannel(&dctx, DCCNativeISO); //size_t len = 0; @@ -5120,6 +5120,18 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { DropField(); return PM3_ESOFT; } + + res = DesfireAuthenticate(&dctx, DACd40); //DACd40 DACEV1 + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (DesfireIsAuthenticated(&dctx)) + PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); + else + return PM3_ESOFT; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index b619e2638..b43e6e7bb 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -19,13 +19,15 @@ #include #include #include +#include "aes.h" #include "ui.h" #include "protocols.h" +#include "commonutil.h" #include "cmdhf14a.h" -#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes -#include "iso7816/iso7816core.h" // APDU logging -#include "util_posix.h" // msleep -#include "mifare/desfire_crypto.h"\ +#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes +#include "iso7816/iso7816core.h" // APDU logging +#include "util_posix.h" // msleep +#include "mifare/desfire_crypto.h" static const char *getstatus(uint16_t *sw) { if (sw == NULL) return "--> sw argument error. This should never happen !"; @@ -155,6 +157,16 @@ void DesfireClearContext(DesfireContext *ctx) { ctx->cmdChannel = DCCNative; ctx->commMode = DCMNone; + ctx->kdfAlgo = 0; + ctx->kdfInputLen = 0; + memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput)); + + DesfireClearSession(ctx); +} + +void DesfireClearSession(DesfireContext *ctx) { + ctx->authChannel = DACNone; // here none - not authenticared + memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC)); memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc)); memset(ctx->lastIV, 0, sizeof(ctx->lastIV)); @@ -171,6 +183,10 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO memcpy(ctx->key, key, desfire_get_key_length(keyType)); } +void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel) { + ctx->cmdChannel = cmdChannel; +} + static int DESFIRESendApdu(bool activate_field, sAPDU apdu, 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; @@ -272,12 +288,12 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t pos += buflen; if (!enable_chaining) { - if (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { + if (sw == DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) || + sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { if (resplen) *resplen = pos; - return PM3_SUCCESS; } - return res; + return PM3_SUCCESS; } while (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { @@ -312,6 +328,7 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t if (resplen) *resplen = (splitbysize) ? i : pos; + return PM3_SUCCESS; } @@ -377,3 +394,273 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL); } +bool DesfireIsAuthenticated(DesfireContext *dctx) { + return dctx->authChannel != DACNone; +} + +int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { + // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) + // 4 different crypto arg1 DES, 3DES, 3K3DES, AES + // 3 different communication modes, PLAIN,MAC,CRYPTO + + DesfireClearSession(dctx); + + if (authChannel == DACNone) + return PM3_SUCCESS; + + mbedtls_aes_context ctx; + + uint8_t keybytes[24] = {0}; + // Crypt constants + uint8_t IV[16] = {0}; + uint8_t RndA[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + uint8_t RndB[16] = {0}; + uint8_t encRndB[16] = {0}; + uint8_t rotRndB[16] = {0}; //RndB' + uint8_t both[32 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') + + // Part 1 + memcpy(keybytes, dctx->key, desfire_get_key_length(dctx->keyType)); + + struct desfire_key dkey = {0}; + desfirekey_t key = &dkey; + + if (dctx->keyType == T_AES) { + mbedtls_aes_init(&ctx); + Desfire_aes_key_new(keybytes, key); + } else if (dctx->keyType == T_3DES) { + Desfire_3des_key_new_with_version(keybytes, key); + } else if (dctx->keyType == T_DES) { + Desfire_des_key_new(keybytes, key); + } else if (dctx->keyType == T_3K3DES) { + Desfire_3k3des_key_new_with_version(keybytes, key); + } + + if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) { + mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen); + PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key))); + } else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) { + // We will overrite any provided KDF input since a gallagher specific KDF was requested. + dctx->kdfInputLen = 11; + + /*if (mfdes_kdf_input_gallagher(tag->info.uid, tag->info.uidlen, dctx->keyNum, tag->selected_application, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input"); + }*/ + + mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen); + PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen)); + PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key))); + + } + + uint8_t subcommand = MFDES_AUTHENTICATE; + dctx->authChannel = authChannel; + if (dctx->authChannel == DACEV1) { + if (dctx->keyType == T_AES) + subcommand = MFDES_AUTHENTICATE_AES; + else + subcommand = MFDES_AUTHENTICATE_ISO; + } + + uint32_t recv_len = 0; + uint8_t respcode = 0; + uint8_t recv_data[256] = {0}; + + // Let's send our auth command + int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false); + if (res != PM3_SUCCESS) { + return 1; + } + + if (!recv_len) { + return 2; + } + + if (respcode != MFDES_ADDITIONAL_FRAME) { + return 3; + } + + uint32_t expectedlen = 8; + if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) { + expectedlen = 16; + } + + if (recv_len != expectedlen) { + return 4; + } + + // Part 2 + uint32_t rndlen = recv_len; + memcpy(encRndB, recv_data, rndlen); + + + // Part 3 + if (dctx->keyType == T_AES) { + if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { + return 5; + } + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB); + } else if (dctx->keyType == T_DES) + des_decrypt(RndB, encRndB, key->data); + else if (dctx->keyType == T_3DES) + tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2); + else if (dctx->keyType == T_3K3DES) { + tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 3); + } + + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8)); + PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, 8)); + } + + // - Rotate RndB by 8 bits + memcpy(rotRndB, RndB, rndlen); + rol(rotRndB, rndlen); + + uint8_t encRndA[16] = {0x00}; + + // - Encrypt our response + if (dctx->authChannel == DACd40) { + des_decrypt(encRndA, RndA, key->data); + memcpy(both, encRndA, rndlen); + + for (uint32_t x = 0; x < rndlen; x++) { + rotRndB[x] = rotRndB[x] ^ encRndA[x]; + } + + des_decrypt(encRndB, rotRndB, key->data); + memcpy(both + rndlen, encRndB, rndlen); + } else if (dctx->authChannel == DACEV1 && dctx->keyType != T_AES) { + if (dctx->keyType == T_3DES) { + uint8_t tmp[16] = {0x00}; + memcpy(tmp, RndA, rndlen); + memcpy(tmp + rndlen, rotRndB, rndlen); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); + PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16)); + } + tdes_nxp_send(tmp, both, 16, key->data, IV, 2); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); + } + } else if (dctx->keyType == T_3K3DES) { + uint8_t tmp[32] = {0x00}; + memcpy(tmp, RndA, rndlen); + memcpy(tmp + rndlen, rotRndB, rndlen); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); + PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32)); + } + tdes_nxp_send(tmp, both, 32, key->data, IV, 3); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); + } + } + } else if (dctx->authChannel == DACEV1 && dctx->keyType == T_AES) { + uint8_t tmp[32] = {0x00}; + memcpy(tmp, RndA, rndlen); + memcpy(tmp + rndlen, rotRndB, rndlen); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); + PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32)); + } + if (dctx->keyType == T_AES) { + if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) { + return 6; + } + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, tmp, both); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); + } + } + } + + uint32_t bothlen = 16; + if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) { + bothlen = 32; + } + + res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false); + if (res != PM3_SUCCESS) { + return 7; + } + + if (!recv_len) { + return 8; + } + + if (respcode != MFDES_S_OPERATION_OK) { + return 9; + } + + // Part 4 + memcpy(encRndA, recv_data, rndlen); + + // tag->session_key = &default_key; + /*struct desfire_key *p = realloc(tag->session_key, sizeof(struct desfire_key)); + if (!p) { + PrintAndLogEx(FAILED, "Cannot allocate memory for session keys"); + free(tag->session_key); + return PM3_EMALLOC; + } + tag->session_key = p; + + memset(tag->session_key, 0x00, sizeof(struct desfire_key)); + */ + struct desfire_key sesskey = {0}; + + Desfire_session_key_new(RndA, RndB, key, &sesskey); + memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); + +PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen)); + if (dctx->keyType == T_DES) + des_decrypt(encRndA, encRndA, key->data); + else if (dctx->keyType == T_3DES) + tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2); + else if (dctx->keyType == T_3K3DES) + tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 3); + else if (dctx->keyType == T_AES) { + if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { + return 10; + } + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndA, encRndA); + } + + rol(RndA, rndlen); +PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen)); +PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen)); + for (uint32_t x = 0; x < rndlen; x++) { + if (RndA[x] != encRndA[x]) { + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, rndlen)); + PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, rndlen)); + } + return 11; + } + } + + // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des + // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes + if (dctx->keyType == T_3DES) { + if (memcmp(key->data, &key->data[8], 8) == 0) + memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8); + } + +// rpayload->sessionkeylen = payload->keylen; + // memcpy(rpayload->sessionkey, tag->session_key->data, rpayload->sessionkeylen); + // memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE); + // tag->authenticated_key_no = payload->keyno; + + if (dctx->authChannel == DACEV1) { + cmac_generate_subkeys(&sesskey, MCD_RECEIVE); + //key->cmac_sk1 and key->cmac_sk2 + //memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); + } + + memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)); +PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType))); + + return PM3_SUCCESS; +} + + diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 2d102fb45..529315405 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -44,11 +44,13 @@ typedef enum { typedef struct DesfireContextS { uint8_t keyNum; - enum DESFIRE_CRYPTOALGO keyType; // des,2tdea,3tdea,aes + enum DESFIRE_CRYPTOALGO keyType; // des/2tdea/3tdea/aes uint8_t key[DESF_MAX_KEY_LEN]; // KDF finction - // KDF input + uint8_t kdfAlgo; + uint8_t kdfInputLen; + uint8_t kdfInput[31]; DesfireAuthChannel authChannel; // none/d40/ev1/ev2 DesfireCommandChannel cmdChannel; // native/nativeiso/iso @@ -64,14 +66,19 @@ typedef struct DesfireContextS { } DesfireContext; void DesfireClearContext(DesfireContext *ctx); +void DesfireClearSession(DesfireContext *ctx); void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key); +void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel); const char *DesfireGetErrorString(int res, uint16_t *sw); -int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); -int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining); +int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); +int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); +int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel); +bool DesfireIsAuthenticated(DesfireContext *dctx); + #endif // __DESFIRECORE_H From 636a1dd457a59311a541751fb7649fab847fce1a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:06:13 +0300 Subject: [PATCH 06/31] DesfireGetAIDList works --- client/src/cmdhfmfdes.c | 14 ++++++++++---- client/src/mifare/desfirecore.c | 29 +++++++++++++++++++++-------- client/src/mifare/desfirecore.h | 6 ++++++ 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 67674a5df..ce3d45f4f 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5110,10 +5110,6 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { DesfireSetCommandChannel(&dctx, DCCNativeISO); - //size_t len = 0; - //uint16_t sw = 0; - //uint8_t buf[APDU_RES_LEN] = {0}; - int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); @@ -5133,8 +5129,18 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { else return PM3_ESOFT; + uint8_t buf[APDU_RES_LEN] = {0}; + size_t buflen = 0; + res = DesfireGetAIDList(&dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + for (int i = 0; i < buflen; i += 3) + PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); DropField(); return PM3_SUCCESS; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index b43e6e7bb..24e6bfa2a 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -148,6 +148,16 @@ const char *DesfireGetErrorString(int res, uint16_t *sw) { return ""; } +uint32_t DesfireAIDByteToUint(uint8_t *data) { + return data[0] + (data[1] << 8) + (data[2] << 16); +} + +void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) { + data[0] = aid & 0xff; + data[1] = (aid >> 8) & 0xff; + data[2] = (aid >> 16) & 0xff; +} + void DesfireClearContext(DesfireContext *ctx) { ctx->keyNum = 0; ctx->keyType = T_DES; @@ -383,13 +393,8 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2) { uint8_t data[6] = {0}; - data[0] = aid1 & 0xff; - data[1] = (aid1 >> 8) & 0xff; - data[2] = (aid1 >> 16) & 0xff; - - data[3] = aid2 & 0xff; - data[4] = (aid2 >> 8) & 0xff; - data[5] = (aid2 >> 16) & 0xff; + DesfireAIDUintToByte(aid1, data); + DesfireAIDUintToByte(aid2, &data[3]); return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL); } @@ -663,4 +668,12 @@ PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfir return PM3_SUCCESS; } - +int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { + uint8_t respcode = 0xff; + int res = DesfireExchange(dctx, MFDES_GET_APPLICATION_IDS, NULL, 0, &respcode, resp, resplen); + if (res != PM3_SUCCESS) + return res; + if (respcode != MFDES_S_OPERATION_OK) + return PM3_EAPDU_FAIL; + return PM3_SUCCESS; +} diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 529315405..cae333015 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -71,14 +71,20 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel); const char *DesfireGetErrorString(int res, uint16_t *sw); +uint32_t DesfireAIDByteToUint(uint8_t *data); +void DesfireAIDUintToByte(uint32_t aid, uint8_t *data); int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining); int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); + int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel); bool DesfireIsAuthenticated(DesfireContext *dctx); +int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); +int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); + #endif // __DESFIRECORE_H From d354ac90fd9cb6f3219230ea7ced870b647824f7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:07:46 +0300 Subject: [PATCH 07/31] fix warning --- client/src/mifare/desfirecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 24e6bfa2a..db4d728fc 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -467,7 +467,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { subcommand = MFDES_AUTHENTICATE_ISO; } - uint32_t recv_len = 0; + size_t recv_len = 0; uint8_t respcode = 0; uint8_t recv_data[256] = {0}; From 0aad993711c8788cb0d6c7249a95567ac3b8acb0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:17:21 +0300 Subject: [PATCH 08/31] remove comments and text fixes --- client/src/cmdhfmfdes.c | 23 +++++++++++++++-------- client/src/mifare/desfirecore.c | 16 ---------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index ce3d45f4f..89c08ef37 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5017,6 +5017,9 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId /* int aidlength = 0; @@ -5100,13 +5103,12 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0); CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen); */ -// SetAPDULogging(APDULogging); - SetAPDULogging(true); + SetAPDULogging(APDULogging); CLIParserFree(ctx); uint8_t key[24] = {0}; DesfireContext dctx; - DesfireSetKey(&dctx, 0, T_DES, key); // T_DES T_3DES T_3K3DES T_AES + DesfireSetKey(&dctx, keyNum, T_DES, key); // T_DES T_3DES T_3K3DES T_AES DesfireSetCommandChannel(&dctx, DCCNativeISO); @@ -5124,10 +5126,12 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { return PM3_ESOFT; } - if (DesfireIsAuthenticated(&dctx)) - PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); - else + if (DesfireIsAuthenticated(&dctx)) { + if (verbose) + PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); + } else { return PM3_ESOFT; + } uint8_t buf[APDU_RES_LEN] = {0}; size_t buflen = 0; @@ -5139,8 +5143,11 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { return PM3_ESOFT; } - for (int i = 0; i < buflen; i += 3) - PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); + if (buflen >= 3) { + PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----"); + for (int i = 0; i < buflen; i += 3) + PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); + } DropField(); return PM3_SUCCESS; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index db4d728fc..de71db69f 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -601,17 +601,6 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { // Part 4 memcpy(encRndA, recv_data, rndlen); - // tag->session_key = &default_key; - /*struct desfire_key *p = realloc(tag->session_key, sizeof(struct desfire_key)); - if (!p) { - PrintAndLogEx(FAILED, "Cannot allocate memory for session keys"); - free(tag->session_key); - return PM3_EMALLOC; - } - tag->session_key = p; - - memset(tag->session_key, 0x00, sizeof(struct desfire_key)); - */ struct desfire_key sesskey = {0}; Desfire_session_key_new(RndA, RndB, key, &sesskey); @@ -651,11 +640,6 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen)); memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8); } -// rpayload->sessionkeylen = payload->keylen; - // memcpy(rpayload->sessionkey, tag->session_key->data, rpayload->sessionkeylen); - // memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE); - // tag->authenticated_key_no = payload->keyno; - if (dctx->authChannel == DACEV1) { cmac_generate_subkeys(&sesskey, MCD_RECEIVE); //key->cmac_sk1 and key->cmac_sk2 From a73c6ef90a041379e620059a4a685c6eedf71bee Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 2 Jul 2021 22:13:45 +0300 Subject: [PATCH 09/31] add array_length --- client/src/util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/util.h b/client/src/util.h index 2730ed44f..9357eb1d0 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -16,6 +16,8 @@ #include #endif +#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) ) + // used for save/load files #ifndef FILE_PATH_SIZE # define FILE_PATH_SIZE 1000 From 850e36ab3168c7ca2d665d57631475f18e3c2486 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:07:21 +0300 Subject: [PATCH 10/31] cli parser text options --- client/deps/cliparser/cliparser.c | 52 +++++++++++++++++++++++++++++++ client/deps/cliparser/cliparser.h | 12 +++++++ 2 files changed, 64 insertions(+) diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index ec9f50e20..265c97103 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -298,6 +298,58 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, size_t option_array_len, int *value) { + char data[200] = {0}; + int datalen = 0; + int res = CLIParamStrToBuf(argstr, (uint8_t *)data, sizeof(data), &datalen); + if (res) + return res; + + // no data to check - we do not touch *value, just return + if (datalen == 0) + return 0; + + str_lower(data); + + int val = -1; + int cntr = 0; + for (int i = 0; i < option_array_len; i++) { + // exact match + if (strcmp(option_array[i].text, data) == 0) { + *value = option_array[i].code; + return 0; + } + // partial match + if (strncmp(option_array[i].text, data, datalen) == 0) { + val = option_array[i].code; + cntr++; + } + } + + // check partial match + if (cntr == 0) { + PrintAndLogEx(ERR, "Parameter error: No similar option to `%s`. Valid options: %s\n", argstr->sval[0], argstr->hdr.datatype); + return 20; + } + if (cntr > 1) { + PrintAndLogEx(ERR, "Parameter error: Several options fit to `%s`. Valid options: %s\n", argstr->sval[0], argstr->hdr.datatype); + return 21; + } + + *value = val; + return 0; +} + +const char *CLIGetOptionListStr(const CLIParserOption *option_array, size_t option_array_len, int value) { + static const char *errmsg = "n/a"; + + for (int i = 0; i < option_array_len; i++) + if (option_array[i].code == value) + return option_array[i].text; + return errmsg; +} + + // hexstr -> u64, w optional len input and default value fallback. // 0 = failed // 1 = OK diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 39a5792f8..f4f9b7dcf 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -51,6 +51,8 @@ #define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), (*datalen), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} +#define CLIGetOptionListWithReturn(ctx, paramnum, option_array, option_array_len, value) if (CLIGetOptionList(arg_get_str((ctx), (paramnum)), (option_array), (option_array_len), (value))) {CLIParserFree((ctx)); return PM3_ESOFT;} + typedef struct { void **argtable; size_t argtableLen; @@ -59,6 +61,12 @@ typedef struct { const char *programHelp; char buf[1024 + 60]; } CLIParserContext; + +typedef struct { + int code; + const char *text; +} CLIParserOption; + int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp); void CLIParserPrintHelp(CLIParserContext *ctx); int CLIParserParseString(CLIParserContext *ctx, const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec); @@ -69,6 +77,10 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); int CLIParamBinToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); +// names in the CLIParserOption array must be in the lowercase format +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, size_t option_array_len, int *value); +const char *CLIGetOptionListStr(const CLIParserOption *option_array, size_t option_array_len, int value); + uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional); int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out); From 7af924eadd3bfff1a6eb1084691bdcecb903c5a3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:07:55 +0300 Subject: [PATCH 11/31] add get key size function --- client/src/mifare/desfire_crypto.c | 18 ++++++++++++++++++ client/src/mifare/desfire_crypto.h | 1 + 2 files changed, 19 insertions(+) diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 1767c9c47..6ec606227 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -407,6 +407,24 @@ size_t key_block_size(const desfirekey_t key) { return block_size; } +size_t key_size(const enum DESFIRE_CRYPTOALGO algo) { + switch (algo) { + case T_DES: + return 8; + break; + case T_3DES: + return 16; + break; + case T_3K3DES: + return 24; + break; + case T_AES: + return 16; + break; + } + return 0; +} + /* * Size of MACing produced with the key. */ diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 9c67b1182..71d17aea7 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -126,6 +126,7 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); size_t key_block_size(const desfirekey_t key); +size_t key_size(const enum DESFIRE_CRYPTOALGO algo); size_t padded_data_length(const size_t nbytes, const size_t block_size); size_t maced_data_length(const desfirekey_t key, const size_t nbytes); size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings); From acca624752d93b2bd23d2cd23ae33462d5c6fdf0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:08:45 +0300 Subject: [PATCH 12/31] added cli text options to command --- client/src/cmdhfmfdes.c | 140 ++++++++++++++------------------ client/src/mifare/desfirecore.h | 2 + 2 files changed, 61 insertions(+), 81 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 89c08ef37..49958e060 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5009,10 +5009,12 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { arg_lit0("a", "apdu", "show APDU requests and responses"), arg_lit0("v", "verbose", "show technical data"), arg_int0("n", "keyno", "", "Key number"), - arg_int0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + 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_int0("f", "kdf", "", "Key Derivation Function (KDF): None(default), AN10922, Gallagher"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None(default), AN10922, Gallagher"), arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Commpunicaton mode: plain(default)/mac/encrypt"), + arg_str0("c", "commc", "", "Commpunicaton channel: native/niso(default)/iso"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5021,95 +5023,71 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { bool verbose = arg_get_lit(ctx, 2); uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId -/* - int aidlength = 0; - uint8_t aid[3] = {0}; - CLIGetHexWithReturn(ctx, 1, aid, &aidlength); - swap24(aid); - uint8_t vkey[16] = {0}; - int vkeylen = 0; - CLIGetHexWithReturn(ctx, 2, vkey, &vkeylen); - if (vkeylen > 0) { - if (vkeylen == 8) { - memcpy(&deskeyList[deskeyListLen], vkey, 8); - deskeyListLen++; - } else if (vkeylen == 16) { - memcpy(&aeskeyList[aeskeyListLen], vkey, 16); - aeskeyListLen++; - } else if (vkeylen == 24) { - memcpy(&k3kkeyList[k3kkeyListLen], vkey, 16); - k3kkeyListLen++; - } else { - PrintAndLogEx(ERR, "Specified key must have 8, 16 or 24 bytes length."); - CLIParserFree(ctx); - return PM3_EINVARG; - } + const CLIParserOption algo_opts[] = { + {T_DES, "des"}, + {T_3DES, "2tdea"}, + {T_3K3DES, "3tdea"}, + {T_AES, "aes"}, + }; + + int ares = T_DES; + CLIGetOptionListWithReturn(ctx, 4, algo_opts, ARRAY_LENGTH(algo_opts), &ares); + PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares)); + + int keylen = 0; + uint8_t key[200] = {0}; + CLIGetHexWithReturn(ctx, 5, key, &keylen); + if (keylen == 0) { + keylen = key_size(ares); + //memcpy(key, defaultkey, key_size(ares)); } - - uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; - int dict_filenamelen = 0; - if (CLIParamStrToBuf(arg_get_str(ctx, 3), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { - PrintAndLogEx(FAILED, "File name too long or invalid."); + if (keylen != key_size(ares)) { + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares), key_size(ares), keylen); CLIParserFree(ctx); return PM3_EINVARG; } - - bool pattern1b = arg_get_lit(ctx, 4); - bool pattern2b = arg_get_lit(ctx, 5); - - if (pattern1b && pattern2b) { - PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - if (dict_filenamelen && (pattern1b || pattern2b)) { - PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint32_t startPattern = 0x0000; - uint8_t vpattern[2]; - int vpatternlen = 0; - CLIGetHexWithReturn(ctx, 6, vpattern, &vpatternlen); - if (vpatternlen > 0) { - if (vpatternlen <= 2) { - startPattern = (vpattern[0] << 8) + vpattern[1]; - } else { - PrintAndLogEx(ERR, "Pattern must be 2-byte length."); - CLIParserFree(ctx); - return PM3_EINVARG; - } - if (!pattern2b) - PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); - } - - uint8_t jsonname[250] = {0}; - int jsonnamelen = 0; - if (CLIParamStrToBuf(arg_get_str(ctx, 7), jsonname, sizeof(jsonname), &jsonnamelen)) { - PrintAndLogEx(ERR, "Invalid json name."); - CLIParserFree(ctx); - return PM3_EINVARG; - } - jsonname[jsonnamelen] = 0; - - bool verbose = arg_get_lit(ctx, 8); - - // Get KDF input - uint8_t kdfInput[31] = {0}; + + const CLIParserOption kdf_opts[] = { + {MFDES_KDF_ALGO_NONE, "none"}, + {MFDES_KDF_ALGO_AN10922, "an10922"}, + {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, + }; + + int kres = MFDES_KDF_ALGO_NONE; + CLIGetOptionListWithReturn(ctx, 6, kdf_opts, ARRAY_LENGTH(kdf_opts), &kres); + PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kres)); + int kdfInputLen = 0; - uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0); - CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen); -*/ + uint8_t kdfInput[50] = {0}; + CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); + + const CLIParserOption cmode_opts[] = { + {DCMPlain, "plain"}, + {DCMMACed, "mac"}, + {DCMEncrypted, "encrypt"}, + }; + + int commmode = DCMPlain; + CLIGetOptionListWithReturn(ctx, 8, cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); + + const CLIParserOption commc_opts[] = { + {DCCNative, "native"}, + {DCCNativeISO, "niso"}, + {DCCISO, "iso"}, + }; + + int commchann = DCCNativeISO; + CLIGetOptionListWithReturn(ctx, 8, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); + SetAPDULogging(APDULogging); CLIParserFree(ctx); - uint8_t key[24] = {0}; DesfireContext dctx; - DesfireSetKey(&dctx, keyNum, T_DES, key); // T_DES T_3DES T_3K3DES T_AES - DesfireSetCommandChannel(&dctx, DCCNativeISO); + DesfireSetKey(&dctx, keyNum, ares, key); // T_DES T_3DES T_3K3DES T_AES + DesfireSetCommandChannel(&dctx, commchann); int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index cae333015..bffcda7bd 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -21,6 +21,8 @@ #define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x ) +typedef enum DESFIRE_CRYPTOALGO DesfireCryptoAlgorythm; + typedef enum { DACNone, DACd40, From f9e006f2e3a091d4cde927b72991a236685bceef Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 12:21:29 +0300 Subject: [PATCH 13/31] added authchann otion --- client/src/cmdhfmfdes.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 49958e060..c8721433b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5011,10 +5011,11 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { 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(default), AN10922, Gallagher"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), - arg_str0("m", "cmode", "", "Commpunicaton mode: plain(default)/mac/encrypt"), - arg_str0("c", "commc", "", "Commpunicaton channel: native/niso(default)/iso"), + arg_str0("m", "cmode", "", "Commpunicaton mode: plain/mac/encrypt"), + arg_str0("c", "commc", "", "Commpunicaton channel: native/niso/iso"), + arg_str0("u", "authc", "", "Authentication channel: d40/ev1/ev2"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5082,6 +5083,16 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { CLIGetOptionListWithReturn(ctx, 8, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); + const CLIParserOption authc_opts[] = { + {DACd40, "d40"}, + {DACEV1, "ev1"}, + {DACEV2, "ev2"}, + }; + + int authchann = DACEV1; + CLIGetOptionListWithReturn(ctx, 9, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); + PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); + SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -5097,7 +5108,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { return PM3_ESOFT; } - res = DesfireAuthenticate(&dctx, DACd40); //DACd40 DACEV1 + res = DesfireAuthenticate(&dctx, authchann); //DACd40 DACEV1 if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); DropField(); From 0d00f567779f1f531e7f838cd3c64026511e48f7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 13:11:17 +0300 Subject: [PATCH 14/31] CmdHF14ADesGetAppNames works --- client/src/cmdhfmfdes.c | 150 +++++++++++++++++++++++++++++++- client/src/mifare/desfirecore.c | 31 ++++--- client/src/mifare/desfirecore.h | 2 +- 3 files changed, 167 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c8721433b..384e67049 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5080,7 +5080,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { }; int commchann = DCCNativeISO; - CLIGetOptionListWithReturn(ctx, 8, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); + CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); const CLIParserOption authc_opts[] = { @@ -5090,7 +5090,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { }; int authchann = DACEV1; - CLIGetOptionListWithReturn(ctx, 9, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); + CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); SetAPDULogging(APDULogging); @@ -5142,8 +5142,152 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { return PM3_SUCCESS; } -// {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, static int CmdHF14ADesGetAppNames(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes getappnames", + "Get Application IDs, ISO IDs and DF names from card. Master key needs to be provided.", + "hf mfdes getappnames -n 0 -t des -k 0000000000000000 -f none -> execute with default factory setup"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Commpunicaton mode: plain/mac/encrypt"), + arg_str0("c", "commc", "", "Commpunicaton channel: native/niso/iso"), + arg_str0("u", "authc", "", "Authentication channel: d40/ev1/ev2"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId + + + const CLIParserOption algo_opts[] = { + {T_DES, "des"}, + {T_3DES, "2tdea"}, + {T_3K3DES, "3tdea"}, + {T_AES, "aes"}, + }; + + int ares = T_DES; + CLIGetOptionListWithReturn(ctx, 4, algo_opts, ARRAY_LENGTH(algo_opts), &ares); + PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares)); + + int keylen = 0; + uint8_t key[200] = {0}; + CLIGetHexWithReturn(ctx, 5, key, &keylen); + if (keylen == 0) { + keylen = key_size(ares); + //memcpy(key, defaultkey, key_size(ares)); + } + if (keylen != key_size(ares)) { + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares), key_size(ares), keylen); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + const CLIParserOption kdf_opts[] = { + {MFDES_KDF_ALGO_NONE, "none"}, + {MFDES_KDF_ALGO_AN10922, "an10922"}, + {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, + }; + + int kres = MFDES_KDF_ALGO_NONE; + CLIGetOptionListWithReturn(ctx, 6, kdf_opts, ARRAY_LENGTH(kdf_opts), &kres); + PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kres)); + + int kdfInputLen = 0; + uint8_t kdfInput[50] = {0}; + CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); + + const CLIParserOption cmode_opts[] = { + {DCMPlain, "plain"}, + {DCMMACed, "mac"}, + {DCMEncrypted, "encrypt"}, + }; + + int commmode = DCMPlain; + CLIGetOptionListWithReturn(ctx, 8, cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); + + const CLIParserOption commc_opts[] = { + {DCCNative, "native"}, + {DCCNativeISO, "niso"}, + {DCCISO, "iso"}, + }; + + int commchann = DCCNativeISO; + CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); + + const CLIParserOption authc_opts[] = { + {DACd40, "d40"}, + {DACEV1, "ev1"}, + {DACEV2, "ev2"}, + }; + + int authchann = DACEV1; + CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); + PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); + + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + + DesfireContext dctx; + DesfireSetKey(&dctx, keyNum, ares, key); + DesfireSetCommandChannel(&dctx, commchann); + + + int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + DropField(); + return PM3_ESOFT; + } + + res = DesfireAuthenticate(&dctx, authchann); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (DesfireIsAuthenticated(&dctx)) { + if (verbose) + PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); + } else { + return PM3_ESOFT; + } + + uint8_t buf[APDU_RES_LEN] = {0}; + size_t buflen = 0; + + // result bytes: 3, 2, 1-16. total record size = 24 + res = DesfireGetDFList(&dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire DesfireGetDFList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + if (buflen > 0) { + PrintAndLogEx(INFO, "----------------------- " _CYAN_("File list") " -----------------------"); + for (int i = 0; i < buflen; i++) + PrintAndLogEx(INFO, "AID: %06x ISO file id: %02x%02x ISO DF name[%d]: %s", + DesfireAIDByteToUint(&buf[i * 24]), + buf[i * 24 + 3], buf[i * 24 + 4], + strlen((char *)&buf[i * 24 + 5]), + &buf[i * 24 + 5]); + } + + DropField(); return PM3_SUCCESS; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index de71db69f..18aa09265 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -256,20 +256,17 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin return PM3_SUCCESS; } -static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { +static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { return PM3_SUCCESS; } -static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { +static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { if (resplen) *resplen = 0; if (respcode) *respcode = 0xff; - // TODO !!! - size_t splitbysize = 0; - uint16_t sw = 0; uint8_t buf[255 * 5] = {0x00}; uint32_t buflen = 0; @@ -342,15 +339,15 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } -int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining) { +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { int res = PM3_SUCCESS; switch(ctx->cmdChannel) { case DCCNative: - res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); + res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); break; case DCCNativeISO: - res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining); + res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); break; case DCCISO: return PM3_EAPDU_FAIL; @@ -361,7 +358,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin } int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen) { - return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true); + return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true, 0); } int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { @@ -376,7 +373,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { size_t resplen = 0; uint8_t respcode = 0; - int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true); + int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true, 0); if (res == PM3_SUCCESS) { if (resplen != 0) return PM3_ECARDEXCHANGE; @@ -472,7 +469,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { uint8_t recv_data[256] = {0}; // Let's send our auth command - int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false); + int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 1; } @@ -585,7 +582,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { bothlen = 32; } - res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false); + res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 7; } @@ -661,3 +658,13 @@ int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { return PM3_EAPDU_FAIL; return PM3_SUCCESS; } + +int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { + uint8_t respcode = 0xff; + int res = DesfireExchangeEx(false, dctx, MFDES_GET_DF_NAMES, NULL, 0, &respcode, resp, resplen, true, 24); + if (res != PM3_SUCCESS) + return res; + if (respcode != MFDES_S_OPERATION_OK) + return PM3_EAPDU_FAIL; + return PM3_SUCCESS; +} diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index bffcda7bd..a0b31babb 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -77,7 +77,7 @@ uint32_t DesfireAIDByteToUint(uint8_t *data); void DesfireAIDUintToByte(uint32_t aid, uint8_t *data); int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen); -int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining); +int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize); int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); From 1b2442ec36a701272e417f51ffdaff966074351a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 3 Jul 2021 17:31:12 +0300 Subject: [PATCH 15/31] regactoring desfire commands. textual fixes --- client/src/cmdhfmfdes.c | 312 ++++++++++++++--------------- client/src/cmdhfmfdes.h | 3 +- client/src/mifare/desfire_crypto.c | 1 + client/src/mifare/desfire_crypto.h | 23 ++- client/src/mifare/desfirecore.c | 48 +++-- client/src/mifare/desfirecore.h | 17 +- 6 files changed, 223 insertions(+), 181 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 384e67049..c29f74cc6 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2014 Iceman +// Copyright (C) 2021 Merlok // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -4997,6 +4998,133 @@ static int CmdHF14aDesMAD(const char *Cmd) { return PM3_SUCCESS; } */ +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, + int *securechannel) { + + 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; + int commset = defaultCommSet; + int secchann = defaultSecureChannel; + + if (keynoid) { + keynum = arg_get_int_def(ctx, keynoid, keynum); + } + + const CLIParserOption algo_opts[] = { + {T_DES, "des"}, + {T_3DES, "2tdea"}, + {T_3K3DES, "3tdea"}, + {T_AES, "aes"}, + }; + + if (algoid) { + if (CLIGetOptionList(arg_get_str(ctx, algoid), algo_opts, ARRAY_LENGTH(algo_opts), &algores)) + return PM3_ESOFT; + PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores)); + } + + 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 != key_size(algores)) { + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores), key_size(algores), keylen); + return PM3_EINVARG; + } + if (keylen) + memcpy(key, keydata, keylen); + } + + if (kdfid) { + const CLIParserOption kdf_opts[] = { + {MFDES_KDF_ALGO_NONE, "none"}, + {MFDES_KDF_ALGO_AN10922, "an10922"}, + {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, + }; + + if (CLIGetOptionList(arg_get_str(ctx, kdfid), kdf_opts, ARRAY_LENGTH(kdf_opts), &kdfAlgo)) + return PM3_ESOFT; + PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kdfAlgo)); + + } + + 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) { + const CLIParserOption cmode_opts[] = { + {DCMPlain, "plain"}, + {DCMMACed, "mac"}, + {DCMEncrypted, "encrypt"}, + }; + + if (CLIGetOptionList(arg_get_str(ctx, cmodeid), cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode)) + return PM3_ESOFT; + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); + } + + if (ccsetid) { + const CLIParserOption commc_opts[] = { + {DCCNative, "native"}, + {DCCNativeISO, "niso"}, + {DCCISO, "iso"}, + }; + + if (CLIGetOptionList(arg_get_str(ctx, ccsetid), commc_opts, ARRAY_LENGTH(commc_opts), &commset)) + return PM3_ESOFT; + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commset)); + } + + if (schannid) { + const CLIParserOption authc_opts[] = { + {DACd40, "d40"}, + {DACEV1, "ev1"}, + {DACEV2, "ev2"}, + }; + + if (CLIGetOptionList(arg_get_str(ctx, schannid), authc_opts, ARRAY_LENGTH(authc_opts), &secchann)) + return PM3_ESOFT; + PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), secchann)); + } + + 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 CmdHF14ADesGetAIDs(const char *Cmd) { CLIParserContext *ctx; @@ -5013,102 +5141,38 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), - arg_str0("m", "cmode", "", "Commpunicaton mode: plain/mac/encrypt"), - arg_str0("c", "commc", "", "Commpunicaton channel: native/niso/iso"), - arg_str0("u", "authc", "", "Authentication channel: d40/ev1/ev2"), + arg_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, false); bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId - - - const CLIParserOption algo_opts[] = { - {T_DES, "des"}, - {T_3DES, "2tdea"}, - {T_3K3DES, "3tdea"}, - {T_AES, "aes"}, - }; - int ares = T_DES; - CLIGetOptionListWithReturn(ctx, 4, algo_opts, ARRAY_LENGTH(algo_opts), &ares); - PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares)); - - int keylen = 0; - uint8_t key[200] = {0}; - CLIGetHexWithReturn(ctx, 5, key, &keylen); - if (keylen == 0) { - keylen = key_size(ares); - //memcpy(key, defaultkey, key_size(ares)); - } - if (keylen != key_size(ares)) { - PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares), key_size(ares), keylen); + DesfireContext dctx; + int securechann = defaultSecureChannel; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann); + if (res) { CLIParserFree(ctx); - return PM3_EINVARG; + return res; } - const CLIParserOption kdf_opts[] = { - {MFDES_KDF_ALGO_NONE, "none"}, - {MFDES_KDF_ALGO_AN10922, "an10922"}, - {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, - }; - - int kres = MFDES_KDF_ALGO_NONE; - CLIGetOptionListWithReturn(ctx, 6, kdf_opts, ARRAY_LENGTH(kdf_opts), &kres); - PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kres)); - - int kdfInputLen = 0; - uint8_t kdfInput[50] = {0}; - CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); - - const CLIParserOption cmode_opts[] = { - {DCMPlain, "plain"}, - {DCMMACed, "mac"}, - {DCMEncrypted, "encrypt"}, - }; - - int commmode = DCMPlain; - CLIGetOptionListWithReturn(ctx, 8, cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode); - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); - - const CLIParserOption commc_opts[] = { - {DCCNative, "native"}, - {DCCNativeISO, "niso"}, - {DCCISO, "iso"}, - }; - - int commchann = DCCNativeISO; - CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); - - const CLIParserOption authc_opts[] = { - {DACd40, "d40"}, - {DACEV1, "ev1"}, - {DACEV2, "ev2"}, - }; - - int authchann = DACEV1; - CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); - PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); - SetAPDULogging(APDULogging); CLIParserFree(ctx); - DesfireContext dctx; - DesfireSetKey(&dctx, keyNum, ares, key); // T_DES T_3DES T_3K3DES T_AES - DesfireSetCommandChannel(&dctx, commchann); + if (verbose) + DesfirePrintContext(&dctx); - - int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); DropField(); return PM3_ESOFT; } - res = DesfireAuthenticate(&dctx, authchann); //DACd40 DACEV1 + res = DesfireAuthenticate(&dctx, securechann); //DACd40 DACEV1 if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); DropField(); @@ -5157,102 +5221,38 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) { arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), - arg_str0("m", "cmode", "", "Commpunicaton mode: plain/mac/encrypt"), - arg_str0("c", "commc", "", "Commpunicaton channel: native/niso/iso"), - arg_str0("u", "authc", "", "Authentication channel: d40/ev1/ev2"), + arg_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, false); bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - uint8_t keyNum = arg_get_int_def(ctx, 3, 0); // defaultKeyId - - - const CLIParserOption algo_opts[] = { - {T_DES, "des"}, - {T_3DES, "2tdea"}, - {T_3K3DES, "3tdea"}, - {T_AES, "aes"}, - }; - - int ares = T_DES; - CLIGetOptionListWithReturn(ctx, 4, algo_opts, ARRAY_LENGTH(algo_opts), &ares); - PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares)); - - int keylen = 0; - uint8_t key[200] = {0}; - CLIGetHexWithReturn(ctx, 5, key, &keylen); - if (keylen == 0) { - keylen = key_size(ares); - //memcpy(key, defaultkey, key_size(ares)); - } - if (keylen != key_size(ares)) { - PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), ares), key_size(ares), keylen); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - const CLIParserOption kdf_opts[] = { - {MFDES_KDF_ALGO_NONE, "none"}, - {MFDES_KDF_ALGO_AN10922, "an10922"}, - {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, - }; - - int kres = MFDES_KDF_ALGO_NONE; - CLIGetOptionListWithReturn(ctx, 6, kdf_opts, ARRAY_LENGTH(kdf_opts), &kres); - PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kres)); - - int kdfInputLen = 0; - uint8_t kdfInput[50] = {0}; - CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); - - const CLIParserOption cmode_opts[] = { - {DCMPlain, "plain"}, - {DCMMACed, "mac"}, - {DCMEncrypted, "encrypt"}, - }; - - int commmode = DCMPlain; - CLIGetOptionListWithReturn(ctx, 8, cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode); - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); - - const CLIParserOption commc_opts[] = { - {DCCNative, "native"}, - {DCCNativeISO, "niso"}, - {DCCISO, "iso"}, - }; - - int commchann = DCCNativeISO; - CLIGetOptionListWithReturn(ctx, 9, commc_opts, ARRAY_LENGTH(commc_opts), &commchann); - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commchann)); - - const CLIParserOption authc_opts[] = { - {DACd40, "d40"}, - {DACEV1, "ev1"}, - {DACEV2, "ev2"}, - }; - - int authchann = DACEV1; - CLIGetOptionListWithReturn(ctx, 10, authc_opts, ARRAY_LENGTH(authc_opts), &authchann); - PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), authchann)); - - SetAPDULogging(APDULogging); - CLIParserFree(ctx); DesfireContext dctx; - DesfireSetKey(&dctx, keyNum, ares, key); - DesfireSetCommandChannel(&dctx, commchann); + int securechann = defaultSecureChannel; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann); + if (res) { + CLIParserFree(ctx); + return res; + } + SetAPDULogging(APDULogging); + CLIParserFree(ctx); - int res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (verbose) + DesfirePrintContext(&dctx); + + res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); DropField(); return PM3_ESOFT; } - res = DesfireAuthenticate(&dctx, authchann); + res = DesfireAuthenticate(&dctx, securechann); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); DropField(); diff --git a/client/src/cmdhfmfdes.h b/client/src/cmdhfmfdes.h index eb4dd77e0..60ef9c35f 100644 --- a/client/src/cmdhfmfdes.h +++ b/client/src/cmdhfmfdes.h @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- -// Iceman, 2014 +// Copyright (C) Iceman, 2014 +// Copyright (C) 2021 Merlok // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 6ec606227..43c0ae3bf 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -1,5 +1,6 @@ /*- * Copyright (C) 2010, Romain Tartiere. + * Copyright (C) 2021 Merlok * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 71d17aea7..281b33978 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -1,4 +1,24 @@ -#ifndef __DESFIRE_CRYPTO_H +/*- + * Copyright (C) 2010, Romain Tartiere. + * Copyright (C) 2021 Merlok + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + * $Id$ + */ + + #ifndef __DESFIRE_CRYPTO_H #define __DESFIRE_CRYPTO_H #include "common.h" @@ -7,6 +27,7 @@ #define MAX_CRYPTO_BLOCK_SIZE 16 +#define DESFIRE_MAX_KEY_SIZE 24 /* Mifare DESFire EV1 Application crypto operations */ #define APPLICATION_CRYPTO_DES 0x00 #define APPLICATION_CRYPTO_3K3DES 0x40 diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 18aa09265..f4bf93d0a 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- // High frequency Desfire core functions //----------------------------------------------------------------------------- -// Info from here and many other soursec from the internet +// Info from here and many other sources from the public internet sites // https://github.com/revk/DESFireAES // https://github.com/step21/desfire_rfid // https://github.com/patsys/desfire-python/blob/master/Desfire/DESFire.py @@ -163,8 +163,8 @@ void DesfireClearContext(DesfireContext *ctx) { ctx->keyType = T_DES; memset(ctx->key, 0, sizeof(ctx->key)); - ctx->authChannel = DACNone; - ctx->cmdChannel = DCCNative; + ctx->secureChannel = DACNone; + ctx->cmdSet = DCCNative; ctx->commMode = DCMNone; ctx->kdfAlgo = 0; @@ -175,7 +175,7 @@ void DesfireClearContext(DesfireContext *ctx) { } void DesfireClearSession(DesfireContext *ctx) { - ctx->authChannel = DACNone; // here none - not authenticared + ctx->secureChannel = DACNone; // here none - not authenticared memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC)); memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc)); @@ -185,6 +185,11 @@ void DesfireClearSession(DesfireContext *ctx) { memset(ctx->TI, 0, sizeof(ctx->TI)); } +void DesfirePrintContext(DesfireContext *ctx) { + //PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores)); + PrintAndLogEx(INFO, "Key num: %d Key type: %d Key[%d]: %s", ctx->keyNum, ctx->keyType, key_size(ctx->keyType), sprint_hex(ctx->key, key_size(ctx->keyType))); +} + void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) { DesfireClearContext(ctx); @@ -193,8 +198,19 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO memcpy(ctx->key, key, desfire_get_key_length(keyType)); } -void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel) { - ctx->cmdChannel = cmdChannel; +void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) { + ctx->cmdSet = cmdSet; +} + +void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode) { + ctx->commMode = commMode; +} + +void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) { + ctx->kdfAlgo = kdfAlgo; + ctx->kdfInputLen = kdfInputLen; + if (kdfInputLen) + memcpy(ctx->kdfInput, kdfInput, kdfInputLen); } static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) { @@ -342,7 +358,7 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { int res = PM3_SUCCESS; - switch(ctx->cmdChannel) { + switch(ctx->cmdSet) { case DCCNative: res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); break; @@ -397,17 +413,17 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin } bool DesfireIsAuthenticated(DesfireContext *dctx) { - return dctx->authChannel != DACNone; + return dctx->secureChannel != DACNone; } -int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { +int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel) { // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) // 4 different crypto arg1 DES, 3DES, 3K3DES, AES // 3 different communication modes, PLAIN,MAC,CRYPTO DesfireClearSession(dctx); - if (authChannel == DACNone) + if (secureChannel == DACNone) return PM3_SUCCESS; mbedtls_aes_context ctx; @@ -456,8 +472,8 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { } uint8_t subcommand = MFDES_AUTHENTICATE; - dctx->authChannel = authChannel; - if (dctx->authChannel == DACEV1) { + dctx->secureChannel = secureChannel; + if (dctx->secureChannel == DACEV1) { if (dctx->keyType == T_AES) subcommand = MFDES_AUTHENTICATE_AES; else @@ -522,7 +538,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { uint8_t encRndA[16] = {0x00}; // - Encrypt our response - if (dctx->authChannel == DACd40) { + if (dctx->secureChannel == DACd40) { des_decrypt(encRndA, RndA, key->data); memcpy(both, encRndA, rndlen); @@ -532,7 +548,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { des_decrypt(encRndB, rotRndB, key->data); memcpy(both + rndlen, encRndB, rndlen); - } else if (dctx->authChannel == DACEV1 && dctx->keyType != T_AES) { + } else if (dctx->secureChannel == DACEV1 && dctx->keyType != T_AES) { if (dctx->keyType == T_3DES) { uint8_t tmp[16] = {0x00}; memcpy(tmp, RndA, rndlen); @@ -558,7 +574,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) { PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); } } - } else if (dctx->authChannel == DACEV1 && dctx->keyType == T_AES) { + } else if (dctx->secureChannel == DACEV1 && dctx->keyType == T_AES) { uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); @@ -637,7 +653,7 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen)); memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8); } - if (dctx->authChannel == DACEV1) { + if (dctx->secureChannel == DACEV1) { cmac_generate_subkeys(&sesskey, MCD_RECEIVE); //key->cmac_sk1 and key->cmac_sk2 //memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index a0b31babb..079c0efe6 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -28,13 +28,13 @@ typedef enum { DACd40, DACEV1, DACEV2 -} DesfireAuthChannel; +} DesfireSecureChannel; typedef enum { DCCNative, DCCNativeISO, DCCISO -} DesfireCommandChannel; +} DesfireCommandSet; typedef enum { DCMNone, @@ -54,9 +54,9 @@ typedef struct DesfireContextS { uint8_t kdfInputLen; uint8_t kdfInput[31]; - DesfireAuthChannel authChannel; // none/d40/ev1/ev2 - DesfireCommandChannel cmdChannel; // native/nativeiso/iso - DesfireCommunicationMode commMode; // plain/mac/enc + DesfireSecureChannel secureChannel; // none/d40/ev1/ev2 + DesfireCommandSet cmdSet; // native/nativeiso/iso + DesfireCommunicationMode commMode; // plain/mac/enc uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN]; uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN]; // look at mifare4.h - mf4Session_t @@ -68,9 +68,12 @@ typedef struct DesfireContextS { } DesfireContext; void DesfireClearContext(DesfireContext *ctx); +void DesfirePrintContext(DesfireContext *ctx); void DesfireClearSession(DesfireContext *ctx); void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key); -void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel); +void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet); +void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode); +void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo,uint8_t *kdfInput, uint8_t kdfInputLen); const char *DesfireGetErrorString(int res, uint16_t *sw); uint32_t DesfireAIDByteToUint(uint8_t *data); @@ -82,7 +85,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); -int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel); +int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel); bool DesfireIsAuthenticated(DesfireContext *dctx); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); From fe5f9ec9d59f3e6cb5e363a598892f17144e5485 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 11:21:31 +0300 Subject: [PATCH 16/31] native channel works --- client/src/mifare/desfirecore.c | 109 +++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index f4bf93d0a..8220a77b8 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -272,11 +272,118 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin return PM3_SUCCESS; } -static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { +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; + if (activate_field) { + DropField(); + msleep(50); + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, "raw>> %s", sprint_hex(data, datalen)); + + int res = ExchangeRAW14a(data, datalen, activate_field, true, result, max_result_len, (int *)result_len, true); + if (res != PM3_SUCCESS) { + return res; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, "raw<< %s", sprint_hex(result, *result_len)); + + if (*result_len < 1) { + return PM3_SUCCESS; + } + + *result_len -= 1 + 2; + uint8_t rcode = result[0]; + if (respcode) *respcode = rcode; + memmove(&result[0], &result[1], *result_len); + + if (rcode != MFDES_S_OPERATION_OK && + rcode != MFDES_S_SIGNATURE && + rcode != MFDES_S_ADDITIONAL_FRAME && + rcode != MFDES_S_NO_CHANGES) { + if (GetAPDULogging()) + PrintAndLogEx(ERR, "Command (%02x) ERROR: 0x%02x", data[0], rcode); + return PM3_EAPDU_FAIL; + } return PM3_SUCCESS; } +static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { + if (resplen) + *resplen = 0; + if (respcode) + *respcode = 0xff; + + uint8_t buf[255 * 5] = {0x00}; + uint32_t buflen = 0; + uint32_t pos = 0; + uint32_t i = 1; + + uint8_t rcode = 0xff; + uint8_t cdata[255] = {0}; + uint32_t cdatalen = 0; + cdata[0] = cmd; + memcpy(&cdata[1], data, datalen); + cdatalen = datalen + 1; + + int res = DESFIRESendRaw(activate_field, cdata, cdatalen, buf, sizeof(buf), &buflen, &rcode); + if (res != PM3_SUCCESS) { + uint16_t ssw = DESFIRE_GET_ISO_STATUS(rcode); + PrintAndLogEx(DEBUG, "error DESFIRESendRaw %s", DesfireGetErrorString(res, &ssw)); + return res; + } + + if (resp) + memcpy(resp, buf, buflen); + if (respcode != NULL) + *respcode = rcode; + + pos += buflen; + if (!enable_chaining) { + if (rcode == MFDES_S_OPERATION_OK || + rcode == MFDES_ADDITIONAL_FRAME) { + if (resplen) + *resplen = pos; + } + return PM3_SUCCESS; + } + + while (rcode == MFDES_ADDITIONAL_FRAME) { + cdata[0] = MFDES_ADDITIONAL_FRAME; //0xAF + + res = DESFIRESendRaw(false, cdata, 1, buf, sizeof(buf), &buflen, &rcode); + if (res != PM3_SUCCESS) { + uint16_t ssw = DESFIRE_GET_ISO_STATUS(rcode); + PrintAndLogEx(DEBUG, "error DESFIRESendRaw %s", DesfireGetErrorString(res, &ssw)); + return res; + } + + if (respcode != NULL) + *respcode = rcode; + + if (resp != NULL) { + if (splitbysize) { + memcpy(&resp[i * splitbysize], buf, buflen); + i += 1; + } else { + memcpy(&resp[pos], buf, buflen); + } + } + pos += buflen; + + if (rcode != MFDES_ADDITIONAL_FRAME) break; + } + + if (resplen) + *resplen = (splitbysize) ? i : pos; + + 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) { if (resplen) *resplen = 0; From 2abd930ef7be71630e7f80840efd36789b8439fc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 12:20:09 +0300 Subject: [PATCH 17/31] simplify cliparser optinlist. added `mfdes default` --- client/deps/cliparser/cliparser.c | 14 ++-- client/deps/cliparser/cliparser.h | 5 +- client/src/cmdhfmfdes.c | 108 ++++++++++++++++++------------ client/src/mifare/desfirecore.c | 43 +++++++++++- client/src/mifare/desfirecore.h | 7 ++ 5 files changed, 128 insertions(+), 49 deletions(-) diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 265c97103..ad89856cd 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -298,7 +298,7 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } -int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, size_t option_array_len, int *value) { +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, int *value) { char data[200] = {0}; int datalen = 0; int res = CLIParamStrToBuf(argstr, (uint8_t *)data, sizeof(data), &datalen); @@ -313,7 +313,10 @@ int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array int val = -1; int cntr = 0; - for (int i = 0; i < option_array_len; i++) { + for (int i = 0; i < CLI_MAX_OPTLIST_LEN; i++) { + // end of array + if (option_array[i].text == NULL) + break; // exact match if (strcmp(option_array[i].text, data) == 0) { *value = option_array[i].code; @@ -340,12 +343,15 @@ int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array return 0; } -const char *CLIGetOptionListStr(const CLIParserOption *option_array, size_t option_array_len, int value) { +const char *CLIGetOptionListStr(const CLIParserOption *option_array, int value) { static const char *errmsg = "n/a"; - for (int i = 0; i < option_array_len; i++) + for (int i = 0; i < CLI_MAX_OPTLIST_LEN; i++) { + if (option_array[i].text == NULL) + break; if (option_array[i].code == value) return option_array[i].text; + } return errmsg; } diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index f4f9b7dcf..d75f43dff 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -62,6 +62,7 @@ typedef struct { char buf[1024 + 60]; } CLIParserContext; +#define CLI_MAX_OPTLIST_LEN 50 typedef struct { int code; const char *text; @@ -78,8 +79,8 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int int CLIParamBinToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); // names in the CLIParserOption array must be in the lowercase format -int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, size_t option_array_len, int *value); -const char *CLIGetOptionListStr(const CLIParserOption *option_array, size_t option_array_len, int value); +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, int *value); +const char *CLIGetOptionListStr(const CLIParserOption *option_array, int value); uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional); diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c29f74cc6..255283211 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5030,17 +5030,10 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct keynum = arg_get_int_def(ctx, keynoid, keynum); } - const CLIParserOption algo_opts[] = { - {T_DES, "des"}, - {T_3DES, "2tdea"}, - {T_3K3DES, "3tdea"}, - {T_AES, "aes"}, - }; - if (algoid) { - if (CLIGetOptionList(arg_get_str(ctx, algoid), algo_opts, ARRAY_LENGTH(algo_opts), &algores)) + if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores)) return PM3_ESOFT; - PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores)); + PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(DesfireAlgoOpts, algores)); } if (keyid) { @@ -5049,7 +5042,7 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen)) return PM3_ESOFT; if (keylen && keylen != key_size(algores)) { - PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores), key_size(algores), keylen); + PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), key_size(algores), keylen); return PM3_EINVARG; } if (keylen) @@ -5057,15 +5050,9 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct } if (kdfid) { - const CLIParserOption kdf_opts[] = { - {MFDES_KDF_ALGO_NONE, "none"}, - {MFDES_KDF_ALGO_AN10922, "an10922"}, - {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, - }; - - if (CLIGetOptionList(arg_get_str(ctx, kdfid), kdf_opts, ARRAY_LENGTH(kdf_opts), &kdfAlgo)) + if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo)) return PM3_ESOFT; - PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(kdf_opts, ARRAY_LENGTH(kdf_opts), kdfAlgo)); + PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, kdfAlgo)); } @@ -5081,39 +5068,21 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct } if (cmodeid) { - const CLIParserOption cmode_opts[] = { - {DCMPlain, "plain"}, - {DCMMACed, "mac"}, - {DCMEncrypted, "encrypt"}, - }; - - if (CLIGetOptionList(arg_get_str(ctx, cmodeid), cmode_opts, ARRAY_LENGTH(cmode_opts), &commmode)) + if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode)) return PM3_ESOFT; - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(cmode_opts, ARRAY_LENGTH(cmode_opts), commmode)); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, commmode)); } if (ccsetid) { - const CLIParserOption commc_opts[] = { - {DCCNative, "native"}, - {DCCNativeISO, "niso"}, - {DCCISO, "iso"}, - }; - - if (CLIGetOptionList(arg_get_str(ctx, ccsetid), commc_opts, ARRAY_LENGTH(commc_opts), &commset)) + if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset)) return PM3_ESOFT; - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(commc_opts, ARRAY_LENGTH(commc_opts), commset)); + PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(DesfireCommandSetOpts, commset)); } if (schannid) { - const CLIParserOption authc_opts[] = { - {DACd40, "d40"}, - {DACEV1, "ev1"}, - {DACEV2, "ev2"}, - }; - - if (CLIGetOptionList(arg_get_str(ctx, schannid), authc_opts, ARRAY_LENGTH(authc_opts), &secchann)) + if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann)) return PM3_ESOFT; - PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(authc_opts, ARRAY_LENGTH(authc_opts), secchann)); + PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(DesfireSecureChannelOpts, secchann)); } DesfireSetKey(dctx, keynum, algores, key); @@ -5126,6 +5095,60 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct return PM3_SUCCESS; } +static int CmdHF14ADesDefault(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes default", + "Get Application IDs, ISO IDs and DF names from card. Master key needs to be provided.", + "hf mfdes getappnames -n 0 -t des -k 0000000000000000 -f none -> execute with default factory setup"); + + void *argtable[] = { + arg_param_begin, + arg_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, &securechann); + 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, key_size(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 CmdHF14ADesGetAIDs(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes getaids", @@ -5294,6 +5317,7 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"}, + {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"}, {"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"}, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 8220a77b8..bab818a39 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -29,6 +29,47 @@ #include "util_posix.h" // msleep #include "mifare/desfire_crypto.h" +const CLIParserOption DesfireAlgoOpts[] = { + {T_DES, "des"}, + {T_3DES, "2tdea"}, + {T_3K3DES, "3tdea"}, + {T_AES, "aes"}, + {0, NULL}, +}; +const size_t DesfireAlgoOptsLen = ARRAY_LENGTH(DesfireAlgoOpts); + +const CLIParserOption DesfireKDFAlgoOpts[] = { + {MFDES_KDF_ALGO_NONE, "none"}, + {MFDES_KDF_ALGO_AN10922, "an10922"}, + {MFDES_KDF_ALGO_GALLAGHER, "gallagher"}, + {0, NULL}, +}; +const size_t DesfireKDFAlgoOptsLen = ARRAY_LENGTH(DesfireKDFAlgoOpts); + +const CLIParserOption DesfireCommunicationModeOpts[] = { + {DCMPlain, "plain"}, + {DCMMACed, "mac"}, + {DCMEncrypted, "encrypt"}, + {0, NULL}, +}; +const size_t DesfireCommunicationModeOptsLen = ARRAY_LENGTH(DesfireCommunicationModeOpts); + +const CLIParserOption DesfireCommandSetOpts[] = { + {DCCNative, "native"}, + {DCCNativeISO, "niso"}, + {DCCISO, "iso"}, + {0, NULL}, +}; +const size_t DesfireCommandSetOptsLen = ARRAY_LENGTH(DesfireCommandSetOpts); + +const CLIParserOption DesfireSecureChannelOpts[] = { + {DACd40, "d40"}, + {DACEV1, "ev1"}, + {DACEV2, "ev2"}, + {0, NULL}, +}; +const size_t DesfireSecureChannelOptsLen = ARRAY_LENGTH(DesfireSecureChannelOpts); + static const char *getstatus(uint16_t *sw) { if (sw == NULL) return "--> sw argument error. This should never happen !"; if (((*sw >> 8) & 0xFF) == 0x91) { @@ -187,7 +228,7 @@ void DesfireClearSession(DesfireContext *ctx) { void DesfirePrintContext(DesfireContext *ctx) { //PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores)); - PrintAndLogEx(INFO, "Key num: %d Key type: %d Key[%d]: %s", ctx->keyNum, ctx->keyType, key_size(ctx->keyType), sprint_hex(ctx->key, key_size(ctx->keyType))); + PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s", ctx->keyNum, CLIGetOptionListStr(DesfireAlgoOpts, ctx->keyType), key_size(ctx->keyType), sprint_hex(ctx->key, key_size(ctx->keyType))); } void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 079c0efe6..d03e8e908 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -14,6 +14,7 @@ #define __DESFIRECORE_H #include "common.h" +#include "cliparser.h" #include "mifare/desfire_crypto.h" #include "mifare/mifare4.h" @@ -67,6 +68,12 @@ typedef struct DesfireContextS { uint8_t TI[4]; // for AES } DesfireContext; +extern const CLIParserOption DesfireAlgoOpts[]; +extern const CLIParserOption DesfireKDFAlgoOpts[]; +extern const CLIParserOption DesfireCommunicationModeOpts[]; +extern const CLIParserOption DesfireCommandSetOpts[]; +extern const CLIParserOption DesfireSecureChannelOpts[]; + void DesfireClearContext(DesfireContext *ctx); void DesfirePrintContext(DesfireContext *ctx); void DesfireClearSession(DesfireContext *ctx); From 5271cb96c3099f3270e90a605c7f137c855e8cfe Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 12:25:34 +0300 Subject: [PATCH 18/31] add commant, remove debug --- client/deps/cliparser/cliparser.h | 1 + client/src/cmdhfmfdes.c | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index d75f43dff..f50fec2ee 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -63,6 +63,7 @@ typedef struct { } CLIParserContext; #define CLI_MAX_OPTLIST_LEN 50 +// option list needs to have NULL at the last record int the field `text` typedef struct { int code; const char *text; diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 255283211..1a3c82166 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5033,7 +5033,6 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct if (algoid) { if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores)) return PM3_ESOFT; - PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(DesfireAlgoOpts, algores)); } if (keyid) { @@ -5052,8 +5051,6 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct if (kdfid) { if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo)) return PM3_ESOFT; - PrintAndLogEx(INFO, "kdf funct: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, kdfAlgo)); - } if (kdfiid) { @@ -5070,19 +5067,16 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct if (cmodeid) { if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode)) return PM3_ESOFT; - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, commmode)); } if (ccsetid) { if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset)) return PM3_ESOFT; - PrintAndLogEx(INFO, "comm mode: %s", CLIGetOptionListStr(DesfireCommandSetOpts, commset)); } if (schannid) { if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann)) return PM3_ESOFT; - PrintAndLogEx(INFO, "auth channel: %s", CLIGetOptionListStr(DesfireSecureChannelOpts, secchann)); } DesfireSetKey(dctx, keynum, algores, key); From 6124b49c9913e9b63ce451147553c1f1b4dd93c7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 12:47:09 +0300 Subject: [PATCH 19/31] DesfirePrintContext prints session state --- client/src/cmdhfmfdes.c | 2 +- client/src/mifare/desfire_crypto.c | 14 +++++++++----- client/src/mifare/desfire_crypto.h | 1 + client/src/mifare/desfirecore.c | 28 +++++++++++++++++++++++++--- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 1a3c82166..c7a195db5 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5195,7 +5195,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { DropField(); return PM3_ESOFT; } - + if (DesfireIsAuthenticated(&dctx)) { if (verbose) PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res); diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 43c0ae3bf..079e7c897 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -390,12 +390,9 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) free(buffer); } -size_t key_block_size(const desfirekey_t key) { - if (key == NULL) { - return 0; - } +size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type) { size_t block_size = 8; - switch (key->type) { + switch (key_type) { case T_DES: case T_3DES: case T_3K3DES: @@ -408,6 +405,13 @@ size_t key_block_size(const desfirekey_t key) { return block_size; } +size_t key_block_size(const desfirekey_t key) { + if (key == NULL) { + return 0; + } + return desfire_get_key_block_length(key->type); +} + size_t key_size(const enum DESFIRE_CRYPTOALGO algo) { switch (algo) { case T_DES: diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 281b33978..1a1f6375c 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -82,6 +82,7 @@ enum DESFIRE_CRYPTOALGO { }; int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type); +size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type); enum DESFIRE_AUTH_SCHEME { AS_LEGACY, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index bab818a39..6fead2fdb 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -227,9 +227,31 @@ void DesfireClearSession(DesfireContext *ctx) { } void DesfirePrintContext(DesfireContext *ctx) { - //PrintAndLogEx(INFO, "algo: %s", CLIGetOptionListStr(algo_opts, ARRAY_LENGTH(algo_opts), algores)); - PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s", ctx->keyNum, CLIGetOptionListStr(DesfireAlgoOpts, ctx->keyType), key_size(ctx->keyType), sprint_hex(ctx->key, key_size(ctx->keyType))); -} + PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s", + ctx->keyNum, + CLIGetOptionListStr(DesfireAlgoOpts, ctx->keyType), + key_size(ctx->keyType), + sprint_hex(ctx->key, + key_size(ctx->keyType))); + + if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) + PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen)); + + PrintAndLogEx(INFO, "Secure channel: %s Command set: %s Communication mode: %s", + CLIGetOptionListStr(DesfireSecureChannelOpts, ctx->secureChannel), + CLIGetOptionListStr(DesfireCommandSetOpts, ctx->cmdSet), + CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode)); + + if (DesfireIsAuthenticated(ctx)) { + PrintAndLogEx(INFO, "Session key MAC [%d]: %s ENC: %s IV [%d]: %s", + key_size(ctx->keyType), + sprint_hex(ctx->sessionKeyMAC, key_size(ctx->keyType)), + sprint_hex(ctx->sessionKeyEnc, key_size(ctx->keyType)), + desfire_get_key_block_length(ctx->keyType), + sprint_hex(ctx->sessionKeyEnc, desfire_get_key_block_length(ctx->keyType))); + + } + } void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) { DesfireClearContext(ctx); From 430f82730d9764562d71ea2fa09287caaa03e0db Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 13:38:12 +0300 Subject: [PATCH 20/31] fix DesfireAuthenticate for d40/ev1 mode --- client/src/mifare/desfirecore.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 6fead2fdb..41b168277 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -708,18 +708,18 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel uint8_t encRndA[16] = {0x00}; // - Encrypt our response - if (dctx->secureChannel == DACd40) { - des_decrypt(encRndA, RndA, key->data); - memcpy(both, encRndA, rndlen); + if ((dctx->secureChannel == DACEV1 || dctx->secureChannel == DACd40) && dctx->keyType != T_AES) { + if (dctx->keyType == T_DES) { + des_decrypt(encRndA, RndA, key->data); + memcpy(both, encRndA, rndlen); - for (uint32_t x = 0; x < rndlen; x++) { - rotRndB[x] = rotRndB[x] ^ encRndA[x]; - } + for (uint32_t x = 0; x < rndlen; x++) { + rotRndB[x] = rotRndB[x] ^ encRndA[x]; + } - des_decrypt(encRndB, rotRndB, key->data); - memcpy(both + rndlen, encRndB, rndlen); - } else if (dctx->secureChannel == DACEV1 && dctx->keyType != T_AES) { - if (dctx->keyType == T_3DES) { + des_decrypt(encRndB, rotRndB, key->data); + memcpy(both + rndlen, encRndB, rndlen); + } else if (dctx->keyType == T_3DES) { uint8_t tmp[16] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); @@ -731,7 +731,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); } - } else if (dctx->keyType == T_3K3DES) { + } else if (dctx->secureChannel == DACEV1 && dctx->keyType == T_3K3DES) { uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); From db87af3bf840c64c8c153d33177f217dda0972e9 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 14:00:35 +0300 Subject: [PATCH 21/31] Revert "fix DesfireAuthenticate for d40/ev1 mode" This reverts commit 430f82730d9764562d71ea2fa09287caaa03e0db. --- client/src/mifare/desfirecore.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 41b168277..6fead2fdb 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -708,18 +708,18 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel uint8_t encRndA[16] = {0x00}; // - Encrypt our response - if ((dctx->secureChannel == DACEV1 || dctx->secureChannel == DACd40) && dctx->keyType != T_AES) { - if (dctx->keyType == T_DES) { - des_decrypt(encRndA, RndA, key->data); - memcpy(both, encRndA, rndlen); + if (dctx->secureChannel == DACd40) { + des_decrypt(encRndA, RndA, key->data); + memcpy(both, encRndA, rndlen); - for (uint32_t x = 0; x < rndlen; x++) { - rotRndB[x] = rotRndB[x] ^ encRndA[x]; - } + for (uint32_t x = 0; x < rndlen; x++) { + rotRndB[x] = rotRndB[x] ^ encRndA[x]; + } - des_decrypt(encRndB, rotRndB, key->data); - memcpy(both + rndlen, encRndB, rndlen); - } else if (dctx->keyType == T_3DES) { + des_decrypt(encRndB, rotRndB, key->data); + memcpy(both + rndlen, encRndB, rndlen); + } else if (dctx->secureChannel == DACEV1 && dctx->keyType != T_AES) { + if (dctx->keyType == T_3DES) { uint8_t tmp[16] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); @@ -731,7 +731,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); } - } else if (dctx->secureChannel == DACEV1 && dctx->keyType == T_3K3DES) { + } else if (dctx->keyType == T_3K3DES) { uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); From 1adfad07bdc3913eaeb3c5a40366481fd08ccd7b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 14:14:43 +0300 Subject: [PATCH 22/31] move des encrypt/decrypt to lib --- client/src/cmdhfmf.c | 7 ------- client/src/crypto/libpcrypto.c | 14 ++++++++++++++ client/src/crypto/libpcrypto.h | 3 +++ client/src/mifare/desfire_crypto.c | 12 ------------ client/src/mifare/desfire_crypto.h | 4 ++-- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index ace8d2d0b..985d156db 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -24,7 +24,6 @@ #include "protocols.h" #include "util_posix.h" // msclock #include "cmdhfmfhard.h" -#include "des.h" // des ecb #include "crapto1/crapto1.h" // prng_successor #include "cmdhf14a.h" // exchange APDU #include "crypto/libpcrypto.h" @@ -5645,12 +5644,6 @@ static int CmdHf14AGen3Freeze(const char *Cmd) { return res; } -static void des_decrypt(void *out, const void *in, const void *key) { - mbedtls_des_context ctx; - mbedtls_des_setkey_dec(&ctx, key); - mbedtls_des_crypt_ecb(&ctx, in, out); -} - static int CmdHf14AMfSuperCard(const char *Cmd) { CLIParserContext *ctx; diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index 723753d5f..f80eedcf0 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,19 @@ #include #include "util.h" #include "ui.h" + +void des_encrypt(void *out, const void *in, const void *key) { + mbedtls_des_context ctx; + mbedtls_des_setkey_enc(&ctx, key); + mbedtls_des_crypt_ecb(&ctx, in, out); +} + +void des_decrypt(void *out, const void *in, const void *key) { + mbedtls_des_context ctx; + mbedtls_des_setkey_dec(&ctx, key); + mbedtls_des_crypt_ecb(&ctx, in, out); +} + // NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) { uint8_t iiv[16] = {0}; diff --git a/client/src/crypto/libpcrypto.h b/client/src/crypto/libpcrypto.h index 099fd4423..b1c4b4eee 100644 --- a/client/src/crypto/libpcrypto.h +++ b/client/src/crypto/libpcrypto.h @@ -16,6 +16,9 @@ #include #include +void des_encrypt(void *out, const void *in, const void *key); +void des_decrypt(void *out, const void *in, const void *key); + int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 079e7c897..d941ae09e 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -65,18 +65,6 @@ int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) { /******************************************************************************/ -void des_encrypt(void *out, const void *in, const void *key) { - mbedtls_des_context ctx; - mbedtls_des_setkey_enc(&ctx, key); - mbedtls_des_crypt_ecb(&ctx, in, out); -} - -void des_decrypt(void *out, const void *in, const void *key) { - mbedtls_des_context ctx; - mbedtls_des_setkey_dec(&ctx, key); - mbedtls_des_crypt_ecb(&ctx, in, out); -} - void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) { if (length % 8) return; diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 1a1f6375c..1aa938017 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -24,6 +24,7 @@ #include "common.h" #include "mifare.h" // structs #include "crc32.h" +#include "crypto/libpcrypto.h" #define MAX_CRYPTO_BLOCK_SIZE 16 @@ -126,8 +127,7 @@ typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */ extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */ -void des_encrypt(void *out, const void *in, const void *key); -void des_decrypt(void *out, const void *in, const void *key); + void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode); void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode); void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key); From fce8affd4881883d96cd8dbaf162efd2eb57b77f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 15:43:57 +0300 Subject: [PATCH 23/31] fix des authentication --- client/src/crypto/libpcrypto.c | 12 ++++++++ client/src/crypto/libpcrypto.h | 2 ++ client/src/mifare/desfirecore.c | 51 ++++++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index f80eedcf0..d3df5dfda 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -41,6 +41,18 @@ void des_decrypt(void *out, const void *in, const void *key) { mbedtls_des_crypt_ecb(&ctx, in, out); } +void des_encrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv) { + mbedtls_des_context ctx; + mbedtls_des_setkey_enc(&ctx, key); + mbedtls_des_crypt_cbc(&ctx, MBEDTLS_DES_ENCRYPT, length, iv, in, out); +} + +void des_decrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv) { + mbedtls_des_context ctx; + mbedtls_des_setkey_dec(&ctx, key); + mbedtls_des_crypt_cbc(&ctx, MBEDTLS_DES_DECRYPT, length, iv, in, out); +} + // NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) { uint8_t iiv[16] = {0}; diff --git a/client/src/crypto/libpcrypto.h b/client/src/crypto/libpcrypto.h index b1c4b4eee..1c7c745dc 100644 --- a/client/src/crypto/libpcrypto.h +++ b/client/src/crypto/libpcrypto.h @@ -18,6 +18,8 @@ void des_encrypt(void *out, const void *in, const void *key); void des_decrypt(void *out, const void *in, const void *key); +void des_encrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv); +void des_decrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv); int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 6fead2fdb..118e30109 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -688,9 +688,12 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return 5; } mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB); - } else if (dctx->keyType == T_DES) - des_decrypt(RndB, encRndB, key->data); - else if (dctx->keyType == T_3DES) + } else if (dctx->keyType == T_DES) { + if (dctx->secureChannel == DACd40) + des_decrypt(RndB, encRndB, key->data); + if (dctx->secureChannel == DACEV1) + des_decrypt_cbc(RndB, encRndB, rndlen, key->data, IV); + } else if (dctx->keyType == T_3DES) tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2); else if (dctx->keyType == T_3K3DES) { tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 3); @@ -709,17 +712,33 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel // - Encrypt our response if (dctx->secureChannel == DACd40) { - des_decrypt(encRndA, RndA, key->data); - memcpy(both, encRndA, rndlen); + if (dctx->keyType == T_DES) { + des_decrypt(encRndA, RndA, key->data); + memcpy(both, encRndA, rndlen); - for (uint32_t x = 0; x < rndlen; x++) { - rotRndB[x] = rotRndB[x] ^ encRndA[x]; + for (uint32_t x = 0; x < rndlen; x++) { + rotRndB[x] = rotRndB[x] ^ encRndA[x]; + } + + des_decrypt(encRndB, rotRndB, key->data); + memcpy(both + rndlen, encRndB, rndlen); + } else if (dctx->keyType == T_3DES) { + //TODO } - - des_decrypt(encRndB, rotRndB, key->data); - memcpy(both + rndlen, encRndB, rndlen); } else if (dctx->secureChannel == DACEV1 && dctx->keyType != T_AES) { - if (dctx->keyType == T_3DES) { + if (dctx->keyType == T_DES) { + uint8_t tmp[16] = {0x00}; + memcpy(tmp, RndA, rndlen); + memcpy(tmp + rndlen, rotRndB, rndlen); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); + PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16)); + } + des_encrypt_cbc(both, tmp, 16, key->data, IV); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); + } + } else if (dctx->keyType == T_3DES) { uint8_t tmp[16] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); @@ -790,9 +809,13 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen)); - if (dctx->keyType == T_DES) - des_decrypt(encRndA, encRndA, key->data); - else if (dctx->keyType == T_3DES) +PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen)); + if (dctx->keyType == T_DES){ + if (dctx->secureChannel == DACd40) + des_decrypt(encRndA, encRndA, key->data); + if (dctx->secureChannel == DACEV1) + des_decrypt_cbc(encRndA, encRndA, rndlen, key->data, IV); + } else if (dctx->keyType == T_3DES) tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2); else if (dctx->keyType == T_3K3DES) tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 3); From aa8c4b3dcaee8d9ee4847fb121b1416b6ac17ac4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 17:49:11 +0300 Subject: [PATCH 24/31] secure channel sketch --- client/src/mifare/desfirecore.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 118e30109..82ec7ccd2 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -525,15 +525,32 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } +static void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; +} + +static void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; +} + int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { int res = PM3_SUCCESS; + uint8_t databuf[250 * 5] = {0}; + size_t databuflen = 0; + switch(ctx->cmdSet) { case DCCNative: - res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); + DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen); + res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); + DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen); break; case DCCNativeISO: - res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, respcode, resp, resplen, enable_chaining, splitbysize); + DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen); + res = DesfireExchangeISO(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); + DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen); break; case DCCISO: return PM3_EAPDU_FAIL; From 998538a60ad10175868820c316815be2799c53ed Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 22:15:53 +0300 Subject: [PATCH 25/31] libcrypto des encrypt/decrypt ecb and change cmdhfemtrd to use des from libcrypto --- client/src/cmdhfemrtd.c | 23 ++++------------------- client/src/crypto/libpcrypto.c | 12 ++++++++++++ client/src/crypto/libpcrypto.h | 2 ++ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7791233dc..312099268 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -19,8 +19,7 @@ #include "protocols.h" // definitions of ISO14A/7816 protocol #include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "iso7816/iso7816core.h" // Iso7816ExchangeEx etc -#include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512) -#include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt +#include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512), des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity #include "crapto1/crapto1.h" // prng_successor #include "commonutil.h" // num_to_bytes @@ -263,20 +262,6 @@ static int emrtd_get_asn1_field_length(uint8_t *datain, int datainlen, int offse return 0; } -static void des_encrypt_ecb(uint8_t *key, uint8_t *input, uint8_t *output) { - mbedtls_des_context ctx_enc; - mbedtls_des_setkey_enc(&ctx_enc, key); - mbedtls_des_crypt_ecb(&ctx_enc, input, output); - mbedtls_des_free(&ctx_enc); -} - -static void des_decrypt_ecb(uint8_t *key, uint8_t *input, uint8_t *output) { - mbedtls_des_context ctx_dec; - mbedtls_des_setkey_dec(&ctx_dec, key); - mbedtls_des_crypt_ecb(&ctx_dec, input, output); - mbedtls_des_free(&ctx_dec); -} - static void des3_encrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inputlen, uint8_t *output) { mbedtls_des3_context ctx; mbedtls_des3_set2key_enc(&ctx, key); @@ -345,15 +330,15 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp intermediate[x] = intermediate[x] ^ block[x]; } - des_encrypt_ecb(k0, intermediate, intermediate_des); + des_encrypt(intermediate_des, intermediate, k0); memcpy(intermediate, intermediate_des, 8); } - des_decrypt_ecb(k1, intermediate, intermediate_des); + des_decrypt(intermediate_des, intermediate, k1); memcpy(intermediate, intermediate_des, 8); - des_encrypt_ecb(k0, intermediate, intermediate_des); + des_encrypt(intermediate_des, intermediate, k0); memcpy(output, intermediate_des, 8); } diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index d3df5dfda..af15c1f5e 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -33,12 +33,24 @@ void des_encrypt(void *out, const void *in, const void *key) { mbedtls_des_context ctx; mbedtls_des_setkey_enc(&ctx, key); mbedtls_des_crypt_ecb(&ctx, in, out); + mbedtls_des_free(&ctx); } void des_decrypt(void *out, const void *in, const void *key) { mbedtls_des_context ctx; mbedtls_des_setkey_dec(&ctx, key); mbedtls_des_crypt_ecb(&ctx, in, out); + mbedtls_des_free(&ctx); +} + +void des_encrypt_ecb(void *out, const void *in, const int length, const void *key) { + for (int i = 0; i < length; i += 8) + des_encrypt((uint8_t *)out + i, (uint8_t *)in + i, key); +} + +void des_decrypt_ecb(void *out, const void *in, const int length, const void *key) { + for (int i = 0; i < length; i += 8) + des_decrypt((uint8_t *)out + i, (uint8_t *)in + i, key); } void des_encrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv) { diff --git a/client/src/crypto/libpcrypto.h b/client/src/crypto/libpcrypto.h index 1c7c745dc..d5f7b809b 100644 --- a/client/src/crypto/libpcrypto.h +++ b/client/src/crypto/libpcrypto.h @@ -18,6 +18,8 @@ void des_encrypt(void *out, const void *in, const void *key); void des_decrypt(void *out, const void *in, const void *key); +void des_encrypt_ecb(void *out, const void *in, const int length, const void *key); +void des_decrypt_ecb(void *out, const void *in, const int length, const void *key); void des_encrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv); void des_decrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv); From 5d8fa054e5df8c8fe6bc9ddebd90d6dd404d66ad Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 22:16:43 +0300 Subject: [PATCH 26/31] added channel logic to d40 mode --- client/src/mifare/desfirecore.c | 102 +++++++++++++++++++++++++++++++- client/src/mifare/desfirecore.h | 1 + 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 82ec7ccd2..656b32889 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -21,6 +21,9 @@ #include #include "aes.h" #include "ui.h" +#include "crc.h" +#include "crc16.h" // crc16 ccitt +#include "crc32.h" #include "protocols.h" #include "commonutil.h" #include "cmdhf14a.h" @@ -218,6 +221,7 @@ void DesfireClearContext(DesfireContext *ctx) { void DesfireClearSession(DesfireContext *ctx) { ctx->secureChannel = DACNone; // here none - not authenticared + memset(ctx->IV, 0, sizeof(ctx->IV)); memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC)); memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc)); memset(ctx->lastIV, 0, sizeof(ctx->lastIV)); @@ -525,9 +529,105 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t return PM3_SUCCESS; } -static void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { +static void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { + uint8_t data[1024] = {0}; + + switch(ctx->keyType) { + case T_DES: + if (ctx->secureChannel == DACd40) { + if (encode) + des_encrypt_ecb(data, srcdata, srcdatalen, ctx->key); + else + des_decrypt_ecb(data, srcdata, srcdatalen, ctx->key); + } if (ctx->secureChannel == DACEV1) { + if (encode) + des_encrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV); + else + des_decrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV); + } + + if (dstdata) + memcpy(dstdata, data, srcdatalen); + break; + case T_3DES: + break; + case T_3K3DES: + break; + case T_AES: + if (encode) + aes_encode(ctx->IV, ctx->key, srcdata, data, srcdatalen); + else + aes_decode(ctx->IV, ctx->key, srcdata, data, srcdatalen); + if (dstdata) + memcpy(dstdata, data, srcdatalen); + break; + } +} + +static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; + + uint8_t data[1024] = {0}; + size_t rlen = 0; + + switch(ctx->commMode) { + case DCMPlain: + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + break; + case DCMMACed: + if (srcdatalen == 0) + break; + + rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType)); + memcpy(data, srcdata, srcdatalen); + DesfireCryptoEncDec(ctx, data, rlen, NULL, true); + memcpy(dstdata, srcdata, srcdatalen); + memcpy(&dstdata[srcdatalen], ctx->IV, desfire_get_key_block_length(ctx->keyType)); + *dstdatalen = rlen; + break; + case DCMEncrypted: + rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16 + memcpy(data, srcdata, srcdatalen); + compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]); + DesfireCryptoEncDec(ctx, data, rlen, dstdata, true); + *dstdatalen = rlen; + break; + case DCMNone:; + } +} + +static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + + switch(ctx->commMode) { + case DCMPlain: + case DCMMACed: + + break; + case DCMEncrypted: + break; + case DCMNone:; + } +} + +static void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + switch(ctx->secureChannel) { + case DACd40: + DesfireSecureChannelEncodeD40(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen); + break; + case DACEV1: + DesfireSecureChannelEncodeEV1(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen); + break; + case DACEV2: + break; + case DACNone: + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + break; + } } static void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index d03e8e908..873e365a8 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -59,6 +59,7 @@ typedef struct DesfireContextS { DesfireCommandSet cmdSet; // native/nativeiso/iso DesfireCommunicationMode commMode; // plain/mac/enc + uint8_t IV[DESF_MAX_KEY_LEN]; uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN]; uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN]; // look at mifare4.h - mf4Session_t uint8_t lastIV[DESF_MAX_KEY_LEN]; From 1aedfc7b6e7c8db221165df92c21b9b7635ab964 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 4 Jul 2021 22:37:27 +0300 Subject: [PATCH 27/31] ev1 mac decode placeholder --- client/src/mifare/desfirecore.c | 72 ++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 656b32889..a461fb254 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -630,9 +630,59 @@ static void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t } } -static void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { +static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; + + switch(ctx->commMode) { + case DCMMACed: + + break; + case DCMEncrypted: + break; + case DCMPlain: + case DACNone: + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + break; + } +} + +static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + + switch(ctx->commMode) { + case DCMPlain: + case DCMMACed: + memcpy(dstdata, srcdata, srcdatalen - 8); + *dstdatalen = srcdatalen - 8; + + break; + case DCMEncrypted: + break; + case DACNone: + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + break; + } +} + +static void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + switch(ctx->secureChannel) { + case DACd40: + DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); + break; + case DACEV1: + DesfireSecureChannelDecodeEV1(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); + break; + case DACEV2: + break; + case DACNone: + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + break; + } } int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { @@ -759,8 +809,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel } uint8_t subcommand = MFDES_AUTHENTICATE; - dctx->secureChannel = secureChannel; - if (dctx->secureChannel == DACEV1) { + if (secureChannel == DACEV1) { if (dctx->keyType == T_AES) subcommand = MFDES_AUTHENTICATE_AES; else @@ -806,9 +855,9 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel } mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB); } else if (dctx->keyType == T_DES) { - if (dctx->secureChannel == DACd40) + if (secureChannel == DACd40) des_decrypt(RndB, encRndB, key->data); - if (dctx->secureChannel == DACEV1) + if (secureChannel == DACEV1) des_decrypt_cbc(RndB, encRndB, rndlen, key->data, IV); } else if (dctx->keyType == T_3DES) tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2); @@ -828,7 +877,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel uint8_t encRndA[16] = {0x00}; // - Encrypt our response - if (dctx->secureChannel == DACd40) { + if (secureChannel == DACd40) { if (dctx->keyType == T_DES) { des_decrypt(encRndA, RndA, key->data); memcpy(both, encRndA, rndlen); @@ -842,7 +891,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel } else if (dctx->keyType == T_3DES) { //TODO } - } else if (dctx->secureChannel == DACEV1 && dctx->keyType != T_AES) { + } else if (secureChannel == DACEV1 && dctx->keyType != T_AES) { if (dctx->keyType == T_DES) { uint8_t tmp[16] = {0x00}; memcpy(tmp, RndA, rndlen); @@ -880,7 +929,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); } } - } else if (dctx->secureChannel == DACEV1 && dctx->keyType == T_AES) { + } else if (secureChannel == DACEV1 && dctx->keyType == T_AES) { uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); @@ -928,9 +977,9 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen)); PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen)); if (dctx->keyType == T_DES){ - if (dctx->secureChannel == DACd40) + if (secureChannel == DACd40) des_decrypt(encRndA, encRndA, key->data); - if (dctx->secureChannel == DACEV1) + if (secureChannel == DACEV1) des_decrypt_cbc(encRndA, encRndA, rndlen, key->data, IV); } else if (dctx->keyType == T_3DES) tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2); @@ -963,12 +1012,13 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen)); memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8); } - if (dctx->secureChannel == DACEV1) { + if (secureChannel == DACEV1) { cmac_generate_subkeys(&sesskey, MCD_RECEIVE); //key->cmac_sk1 and key->cmac_sk2 //memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); } + dctx->secureChannel = secureChannel; memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)); PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType))); From 003a0b0de4916b85435b3755b2e802008e1e5151 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 5 Jul 2021 12:40:07 +0300 Subject: [PATCH 28/31] splitbysize now put length of message at the first bytes of array's memory --- client/src/cmdhfmfdes.c | 8 ++++---- client/src/mifare/desfirecore.c | 26 ++++++++++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c7a195db5..3560d5bf3 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5298,10 +5298,10 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) { PrintAndLogEx(INFO, "----------------------- " _CYAN_("File list") " -----------------------"); for (int i = 0; i < buflen; i++) PrintAndLogEx(INFO, "AID: %06x ISO file id: %02x%02x ISO DF name[%d]: %s", - DesfireAIDByteToUint(&buf[i * 24]), - buf[i * 24 + 3], buf[i * 24 + 4], - strlen((char *)&buf[i * 24 + 5]), - &buf[i * 24 + 5]); + DesfireAIDByteToUint(&buf[i * 24 + 1]), + buf[i * 24 + 1 + 3], buf[i * 24 + 1 + 4], + strlen((char *)&buf[i * 24 + 1 + 5]), + &buf[i * 24 + 1 + 5]); } DropField(); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index a461fb254..fee49ca5a 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -404,8 +404,14 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8 return res; } - if (resp) - memcpy(resp, buf, buflen); + if (resp) { + if (splitbysize) { + resp[0] = buflen; + memcpy(&resp[1], buf, buflen); + } else { + memcpy(resp, buf, buflen); + } + } if (respcode != NULL) *respcode = rcode; @@ -434,7 +440,8 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8 if (resp != NULL) { if (splitbysize) { - memcpy(&resp[i * splitbysize], buf, buflen); + resp[i * splitbysize] = buflen; + memcpy(&resp[i * splitbysize + 1], buf, buflen); i += 1; } else { memcpy(&resp[pos], buf, buflen); @@ -480,8 +487,14 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t if (respcode != NULL && ((sw & 0xff00) == 0x9100)) *respcode = sw & 0xff; - if (resp) - memcpy(resp, buf, buflen); + if (resp) { + if (splitbysize) { + resp[0] = buflen; + memcpy(&resp[1], buf, buflen); + } else { + memcpy(resp, buf, buflen); + } + } pos += buflen; if (!enable_chaining) { @@ -512,7 +525,8 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t if (resp != NULL) { if (splitbysize) { - memcpy(&resp[i * splitbysize], buf, buflen); + resp[i * splitbysize] = buflen; + memcpy(&resp[i * splitbysize + 1], buf, buflen); i += 1; } else { memcpy(&resp[pos], buf, buflen); From 96d18a1cd7f70c6a8b0fe6644f16631bb5b1f16c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 5 Jul 2021 14:00:51 +0300 Subject: [PATCH 29/31] splitbysize works correctly in the all the cases --- client/src/mifare/desfirecore.c | 52 +++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index fee49ca5a..449f144e2 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -699,6 +699,32 @@ static void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, si } } +// 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; + for(int i = 0; i < blockdatacount; i++) { + memcpy(&dstdata[*dstdatalen], &blockdata[i * blockdatasize + 1], blockdata[i * blockdatasize]); + *dstdatalen += blockdata[i * blockdatasize]; + } +} + +// move data from single data block to blockdata [format: ...] +// lengths in the blockdata is not changed. result - in the blockdata +static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t dstdatalen) { + size_t len = 0; + for(int i = 0; i < *blockdatacount; i++) { + size_t tlen = len + blockdata[i * blockdatasize]; + if (tlen > dstdatalen) + tlen = dstdatalen; + if (len == tlen) { + *blockdatacount = i; + break; + } + memcpy(&blockdata[i * blockdatasize + 1], &dstdata[len], tlen - len); + len = tlen; + } +} + int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) { int res = PM3_SUCCESS; @@ -707,14 +733,28 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin switch(ctx->cmdSet) { case DCCNative: - DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen); - res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); - DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen); - break; case DCCNativeISO: DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen); - res = DesfireExchangeISO(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); - DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen); + + 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); + + if (splitbysize) { + uint8_t sdata[250 * 5] = {0}; + size_t sdatalen = 0; + DesfireJoinBlockToBytes(databuf, databuflen, splitbysize, sdata, &sdatalen); + + //PrintAndLogEx(INFO, "block : %s", sprint_hex(sdata, sdatalen)); + DesfireSecureChannelDecode(ctx, sdata, sdatalen, *respcode, resp, resplen); + + DesfireSplitBytesToBlock(databuf, &databuflen, splitbysize, resp, *resplen); + memcpy(resp, databuf, databuflen * splitbysize); + *resplen = databuflen; + } else { + DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen); + } break; case DCCISO: return PM3_EAPDU_FAIL; From e9b8e1843039d6dbd7479dc4a2cc448cabd02d64 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 5 Jul 2021 14:15:39 +0300 Subject: [PATCH 30/31] remove key_size --- client/src/cmdhfmfdes.c | 6 +++--- client/src/mifare/desfire_crypto.c | 18 ------------------ client/src/mifare/desfire_crypto.h | 1 - client/src/mifare/desfirecore.c | 10 +++++----- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 3560d5bf3..79c770348 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5040,8 +5040,8 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct uint8_t keydata[200] = {0}; if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen)) return PM3_ESOFT; - if (keylen && keylen != key_size(algores)) { - PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), key_size(algores), keylen); + 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) @@ -5133,7 +5133,7 @@ static int CmdHF14ADesDefault(const char *Cmd) { PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum); PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); - PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, key_size(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)); diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index d941ae09e..85abb4c43 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -400,24 +400,6 @@ size_t key_block_size(const desfirekey_t key) { return desfire_get_key_block_length(key->type); } -size_t key_size(const enum DESFIRE_CRYPTOALGO algo) { - switch (algo) { - case T_DES: - return 8; - break; - case T_3DES: - return 16; - break; - case T_3K3DES: - return 24; - break; - case T_AES: - return 16; - break; - } - return 0; -} - /* * Size of MACing produced with the key. */ diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 1aa938017..98f835f4e 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -148,7 +148,6 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); size_t key_block_size(const desfirekey_t key); -size_t key_size(const enum DESFIRE_CRYPTOALGO algo); size_t padded_data_length(const size_t nbytes, const size_t block_size); size_t maced_data_length(const desfirekey_t key, const size_t nbytes); size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 449f144e2..9b80ede51 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -234,9 +234,9 @@ void DesfirePrintContext(DesfireContext *ctx) { PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s", ctx->keyNum, CLIGetOptionListStr(DesfireAlgoOpts, ctx->keyType), - key_size(ctx->keyType), + desfire_get_key_length(ctx->keyType), sprint_hex(ctx->key, - key_size(ctx->keyType))); + desfire_get_key_length(ctx->keyType))); if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen)); @@ -248,9 +248,9 @@ void DesfirePrintContext(DesfireContext *ctx) { if (DesfireIsAuthenticated(ctx)) { PrintAndLogEx(INFO, "Session key MAC [%d]: %s ENC: %s IV [%d]: %s", - key_size(ctx->keyType), - sprint_hex(ctx->sessionKeyMAC, key_size(ctx->keyType)), - sprint_hex(ctx->sessionKeyEnc, key_size(ctx->keyType)), + desfire_get_key_length(ctx->keyType), + sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)), + sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)), desfire_get_key_block_length(ctx->keyType), sprint_hex(ctx->sessionKeyEnc, desfire_get_key_block_length(ctx->keyType))); From d6dc117ed3ac7c55c52a6ea2615f28be05993002 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 5 Jul 2021 14:18:05 +0300 Subject: [PATCH 31/31] mark commands with `new` sign --- client/src/cmdhfmfdes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 79c770348..d141a22b8 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -5311,7 +5311,7 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"}, - {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, + {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "[new]Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"}, {"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"}, @@ -5327,8 +5327,8 @@ static command_t CommandTable[] = { {"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"}, {"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"}, {"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, - {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, - {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, + {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "[new]Get Application IDs list"}, + {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "[new]Get Applications list"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"}, {"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},