diff --git a/Makefile.platform.sample b/Makefile.platform.sample index 9d0e2d965..8d587e3b7 100644 --- a/Makefile.platform.sample +++ b/Makefile.platform.sample @@ -5,3 +5,4 @@ PLATFORM=PM3RDV4 # If you want more than one PLATFORM_EXTRAS option, separate them by spaces: #PLATFORM_EXTRAS=BTADDON #STANDALONE=LF_SAMYRUN +STANDALONE=LF_ICEHID diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 23b3a2239..f789d87c6 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2672,8 +2672,10 @@ void ReaderIso14443a(PacketCommandNG *c) { uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t par[MAX_PARITY_SIZE] = {0x00}; - if ((param & ISO14A_CONNECT)) + if ((param & ISO14A_CONNECT)) { + iso14_pcb_blocknum = 0; clear_trace(); + } set_tracing(true); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 31f2cae58..10beb4489 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -29,7 +29,7 @@ # define FWT_TIMEOUT_14B 35312 #endif #ifndef ISO14443B_DMA_BUFFER_SIZE -# define ISO14443B_DMA_BUFFER_SIZE 256 +# define ISO14443B_DMA_BUFFER_SIZE 512 //changed this from 256 #endif #ifndef RECEIVE_MASK # define RECEIVE_MASK (ISO14443B_DMA_BUFFER_SIZE-1) @@ -37,7 +37,7 @@ // Guard Time (per 14443-2) #ifndef TR0 -# define TR0 0 +# define TR0 32 //this value equals 8 ETU = 32 ssp clk (w/ 424 khz) #endif // Synchronization time (per 14443-2) @@ -261,6 +261,10 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { // 80/fs < TR1 < 200/fs // 10 ETU < TR1 < 24 ETU + // Send TR1. + // 10-11 ETU * 4times samples ONES + for (int i = 0; i < 10; i++) { SEND4STUFFBIT(1); } + // Send SOF. // 10-11 ETU * 4times samples ZEROS for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } @@ -307,7 +311,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } // why this? - for (int i = 0; i < 40; i++) { SEND4STUFFBIT(1); } + for (int i = 0; i < 2; i++) { SEND4STUFFBIT(1); } //for(i = 0; i < 40; i++) { ToSendStuffBit(1); } // Convert from last byte pos to length diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index be8889d48..af902e868 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -132,6 +132,9 @@ void MifareDesfireGetInformation() { clear_trace(); set_tracing(true); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // reset the pcb_blocknum, + pcb_blocknum = 0; // card select - information if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 52894c52b..7aeac0bc7 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -709,7 +709,6 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { pos++; for (uint8_t i = 0; i < 2; i++, pos++) { - switch (cmd[pos]) { case MFDES_CREATE_APPLICATION: snprintf(exp, size, "CREATE APPLICATION"); @@ -822,6 +821,9 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { case MFDES_ADDITIONAL_FRAME: snprintf(exp, size, "AUTH FRAME / NEXT FRAME"); break; + case MFDES_READSIG: + snprintf(exp, size, "READ SIGNATURE"); + break; default: break; } diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index ec44404a8..d910cb669 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -52,12 +52,13 @@ typedef enum { typedef enum { UNKNOWN = 0, - MF3ICD40, - EV1, - EV2, - EV3, - LIGHT, -} desfire_cardtype_t; + DESFIRE_MF3ICD40, + DESFIRE_EV1, + DESFIRE_EV2, + DESFIRE_EV3, + DESFIRE_LIGHT, + PLUS_EV1, +} nxp_cardtype_t; typedef struct { uint8_t aid[3]; @@ -68,14 +69,65 @@ typedef struct { static int CmdHelp(const char *Cmd); /* - uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; - int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); - - if (!res && datalen > 1 && data[0] == 0x09) { - SLmode = 0; - } - + The 7 MSBits (= n) code the storage size itself based on 2^n, + the LSBit is set to '0' if the size is exactly 2^n + and set to '1' if the storage size is between 2^n and 2^(n+1). + For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'. */ +static char *getCardSizeStr(uint8_t fsize) { + + static char buf[40] = {0x00}; + char *retStr = buf; + + uint16_t usize = 1 << ((fsize >> 1) + 1); + uint16_t lsize = 1 << (fsize >> 1); + + // is LSB set? + if (fsize & 1) + sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); + else + sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize); + return buf; +} + +static char *getProtocolStr(uint8_t id, bool hw) { + + static char buf[50] = {0x00}; + char *retStr = buf; + + if (id == 0x04) { + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); + } else if (id == 0x05) { + if (hw) + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id); + else + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); + } else { + sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id); + } + return buf; +} + +static char *getVersionStr(uint8_t major, uint8_t minor) { + + static char buf[40] = {0x00}; + char *retStr = buf; + + if (major == 0x00) + sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor); + else if (major == 0x01 && minor == 0x00) + sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor); + else if (major == 0x12 && minor == 0x00) + sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor); +// else if (major == 0x13 && minor == 0x00) +// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor); + else if (major == 0x30 && minor == 0x00) + sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor); + else + sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor); + return buf; +} + int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) { @@ -121,7 +173,7 @@ int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t if (sw) *sw = isw; - if (isw != 0x9000 && isw != status(MFDES_OPERATION_OK) && isw != status(MFDES_SIGNATURE) && isw != status(MFDES_ADDITIONAL_FRAME) && isw != status(MFDES_NO_CHANGES)) { + if (isw != 0x9000 && isw != status(MFDES_S_OPERATION_OK) && isw != status(MFDES_S_SIGNATURE) && isw != status(MFDES_S_ADDITIONAL_FRAME) && isw != status(MFDES_S_NO_CHANGES)) { if (GetAPDULogging()) { if (isw >> 8 == 0x61) { PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff); @@ -254,15 +306,23 @@ static char *GetErrorString(int res, uint16_t *sw) { return ""; } - static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) { - if (g_debugMode > 1) { - if (apdu == NULL) PrintAndLogEx(ERR, "APDU=NULL"); - if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); - if (sw == NULL) PrintAndLogEx(ERR, "SW=NULL"); - if (recv_len == NULL) PrintAndLogEx(ERR, "RECV_LEN=NULL"); + if (apdu == NULL) { + PrintAndLogEx(DEBUG, "APDU=NULL"); + return PM3_EINVARG; + } + if (dest == NULL) { + PrintAndLogEx(DEBUG, "DEST=NULL"); + return PM3_EINVARG; + } + if (sw == NULL) { + PrintAndLogEx(DEBUG, "SW=NULL"); + return PM3_EINVARG; + } + if (recv_len == NULL) { + PrintAndLogEx(DEBUG, "RECV_LEN=NULL"); + return PM3_EINVARG; } - if (apdu == NULL || sw == NULL || recv_len == NULL) return PM3_EINVARG; *sw = 0; uint8_t data[255 * 5] = {0x00}; @@ -271,7 +331,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l int i = 1; int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw); if (res != PM3_SUCCESS) { - if (g_debugMode > 1) GetErrorString(res, sw); + PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw)); return res; } if (dest != NULL) { @@ -290,6 +350,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l } return res; } + while (*sw == status(MFDES_ADDITIONAL_FRAME)) { apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF apdu->Lc = 0; @@ -298,9 +359,10 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw); if (res != PM3_SUCCESS) { - if (g_debugMode > 1) GetErrorString(res, sw); + PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw)); return res; } + if (dest != NULL) { if (splitbysize) { memcpy(&dest[i * splitbysize], data, resplen); @@ -310,33 +372,33 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l } } pos += resplen; + if (*sw != status(MFDES_ADDITIONAL_FRAME)) break; } - if (splitbysize) *recv_len = i; - else { - *recv_len = pos; - } - return PM3_SUCCESS; + *recv_len = (splitbysize) ? i : pos; + return PM3_SUCCESS; } -static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) { +static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { if (major == 0x00) - return MF3ICD40; - else if (major == 0x01 && minor == 0x00) - return EV1; - else if (major == 0x12 && minor == 0x00) - return EV2; -// else if (major == 0x13 && minor == 0x00) -// return EV3; - else if (major == 0x30 && minor == 0x00) - return LIGHT; - else - return UNKNOWN; + return DESFIRE_MF3ICD40; + if (major == 0x01 && minor == 0x00) + return DESFIRE_EV1; + if (major == 0x12 && minor == 0x00) + return DESFIRE_EV2; +// if (major == 0x13 && minor == 0x00) +// return DESFIRE_EV3; + if (major == 0x30 && minor == 0x00) + return DESFIRE_LIGHT; + if (major == 0x11 && minor == 0x00 ) + return PLUS_EV1; + + return UNKNOWN; } -//none, verified +// -- test if card supports 0x0A static int test_desfire_authenticate() { uint8_t data[] = {0x00}; sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0 @@ -345,7 +407,7 @@ static int test_desfire_authenticate() { return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); } -// none, verified +// -- test if card supports 0x1A static int test_desfire_authenticate_iso() { uint8_t data[] = {0x00}; sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0 @@ -354,7 +416,7 @@ static int test_desfire_authenticate_iso() { return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); } -//none, verified +// -- test if card supports 0xAA static int test_desfire_authenticate_aes() { uint8_t data[] = {0x00}; sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0 @@ -363,37 +425,44 @@ static int test_desfire_authenticate_aes() { return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); } -// --- FREE MEM, verified +// --- 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; } -// init / disconnect, verified static int get_desfire_freemem(uint32_t *free_mem) { if (free_mem == NULL) return PM3_EINVARG; + sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E + *free_mem = 0; int recv_len = 0; uint16_t sw = 0; uint8_t fmem[4] = {0}; int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true); - if (res == PM3_SUCCESS) { - *free_mem = le24toh(fmem); + + if (res != PM3_SUCCESS ) return res; - } - *free_mem = 0; + + if (sw != status(MFDES_S_OPERATION_OK)) + return PM3_ESOFT; + + *free_mem = le24toh(fmem); return res; } +// --- GET SIGNATURE +static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) { -// --- GET SIGNATURE, verified -static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, desfire_cardtype_t card_type) { - if (g_debugMode > 1) { - if (uid == NULL) PrintAndLogEx(ERR, "UID=NULL"); - if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL"); + if (uid == NULL) { + PrintAndLogEx(DEBUG, "UID=NULL"); + return PM3_EINVARG; + } + if (signature == NULL) { + PrintAndLogEx(DEBUG, "SIGNATURE=NULL"); + return PM3_EINVARG; } - if (uid == NULL || signature == NULL) return PM3_EINVARG; // DESFire Ev3 - wanted // ref: MIFARE Desfire Originality Signature Validation @@ -403,7 +472,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign {"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"}, {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, - {"DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, + {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} }; @@ -427,8 +496,8 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); +// PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16); @@ -443,35 +512,34 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign return PM3_SUCCESS; } -// init / disconnect, verified static int get_desfire_signature(uint8_t *signature, size_t *signature_len) { - if (g_debugMode > 1) { - if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL"); - if (signature_len == NULL) PrintAndLogEx(ERR, "SIGNATURE_LEN=NULL"); + + if (signature == NULL) { + PrintAndLogEx(DEBUG, "SIGNATURE=NULL"); + return PM3_EINVARG; } - if (signature == NULL || signature_len == NULL) return PM3_EINVARG; - uint8_t c = 0x00; - sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, 0x01, &c}; // 0x3C + 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 int 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; - DropField(); - return PM3_ESOFT; + res = PM3_ESOFT; } else { *signature_len = recv_len; - } - DropField(); - return PM3_SUCCESS; } DropField(); return res; } - // --- KEY SETTING static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) { @@ -504,23 +572,29 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) { return PM3_SUCCESS; } -// none, verified static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { - if (g_debugMode > 1) { - if (key_settings == NULL) PrintAndLogEx(ERR, "KEY_SETTINGS=NULL"); - if (num_keys == NULL) PrintAndLogEx(ERR, "NUM_KEYS=NULL"); + if (key_settings == NULL) { + PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL"); + return PM3_EINVARG; + } + if (num_keys == NULL) { + PrintAndLogEx(DEBUG, "NUM_KEYS=NULL"); + return PM3_EINVARG; } - if (key_settings == NULL || num_keys == NULL) return PM3_EINVARG; sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45 int recv_len = 0; uint16_t sw = 0; uint8_t data[2] = {0}; int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true); - if (res != PM3_SUCCESS) return res; + + if (res != PM3_SUCCESS ) + return res; + if (sw != status(MFDES_S_OPERATION_OK)) + return PM3_ESOFT; *key_settings = data[0]; *num_keys = data[1]; - return PM3_SUCCESS; + return res; } // --- KEY VERSION @@ -529,37 +603,52 @@ static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) { return PM3_SUCCESS; } -// none, verified static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { - if (g_debugMode > 1) { - if (num_versions == NULL) PrintAndLogEx(ERR, "NUM_VERSIONS=NULL"); + if (num_versions == NULL) { + PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL"); + return PM3_EINVARG; } - if (num_versions == NULL) return PM3_EINVARG; sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 int 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; } - -// init / disconnect, verified +// --- GET APPIDS static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) { - if (g_debugMode > 1) { - if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); - if (app_ids_len == NULL) PrintAndLogEx(ERR, "APP_IDS_LEN=NULL"); + if (dest == NULL) { + PrintAndLogEx(DEBUG, "DEST=NULL"); + return PM3_EINVARG; } - if (dest == NULL || app_ids_len == NULL) return PM3_EINVARG; + if (app_ids_len == NULL) { + PrintAndLogEx(DEBUG, "APP_IDS_LEN=NULL"); + return PM3_EINVARG; + } + sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a int recv_len = 0; uint16_t sw = 0; int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true); - if (res != PM3_SUCCESS) return res; + + if (res != PM3_SUCCESS ) + return res; + + if (sw != status(MFDES_S_OPERATION_OK)) + return PM3_ESOFT; + *app_ids_len = (uint8_t)recv_len & 0xFF; return res; } -// init, verified +// --- GET DF NAMES static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) { if (g_debugMode > 1) { if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); @@ -570,13 +659,14 @@ static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) { int 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 (res != PM3_SUCCESS) + return res; + if (sw != status(MFDES_S_OPERATION_OK)) + return PM3_ESOFT; *dfname_count = recv_len; return res; } - -// init, verified static int get_desfire_select_application(uint8_t *aid) { if (g_debugMode > 1) { if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL"); @@ -646,7 +736,7 @@ static int get_desfire_createapp(aidhdr_t *aidhdr) { sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA uint16_t sw = 0; int recvlen = 0; - int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true); + int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw)); DropField(); @@ -660,7 +750,7 @@ static int get_desfire_deleteapp(uint8_t *aid) { sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, aid}; // 0xDA uint16_t sw = 0; int recvlen = 0; - int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true); + 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)); DropField(); @@ -669,6 +759,116 @@ static int get_desfire_deleteapp(uint8_t *aid) { return res; } +int getKeySettings(uint8_t *aid) { + if (aid == NULL) return PM3_EINVARG; + + int res = 0; + if (memcmp(aid, "\x00\x00\x00", 3) == 0) { + + // CARD MASTER KEY + //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); + res = get_desfire_select_application(aid); + if (res != PM3_SUCCESS) return res; + + // KEY Settings - AMK + uint8_t num_keys = 0; + uint8_t key_setting = 0; + res = get_desfire_keysettings(&key_setting, &num_keys); + if (res == PM3_SUCCESS) { + // number of Master keys (0x01) + PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); + + PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO"); + PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO"); + PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO"); + PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO"); + } else { + PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); + } + + const char *str = " Operation of PICC master key : " _YELLOW_("%s"); + + // 2 MSB denotes + switch (num_keys >> 6) { + case 0: + PrintAndLogEx(SUCCESS, str, "(3)DES"); + break; + case 1: + PrintAndLogEx(SUCCESS, str, "3K3DES"); + break; + case 2: + PrintAndLogEx(SUCCESS, str, "AES"); + break; + default: + break; + } + + uint8_t cmk_num_versions = 0; + if (get_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_ETIMEOUT) return res; + PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + res = test_desfire_authenticate_iso(); + if (res == PM3_ETIMEOUT) return res; + PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + res = test_desfire_authenticate_aes(); + if (res == PM3_ETIMEOUT) return res; + PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + + } else { + + // AID - APPLICATION MASTER KEYS + //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); + res = get_desfire_select_application(aid); + if (res != PM3_SUCCESS) return res; + + // KEY Settings - AMK + uint8_t num_keys = 0; + uint8_t key_setting = 0; + res = get_desfire_keysettings(&key_setting, &num_keys); + if (res == PM3_SUCCESS) { + desfire_print_keysetting(key_setting, num_keys); + } else { + PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); + } + + // KEY VERSION - AMK + uint8_t num_version = 0; + if (get_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 (get_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); + } + } + } + } + + DropField(); + return PM3_SUCCESS; +} + + static int CmdHF14ADesCreateApp(const char *Cmd) { clearCommandBuffer(); @@ -929,13 +1129,12 @@ static int CmdHF14ADesInfo(const char *Cmd) { struct p *package = (struct p *) resp.data.asBytes; if (resp.status != PM3_SUCCESS) { - switch (package->isOK) { case 1: PrintAndLogEx(WARNING, "Can't select card"); break; case 2: - PrintAndLogEx(WARNING, "Card is most likely not Desfire. Its UID has wrong size"); + PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID"); break; case 3: default: @@ -944,6 +1143,12 @@ static int CmdHF14ADesInfo(const char *Cmd) { } return PM3_ESOFT; } + + nxp_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]); + if (cardtype == PLUS_EV1) { + PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`")); + return PM3_SUCCESS; + } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------"); @@ -958,7 +1163,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]); PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5])); - PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6])); + PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0])); @@ -966,7 +1171,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]); PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5])); - PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6])); + PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6], false)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities")); @@ -990,32 +1195,36 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (major == 0 && minor == 2) PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); - // Signature originality check - uint8_t signature[56] = {0}; - size_t signature_len = 0; - desfire_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]); + if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) { + // Signature originality check + uint8_t signature[56] = {0}; + size_t signature_len = 0; - if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) - desfire_print_signature(package->uid, signature, signature_len, cardtype); - else { - PrintAndLogEx(WARNING, "--- " _YELLOW_("Couldn't verify signature. Unknown public key ?")); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); + if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) { + desfire_print_signature(package->uid, signature, signature_len, cardtype); + } else { + PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd"); + } } // Master Key settings uint8_t master_aid[3] = {0x00, 0x00, 0x00}; getKeySettings(master_aid); - // Free memory on card - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Free memory")); - uint32_t free_mem = 0; - if (get_desfire_freemem(&free_mem) == PM3_SUCCESS) { - desfire_print_freemem(free_mem); - } else { - PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); + if (cardtype != DESFIRE_LIGHT) { + // Free memory on card + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Free memory")); + uint32_t free_mem = 0; + if (get_desfire_freemem(&free_mem) == PM3_SUCCESS) { + desfire_print_freemem(free_mem); + } else { + PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); + } + PrintAndLogEx(INFO, "-------------------------------------------------------------"); } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - /* Card Master key (CMK) 0x00 AID = 00 00 00 (card level) Application Master Key (AMK) 0x00 AID != 00 00 00 @@ -1035,167 +1244,6 @@ static int CmdHF14ADesInfo(const char *Cmd) { return PM3_SUCCESS; } -/* - The 7 MSBits (= n) code the storage size itself based on 2^n, - the LSBit is set to '0' if the size is exactly 2^n - and set to '1' if the storage size is between 2^n and 2^(n+1). - For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'. -*/ -char *getCardSizeStr(uint8_t fsize) { - - static char buf[40] = {0x00}; - char *retStr = buf; - - uint16_t usize = 1 << ((fsize >> 1) + 1); - uint16_t lsize = 1 << (fsize >> 1); - - // is LSB set? - if (fsize & 1) - sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); - else - sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize); - return buf; -} - -char *getProtocolStr(uint8_t id) { - - static char buf[40] = {0x00}; - char *retStr = buf; - - if (id == 0x05) - sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); - else - sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id); - return buf; -} - -char *getVersionStr(uint8_t major, uint8_t minor) { - - static char buf[40] = {0x00}; - char *retStr = buf; - - if (major == 0x00) - sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor); - else if (major == 0x01 && minor == 0x00) - sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor); - else if (major == 0x12 && minor == 0x00) - sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor); -// else if (major == 0x13 && minor == 0x00) -// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor); - else if (major == 0x30 && minor == 0x00) - sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor); - else - sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor); - return buf; -} - -int getKeySettings(uint8_t *aid) { - if (aid == NULL) return PM3_EINVARG; - int res = 0; - if (memcmp(aid, "\x00\x00\x00", 3) == 0) { - - // CARD MASTER KEY - //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); - res = get_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - // KEY Settings - AMK - uint8_t num_keys = 0; - uint8_t key_setting = 0; - res = get_desfire_keysettings(&key_setting, &num_keys); - if (res == PM3_SUCCESS) { - // number of Master keys (0x01) - PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); - - PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO"); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); - } - - const char *str = " Operation of PICC master key : " _YELLOW_("%s"); - - // 2 MSB denotes - switch (num_keys >> 6) { - case 0: - PrintAndLogEx(SUCCESS, str, "(3)DES"); - break; - case 1: - PrintAndLogEx(SUCCESS, str, "3K3DES"); - break; - case 2: - PrintAndLogEx(SUCCESS, str, "AES"); - break; - default: - break; - } - - uint8_t cmk_num_versions = 0; - if (get_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_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_iso(); - if (res == PM3_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_aes(); - if (res == PM3_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - - } else { - - // AID - APPLICATION MASTER KEYS - //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); - res = get_desfire_select_application(aid); - if (res != PM3_SUCCESS) return res; - - // KEY Settings - AMK - uint8_t num_keys = 0; - uint8_t key_setting = 0; - res = get_desfire_keysettings(&key_setting, &num_keys); - if (res == PM3_SUCCESS) { - desfire_print_keysetting(key_setting, num_keys); - } else { - PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); - } - - // KEY VERSION - AMK - uint8_t num_version = 0; - if (get_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 (get_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); - } - } - } - } - - DropField(); - return PM3_SUCCESS; -} static void DecodeFileType(uint8_t filetype) { switch (filetype) { @@ -1238,8 +1286,10 @@ static void DecodeComSet(uint8_t comset) { } static char *DecodeAccessValue(uint8_t value) { - char *car = (char *)malloc(255); - memset(car, 0x0, 255); + char *car = (char *)calloc(255, sizeof(char)); + if (car == NULL) + return NULL; + switch (value) { case 0xE: strcat(car, "(Free Access)"); @@ -1260,9 +1310,17 @@ static void DecodeAccessRights(uint16_t accrights) { 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) return; + char *wa = DecodeAccessValue(write_access); + if (wa == NULL) return; + char *ra = DecodeAccessValue(read_access); + if (ra == NULL) return; + PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra); free(car); free(rwa); @@ -1270,23 +1328,23 @@ static void DecodeAccessRights(uint16_t accrights) { free(ra); } -static int DecodeFileSettings(uint8_t *filesettings, int fileset_len, int maclen) { - uint8_t filetype = filesettings[0]; - uint8_t comset = filesettings[1]; +static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) { + uint8_t filetype = src[0]; + uint8_t comset = src[1]; - uint16_t accrights = (filesettings[4] << 8) + filesettings[3]; - if (fileset_len == 1 + 1 + 2 + 3 + maclen) { - int filesize = (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5]; + uint16_t accrights = (src[4] << 8) + src[3]; + if (src_len == 1 + 1 + 2 + 3 + maclen) { + int filesize = (src[7] << 16) + (src[6] << 8) + src[5]; DecodeFileType(filetype); DecodeComSet(comset); DecodeAccessRights(accrights); PrintAndLogEx(INFO, " Filesize: %d", filesize); return PM3_SUCCESS; - } else if (fileset_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) { - int lowerlimit = (filesettings[8] << 24) + (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5]; - int upperlimit = (filesettings[12] << 24) + (filesettings[11] << 16) + (filesettings[10] << 8) + filesettings[9]; - int limitcredvalue = (filesettings[16] << 24) + (filesettings[15] << 16) + (filesettings[14] << 8) + filesettings[13]; - uint8_t limited_credit_enabled = filesettings[17]; + } else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) { + int lowerlimit = (src[8] << 24) + (src[7] << 16) + (src[6] << 8) + src[5]; + int upperlimit = (src[12] << 24) + (src[11] << 16) + (src[10] << 8) + src[9]; + int limitcredvalue = (src[16] << 24) + (src[15] << 16) + (src[14] << 8) + src[13]; + uint8_t limited_credit_enabled = src[17]; DecodeFileType(filetype); DecodeComSet(comset); DecodeAccessRights(accrights); @@ -1590,6 +1648,5 @@ static int CmdHelp(const char *Cmd) { int CmdHFMFDes(const char *Cmd) { // flush clearCommandBuffer(); - //g_debugMode=2; return CmdsParse(CommandTable, Cmd); } diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h index c1ed4ed60..eb4dd77e0 100644 --- a/client/cmdhfmfdes.h +++ b/client/cmdhfmfdes.h @@ -14,10 +14,11 @@ int CmdHFMFDes(const char *Cmd); +/* char *getCardSizeStr(uint8_t fsize); -char *getProtocolStr(uint8_t id); char *getVersionStr(uint8_t major, uint8_t minor); int getKeySettings(uint8_t *aid); +*/ // Ev1 card limits #define MAX_NUM_KEYS 0x0F @@ -26,6 +27,14 @@ int getKeySettings(uint8_t *aid); #define MAX_FRAME_SIZE 60 #define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) +// Ev2 card limits + +// Ev3 card limits + +// Light card limits + +// Light Ev1 card limits + #define NOT_YET_AUTHENTICATED 0xFF diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 71da93bcc..e85f0861a 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -27,11 +27,19 @@ #include "protocols.h" #include "crypto/libpcrypto.h" - static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; +typedef enum { + MFP_UNKNOWN = 0, + DESFIRE_MF3ICD40, + DESFIRE_EV1, + DESFIRE_EV2, + DESFIRE_EV3, + DESFIRE_LIGHT, + PLUS_EV1, +} nxp_cardtype_t; + static int CmdHelp(const char *Cmd); /* @@ -56,15 +64,21 @@ static char *getCardSizeStr(uint8_t fsize) { return buf; } -static char *getProtocolStr(uint8_t id) { +static char *getProtocolStr(uint8_t id, bool hw) { - static char buf[40] = {0x00}; + static char buf[50] = {0x00}; char *retStr = buf; - if (id == 0x05) - sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); - else + if (id == 0x04) { + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); + } else if (id == 0x05) { + if (hw) + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id); + else + sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); + } else { sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id); + } return buf; } @@ -91,6 +105,59 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { return buf; } +static char *getTypeStr(uint8_t type) { + + static char buf[40] = {0x00}; + char *retStr = buf; + + switch (type) { + case 1: + sprintf(retStr, "0x%02X ( " _YELLOW_("DESFire") ")", type); + break; + case 2: + sprintf(retStr, "0x%02X ( " _YELLOW_("Plus") ")", type); + break; + case 3: + sprintf(retStr, "0x%02X ( " _YELLOW_("Ultralight") ")", type); + break; + case 4: + sprintf(retStr, "0x%02X ( " _YELLOW_("NTAG") ")", type); + break; + default: + break; + } + return buf; +} + +static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { + + // DESFire MF3ICD40 + if (major == 0x00 && minor == 0x00 ) + return DESFIRE_MF3ICD40; + + // DESFire EV1 + if (major == 0x01 && minor == 0x00 ) + return DESFIRE_EV1; + + // DESFire EV2 + if (major == 0x12 && minor == 0x00 ) + return DESFIRE_EV2; + + // DESFire EV3 +// if (major == 0x13 && minor == 0x00 ) +// return DESFIRE_EV3; + + // DESFire Light + if (major == 0x30 && minor == 0x00 ) + return DESFIRE_LIGHT; + + // Plus EV1 + if (major == 0x11 && minor == 0x00 ) + return PLUS_EV1; + + return MFP_UNKNOWN; +} + // --- GET SIGNATURE static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) { @@ -115,13 +182,15 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature if (is_valid) break; } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); + if (is_valid == false) { PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_plus_public_keys[i].value); PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 16); @@ -162,19 +231,19 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); - PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]); + PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); PrintAndLogEx(INFO, " Version: %s", getVersionStr(version[3], version[4])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5])); - PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6])); + PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); - PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); - PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]); - PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); - PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), version[3], version[4]); - PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5])); - PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6])); + PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7])); + PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8])); + PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]); + PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), version[10], version[11]); + PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[12])); + PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false)); return PM3_SUCCESS; } static int get_plus_version(uint8_t *version, int *version_len) { @@ -235,17 +304,28 @@ static int CmdHFMFPInfo(const char *Cmd) { if (select_status == 1 || select_status == 2) { PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint")); - - if (supportVersion && supportSignature) { - PrintAndLogEx(INFO, " Tech: " _GREEN_("MIFARE Plus EV1")); - } else { - PrintAndLogEx(INFO, " Tech: " _YELLOW_("MIFARE Plus SE/X")); + + bool isPlus = false; + + if (supportVersion) { + + int cardtype = getCardType(version[3], version[4]); + + if (cardtype == 6) { + if (supportSignature) { + PrintAndLogEx(INFO, " Tech: " _GREEN_("MIFARE Plus EV1")); + } else { + PrintAndLogEx(INFO, " Tech: " _YELLOW_("MIFARE Plus SE/X")); + } + isPlus = true; + } else { + + } } // MIFARE Type Identification Procedure // https://www.nxp.com/docs/en/application-note/AN10833.pdf uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8); - bool isPlus = false; if (ATQA & 0x0004) { PrintAndLogEx(INFO, " SIZE: " _GREEN_("2K") "(%s UID)", (ATQA & 0x0040) ? "7" : "4"); @@ -289,6 +369,10 @@ static int CmdHFMFPInfo(const char *Cmd) { uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false); + // DESFire answers 0x1C + // Plus answers 0x0B, 0x09 + PrintAndLogEx(INFO, "ICEE: %s", sprint_hex(data, datalen)); + if (memcmp(data, "\x67\x00", 2) == 0) { PrintAndLogEx(INFO, "\tMost likely a MIFARE DESFire tag"); PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`")); @@ -1105,10 +1189,13 @@ static int CmdHFMFPChk(const char *Cmd) { if (keyListLen == 0) { PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); return PM3_EINVARG; + } else { + PrintAndLogEx(INFO, "Loaded " _YELLOW_("%zu") "keys", keyListLen); } if (!verbose) printf("Search keys:"); + while (true) { res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); if (res == PM3_EOPABORTED) diff --git a/client/util.c b/client/util.c index 36362f83b..654a87cc3 100644 --- a/client/util.c +++ b/client/util.c @@ -212,7 +212,6 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex sprintf(tmp, " "); // remove last space - --tmp; *tmp = '\0'; return; } diff --git a/include/protocols.h b/include/protocols.h index 357fa9e4d..b927058b0 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -349,16 +349,12 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. // 6x xx = ERROR // MIFARE DESFire command set: - -#define MFDES_GET_VERSION 0x60 #define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE #define MFDES_AUTHENTICATE_ISO 0x1A // AUTHENTICATE_STANDARD #define MFDES_AUTHENTICATE_AES 0xAA -#define MFDES_CREATE_APPLICATION 0xCA -#define MFDES_DELETE_APPLICATION 0xDA + #define MFDES_CREDIT 0x0C #define MFDES_LIMITED_CREDIT 0x1C -#define MFDES_DEBIT 0xDC #define MFDES_WRITE_RECORD 0x3B #define MFDES_READSIG 0x3C #define MFDES_WRITE_DATA 0x3D @@ -366,6 +362,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MFDES_CHANGE_KEY_SETTINGS 0x54 #define MFDES_SELECT_APPLICATION 0x5A #define MFDES_CHANGE_FILE_SETTINGS 0x5F +#define MFDES_GET_VERSION 0x60 #define MFDES_GET_ISOFILE_IDS 0x61 #define MFDES_GET_KEY_VERSION 0x64 #define MFDES_GET_APPLICATION_IDS 0x6A @@ -373,15 +370,32 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MFDES_GET_FREE_MEMORY 0x6E #define MFDES_GET_DF_NAMES 0x6D #define MFDES_GET_FILE_IDS 0x6F +#define MFDES_ABORT_TRANSACTION 0xA7 +#define MFDES_ADDITIONAL_FRAME 0xAF #define MFDES_READ_RECORDS 0xBB #define MFDES_READ_DATA 0xBD -#define MFDES_ABORT_TRANSACTION 0xA7 +#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0 +#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1 +#define MFDES_CHANGE_KEY 0xC4 +#define MFDES_COMMIT_TRANSACTION 0xC7 +#define MFDES_CREATE_APPLICATION 0xCA +#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB +#define MFDES_CREATE_VALUE_FILE 0xCC +#define MFDES_CREATE_STD_DATA_FILE 0xCD +#define MFDES_DELETE_APPLICATION 0xDA +#define MFDES_DEBIT 0xDC +#define MFDES_DELETE_FILE 0xDF +#define MFDES_CLEAR_RECORD_FILE 0xEB +#define MFDES_GET_FILE_SETTINGS 0xF5 +#define MFDES_FORMAT_PICC 0xFC -// MIFARE DESFire status set: -#define MFDES_OPERATION_OK 0x00 -#define MFDES_NO_CHANGES 0x0C -#define MFDES_ADDITIONAL_FRAME 0xAF +// MIFARE DESFire status & error codes: +#define MFDES_S_OPERATION_OK 0x00 +#define MFDES_S_NO_CHANGES 0x0C +#define MFDES_S_SIGNATURE 0x90 +#define MFDES_S_ADDITIONAL_FRAME 0xAF + #define MFDES_E_OUT_OF_EEPROM 0x0E #define MFDES_E_ILLEGAL_COMMAND_CODE 0x1C #define MFDES_E_INTEGRITY_ERROR 0x1E @@ -401,26 +415,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MFDES_E_EEPROM 0xEE #define MFDES_E_FILE_NOT_FOUND 0xF0 #define MFDES_E_FILE_INTEGRITY 0xF1 -#define MFDES_SIGNATURE 0x90 -#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0 -#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1 -#define MFDES_CHANGE_KEY 0xC4 -#define MFDES_COMMIT_TRANSACTION 0xC7 -#define MFDES_CREATE_APPLICATION 0xCA -#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB -#define MFDES_CREATE_VALUE_FILE 0xCC -#define MFDES_CREATE_STD_DATA_FILE 0xCD - -#define MFDES_CLEAR_RECORD_FILE 0xEB - -#define MFDES_DELETE_APPLICATION 0xDA -#define MFDES_DELETE_FILE 0xDF - -#define MFDES_GET_FILE_SETTINGS 0xF5 -#define MFDES_FORMAT_PICC 0xFC - // LEGIC Commands #define LEGIC_MIM_22 0x0D #define LEGIC_MIM_256 0x1D