diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 21ebf9efd..64dd713a3 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -222,6 +222,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/loclass/hash1_brute.c ${PM3_ROOT}/client/src/loclass/ikeys.c ${PM3_ROOT}/client/src/mifare/mad.c + ${PM3_ROOT}/client/src/mifare/aiddesfire.c ${PM3_ROOT}/client/src/mifare/mfkey.c ${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifaredefault.c @@ -236,7 +237,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/image.ui - ${PM3_ROOT}/client/src/aiddesfire.c ${PM3_ROOT}/client/src/aidsearch.c ${PM3_ROOT}/client/src/cmdanalyse.c ${PM3_ROOT}/client/src/cmdcrc.c diff --git a/client/Makefile b/client/Makefile index 51f7cb2df..bcdfb7140 100644 --- a/client/Makefile +++ b/client/Makefile @@ -474,7 +474,7 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@ # enumerations # ################ -SRCS = aiddesfire.c \ +SRCS = mifare/aiddesfire.c \ aidsearch.c \ cmdanalyse.c \ cmdcrc.c \ diff --git a/client/src/aiddesfire.c b/client/src/aiddesfire.c deleted file mode 100644 index b628ea072..000000000 --- a/client/src/aiddesfire.c +++ /dev/null @@ -1,133 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// AID DESFire functions -//----------------------------------------------------------------------------- - -#include "aiddesfire.h" -#include "pm3_cmd.h" -#include "fileutils.h" -#include "jansson.h" - -static json_t *df_known_aids = NULL; - -static int open_aiddf_file(json_t **root, bool verbose) { - - char *path; - int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true); - if (res != PM3_SUCCESS) { - return PM3_EFILE; - } - - int retval = PM3_SUCCESS; - json_error_t error; - - *root = json_load_file(path, 0, &error); - if (!*root) { - PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text); - retval = PM3_ESOFT; - goto out; - } - - if (!json_is_array(*root)) { - PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path); - retval = PM3_ESOFT; - goto out; - } - - if (verbose) - PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root)); -out: - free(path); - return retval; -} - -static int close_aiddf_file(json_t *root) { - json_decref(root); - return PM3_SUCCESS; -} - -static const char *aiddf_json_get_str(json_t *data, const char *name) { - - json_t *jstr = json_object_get(data, name); - if (jstr == NULL) - return NULL; - - if (!json_is_string(jstr)) { - PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); - return NULL; - } - - const char *cstr = json_string_value(jstr); - if (strlen(cstr) == 0) - return NULL; - - return cstr; -} - -static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { - char laid[7] = {0}; - sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase - - json_t *elm = NULL; - - for (uint32_t idx = 0; idx < json_array_size(root); idx++) { - json_t *data = json_array_get(root, idx); - if (!json_is_object(data)) { - PrintAndLogEx(ERR, "data [%d] is not an object\n", idx); - continue; - } - const char *faid = aiddf_json_get_str(data, "AID"); - char lfaid[strlen(faid) + 1]; - strcpy(lfaid, faid); - str_lower(lfaid); - if (strcmp(laid, lfaid) == 0) { - elm = data; - break; - } - } - - if (elm == NULL) { - PrintAndLogEx(INFO, fmt, " (unknown)"); - return PM3_ENODATA; - } - const char *vaid = aiddf_json_get_str(elm, "AID"); - const char *vendor = aiddf_json_get_str(elm, "Vendor"); - const char *country = aiddf_json_get_str(elm, "Country"); - const char *name = aiddf_json_get_str(elm, "Name"); - const char *description = aiddf_json_get_str(elm, "Description"); - const char *type = aiddf_json_get_str(elm, "Type"); - - if (name && vendor) { - char result[5 + strlen(name) + strlen(vendor)]; - sprintf(result, " %s [%s]", name, vendor); - PrintAndLogEx(INFO, fmt, result); - } - - if (verbose) { - PrintAndLogEx(SUCCESS, " AID: %s", vaid); - if (name) - PrintAndLogEx(SUCCESS, " Name: %s", name); - if (description) - PrintAndLogEx(SUCCESS, " Description: %s", description); - if (type) - PrintAndLogEx(SUCCESS, " Type: %s", type); - if (vendor) - PrintAndLogEx(SUCCESS, " Vendor: %s", vendor); - if (country) - PrintAndLogEx(SUCCESS, " Country: %s", country); - } - return PM3_SUCCESS; -} - -int AIDDFDecodeAndPrint(uint8_t aid[3]) { - open_aiddf_file(&df_known_aids, false); - - char fmt[80]; - sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s"); - print_aiddf_description(df_known_aids, aid, fmt, false); - close_aiddf_file(df_known_aids); - return PM3_SUCCESS; -} diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e93531403..83e3bf904 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -38,7 +38,7 @@ #include "nfc/ndef.h" // NDEF #include "mifare/mad.h" #include "generator.h" -#include "aiddesfire.h" +#include "mifare/aiddesfire.h" #include "util.h" #define MAX_KEY_LEN 24 @@ -146,202 +146,6 @@ typedef enum { MFDES_VALUE_FILE } MFDES_FILE_TYPE_T; -// NXP Appnote AN10787 - Application Directory (MAD) -typedef enum { - CL_ADMIN = 0, - CL_MISC1, - CL_MISC2, - CL_MISC3, - CL_MISC4, - CL_MISC5, - CL_MISC6, - CL_MISC7, - CL_AIRLINES = 8, - CL_FERRY, - CL_RAIL, - CL_MISC, - CL_TRANSPORT, - CL_SECURITY = 0x14, - CL_CITYTRAFFIC = 0x18, - CL_CZECH_RAIL, - CL_BUS, - CL_MMT, - CL_TAXI = 0x28, - CL_TOLL = 0x30, - CL_GENERIC_TRANS, - CL_COMPANY_SERVICES = 0x38, - CL_CITYCARD = 0x40, - CL_ACCESS_CONTROL_1 = 0x47, - CL_ACCESS_CONTROL_2, - CL_VIGIK = 0x49, - CL_NED_DEFENCE = 0x4A, - CL_BOSCH_TELECOM = 0x4B, - CL_EU = 0x4C, - CL_SKI_TICKET = 0x50, - CL_SOAA = 0x55, - CL_ACCESS2 = 0x56, - CL_FOOD = 0x60, - CL_NONFOOD = 0x68, - CL_HOTEL = 0x70, - CL_LOYALTY = 0x71, - CL_AIRPORT = 0x75, - CL_CAR_RENTAL = 0x78, - CL_NED_GOV = 0x79, - CL_ADMIN2 = 0x80, - CL_PURSE = 0x88, - CL_TV = 0x90, - CL_CRUISESHIP = 0x91, - CL_IOPTA = 0x95, - CL_METERING = 0x97, - CL_TELEPHONE = 0x98, - CL_HEALTH = 0xA0, - CL_WAREHOUSE = 0xA8, - CL_BANKING = 0xB8, - CL_ENTERTAIN = 0xC0, - CL_PARKING = 0xC8, - CL_FLEET = 0xC9, - CL_FUEL = 0xD0, - CL_INFO = 0xD8, - CL_PRESS = 0xE0, - CL_NFC = 0xE1, - CL_COMPUTER = 0xE8, - CL_MAIL = 0xF0, - CL_AMISC = 0xF8, - CL_AMISC1 = 0xF9, - CL_AMISC2 = 0xFA, - CL_AMISC3 = 0xFB, - CL_AMISC4 = 0xFC, - CL_AMISC5 = 0xFD, - CL_AMISC6 = 0xFE, - CL_AMISC7 = 0xFF, -} aidcluster_h; - -static const char *cluster_to_text(uint8_t cluster) { - switch (cluster) { - case CL_ADMIN: - return "card administration"; - case CL_MISC1: - case CL_MISC2: - case CL_MISC3: - case CL_MISC4: - case CL_MISC5: - case CL_MISC6: - case CL_MISC7: - return "miscellaneous applications"; - case CL_AIRLINES: - return "airlines"; - case CL_FERRY: - return "ferry traffic"; - case CL_RAIL: - return "railway services"; - case CL_MISC: - return "miscellaneous applications"; - case CL_TRANSPORT: - return "transport"; - case CL_SECURITY: - return "security solutions"; - case CL_CITYTRAFFIC: - return "city traffic"; - case CL_CZECH_RAIL: - return "Czech Railways"; - case CL_BUS: - return "bus services"; - case CL_MMT: - return "multi modal transit"; - case CL_TAXI: - return "taxi"; - case CL_TOLL: - return "road toll"; - case CL_GENERIC_TRANS: - return "generic transport"; - case CL_COMPANY_SERVICES: - return "company services"; - case CL_CITYCARD: - return "city card services"; - case CL_ACCESS_CONTROL_1: - case CL_ACCESS_CONTROL_2: - return "access control & security"; - case CL_VIGIK: - return "VIGIK"; - case CL_NED_DEFENCE: - return "Ministry of Defence, Netherlands"; - case CL_BOSCH_TELECOM: - return "Bosch Telecom, Germany"; - case CL_EU: - return "European Union Institutions"; - case CL_SKI_TICKET: - return "ski ticketing"; - case CL_SOAA: - return "SOAA standard for offline access standard"; - case CL_ACCESS2: - return "access control & security"; - case CL_FOOD: - return "food"; - case CL_NONFOOD: - return "non-food trade"; - case CL_HOTEL: - return "hotel"; - case CL_LOYALTY: - return "loyalty"; - case CL_AIRPORT: - return "airport services"; - case CL_CAR_RENTAL: - return "car rental"; - case CL_NED_GOV: - return "Dutch government"; - case CL_ADMIN2: - return "administration services"; - case CL_PURSE: - return "electronic purse"; - case CL_TV: - return "television"; - case CL_CRUISESHIP: - return "cruise ship"; - case CL_IOPTA: - return "IOPTA"; - case CL_METERING: - return "metering"; - case CL_TELEPHONE: - return "telephone"; - case CL_HEALTH: - return "health services"; - case CL_WAREHOUSE: - return "warehouse"; - case CL_BANKING: - return "banking"; - case CL_ENTERTAIN: - return "entertainment & sports"; - case CL_PARKING: - return "car parking"; - case CL_FLEET: - return "fleet management"; - case CL_FUEL: - return "fuel, gasoline"; - case CL_INFO: - return "info services"; - case CL_PRESS: - return "press"; - case CL_NFC: - return "NFC Forum"; - case CL_COMPUTER: - return "computer"; - case CL_MAIL: - return "mail"; - case CL_AMISC: - case CL_AMISC1: - case CL_AMISC2: - case CL_AMISC3: - case CL_AMISC4: - case CL_AMISC5: - case CL_AMISC6: - case CL_AMISC7: - return "miscellaneous applications"; - default: - break; - } - return "reserved"; -} - typedef enum { DESFIRE_UNKNOWN = 0, DESFIRE_MF3ICD40, @@ -916,87 +720,6 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp return PM3_SUCCESS; } -// -- test if card supports 0x0A -static int test_desfire_authenticate(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// -- test if card supports 0x1A -static int test_desfire_authenticate_iso(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// -- test if card supports 0xAA -static int test_desfire_authenticate_aes(void) { - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false); - if (res == PM3_SUCCESS) - if (sw == status(MFDES_ADDITIONAL_FRAME)) { - DropFieldDesfire(); - return res; - } - return res; -} - -// --- GET FREE MEM -static int desfire_print_freemem(uint32_t free_mem) { - PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem); - return PM3_SUCCESS; -} - -static int handler_desfire_freemem(uint32_t *free_mem) { - if (free_mem == NULL) return PM3_EINVARG; - - uint8_t data[] = {0x00}; - sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, data}; // 0x6E - *free_mem = 0; - uint32_t recv_len = 0; - uint16_t sw = 0; - uint8_t fmem[4] = {0}; - - size_t plen = apdu.Lc; - uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND); - apdu.Lc = (uint8_t)plen; - apdu.data = p; - - int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS) - return res; - - size_t dlen = recv_len; - p = mifare_cryto_postprocess_data(tag, apdu.data, &dlen, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); - (void)p; - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - *free_mem = le24toh(fmem); - return res; -} - /*static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) { if (new_key == NULL || old_key == NULL) { @@ -1289,155 +1012,6 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat return PM3_SUCCESS; } -static int handler_desfire_signature(uint8_t *signature, size_t *signature_len) { - - if (signature == NULL) { - PrintAndLogEx(DEBUG, "SIGNATURE=NULL"); - return PM3_EINVARG; - } - if (signature_len == NULL) { - PrintAndLogEx(DEBUG, "SIGNATURE_LEN=NULL"); - return PM3_EINVARG; - } - - uint8_t c[] = {0x00}; - sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, sizeof(c), c}; // 0x3C - - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true); - if (res == PM3_SUCCESS) { - if (recv_len != 56) { - *signature_len = 0; - res = PM3_ESOFT; - } else { - *signature_len = recv_len; - } - } - DropFieldDesfire(); - return res; -} - -// --- KEY VERSION -static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) { - PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version); - return PM3_SUCCESS; -} - -static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { - if (num_versions == NULL) { - PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL"); - return PM3_EINVARG; - } - sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS) - return res; - - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - return res; -} - -// --- KEY SETTING Application Master Key -static int desfire_print_amk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { - PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings); - // 2 MSB denotes - const char *str = " Max key number and type : %d, " _YELLOW_("%s"); - - if (algo == MFDES_ALGO_DES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES"); - else if (algo == MFDES_ALGO_AES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES"); - else if (algo == MFDES_ALGO_3K3DES) - PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES"); - - //PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(SUCCESS, " Changekey Access rights"); - - // Access rights. - uint8_t rights = ((key_settings >> 4) & 0x0F); - switch (rights) { - case 0x0: - PrintAndLogEx(SUCCESS, " -- AMK authentication is necessary to change any key (default)"); - break; - case 0xE: - PrintAndLogEx(SUCCESS, " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key"); - break; - case 0xF: - PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen"); - break; - default: - PrintAndLogEx(SUCCESS, - " -- Authentication with the specified key is necessary to change any key.\n" - "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n" - "For keys other then the master or change key, an authentication with the same key is needed." - ); - break; - } - - PrintAndLogEx(SUCCESS, " [%c...] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, " [.%c..] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [...%c] AMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); - return PM3_SUCCESS; -} - -// --- KEY SETTING PICC Master Key (CMK) -static int desfire_print_piccmk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { - //PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings")); - // number of Master keys (0x01) - PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); - const char *str = " Operation of PICC master key : " _YELLOW_("%s"); - - if (algo == MFDES_ALGO_DES) - PrintAndLogEx(SUCCESS, str, "(3)DES"); - else if (algo == MFDES_ALGO_AES) - PrintAndLogEx(SUCCESS, str, "AES"); - else if (algo == MFDES_ALGO_3K3DES) - PrintAndLogEx(SUCCESS, str, "3K3DES"); - - uint8_t cmk_num_versions = 0; - if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions); - } - - PrintAndLogEx(INFO, " ----------------------------------------------------------"); - - // Authentication tests - int res = test_desfire_authenticate(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_iso(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_aes(); - if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, " Key setting: 0x%02X [%c%c%c%c]", - key_settings, - (key_settings & (1 << 3)) ? '1' : '0', - (key_settings & (1 << 2)) ? '1' : '0', - (key_settings & (1 << 1)) ? '1' : '0', - (key_settings & (1 << 0)) ? '1' : '0' - ); - - PrintAndLogEx(SUCCESS, " [%c...] CMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, " [.%c..] CMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with CMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, " [...%c] CMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); - return PM3_SUCCESS; -} - static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_keys) { if (key_settings == NULL) { PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL"); @@ -1490,33 +1064,6 @@ static int handler_desfire_appids(uint8_t *dest, uint32_t *app_ids_len) { return res; } -// --- GET DF NAMES -static int handler_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) { - - if (g_debugMode > 1) { - if (dest == NULL) PrintAndLogEx(ERR, "DEST = NULL"); - if (dfname_count == NULL) PrintAndLogEx(ERR, "DFNAME_COUNT = NULL"); - } - - if (dest == NULL || dfname_count == NULL) - return PM3_EINVARG; - - *dfname_count = 0; - sAPDU apdu = {0x90, MFDES_GET_DF_NAMES, 0x00, 0x00, 0x00, NULL}; //0x6d - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true); - if (res != PM3_SUCCESS) { - return res; - } - - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - *dfname_count = recv_len; - return res; -} - static int handler_desfire_select_application(uint8_t *aid) { if (g_debugMode > 1) { if (aid == NULL) { @@ -1545,28 +1092,6 @@ static int handler_desfire_select_application(uint8_t *aid) { return PM3_SUCCESS; } -static int key_setting_to_algo(uint8_t aid[3], uint8_t *key_setting, mifare_des_authalgo_t *algo, uint8_t *num_keys) { - int res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - *num_keys = 0; - res = handler_desfire_getkeysettings(key_setting, num_keys); - if (res == PM3_SUCCESS) { - switch (*num_keys >> 6) { - case 0: - *algo = MFDES_ALGO_DES; - break; - case 1: - *algo = MFDES_ALGO_3K3DES; - break; - case 2: - *algo = MFDES_ALGO_AES; - break; - } - } - return res; -} - static int handler_desfire_fileids(uint8_t *dest, uint32_t *file_ids_len) { if (g_debugMode > 1) { if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); @@ -1605,70 +1130,6 @@ static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t return res; } -static int getKeySettings(uint8_t *aid) { - if (aid == NULL) return PM3_EINVARG; - - uint8_t num_keys = 0; - uint8_t key_setting = 0; - int res = 0; - if (memcmp(aid, "\x00\x00\x00", 3) == 0) { - - // CARD MASTER KEY - //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); - - // KEY Settings - AMK - mifare_des_authalgo_t algo = MFDES_ALGO_DES; - res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); - - if (res == PM3_SUCCESS) { - desfire_print_piccmk_keysetting(key_setting, num_keys, algo); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read PICC Master key settings")); - } - - } else { - - // AID - APPLICATION MASTER KEYS - //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); - res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - // KEY Settings - AMK - mifare_des_authalgo_t algo = MFDES_ALGO_DES; - res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); - if (res == PM3_SUCCESS) { - desfire_print_amk_keysetting(key_setting, num_keys, algo); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); - } - - // KEY VERSION - AMK - uint8_t num_version = 0; - if (handler_desfire_keyversion(0, &num_version) == PM3_SUCCESS) { - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, " Application keys"); - desfire_print_keyversion(0, num_version); - } else { - PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys"); - } - - // From 0x01 to numOfKeys. We already got 0x00. (AMK) - num_keys &= 0x3F; - if (num_keys > 1) { - for (uint8_t i = 0x01; i < num_keys; ++i) { - if (handler_desfire_keyversion(i, &num_version) == PM3_SUCCESS) { - desfire_print_keyversion(i, num_version); - } else { - PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i); - } - } - } - } - - DropFieldDesfire(); - return PM3_SUCCESS; -} - static void swap24(uint8_t *data) { if (data == NULL) return; uint8_t tmp = data[0]; @@ -1794,7 +1255,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - DropFieldDesfire(); + DropField(); mfdes_info_res_t info; int res = mfdes_get_info(&info); @@ -1809,8 +1270,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "---------------------------------- " _CYAN_("Tag Information") " ----------------------------------"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen)); PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5)); PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]); @@ -1835,7 +1295,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionSW[6], false)); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities")); + PrintAndLogEx(INFO, "--------------------------------- " _CYAN_("Card capabilities") " ---------------------------------"); uint8_t major = info.versionSW[3]; uint8_t minor = info.versionSW[4]; if (major == 0 && minor == 4) @@ -1855,40 +1315,67 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (major == 0 && minor == 2) PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); - + + DesfireContext dctx = {0}; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCNative; + res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0); + if (res != PM3_SUCCESS) + return res; + + PICCInfoS PICCInfo = {0}; + + uint8_t aidbuf[250] = {0}; + size_t aidbuflen = 0; + res = DesfireGetAIDList(&dctx, aidbuf, &aidbuflen); + if (res == PM3_SUCCESS) { + PICCInfo.appCount = aidbuflen / 3; + } + if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3 || cardtype == NTAG413DNA) { // Signature originality check - uint8_t signature[56] = {0}; + uint8_t signature[250] = {0}; // must be 56 size_t signature_len = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); - if (handler_desfire_signature(signature, &signature_len) == PM3_SUCCESS) { - desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype); + res = DesfireReadSignature(&dctx, 0x00, signature, &signature_len); + if (res == PM3_SUCCESS) { + if (signature_len == 56) + desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype); + else + PrintAndLogEx(WARNING, "--- GetSignature returned wrong signature length: %zu", signature_len); } else { PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd"); } } - - // Master Key settings - uint8_t master_aid[3] = {0x00, 0x00, 0x00}; - getKeySettings(master_aid); + + if (aidbuflen > 2) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list")); + PrintAndLogEx(SUCCESS, "AIDs: " NOLF); + for (int i = 0; i < aidbuflen; i += 3) + PrintAndLogEx(NORMAL, "%s %06x" NOLF, (i == 0) ? "" : ",", DesfireAIDByteToUint(&aidbuf[i])); + PrintAndLogEx(NORMAL, "\n"); + } + + DesfireFillPICCInfo(&dctx, &PICCInfo, true); + DesfirePrintPICCInfo(&dctx, &PICCInfo); if (cardtype != DESFIRE_LIGHT) { // Free memory on card PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Free memory")); - uint32_t free_mem = 0; - if (handler_desfire_freemem(&free_mem) == PM3_SUCCESS) { - desfire_print_freemem(free_mem); + if (PICCInfo.freemem != 0xffffffff) { + PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), PICCInfo.freemem); } else { PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); } + PrintAndLogEx(NORMAL, ""); iso14a_card_select_t card; @@ -1931,239 +1418,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { */ - DropFieldDesfire(); - return PM3_SUCCESS; -} - -static void DecodeFileType(uint8_t filetype) { - switch (filetype) { - case 0x00: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Standard Data File", filetype); - break; - case 0x01: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Backup Data File", filetype); - break; - case 0x02: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Value Files with Backup", filetype); - break; - case 0x03: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Linear Record Files with Backup", filetype); - break; - case 0x04: - PrintAndLogEx(INFO, " File Type: 0x%02X -> Cyclic Record Files with Backup", filetype); - break; - default: - PrintAndLogEx(INFO, " File Type: 0x%02X", filetype); - break; - } -} - -static void DecodeComSet(uint8_t comset) { - switch (comset) { - case 0x00: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain", comset); - break; - case 0x01: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain + MAC", comset); - break; - case 0x03: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Enciphered", comset); - break; - default: - PrintAndLogEx(INFO, " Com.Setting: 0x%02X", comset); - break; - } -} - -static char *DecodeAccessValue(uint8_t value) { - - char *car = (char *)calloc(255, sizeof(char)); - if (car == NULL) - return NULL; - - switch (value) { - case 0xE: - strcat(car, "(Free Access)"); - break; - case 0xF: - strcat(car, "(Denied Access)"); - break; - default: - snprintf(car, 255, "(Access Key: %d)", value); - break; - } - return car; -} - -static void DecodeAccessRights(uint16_t accrights) { - int change_access_rights = accrights & 0xF; - int read_write_access = (accrights >> 4) & 0xF; - int write_access = (accrights >> 8) & 0xF; - int read_access = (accrights >> 12) & 0xF; - char *car = DecodeAccessValue(change_access_rights); - if (car == NULL) return; - - char *rwa = DecodeAccessValue(read_write_access); - if (rwa == NULL) { - free(car); - return; - } - - char *wa = DecodeAccessValue(write_access); - if (wa == NULL) { - free(car); - free(rwa); - return; - } - - char *ra = DecodeAccessValue(read_access); - if (ra == NULL) { - free(car); - free(rwa); - free(wa); - return; - } - - PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra); - free(car); - free(rwa); - free(wa); - free(ra); -} - -static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) { - uint8_t filetype = src[0]; - uint8_t comset = src[1]; - - uint16_t accrights = (src[3] << 8) + src[2]; - if (src_len == 1 + 1 + 2 + 3 + maclen) { - int filesize = (src[6] << 16) + (src[5] << 8) + src[4]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Filesize: %d (0x%X)", filesize, filesize); - return PM3_SUCCESS; - } else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) { - int lowerlimit = (src[7] << 24) + (src[6] << 16) + (src[5] << 8) + src[4]; - int upperlimit = (src[11] << 24) + (src[10] << 16) + (src[9] << 8) + src[8]; - int limitcredvalue = (src[15] << 24) + (src[14] << 16) + (src[13] << 8) + src[12]; - uint8_t limited_credit_enabled = src[17]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Lower limit: %d (0x%X) - Upper limit: %d (0x%X) - limited credit value: %d (0x%X) - limited credit enabled: %d", lowerlimit, lowerlimit, upperlimit, upperlimit, limitcredvalue, limitcredvalue, limited_credit_enabled); - return PM3_SUCCESS; - } else if (src_len == 1 + 1 + 2 + 3 + 3 + 3 + maclen) { - uint32_t recordsize = (src[6] << 16) + (src[5] << 8) + src[4]; - uint32_t maxrecords = (src[9] << 16) + (src[8] << 8) + src[7]; - uint32_t currentrecord = (src[12] << 16) + (src[11] << 8) + src[10]; - DecodeFileType(filetype); - DecodeComSet(comset); - DecodeAccessRights(accrights); - PrintAndLogEx(INFO, " Record size: %d (0x%X) - MaxNumberRecords: %d (0x%X) - Current Number Records: %d (0x%X)", recordsize, recordsize, maxrecords, maxrecords, currentrecord, currentrecord); - return PM3_SUCCESS; - } - return PM3_ESOFT; -} - -static int CmdHF14ADesEnumApplications(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes enum", - "Enumerate all AID's on MIFARE DESfire tag", - "hf mfdes enum"); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - DropFieldDesfire(); - - uint8_t aid[3] = {0}; - uint8_t app_ids[78] = {0}; - uint32_t app_ids_len = 0; - - uint8_t file_ids[33] = {0}; - uint32_t file_ids_len = 0; - - dfname_t dfnames[255]; - uint8_t dfname_count = 0; - - if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Can't get list of applications on tag"); - DropFieldDesfire(); - return PM3_ESOFT; - } - - if (handler_desfire_dfnames(dfnames, &dfname_count) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_("Can't get DF Names")); - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-- MIFARE DESFire Enumerate applications --------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's'); - - for (uint32_t i = 0; i < app_ids_len; i += 3) { - - aid[0] = app_ids[i]; - aid[1] = app_ids[i + 1]; - aid[2] = app_ids[i + 2]; - - PrintAndLogEx(NORMAL, ""); - - if (memcmp(aid, "\x00\x00\x00", 3) == 0) { - // CARD MASTER KEY - PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); - } else { - PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); - } - - PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]); - if ((aid[2] >> 4) == 0xF) { - uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); - PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); - MADDFDecodeAndPrint(short_aid); - } else { - AIDDFDecodeAndPrint(aid); - } - for (uint8_t m = 0; m < dfname_count; m++) { - if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) { - PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name); - } - } - - int res = getKeySettings(aid); - if (res != PM3_SUCCESS) continue; - - res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) continue; - - res = handler_desfire_fileids(file_ids, &file_ids_len); - if (res != PM3_SUCCESS) continue; - - PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's'); - for (int j = (int)file_ids_len - 1; j >= 0; j--) { - PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[j], file_ids[j]); - - uint8_t filesettings[20] = {0}; - uint32_t fileset_len = 0; - uint32_t maclen = 0; // To be implemented - - res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len); - if (res != PM3_SUCCESS) continue; - - if (DecodeFileSettings(filesettings, fileset_len, maclen) != PM3_SUCCESS) { - PrintAndLogEx(INFO, " Settings [%u] %s", fileset_len, sprint_hex(filesettings, fileset_len)); - } - } - - } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - DropFieldDesfire(); + DropField(); return PM3_SUCCESS; } @@ -2849,29 +2104,6 @@ static int CmdHF14aDesMAD(const char *Cmd) { } */ -/*static int CmdTest(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - uint8_t IV[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t key[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - uint8_t encRndB[8] = {0x1A, 0xBE, 0x10, 0x8D, 0x09, 0xE0, 0x18, 0x13}; - uint8_t RndB[8] = {0}; - uint8_t RndA[8] = {0x6E, 0x6A, 0xEB, 0x86, 0x6E, 0x6A, 0xEB, 0x86}; - tdes_nxp_receive(encRndB, RndB, 8, key, IV, 2); - uint8_t rotRndB[8] = {0}; - memcpy(rotRndB, RndB, 8); - rol(rotRndB, 8); - uint8_t tmp[16] = {0x00}; - uint8_t both[16] = {0x00}; - memcpy(tmp, RndA, 8); - memcpy(tmp + 8, rotRndB, 8); - PrintAndLogEx(INFO, "3keyenc: %s", sprint_hex(tmp, 16)); - PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(IV, 8)); - tdes_nxp_send(tmp, both, 16, key, IV, 2); - PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(both, 16)); - return PM3_SUCCESS; -} -*/ static uint8_t defaultKeyNum = 0; static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES; static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; @@ -6164,19 +5396,76 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { return res; } - PrintAndLogEx(INFO, "---------------------------- " _CYAN_("File list") " -----------------------(r w rw ch)-----"); - for (int i = 0; i < filescount; i++) { - PrintAndLogEx(SUCCESS, "ID: " _GREEN_("%02x ") NOLF, FileList[i].fileNum); - if (isopresent) { - if (FileList[i].fileISONum != 0) - PrintAndLogEx(NORMAL, "ISO ID: " _CYAN_("%04x ") NOLF, FileList[i].fileISONum); - else - PrintAndLogEx(NORMAL, "ISO ID: " _YELLOW_("n/a ") NOLF); - } + PrintAndLogEx(INFO, "------------------------------------------ " _CYAN_("File list") " -----------------------------------------------------"); + for (int i = 0; i < filescount; i++) + DesfirePrintFileSettingsTable((i == 0), FileList[i].fileNum, isopresent, FileList[i].fileISONum, &FileList[i].fileSettings); - DesfirePrintFileSettingsOneLine(&FileList[i].fileSettings); + DropField(); + return PM3_SUCCESS; +} + +static int CmdHF14ADesLsApp(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes lsapp", + "Show application list. Master key needs to be provided or flag --no-auth set (depend on cards settings).", + "hf mfdes lsapp -> show application list with defaults from `default` command\n" + "hf mfdes lsapp --files -> show application list and show each file type/settings/etc for each application"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Communicaton mode: plain/mac/encrypt"), + arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), + arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), + arg_lit0(NULL, "no-auth", "execute without authentication"), + arg_lit0(NULL, "no-deep", "not to check authentication commands that avail for any application"), + arg_lit0(NULL, "files", "scan files and print file settings for each application"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + bool noauth = arg_get_lit(ctx, 11); + bool nodeep = arg_get_lit(ctx, 12); + bool scanfiles = arg_get_lit(ctx, 13); + + DesfireContext dctx; + int securechann = defaultSecureChannel; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMPlain, NULL); + if (res) { + CLIParserFree(ctx); + return res; } + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + + PrintAndLogEx(INPLACE, _YELLOW_("It may take up to 15 seconds. Processing....")); + + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + PICCInfoS PICCInfo = {0}; + AppListS AppList = {0}; + DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles); + + printf("\33[2K\r"); // clear current line before printing + PrintAndLogEx(NORMAL, ""); + + // print zone + DesfirePrintPICCInfo(&dctx, &PICCInfo); + DesfirePrintAppList(&dctx, &PICCInfo, AppList); + DropField(); return PM3_SUCCESS; } @@ -6239,16 +5528,7 @@ static int CmdHF14ADesDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Application " _CYAN_("%06x") " have " _GREEN_("%zu") " files", appid, filescount); - uint8_t aid[3] = {0}; - DesfireAIDUintToByte(appid, aid); - if ((aid[2] >> 4) == 0xF) { - uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); - PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); - PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8)); - MADDFDecodeAndPrint(short_aid); - } else { - AIDDFDecodeAndPrint(aid); - } + DesfirePrintAIDFunctions(appid); if (filescount == 0) { PrintAndLogEx(INFO, "There is no files in the application %06x", appid); @@ -6293,30 +5573,30 @@ static int CmdHF14ADesTest(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"}, + {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"}, + {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get uid from card"}, {"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "MIFARE DesFire Authentication"}, {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "[old]Check keys"}, - {"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "[old]Tries enumerate all applications"}, - {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"freemem", CmdHF14ADesGetFreeMem, IfPm3Iso14443a, "Get free memory size"}, - {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get uid from card"}, {"setconfig", CmdHF14ADesSetConfiguration, IfPm3Iso14443a, "Set card configuration"}, - {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "[old]Tag information"}, + {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"}, // {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, + {"lsapp", CmdHF14ADesLsApp, IfPm3Iso14443a, "Show all applications with files list"}, + {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, + {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, + {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, + {"createapp", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application"}, + {"deleteapp", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application"}, + {"selectapp", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, {"-----------", CmdHelp, IfPm3Iso14443a, "------------------------ " _CYAN_("Keys") " -----------------------"}, {"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"}, {"chkeysettings", CmdHF14ADesChKeySettings, IfPm3Iso14443a, "Change Key Settings"}, {"getkeysettings", CmdHF14ADesGetKeySettings, IfPm3Iso14443a, "Get Key Settings"}, {"getkeyversions", CmdHF14ADesGetKeyVersions, IfPm3Iso14443a, "Get Key Versions"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, - {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, - {"createapp", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application"}, - {"deleteapp", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application"}, - {"selectapp", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, - {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, - {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"getfileids", CmdHF14ADesGetFileIDs, IfPm3Iso14443a, "Get File IDs list"}, {"getfileisoids", CmdHF14ADesGetFileISOIDs, IfPm3Iso14443a, "Get File ISO IDs list"}, diff --git a/client/src/mifare/aiddesfire.c b/client/src/mifare/aiddesfire.c new file mode 100644 index 000000000..0957fe6b3 --- /dev/null +++ b/client/src/mifare/aiddesfire.c @@ -0,0 +1,329 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// AID DESFire functions +//----------------------------------------------------------------------------- + +#include "aiddesfire.h" +#include "pm3_cmd.h" +#include "fileutils.h" +#include "jansson.h" + +// NXP Appnote AN10787 - Application Directory (MAD) +typedef enum { + CL_ADMIN = 0, + CL_MISC1, + CL_MISC2, + CL_MISC3, + CL_MISC4, + CL_MISC5, + CL_MISC6, + CL_MISC7, + CL_AIRLINES = 8, + CL_FERRY, + CL_RAIL, + CL_MISC, + CL_TRANSPORT, + CL_SECURITY = 0x14, + CL_CITYTRAFFIC = 0x18, + CL_CZECH_RAIL, + CL_BUS, + CL_MMT, + CL_TAXI = 0x28, + CL_TOLL = 0x30, + CL_GENERIC_TRANS, + CL_COMPANY_SERVICES = 0x38, + CL_CITYCARD = 0x40, + CL_ACCESS_CONTROL_1 = 0x47, + CL_ACCESS_CONTROL_2, + CL_VIGIK = 0x49, + CL_NED_DEFENCE = 0x4A, + CL_BOSCH_TELECOM = 0x4B, + CL_EU = 0x4C, + CL_SKI_TICKET = 0x50, + CL_SOAA = 0x55, + CL_ACCESS2 = 0x56, + CL_FOOD = 0x60, + CL_NONFOOD = 0x68, + CL_HOTEL = 0x70, + CL_LOYALTY = 0x71, + CL_AIRPORT = 0x75, + CL_CAR_RENTAL = 0x78, + CL_NED_GOV = 0x79, + CL_ADMIN2 = 0x80, + CL_PURSE = 0x88, + CL_TV = 0x90, + CL_CRUISESHIP = 0x91, + CL_IOPTA = 0x95, + CL_METERING = 0x97, + CL_TELEPHONE = 0x98, + CL_HEALTH = 0xA0, + CL_WAREHOUSE = 0xA8, + CL_BANKING = 0xB8, + CL_ENTERTAIN = 0xC0, + CL_PARKING = 0xC8, + CL_FLEET = 0xC9, + CL_FUEL = 0xD0, + CL_INFO = 0xD8, + CL_PRESS = 0xE0, + CL_NFC = 0xE1, + CL_COMPUTER = 0xE8, + CL_MAIL = 0xF0, + CL_AMISC = 0xF8, + CL_AMISC1 = 0xF9, + CL_AMISC2 = 0xFA, + CL_AMISC3 = 0xFB, + CL_AMISC4 = 0xFC, + CL_AMISC5 = 0xFD, + CL_AMISC6 = 0xFE, + CL_AMISC7 = 0xFF, +} aidcluster_h; + +const char *nxp_cluster_to_text(uint8_t cluster) { + switch (cluster) { + case CL_ADMIN: + return "card administration"; + case CL_MISC1: + case CL_MISC2: + case CL_MISC3: + case CL_MISC4: + case CL_MISC5: + case CL_MISC6: + case CL_MISC7: + return "miscellaneous applications"; + case CL_AIRLINES: + return "airlines"; + case CL_FERRY: + return "ferry traffic"; + case CL_RAIL: + return "railway services"; + case CL_MISC: + return "miscellaneous applications"; + case CL_TRANSPORT: + return "transport"; + case CL_SECURITY: + return "security solutions"; + case CL_CITYTRAFFIC: + return "city traffic"; + case CL_CZECH_RAIL: + return "Czech Railways"; + case CL_BUS: + return "bus services"; + case CL_MMT: + return "multi modal transit"; + case CL_TAXI: + return "taxi"; + case CL_TOLL: + return "road toll"; + case CL_GENERIC_TRANS: + return "generic transport"; + case CL_COMPANY_SERVICES: + return "company services"; + case CL_CITYCARD: + return "city card services"; + case CL_ACCESS_CONTROL_1: + case CL_ACCESS_CONTROL_2: + return "access control & security"; + case CL_VIGIK: + return "VIGIK"; + case CL_NED_DEFENCE: + return "Ministry of Defence, Netherlands"; + case CL_BOSCH_TELECOM: + return "Bosch Telecom, Germany"; + case CL_EU: + return "European Union Institutions"; + case CL_SKI_TICKET: + return "ski ticketing"; + case CL_SOAA: + return "SOAA standard for offline access standard"; + case CL_ACCESS2: + return "access control & security"; + case CL_FOOD: + return "food"; + case CL_NONFOOD: + return "non-food trade"; + case CL_HOTEL: + return "hotel"; + case CL_LOYALTY: + return "loyalty"; + case CL_AIRPORT: + return "airport services"; + case CL_CAR_RENTAL: + return "car rental"; + case CL_NED_GOV: + return "Dutch government"; + case CL_ADMIN2: + return "administration services"; + case CL_PURSE: + return "electronic purse"; + case CL_TV: + return "television"; + case CL_CRUISESHIP: + return "cruise ship"; + case CL_IOPTA: + return "IOPTA"; + case CL_METERING: + return "metering"; + case CL_TELEPHONE: + return "telephone"; + case CL_HEALTH: + return "health services"; + case CL_WAREHOUSE: + return "warehouse"; + case CL_BANKING: + return "banking"; + case CL_ENTERTAIN: + return "entertainment & sports"; + case CL_PARKING: + return "car parking"; + case CL_FLEET: + return "fleet management"; + case CL_FUEL: + return "fuel, gasoline"; + case CL_INFO: + return "info services"; + case CL_PRESS: + return "press"; + case CL_NFC: + return "NFC Forum"; + case CL_COMPUTER: + return "computer"; + case CL_MAIL: + return "mail"; + case CL_AMISC: + case CL_AMISC1: + case CL_AMISC2: + case CL_AMISC3: + case CL_AMISC4: + case CL_AMISC5: + case CL_AMISC6: + case CL_AMISC7: + return "miscellaneous applications"; + default: + break; + } + return "reserved"; +} + +static json_t *df_known_aids = NULL; + +static int open_aiddf_file(json_t **root, bool verbose) { + + char *path; + int res = searchFile(&path, RESOURCES_SUBDIR, "aid_desfire", ".json", true); + if (res != PM3_SUCCESS) { + return PM3_EFILE; + } + + int retval = PM3_SUCCESS; + json_error_t error; + + *root = json_load_file(path, 0, &error); + if (!*root) { + PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text); + retval = PM3_ESOFT; + goto out; + } + + if (!json_is_array(*root)) { + PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path); + retval = PM3_ESOFT; + goto out; + } + + if (verbose) + PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root)); +out: + free(path); + return retval; +} + +static int close_aiddf_file(json_t *root) { + json_decref(root); + return PM3_SUCCESS; +} + +static const char *aiddf_json_get_str(json_t *data, const char *name) { + + json_t *jstr = json_object_get(data, name); + if (jstr == NULL) + return NULL; + + if (!json_is_string(jstr)) { + PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); + return NULL; + } + + const char *cstr = json_string_value(jstr); + if (strlen(cstr) == 0) + return NULL; + + return cstr; +} + +static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { + char laid[7] = {0}; + sprintf(laid, "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase + + json_t *elm = NULL; + + for (uint32_t idx = 0; idx < json_array_size(root); idx++) { + json_t *data = json_array_get(root, idx); + if (!json_is_object(data)) { + PrintAndLogEx(ERR, "data [%d] is not an object\n", idx); + continue; + } + const char *faid = aiddf_json_get_str(data, "AID"); + char lfaid[strlen(faid) + 1]; + strcpy(lfaid, faid); + str_lower(lfaid); + if (strcmp(laid, lfaid) == 0) { + elm = data; + break; + } + } + + if (elm == NULL) { + PrintAndLogEx(INFO, fmt, " (unknown)"); + return PM3_ENODATA; + } + const char *vaid = aiddf_json_get_str(elm, "AID"); + const char *vendor = aiddf_json_get_str(elm, "Vendor"); + const char *country = aiddf_json_get_str(elm, "Country"); + const char *name = aiddf_json_get_str(elm, "Name"); + const char *description = aiddf_json_get_str(elm, "Description"); + const char *type = aiddf_json_get_str(elm, "Type"); + + if (name && vendor) { + char result[5 + strlen(name) + strlen(vendor)]; + sprintf(result, " %s [%s]", name, vendor); + PrintAndLogEx(INFO, fmt, result); + } + + if (verbose) { + PrintAndLogEx(SUCCESS, " AID: %s", vaid); + if (name) + PrintAndLogEx(SUCCESS, " Name: %s", name); + if (description) + PrintAndLogEx(SUCCESS, " Description: %s", description); + if (type) + PrintAndLogEx(SUCCESS, " Type: %s", type); + if (vendor) + PrintAndLogEx(SUCCESS, " Vendor: %s", vendor); + if (country) + PrintAndLogEx(SUCCESS, " Country: %s", country); + } + return PM3_SUCCESS; +} + +int AIDDFDecodeAndPrint(uint8_t aid[3]) { + open_aiddf_file(&df_known_aids, false); + + char fmt[80]; + sprintf(fmt, " DF AID Function %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s"); + print_aiddf_description(df_known_aids, aid, fmt, false); + close_aiddf_file(df_known_aids); + return PM3_SUCCESS; +} diff --git a/client/src/aiddesfire.h b/client/src/mifare/aiddesfire.h similarity index 91% rename from client/src/aiddesfire.h rename to client/src/mifare/aiddesfire.h index bb67dab83..c09f6e971 100644 --- a/client/src/aiddesfire.h +++ b/client/src/mifare/aiddesfire.h @@ -11,6 +11,7 @@ #include "common.h" +const char *nxp_cluster_to_text(uint8_t cluster); int AIDDFDecodeAndPrint(uint8_t aid[3]); #endif // _AIDDESFIRE_H_ diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index e60093317..bd79f4711 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -32,6 +32,8 @@ #include "util_posix.h" // msleep #include "mifare/desfire_crypto.h" #include "desfiresecurechan.h" +#include "mifare/mad.h" +#include "mifare/aiddesfire.h" const CLIParserOption DesfireAlgoOpts[] = { {T_DES, "des"}, @@ -694,9 +696,15 @@ static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, s 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++) { + memset(&blockdata[i * blockdatasize + 1], 0, blockdatasize - 1); size_t tlen = len + blockdata[i * blockdatasize]; - if (tlen > dstdatalen) + if (tlen > dstdatalen) { tlen = dstdatalen; + if (tlen >= len) + blockdata[i * blockdatasize] = tlen - len; + else + blockdata[i * blockdatasize] = 0; + } if (len == tlen) { *blockdatacount = i; break; @@ -764,6 +772,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { size_t resplen = 0; uint8_t respcode = 0; + ctx->secureChannel = DACNone; 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) @@ -800,6 +809,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { size_t resplen = 0; uint8_t respcode = 0; + ctx->secureChannel = DACNone; int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0); if (res == PM3_SUCCESS) { if (resplen != 0) @@ -809,11 +819,28 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { if (respcode != MFDES_S_OPERATION_OK) return PM3_EAPDU_FAIL; + DesfireClearSession(ctx); + ctx->appSelected = (aid != 0x000000); + return PM3_SUCCESS; } return res; } +void DesfirePrintAIDFunctions(uint32_t appid) { + uint8_t aid[3] = {0}; + DesfireAIDUintToByte(appid, aid); + if ((aid[2] >> 4) == 0xF) { + uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); + PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid); + PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8)); + MADDFDecodeAndPrint(short_aid); + } else { + AIDDFDecodeAndPrint(aid); + } +} + + int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) { if (verbose) DesfirePrintContext(dctx); @@ -1344,6 +1371,279 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return 100; } +static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd) { + size_t recv_len = 0; + uint8_t respcode = 0; + uint8_t recv_data[256] = {0}; + + DesfireContext dctx = {0}; + dctx.keyNum = keyNum; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCNative; + + // if cant select - return false + int res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + if (res != PM3_SUCCESS) + return false; + + uint8_t data[] = {keyNum, 0x00}; + res = DesfireExchangeEx(false, &dctx, authcmd, data, (authcmd == MFDES_AUTHENTICATE_EV2F) ? 2 : 1, &respcode, recv_data, &recv_len, false, 0); + DropField(); + return (res == PM3_SUCCESS && respcode == 0xaf); +} + +static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorythm keytype) { + + DesfireContext dctx = {0}; + dctx.keyNum = keyNum; + dctx.commMode = DCMPlain; + dctx.cmdSet = DCCISO; + + bool app_level = (appAID != 0x000000); + int res = 0; + if (dfname == NULL || strnlen(dfname, 16) == 0) { + if (appAID == 0x000000) { + res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, NULL, NULL); + if (res != PM3_SUCCESS) + return false; + } else { + res = DesfireSelectAIDHex(&dctx, appAID, false, 0); + if (res != PM3_SUCCESS) + return false; + } + } else { + res = DesfireISOSelectDF(&dctx, dfname, NULL, NULL); + if (res != PM3_SUCCESS) + return false; + app_level = true; + } + + uint8_t rndlen = DesfireGetRndLenForKey(keytype); + + uint8_t piccrnd[64] = {0}; + size_t xlen = 0; + res = DesfireISOGetChallenge(&dctx, keytype, piccrnd, &xlen); + if (res != PM3_SUCCESS || xlen != rndlen) + return false; + + uint8_t resp[250] = {0}; + size_t resplen = 0; + + uint16_t sw = 0; + uint8_t p1 = DesfireKeyToISOKey(keytype); + uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum; + res = DesfireExchangeISO(false, &dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw); + DropField(); + return (sw == 0x9000 || sw == 0x6982); +} + +void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck) { + memset(authCmdCheck, 0, sizeof(AuthCommandsChk)); + + authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE); + authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO); + authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES); + authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F); + authCmdCheck->authISONative = DesfireCheckISOAuthCmd(appAID, dfname, keyNum, T_DES); + authCmdCheck->checked = true; +} + +void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) { + PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s", + authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"), + authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO") + ); +} + +int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode) { + uint8_t buf[250] = {0}; + size_t buflen = 0; + + uint32_t freemem = 0; + int res = DesfireGetFreeMem(dctx, &freemem); + if (res == PM3_SUCCESS) + PICCInfo->freemem = freemem; + else + PICCInfo->freemem = 0xffffffff; + + PICCInfo->keySettings = 0; + PICCInfo->numKeysRaw = 0; + PICCInfo->keyVersion0 = 0; + res = DesfireGetKeySettings(dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + PICCInfo->keySettings = buf[0]; + PICCInfo->numKeysRaw = buf[1]; + PICCInfo->numberOfKeys = PICCInfo->numKeysRaw & 0x1f; + if (PICCInfo->numKeysRaw > 0) { + uint8_t keyNum0 = 0; + res = DesfireGetKeyVersion(dctx, &keyNum0, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + PICCInfo->keyVersion0 = buf[0]; + } + } + } + + // field on-off zone + if (deepmode) + DesfireCheckAuthCommands(0x000000, NULL, 0, &PICCInfo->authCmdCheck); + + return PM3_SUCCESS; +} + +static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) { + for (int i = 0; i < appcount; i++) + if (AppList[i].appNum == appNum) + return i; + + return -1; +} + +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles) { + uint8_t buf[250] = {0}; + size_t buflen = 0; + + int res = DesfireGetAIDList(dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res); + DropField(); + return PM3_ESOFT; + } + + PICCInfo->appCount = buflen / 3; + for (int i = 0; i < buflen; i += 3) + appList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]); + + // result bytes: 3, 2, 1-16. total record size = 24 + res = DesfireGetDFList(dctx, buf, &buflen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res); + } else if (buflen > 1) { + for (int i = 0; i < buflen; i++) { + int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), appList, PICCInfo->appCount); + if (indx >= 0) { + appList[indx].appISONum = MemBeToUint2byte(&buf[i * 24 + 1 + 3]); + memcpy(appList[indx].appDFName, &buf[i * 24 + 1 + 5], strnlen((char *)&buf[i * 24 + 1 + 5], 16)); + } + } + } + + // field on-off zone + DesfireFillPICCInfo(dctx, PICCInfo, deepmode); + + if (PICCInfo->appCount > 0) { + for (int i = 0; i < PICCInfo->appCount; i++) { + if (i == 0) + res = DesfireSelectAIDHex(dctx, appList[i].appNum, false, 0); + else + res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum); + if (res != PM3_SUCCESS) + continue; + + DesfireGetKeySettings(dctx, buf, &buflen); + if (res == PM3_SUCCESS && buflen >= 2) { + appList[i].keySettings = buf[0]; + appList[i].numKeysRaw = buf[1]; + appList[i].numberOfKeys = appList[i].numKeysRaw & 0x1f; + appList[i].isoFileIDEnabled = ((appList[i].numKeysRaw & 0x20) != 0); + appList[i].keyType = DesfireKeyTypeToAlgo(appList[i].numKeysRaw >> 6); + + if (appList[i].numberOfKeys > 0) + for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { + res = DesfireGetKeyVersion(dctx, &keyn, 1, buf, &buflen); + if (res == PM3_SUCCESS && buflen > 0) { + appList[i].keyVersions[keyn] = buf[0]; + } + } + + appList[i].filesReaded = false; + if (readFiles) { + res = DesfireFillFileList(dctx, appList[i].fileList, &appList[i].filesCount, &appList[i].isoPresent); + appList[i].filesReaded = (res == PM3_SUCCESS); + } + } + } + } + + // field on-off zone + if (PICCInfo->appCount > 0 && deepmode) { + for (int i = 0; i < PICCInfo->appCount; i++) { + DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); + } + } + + return PM3_SUCCESS; +} + +void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) { + PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------"); + if (PICCInfo->freemem == 0xffffffff) + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount); + else + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem); + PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); + if (PICCInfo->authCmdCheck.checked) + DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); + if (PICCInfo->numberOfKeys > 0) { + PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true); + PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0); + } +} + +void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList) { + if (PICCInfo->appCount == 0) + return; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------"); + + for (int i = 0; i < PICCInfo->appCount; i++) { + PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName); + + DesfirePrintAIDFunctions(appList[i].appNum); + + if (PICCInfo->authCmdCheck.checked) { + PrintAndLogEx(SUCCESS, "Auth commands: " NOLF); + DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck); + PrintAndLogEx(SUCCESS, ""); + } + + if (appList[i].numberOfKeys > 0) { + PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true); + + if (appList[i].numberOfKeys > 0) { + PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1); + for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) { + PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]); + } + PrintAndLogEx(NORMAL, "\n"); + } + + if (appList[i].filesReaded) { + PrintAndLogEx(SUCCESS, "Application have " _GREEN_("%zu") " files", appList[i].filesCount); + + if (appList[i].filesCount > 0) { + for (int fnum = 0; fnum < appList[i].filesCount; fnum++) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("File %02x") " ----------------------------------", appList[i].fileList[fnum].fileNum); + PrintAndLogEx(SUCCESS, "File ID : " _GREEN_("%02x"), appList[i].fileList[fnum].fileNum); + if (appList[i].isoPresent) { + if (appList[i].fileList[fnum].fileISONum != 0) + PrintAndLogEx(SUCCESS, "File ISO ID : %04x", appList[i].fileList[fnum].fileISONum); + else + PrintAndLogEx(SUCCESS, "File ISO ID : " _YELLOW_("n/a")); + } + DesfirePrintFileSettingsExtended(&appList[i].fileList[fnum].fileSettings); + } + } + PrintAndLogEx(NORMAL, ""); + } + } + } +} + static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { if (resplen) *resplen = 0; @@ -1397,6 +1697,26 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem) { return res; } +int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen) { + *resplen = 0; + + uint8_t xresp[257] = {0}; + size_t xresplen = 0; + uint8_t respcode = 0xff; + + int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen); + if (res != PM3_SUCCESS) + return res; + + if (respcode != 0x90) + return PM3_EAPDU_FAIL; + + memcpy(resp, xresp, xresplen); + *resplen = xresplen; + + return PM3_SUCCESS; +} + int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1); } @@ -1610,46 +1930,18 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin return DesfireCommandTxData(dctx, MFDES_UPDATE_RECORD, xdata, 10 + len); } -uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) { - switch (keyType) { - case T_DES: - return 0x00; - case T_3DES: - return 0x00; - case T_3K3DES: - return 0x01; - case T_AES: - return 0x02; - } - return 0; -} -static void PrintKeyType(uint8_t keytype) { - switch (keytype) { - case 00: - PrintAndLogEx(SUCCESS, "Key: 2TDEA"); - break; - case 01: - PrintAndLogEx(SUCCESS, "Key: 3TDEA"); - break; - case 02: - PrintAndLogEx(SUCCESS, "Key: AES"); - break; - default: - PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keytype); - break; - } -} - static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { PrintAndLogEx(SUCCESS, "PICC level rights:"); - PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); - PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); - if (print2ndbyte) + if (print2ndbyte) { + DesfirePrintCardKeyType(numkeys >> 6); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); + } } static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { @@ -1676,14 +1968,14 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print break; } - PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); - PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); if (print2ndbyte) { - PrintKeyType(numkeys >> 6); + DesfirePrintCardKeyType(numkeys >> 6); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); if (numkeys & 0x20) PrintAndLogEx(SUCCESS, "iso file id: enabled"); @@ -1701,6 +1993,7 @@ void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool static const char *DesfireUnknownStr = "unknown"; static const char *DesfireDisabledStr = "disabled"; static const char *DesfireFreeStr = "free"; +static const char *DesfireNAStr = "n/a"; static const DesfireCreateFileCommandsS DesfireFileCommands[] = { {0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true}, {0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true}, @@ -1771,6 +2064,32 @@ const char *GetDesfireAccessRightStr(uint8_t right) { return DesfireUnknownStr; } +const char *AccessRightShortStr[] = { + "key0", + "key1", + "key2", + "key3", + "key4", + "key5", + "key6", + "key7", + "key8", + "key9", + "keyA", + "keyB", + "keyC", + "keyD", + "free", + "deny" +}; + +const char *GetDesfireAccessRightShortStr(uint8_t right) { + if (right > 0x0f) + return DesfireNAStr; + + return AccessRightShortStr[right]; +} + void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch) { mode[0] = (ch & 0x0f) | ((rw << 4) & 0xf0); mode[1] = (w & 0x0f) | ((r << 4) & 0xf0); @@ -1863,10 +2182,7 @@ void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsett } } -void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { - PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); - PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); - +static void DesfirePrintShortFileTypeSettings(FileSettingsS *fsettings) { switch (fsettings->fileType) { case 0x00: case 0x01: { @@ -1874,13 +2190,13 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { break; } case 0x02: { - PrintAndLogEx(NORMAL, "[%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF, + PrintAndLogEx(NORMAL, "value [%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF, fsettings->lowerLimit, fsettings->upperLimit, fsettings->limitedCredit, fsettings->value, fsettings->value); break; } case 0x03: case 0x04: { - PrintAndLogEx(NORMAL, "%d/%d record size: %d [0x%x]b " NOLF, + PrintAndLogEx(NORMAL, "record count %d/%d size: %d [0x%x]b " NOLF, fsettings->curRecordCount, fsettings->maxRecordCount, fsettings->recordSize, fsettings->recordSize); break; } @@ -1891,13 +2207,50 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { default: { break; } - } + } +} + +void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { + PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); + PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); + + DesfirePrintShortFileTypeSettings(fsettings); PrintAndLogEx(NORMAL, "(%s %s %s %s)", - GetDesfireAccessRightStr(fsettings->rAccess), - GetDesfireAccessRightStr(fsettings->wAccess), - GetDesfireAccessRightStr(fsettings->rwAccess), - GetDesfireAccessRightStr(fsettings->chAccess)); + GetDesfireAccessRightShortStr(fsettings->rAccess), + GetDesfireAccessRightShortStr(fsettings->wAccess), + GetDesfireAccessRightShortStr(fsettings->rwAccess), + GetDesfireAccessRightShortStr(fsettings->chAccess)); +} + +void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings) { + if (printheader) { + PrintAndLogEx(SUCCESS, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings "); + PrintAndLogEx(SUCCESS, "----------------------------------------------------------------------------------------------------------"); + } + PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id); + if (isoidavail) { + if (isoid != 0) + PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid); + else + PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF); + } else { + PrintAndLogEx(NORMAL, " |" NOLF); + } + + PrintAndLogEx(NORMAL, "0x%02x " _CYAN_("%-13s") " |" NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType)); + PrintAndLogEx(NORMAL, " %-5s |" NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode)); + + PrintAndLogEx(NORMAL, "%04x, %-4s %-4s %-4s %-4s |" NOLF, + fsettings->rawAccessRights, + GetDesfireAccessRightShortStr(fsettings->rAccess), + GetDesfireAccessRightShortStr(fsettings->wAccess), + GetDesfireAccessRightShortStr(fsettings->rwAccess), + GetDesfireAccessRightShortStr(fsettings->chAccess)); + + PrintAndLogEx(NORMAL, " " NOLF); + DesfirePrintShortFileTypeSettings(fsettings); + PrintAndLogEx(NORMAL, ""); } void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index a149ba36c..4f849e135 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -85,6 +85,48 @@ typedef struct { typedef FileListElmS FileListS[32]; +typedef struct { + bool checked; + bool auth; + bool authISO; + bool authAES; + bool authEV2; + bool authISONative; +} AuthCommandsChk; + +typedef struct { + uint32_t appNum; + uint16_t appISONum; + char appDFName[16]; + AuthCommandsChk authCmdCheck; + + uint8_t keySettings; + uint8_t numKeysRaw; + bool isoFileIDEnabled; // from numKeysRaw + uint8_t numberOfKeys; // from numKeysRaw + DesfireCryptoAlgorythm keyType; // from numKeysRaw + + uint8_t keyVersions[16]; + + bool filesReaded; + size_t filesCount; + bool isoPresent; + FileListS fileList; +} AppListElmS; +typedef AppListElmS AppListS[64]; + +typedef struct { + size_t appCount; + uint32_t freemem; + AuthCommandsChk authCmdCheck; + + uint8_t keySettings; + uint8_t numKeysRaw; + uint8_t numberOfKeys; // from numKeysRaw + + uint8_t keyVersion0; +} PICCInfoS; + typedef enum { RFTAuto, RFTData, @@ -111,20 +153,29 @@ void DesfirePrintContext(DesfireContext *ctx); 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, size_t splitbysize); +int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen); + int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); +void DesfirePrintAIDFunctions(uint32_t appid); const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose); +void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck); +void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck); int DesfireFormatPICC(DesfireContext *dctx); int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem); int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); +int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode); +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles); +void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo); +void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList); int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen); int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid); @@ -133,7 +184,6 @@ int DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *data, size_t len, uint8_ int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len); void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte); -uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType); int DesfireChangeKeyCmd(DesfireContext *dctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen); int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newkeynum, DesfireCryptoAlgorythm newkeytype, uint32_t newkeyver, uint8_t *newkey, DesfireCryptoAlgorythm oldkeytype, uint8_t *oldkey, bool verbose); @@ -147,6 +197,7 @@ int DesfireGetFileISOIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsettings); void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings); +void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings); void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings); int DesfireGetFileSettings(DesfireContext *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen); int DesfireGetFileSettingsStruct(DesfireContext *dctx, uint8_t fileid, FileSettingsS *fsettings); @@ -154,6 +205,7 @@ int DesfireChangeFileSettings(DesfireContext *dctx, uint8_t *data, size_t datale const DesfireCreateFileCommandsS *GetDesfireFileCmdRec(uint8_t type); const char *GetDesfireAccessRightStr(uint8_t right); +const char *GetDesfireAccessRightShortStr(uint8_t right); void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch); void DesfireDecodeFileAcessMode(uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch); void DesfirePrintAccessRight(uint8_t *data); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index ba82cdae0..d6ac6332e 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -353,6 +353,50 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key) { return version; } +DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType) { + switch (keyType) { + case 00: + return T_3DES; + case 01: + return T_3K3DES; + case 02: + return T_AES; + default: + return T_3DES; // unknown.... + } +} + +uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) { + switch (keyType) { + case T_DES: + return 0x00; + case T_3DES: + return 0x00; + case T_3K3DES: + return 0x01; + case T_AES: + return 0x02; + } + return 0; +} + +void DesfirePrintCardKeyType(uint8_t keyType) { + switch (keyType) { + case 00: + PrintAndLogEx(SUCCESS, "Key: 2TDEA"); + break; + case 01: + PrintAndLogEx(SUCCESS, "Key: 3TDEA"); + break; + case 02: + PrintAndLogEx(SUCCESS, "Key: AES"); + break; + default: + PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keyType); + break; + } +} + DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode) { DesfireCommunicationMode mode = DCMNone; switch (file_comm_mode & 0x03) { diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index a336f9e3f..cf7dacfe0 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -107,6 +107,10 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); uint8_t DesfireDESKeyGetVersion(uint8_t *key); +DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType); +uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType); +void DesfirePrintCardKeyType(uint8_t keyType); + DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode);