Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into new-standalone-mode

This commit is contained in:
Ray Lee 2021-08-08 14:58:29 +08:00
commit f317fc38f5
26 changed files with 2140 additions and 1288 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Added support to demodulate Electra tags and column parity check for EM410x (@doegox)
- Fix demod plot for various demodulations (@doegox) - Fix demod plot for various demodulations (@doegox)
- Fix `lf t55xx detect/rdbl/dump` - to override if user set `lf config` and use default values during operation (@iceman1001) - Fix `lf t55xx detect/rdbl/dump` - to override if user set `lf config` and use default values during operation (@iceman1001)
- Added `hf iclass encode --wiegand/--fc/--cn` - direct fmt/fc/cn support (@bettse) - Added `hf iclass encode --wiegand/--fc/--cn` - direct fmt/fc/cn support (@bettse)

View file

@ -96,8 +96,9 @@ static uint32_t IceEM410xdemod(void) {
return PM3_ESOFT; return PM3_ESOFT;
} }
errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); int type = Em410xDecode(dest, &size, &idx, &hi, &lo);
if (errCnt != 1) { // Did we find a Short EM or a Long EM?
if ((type & (0x1 | 0x2)) == 0) {
BigBuf_free(); BigBuf_free();
return PM3_ESOFT; return PM3_ESOFT;
} }

View file

@ -1476,17 +1476,8 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) {
WDT_HIT(); WDT_HIT();
errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); int type = Em410xDecode(dest, &size, &idx, &hi, &lo);
if (errCnt == 1) { if (type & 0x1) {
if (size == 128) {
Dbprintf("EM XL TAG ID: " _GREEN_("%06x%08x%08x") " - ( %05d_%03d_%08d )",
hi,
(uint32_t)(lo >> 32),
(uint32_t)lo,
(uint32_t)(lo & 0xFFFF),
(uint32_t)((lo >> 16LL) & 0xFF),
(uint32_t)(lo & 0xFFFFFF));
} else {
Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d )", Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d )",
(uint32_t)(lo >> 32), (uint32_t)(lo >> 32),
(uint32_t)lo, (uint32_t)lo,
@ -1494,13 +1485,43 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) {
(uint32_t)((lo >> 16LL) & 0xFF), (uint32_t)((lo >> 16LL) & 0xFF),
(uint32_t)(lo & 0xFFFFFF)); (uint32_t)(lo & 0xFFFFFF));
} }
if (type & 0x2) {
if (findone) { Dbprintf("EM XL TAG ID: " _GREEN_("%06x%08x%08x") " - ( %05d_%03d_%08d )",
hi,
(uint32_t)(lo >> 32),
(uint32_t)lo,
(uint32_t)(lo & 0xFFFF),
(uint32_t)((lo >> 16LL) & 0xFF),
(uint32_t)(lo & 0xFFFFFF));
}
if (type & 0x4) {
uint64_t data = (lo << 20) >> 20;
// Convert back to Short ID
uint64_t id = ((uint64_t)hi << 16) | (lo >> 48);
if ((data & 0xFFFFFFFF) == 0) {
Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) Electra "_GREEN_("%i"),
(uint32_t)(id >> 32),
(uint32_t)id,
(uint32_t)(id & 0xFFFF),
(uint32_t)((id >> 16LL) & 0xFF),
(uint32_t)(id & 0xFFFFFF),
(uint32_t)(data >> 32));
} else {
Dbprintf("EM TAG ID: " _GREEN_("%02x%08x") " - ( %05d_%03d_%08d ) on 128b frame with data "_GREEN_("%03x%08x"),
(uint32_t)(id >> 32),
(uint32_t)id,
(uint32_t)(id & 0xFFFF),
(uint32_t)((id >> 16LL) & 0xFF),
(uint32_t)(id & 0xFFFFFF),
(uint32_t)(data >> 32),
(uint32_t)data);
}
}
if ((type > 0) && findone) {
*high = hi; *high = hi;
*low = lo; *low = lo;
break; break;
} }
}
hi = lo = size = idx = 0; hi = lo = size = idx = 0;
clk = invert = 0; clk = invert = 0;
} }

View file

@ -222,6 +222,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/loclass/hash1_brute.c ${PM3_ROOT}/client/src/loclass/hash1_brute.c
${PM3_ROOT}/client/src/loclass/ikeys.c ${PM3_ROOT}/client/src/loclass/ikeys.c
${PM3_ROOT}/client/src/mifare/mad.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/mfkey.c
${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifare4.c
${PM3_ROOT}/client/src/mifare/mifaredefault.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/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
${PM3_ROOT}/client/src/ui/image.ui ${PM3_ROOT}/client/src/ui/image.ui
${PM3_ROOT}/client/src/aiddesfire.c
${PM3_ROOT}/client/src/aidsearch.c ${PM3_ROOT}/client/src/aidsearch.c
${PM3_ROOT}/client/src/cmdanalyse.c ${PM3_ROOT}/client/src/cmdanalyse.c
${PM3_ROOT}/client/src/cmdcrc.c ${PM3_ROOT}/client/src/cmdcrc.c

View file

@ -474,7 +474,7 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@
# enumerations # # enumerations #
################ ################
SRCS = aiddesfire.c \ SRCS = mifare/aiddesfire.c \
aidsearch.c \ aidsearch.c \
cmdanalyse.c \ cmdanalyse.c \
cmdcrc.c \ cmdcrc.c \

View file

@ -7875,6 +7875,13 @@
"service_provider": "Atelei Engineering", "service_provider": "Atelei Engineering",
"system_integrator": "Atelei Engineering" "system_integrator": "Atelei Engineering"
}, },
{
"application": "Access control",
"company": "LEAF Identity",
"mad": "0x51CD",
"service_provider": "",
"system_integrator": ""
},
{ {
"application": "Access & biometrics application", "application": "Access & biometrics application",
"company": "Manufacture Francaise des Pneumatiques MICHELIN", "company": "Manufacture Francaise des Pneumatiques MICHELIN",

View file

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

View file

@ -592,10 +592,11 @@ static int Cmdmandecoderaw(const char *Cmd) {
uint64_t id = 0; uint64_t id = 0;
uint32_t hi = 0; uint32_t hi = 0;
size_t idx = 0; size_t idx = 0;
if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) { int res = Em410xDecode(bits, &size, &idx, &hi, &id);
if (res > 0) {
//need to adjust to set bitstream back to manchester encoded data //need to adjust to set bitstream back to manchester encoded data
//setDemodBuff(bits, size, idx); //setDemodBuff(bits, size, idx);
printEM410x(hi, id, false); printEM410x(hi, id, false, res);
} }
} }
setDemodBuff(bits, size, 0); setDemodBuff(bits, size, 0);

File diff suppressed because it is too large Load diff

View file

@ -1269,6 +1269,7 @@ uint32_t GetHF14AMfU_Type(void) {
NT2H1001G0DUx 0004040202000B03 NT2H1001G0DUx 0004040202000B03
NT2H1311TTDUx 0004040203000F03 NT2H1311TTDUx 0004040203000F03
Micron UL 0034210101000E03 Micron UL 0034210101000E03
Feiju NTAG 0053040201000F03
*/ */
if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; } if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; }
@ -1281,6 +1282,7 @@ uint32_t GetHF14AMfU_Type(void) {
else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = NTAG_210u; break; } else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = NTAG_210u; break; }
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; } else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; }
else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } //Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter)
else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; }

View file

@ -100,10 +100,47 @@ static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock, uint8_t gap
} }
//print 64 bit EM410x ID in multiple formats //print 64 bit EM410x ID in multiple formats
void printEM410x(uint32_t hi, uint64_t id, bool verbose) { void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type) {
if (!id && !hi) return; if (!id && !hi) return;
if (verbose == false) {
if (type & 0x1) { // Short ID
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
}
if (type & 0x2) { // Long ID
PrintAndLogEx(SUCCESS, "EM 410x XL ID "_GREEN_("%06X%016" PRIX64), hi, id);
}
if (type & 0x4) { // Short Extended ID
uint64_t data = (id << 20) >> 20;
// Convert back to Short ID
id = ((uint64_t)hi << 16) | (id >> 48);
if ((data & 0xFFFFFFFF) == 0) {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64)" Electra "_GREEN_("%03" PRIu64), id, data >> 32);
} else {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64)" on 128b frame with data "_GREEN_("%011" PRIX64), id, data);
}
}
return;
}
if (type & 0x2) { // Long ID
//output 88 bit em id
PrintAndLogEx(SUCCESS, "EM 410x XL ID "_GREEN_("%06X%016" PRIX64)" ( RF/%d )", hi, id, g_DemodClock);
}
if (type & 0x4) { // Short Extended ID
PrintAndLogEx(SUCCESS, "EM 410x Short ID found on a 128b frame");
uint64_t data = (id << 20) >> 20;
PrintAndLogEx(SUCCESS, " Data after ID: "_GREEN_("%011" PRIX64), data);
if ((data & 0xFFFFFFFF) == 0) {
PrintAndLogEx(SUCCESS, " Possibly an Electra (RO), 0x"_GREEN_("%03" PRIX64)" = "_GREEN_("%03" PRIu64), data >> 32, data >> 32);
}
PrintAndLogEx(SUCCESS, " Short ID details:");
// Convert back to Short ID
id = ((uint64_t)hi << 16) | (id >> 48);
}
if (type & (0x4 | 0x1)) { // Short Extended or Short ID
//output 40 bit em id
uint64_t n = 1; uint64_t n = 1;
uint64_t id2lo = 0; uint64_t id2lo = 0;
uint8_t m, i; uint8_t m, i;
@ -112,23 +149,6 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose) {
id2lo = (id2lo << 1LL) | ((id & (n << (i + ((m - 1) * 8)))) >> (i + ((m - 1) * 8))); id2lo = (id2lo << 1LL) | ((id & (n << (i + ((m - 1) * 8)))) >> (i + ((m - 1) * 8)));
} }
} }
if (verbose == false) {
if (hi) {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id);
} else {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
}
return;
}
if (hi) {
//output 88 bit em id
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id);
PrintAndLogEx(SUCCESS, "EM410x XL ( RF/%d )", g_DemodClock);
} else {
//output 40 bit em id
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock); PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock);
PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------");
@ -252,7 +272,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) {
printDemodBuff(0, false, false, true); printDemodBuff(0, false, false, true);
} }
printEM410x(*hi, *lo, verbose); printEM410x(*hi, *lo, verbose, ans);
g_em410xid = *lo; g_em410xid = *lo;
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -16,7 +16,7 @@
int CmdLFEM410X(const char *Cmd); int CmdLFEM410X(const char *Cmd);
int demodEM410x(bool verbose); int demodEM410x(bool verbose);
void printEM410x(uint32_t hi, uint64_t id, bool verbose); void printEM410x(uint32_t hi, uint64_t id, bool verbose, int type);
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose); int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);

View file

@ -198,12 +198,17 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
parity |= DemodBuffer[34] << 1; // b2 parity |= DemodBuffer[34] << 1; // b2
parity |= DemodBuffer[38] << 0; // b1 parity |= DemodBuffer[38] << 0; // b1
uint8_t checksum = 0;
checksum |= DemodBuffer[62] << 1; // b2
checksum |= DemodBuffer[63] << 0; // b1
PrintAndLogEx(SUCCESS, "Fmt " _GREEN_("26") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u") " Parity: " _GREEN_("%1d%1d") PrintAndLogEx(SUCCESS, "Fmt " _GREEN_("26") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u") " Parity: " _GREEN_("%1d%1d")
, fc , fc
, csn , csn
, parity >> 1 & 0x01 , parity >> 1 & 0x01
, parity & 0x01 , parity & 0x01
); );
PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01);
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
// This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS // This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS

View file

@ -327,7 +327,7 @@ bool asn1_tag_dump(const struct tlv *tlv, int level, bool *candump) {
*/ */
PrintAndLogEx(INFO, PrintAndLogEx(INFO,
"%*s-- %02X [%02ZX] '"_YELLOW_("%s") "'" NOLF "%*s-- %02X [%02zX] '"_YELLOW_("%s") "'" NOLF
, (level * 4) , (level * 4)
, " " , " "
, tlv->tag , tlv->tag

View file

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

View file

@ -11,6 +11,7 @@
#include "common.h" #include "common.h"
const char *nxp_cluster_to_text(uint8_t cluster);
int AIDDFDecodeAndPrint(uint8_t aid[3]); int AIDDFDecodeAndPrint(uint8_t aid[3]);
#endif // _AIDDESFIRE_H_ #endif // _AIDDESFIRE_H_

View file

@ -32,6 +32,8 @@
#include "util_posix.h" // msleep #include "util_posix.h" // msleep
#include "mifare/desfire_crypto.h" #include "mifare/desfire_crypto.h"
#include "desfiresecurechan.h" #include "desfiresecurechan.h"
#include "mifare/mad.h"
#include "mifare/aiddesfire.h"
const CLIParserOption DesfireAlgoOpts[] = { const CLIParserOption DesfireAlgoOpts[] = {
{T_DES, "des"}, {T_DES, "des"},
@ -261,6 +263,10 @@ const char *DesfireAuthErrorToStr(int error) {
return "Can't select application."; return "Can't select application.";
case 201: case 201:
return "Authentication retured no error but channel not authenticated."; return "Authentication retured no error but channel not authenticated.";
case 202:
return "Can't select application by ISO ID.";
case 203:
return "Can't select file by ISO ID.";
case 301: case 301:
return "ISO Get challenge error."; return "ISO Get challenge error.";
case 302: case 302:
@ -347,7 +353,7 @@ void DesfirePrintContext(DesfireContext *ctx) {
desfire_get_key_block_length(ctx->keyType), desfire_get_key_block_length(ctx->keyType),
sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType))); sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType)));
if (ctx->secureChannel == DACEV2) { if (ctx->secureChannel == DACEV2) {
PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%08x", PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%04x",
sprint_hex(ctx->TI, 4), sprint_hex(ctx->TI, 4),
ctx->cmdCntr); ctx->cmdCntr);
} }
@ -671,11 +677,12 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext *ctx, ui
} }
static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) { static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) {
uint32_t rlen = 0; uint8_t data[1050] = {0};
int res = DESFIRESendApduEx(activate_field, apdu, le, resp, 255, &rlen, sw); uint32_t datalen = 0;
int res = DESFIRESendApduEx(activate_field, apdu, le, data, sizeof(data), &datalen, sw);
if (res == PM3_SUCCESS) if (res == PM3_SUCCESS)
*resplen = rlen; DesfireSecureChannelDecode(ctx, data, datalen, 0, resp, resplen);
return res; return res;
} }
@ -694,9 +701,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) { static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t dstdatalen) {
size_t len = 0; size_t len = 0;
for (int i = 0; i < *blockdatacount; i++) { for (int i = 0; i < *blockdatacount; i++) {
memset(&blockdata[i * blockdatasize + 1], 0, blockdatasize - 1);
size_t tlen = len + blockdata[i * blockdatasize]; size_t tlen = len + blockdata[i * blockdatasize];
if (tlen > dstdatalen) if (tlen > dstdatalen) {
tlen = dstdatalen; tlen = dstdatalen;
if (tlen >= len)
blockdata[i * blockdatasize] = tlen - len;
else
blockdata[i * blockdatasize] = 0;
}
if (len == tlen) { if (len == tlen) {
*blockdatacount = i; *blockdatacount = i;
break; break;
@ -764,6 +777,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
size_t resplen = 0; size_t resplen = 0;
uint8_t respcode = 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); int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true, 0);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
if (resplen != 0) if (resplen != 0)
@ -800,6 +814,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
size_t resplen = 0; size_t resplen = 0;
uint8_t respcode = 0; uint8_t respcode = 0;
ctx->secureChannel = DACNone;
int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0); int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
if (resplen != 0) if (resplen != 0)
@ -809,11 +824,28 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
if (respcode != MFDES_S_OPERATION_OK) if (respcode != MFDES_S_OPERATION_OK)
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
DesfireClearSession(ctx);
ctx->appSelected = (aid != 0x000000);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
return res; 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) { int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
if (verbose) if (verbose)
DesfirePrintContext(dctx); DesfirePrintContext(dctx);
@ -859,6 +891,62 @@ int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secu
return DesfireSelectAndAuthenticateEx(dctx, secureChannel, aid, false, verbose); return DesfireSelectAndAuthenticateEx(dctx, secureChannel, aid, false, verbose);
} }
int DesfireSelectAndAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, uint16_t isofileid, bool noauth, bool verbose) {
if (verbose)
DesfirePrintContext(dctx);
int res = 0;
if (useaid) {
dctx->cmdSet = DCCNativeISO;
if (verbose)
PrintAndLogEx(INFO, "Select via " _CYAN_("native iso wrapping") " interface");
res = DesfireSelectAIDHex(dctx, aid, false, 0);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
return 200;
}
if (verbose)
PrintAndLogEx(INFO, "App %06x via native iso channel is " _GREEN_("selected"), aid);
dctx->cmdSet = DCCISO;
} else {
res = DesfireSelectEx(dctx, true, ISWIsoID, isoappid, NULL);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire iso application select " _RED_("error") ".");
return 202;
}
if (verbose)
PrintAndLogEx(INFO, "Application iso id %04x is " _GREEN_("selected"), isoappid);
res = DesfireSelectEx(dctx, false, ISWIsoID, isofileid, NULL);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire iso file select " _RED_("error") ".");
return 203;
}
if (verbose)
PrintAndLogEx(INFO, "Application iso id %04x file iso id %04x is " _GREEN_("selected"), isoappid, isofileid);
}
if (!noauth) {
res = DesfireAuthenticate(dctx, secureChannel, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res));
return res;
}
if (DesfireIsAuthenticated(dctx)) {
if (verbose)
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
} else {
return 201;
}
}
return PM3_SUCCESS;
}
static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES // 4 different crypto arg1 DES, 3DES, 3K3DES, AES
@ -1153,6 +1241,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0}; uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0};
uint8_t rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA'
uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB' uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB'
uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
@ -1201,8 +1290,6 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE);
rol(rotRndB, CRYPTO_AES_BLOCK_SIZE); rol(rotRndB, CRYPTO_AES_BLOCK_SIZE);
uint8_t encRndA[16] = {0x00};
// - Encrypt our response // - Encrypt our response
uint8_t tmp[32] = {0x00}; uint8_t tmp[32] = {0x00};
memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE); memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
@ -1232,20 +1319,21 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
} }
// Part 4 // Part 4
memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE);
uint8_t data[32] = {0}; uint8_t data[32] = {0};
if (aes_decode(IV, key, recv_data, data, recv_len)) if (aes_decode(IV, key, recv_data, data, recv_len))
return 10; return 10;
rol(RndA, CRYPTO_AES_BLOCK_SIZE); // rotate rndA to check
memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE);
rol(rotRndA, CRYPTO_AES_BLOCK_SIZE);
uint8_t *recRndA = (firstauth) ? &data[4] : data; uint8_t *recRndA = (firstauth) ? &data[4] : data;
if (memcmp(RndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) {
if (g_debugMode > 1) { if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE));
PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE));
} }
return 11; return 11;
} }
@ -1295,7 +1383,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
// encode // encode
DesfireClearIV(dctx); DesfireClearIV(dctx);
DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303 DesfireCryptoEncDec(dctx, DCOMainKey, both, rndlen * 2, both, true); // error 303
// external authenticate // external authenticate
res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both); res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both);
@ -1314,7 +1402,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
// decode rnddata // decode rnddata
uint8_t piccrnd2[64] = {0}; uint8_t piccrnd2[64] = {0};
DesfireCryptoEncDec(dctx, false, rnddata, rndlen * 2, piccrnd2, false); // error 307 DesfireCryptoEncDec(dctx, DCOMainKey, rnddata, rndlen * 2, piccrnd2, false); // error 307
// check // check
if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0) if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0)
@ -1344,6 +1432,279 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
return 100; 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 > 0) {
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) { 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) if (resplen)
*resplen = 0; *resplen = 0;
@ -1397,6 +1758,26 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem) {
return res; 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) { int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1); return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1);
} }
@ -1502,8 +1883,7 @@ int DesfireFillFileList(DesfireContext *dctx, FileListS FileList, size_t *filesc
isoindx++; isoindx++;
} }
} }
if (isoindx > 0)
isoindx--;
if (isoindx * 2 != buflen) if (isoindx * 2 != buflen)
PrintAndLogEx(WARNING, "Wrong ISO ID list length. must be %zu but %zu", buflen, isoindx * 2); PrintAndLogEx(WARNING, "Wrong ISO ID list length. must be %zu but %zu", buflen, isoindx * 2);
} else { } else {
@ -1610,47 +1990,19 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin
return DesfireCommandTxData(dctx, MFDES_UPDATE_RECORD, xdata, 10 + len); 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) { static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
PrintAndLogEx(SUCCESS, "PICC level rights:"); 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..] 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.] 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, ""); PrintAndLogEx(SUCCESS, "");
if (print2ndbyte) if (print2ndbyte) {
DesfirePrintCardKeyType(numkeys >> 6);
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
} }
}
static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
// Access rights. // Access rights.
@ -1676,14 +2028,14 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print
break; break;
} }
PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _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)) ? "NO" : "YES"); 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)) ? "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") : "NO (frozen)"); PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
PrintAndLogEx(SUCCESS, ""); PrintAndLogEx(SUCCESS, "");
if (print2ndbyte) { if (print2ndbyte) {
PrintKeyType(numkeys >> 6); DesfirePrintCardKeyType(numkeys >> 6);
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f); PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
if (numkeys & 0x20) if (numkeys & 0x20)
PrintAndLogEx(SUCCESS, "iso file id: enabled"); PrintAndLogEx(SUCCESS, "iso file id: enabled");
@ -1701,6 +2053,7 @@ void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool
static const char *DesfireUnknownStr = "unknown"; static const char *DesfireUnknownStr = "unknown";
static const char *DesfireDisabledStr = "disabled"; static const char *DesfireDisabledStr = "disabled";
static const char *DesfireFreeStr = "free"; static const char *DesfireFreeStr = "free";
static const char *DesfireNAStr = "n/a";
static const DesfireCreateFileCommandsS DesfireFileCommands[] = { static const DesfireCreateFileCommandsS DesfireFileCommands[] = {
{0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true}, {0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true},
{0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true}, {0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true},
@ -1771,6 +2124,32 @@ const char *GetDesfireAccessRightStr(uint8_t right) {
return DesfireUnknownStr; 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) { 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[0] = (ch & 0x0f) | ((rw << 4) & 0xf0);
mode[1] = (w & 0x0f) | ((r << 4) & 0xf0); mode[1] = (w & 0x0f) | ((r << 4) & 0xf0);
@ -1863,10 +2242,7 @@ void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsett
} }
} }
void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) { static void DesfirePrintShortFileTypeSettings(FileSettingsS *fsettings) {
PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
switch (fsettings->fileType) { switch (fsettings->fileType) {
case 0x00: case 0x00:
case 0x01: { case 0x01: {
@ -1874,13 +2250,13 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
break; break;
} }
case 0x02: { 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); fsettings->lowerLimit, fsettings->upperLimit, fsettings->limitedCredit, fsettings->value, fsettings->value);
break; break;
} }
case 0x03: case 0x03:
case 0x04: { 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); fsettings->curRecordCount, fsettings->maxRecordCount, fsettings->recordSize, fsettings->recordSize);
break; break;
} }
@ -1892,12 +2268,49 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
break; 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)", PrintAndLogEx(NORMAL, "(%s %s %s %s)",
GetDesfireAccessRightStr(fsettings->rAccess), GetDesfireAccessRightShortStr(fsettings->rAccess),
GetDesfireAccessRightStr(fsettings->wAccess), GetDesfireAccessRightShortStr(fsettings->wAccess),
GetDesfireAccessRightStr(fsettings->rwAccess), GetDesfireAccessRightShortStr(fsettings->rwAccess),
GetDesfireAccessRightStr(fsettings->chAccess)); 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) { void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings) {
@ -2158,7 +2571,7 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke
iso14443a_crc(nkeybuf, nkeylen, &cdata[cdatalen]); iso14443a_crc(nkeybuf, nkeylen, &cdata[cdatalen]);
cdatalen += 2; cdatalen += 2;
} }
} else { } else if (dctx->secureChannel == DACEV1) {
// EV1 Checksum must cover : <KeyNo> <PrevKey XOR Newkey> [<AES NewKeyVer>] // EV1 Checksum must cover : <KeyNo> <PrevKey XOR Newkey> [<AES NewKeyVer>]
desfire_crc32_append(pckcdata, cdatalen + 2); desfire_crc32_append(pckcdata, cdatalen + 2);
cdatalen += 4; cdatalen += 4;
@ -2166,12 +2579,18 @@ int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newke
desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]); desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]);
cdatalen += 4; cdatalen += 4;
} }
} else if (dctx->secureChannel == DACEV2) {
// EV2 : <PrevKey XOR Newkey> [<AES NewKeyVer>]
if (newkeynum != dctx->keyNum) {
desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]);
cdatalen += 4;
}
} }
// send command // send command
uint8_t resp[257] = {0}; uint8_t resp[257] = {0};
size_t resplen = 0; size_t resplen = 0;
int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen, resp, &resplen); int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen + 1, resp, &resplen);
// check response // check response
if (res == 0 && resplen > 0) if (res == 0 && resplen > 0)
@ -2192,21 +2611,9 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para
memcpy(&data[1], param, paramlen); memcpy(&data[1], param, paramlen);
size_t datalen = 1 + paramlen; size_t datalen = 1 + paramlen;
// add crc
if (dctx->secureChannel == DACd40) {
iso14443a_crc_append(&data[1], datalen - 1);
datalen += 2;
} else {
desfire_crc32_append(cdata, datalen + 1);
datalen += 4;
}
// dynamic length // dynamic length
if (paramid == 0x02) { if (paramid == 0x02 && dctx->commMode == DCMEncrypted)
data[datalen] = 0x80; dctx->commMode = DCMEncryptedWithPadding;
datalen++;
}
// send command // send command
uint8_t resp[257] = {0}; uint8_t resp[257] = {0};
@ -2220,11 +2627,11 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para
return res; return res;
} }
int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) { int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) {
uint8_t xresp[250] = {0}; uint8_t xresp[250] = {0};
size_t xresplen = 0; size_t xresplen = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw); int res = DesfireExchangeISO(fieldon, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000) if (res == PM3_SUCCESS && sw != 0x9000)
return PM3_ESOFT; return PM3_ESOFT;
@ -2239,6 +2646,10 @@ int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t
return res; return res;
} }
int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) {
return DesfireISOSelectEx(dctx, true, cntr, data, datalen, resp, resplen);
}
int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) { int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) {
return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen); return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen);
} }
@ -2280,3 +2691,87 @@ int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum,
return res; return res;
} }
int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen) {
uint8_t p1 = 0;
if (use_file_id)
p1 = 0x80 | (fileid & 0x1f);
else
p1 = (offset >> 8) & 0x7f;
uint8_t p2 = offset & 0xff;
uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000)
return PM3_ESOFT;
return res;
}
int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen) {
uint8_t p1 = 0;
if (use_file_id)
p1 = 0x80 | (fileid & 0x1f);
else
p1 = (offset >> 8) & 0x7f;
uint8_t p2 = offset & 0xff;
uint8_t resp[250] = {0};
size_t resplen = 0;
uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000)
return PM3_ESOFT;
return res;
}
int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen) {
uint8_t p2 = ((fileid & 0x1f) << 3) | ((read_all_records) ? 0x05 : 0x04);
uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000)
return PM3_ESOFT;
return res;
}
int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen) {
uint8_t p2 = ((fileid & 0x1f) << 3);
uint8_t resp[250] = {0};
size_t resplen = 0;
uint16_t sw = 0;
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw);
if (res == PM3_SUCCESS && sw != 0x9000)
return PM3_ESOFT;
return res;
}
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname) {
uint8_t resp[250] = {0};
size_t resplen = 0;
if (way == ISWMF || (way == ISWDFName && dfname == NULL)) {
return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen);
} else if (way == ISW6bAID) {
if (fieldon)
return DesfireSelectAIDHex(ctx, id, false, 0);
else
return DesfireSelectAIDHexNoFieldOn(ctx, id);
} else if (way == ISWIsoID) {
uint8_t data[2] = {0};
Uint2byteToMemBe(data, id);
return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, data, 2, resp, &resplen);
} else if (way == ISWDFName) {
return DesfireISOSelect(ctx, ISSMFDFEF, NULL, 0, resp, &resplen);
}
return PM3_ESOFT;
}
int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname) {
return DesfireSelectEx(ctx, true, way, id, dfname);
}

View file

@ -30,6 +30,14 @@ enum DesfireISOSelectControlEnum {
}; };
typedef enum DesfireISOSelectControlEnum DesfireISOSelectControl; typedef enum DesfireISOSelectControlEnum DesfireISOSelectControl;
enum DesfireISOSelectWayEnum {
ISW6bAID,
ISWMF,
ISWIsoID,
ISWDFName
};
typedef enum DesfireISOSelectWayEnum DesfireISOSelectWay;
typedef struct { typedef struct {
const uint8_t id; const uint8_t id;
const char *text; const char *text;
@ -85,6 +93,48 @@ typedef struct {
typedef FileListElmS FileListS[32]; 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 { typedef enum {
RFTAuto, RFTAuto,
RFTData, RFTData,
@ -111,20 +161,33 @@ 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 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 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 DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid);
void DesfirePrintAIDFunctions(uint32_t appid);
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname);
int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname);
const char *DesfireAuthErrorToStr(int error); const char *DesfireAuthErrorToStr(int error);
int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); 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 DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose);
int DesfireSelectAndAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, uint16_t isofileid, bool noauth, bool verbose);
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, 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 DesfireFormatPICC(DesfireContext *dctx);
int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem); int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem);
int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireGetAIDList(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 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 DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen);
int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid); int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid);
@ -133,7 +196,6 @@ int DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *data, size_t len, uint8_
int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len); int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len);
void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte); 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 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); 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 +209,7 @@ int DesfireGetFileISOIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen
void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsettings); void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsettings);
void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings); void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings);
void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings);
void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings); void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings);
int DesfireGetFileSettings(DesfireContext *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen); int DesfireGetFileSettings(DesfireContext *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen);
int DesfireGetFileSettingsStruct(DesfireContext *dctx, uint8_t fileid, FileSettingsS *fsettings); int DesfireGetFileSettingsStruct(DesfireContext *dctx, uint8_t fileid, FileSettingsS *fsettings);
@ -154,6 +217,7 @@ int DesfireChangeFileSettings(DesfireContext *dctx, uint8_t *data, size_t datale
const DesfireCreateFileCommandsS *GetDesfireFileCmdRec(uint8_t type); const DesfireCreateFileCommandsS *GetDesfireFileCmdRec(uint8_t type);
const char *GetDesfireAccessRightStr(uint8_t right); 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 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 DesfireDecodeFileAcessMode(uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch);
void DesfirePrintAccessRight(uint8_t *data); void DesfirePrintAccessRight(uint8_t *data);
@ -178,8 +242,15 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin
int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen); int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen);
int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen); int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen);
int DesfireISOSelectFile(DesfireContext *dctx, char *appdfname, uint16_t appid, uint16_t fileid);
int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen);
int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen); int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen);
int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data); int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data);
int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen); int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen);
int DesfireISOReadBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen);
int DesfireISOUpdateBinary(DesfireContext *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen);
int DesfireISOReadRecords(DesfireContext *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen);
int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, size_t datalen);
#endif // __DESFIRECORE_H #endif // __DESFIRECORE_H

View file

@ -217,7 +217,7 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm
memcpy(dstdata, edata, block_size); memcpy(dstdata, edata, block_size);
} }
void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) { void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) {
uint8_t data[1024] = {0}; uint8_t data[1024] = {0};
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
@ -234,10 +234,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
size_t offset = 0; size_t offset = 0;
while (offset < srcdatalen) { while (offset < srcdatalen) {
if (use_session_key) if (key_type == DCOSessionKeyMac) {
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
else } else if (key_type == DCOSessionKeyEnc) {
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyEnc, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
} else {
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
}
offset += block_size; offset += block_size;
} }
@ -250,13 +253,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
memcpy(dstdata, data, srcdatalen); memcpy(dstdata, data, srcdatalen);
} }
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
bool dir_to_send = encode; bool dir_to_send = encode;
bool xencode = encode; bool xencode = encode;
if (ctx->secureChannel == DACd40) if (ctx->secureChannel == DACd40)
xencode = false; xencode = false;
DesfireCryptoEncDecEx(ctx, use_session_key, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL);
} }
static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) { static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
@ -269,7 +272,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
uint8_t ivect[kbs]; uint8_t ivect[kbs];
memset(ivect, 0, kbs); memset(ivect, 0, kbs);
DesfireCryptoEncDecEx(ctx, true, l, kbs, l, true, true, ivect); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect);
bool txor = false; bool txor = false;
@ -314,7 +317,7 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
bin_xor(buffer + len - kbs, sk1, kbs); bin_xor(buffer + len - kbs, sk1, kbs);
} }
DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true); DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true);
if (cmac != NULL) if (cmac != NULL)
memcpy(cmac, ctx->IV, kbs); memcpy(cmac, ctx->IV, kbs);
@ -353,6 +356,50 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key) {
return version; 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 DesfireFileCommModeToCommMode(uint8_t file_comm_mode) {
DesfireCommunicationMode mode = DCMNone; DesfireCommunicationMode mode = DCMNone;
switch (file_comm_mode & 0x03) { switch (file_comm_mode & 0x03) {
@ -382,6 +429,7 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode) {
fmode = 0x01; fmode = 0x01;
break; break;
case DCMEncrypted: case DCMEncrypted:
case DCMEncryptedWithPadding:
case DCMEncryptedPlain: case DCMEncryptedPlain:
fmode = 0x11; fmode = 0x11;
break; break;
@ -474,6 +522,19 @@ void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv) {
memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE); memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE);
} }
int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) {
uint8_t mdata[1050] = {0};
size_t mdatalen = 0;
mdata[0] = cmd;
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
memcpy(&mdata[3], ctx->TI, 4);
if (data != NULL && datalen > 0)
memcpy(&mdata[7], data, datalen);
mdatalen = 1 + 2 + 4 + datalen;
return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen);
}
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) { void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
crc32_ex(data, len, crc); crc32_ex(data, len, crc);

View file

@ -58,9 +58,15 @@ typedef enum {
DCMPlain, DCMPlain,
DCMMACed, DCMMACed,
DCMEncrypted, DCMEncrypted,
DCMEncryptedWithPadding,
DCMEncryptedPlain DCMEncryptedPlain
} DesfireCommunicationMode; } DesfireCommunicationMode;
typedef enum {
DCOMainKey,
DCOSessionKeyMac,
DCOSessionKeyEnc
} DesfireCryptoOpKeyType;
typedef struct DesfireContextS { typedef struct DesfireContextS {
uint8_t keyNum; uint8_t keyNum;
@ -100,19 +106,24 @@ size_t DesfireGetMACLength(DesfireContext *ctx);
size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen); size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen);
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode); void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv); void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv);
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac); void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version);
uint8_t DesfireDESKeyGetVersion(uint8_t *key); 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); DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode);
uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode);
void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key); void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key);
void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey); void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey);
void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv); void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv);
int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac);
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc); void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc);
void desfire_crc32_append(uint8_t *data, const size_t len); void desfire_crc32_append(uint8_t *data, const size_t len);

View file

@ -41,27 +41,24 @@ static bool CommandCanUseAnyChannel(uint8_t cmd) {
} }
static const AllowedChannelModesS AllowedChannelModes[] = { static const AllowedChannelModesS AllowedChannelModes[] = {
// D40 channel
{MFDES_SELECT_APPLICATION, DACd40, DCCNative, DCMPlain}, {MFDES_SELECT_APPLICATION, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMPlain},
{MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMPlain},
{MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMPlain},
{MFDES_GET_DF_NAMES, DACd40, DCCNative, DCMPlain},
{MFDES_GET_KEY_SETTINGS, DACd40, DCCNative, DCMPlain},
{MFDES_GET_KEY_VERSION, DACd40, DCCNative, DCMPlain},
{MFDES_GET_FREE_MEMORY, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_STD_DATA_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_BACKUP_DATA_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_VALUE_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_LINEAR_RECORD_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_CYCLIC_RECORD_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_GET_VALUE, DACd40, DCCNative, DCMPlain},
{MFDES_CREDIT, DACd40, DCCNative, DCMPlain},
{MFDES_LIMITED_CREDIT, DACd40, DCCNative, DCMPlain},
{MFDES_DEBIT, DACd40, DCCNative, DCMPlain},
{MFDES_COMMIT_TRANSACTION, DACd40, DCCNative, DCMPlain},
{MFDES_CLEAR_RECORD_FILE, DACd40, DCCNative, DCMPlain},
{MFDES_GET_FILE_SETTINGS, DACd40, DCCNative, DCMPlain},
{MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMMACed},
{MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMMACed},
{MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMMACed},
{MFDES_GET_DF_NAMES, DACd40, DCCNative, DCMMACed},
{MFDES_GET_KEY_SETTINGS, DACd40, DCCNative, DCMMACed},
{MFDES_GET_KEY_VERSION, DACd40, DCCNative, DCMMACed},
{MFDES_GET_FREE_MEMORY, DACd40, DCCNative, DCMMACed},
{MFDES_CREATE_STD_DATA_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_CREATE_BACKUP_DATA_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_CREATE_VALUE_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_CREATE_LINEAR_RECORD_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_CREATE_CYCLIC_RECORD_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_COMMIT_TRANSACTION, DACd40, DCCNative, DCMMACed},
{MFDES_CLEAR_RECORD_FILE, DACd40, DCCNative, DCMMACed},
{MFDES_GET_FILE_SETTINGS, DACd40, DCCNative, DCMMACed},
{MFDES_GET_VALUE, DACd40, DCCNative, DCMMACed}, {MFDES_GET_VALUE, DACd40, DCCNative, DCMMACed},
{MFDES_CREDIT, DACd40, DCCNative, DCMMACed}, {MFDES_CREDIT, DACd40, DCCNative, DCMMACed},
{MFDES_DEBIT, DACd40, DCCNative, DCMMACed}, {MFDES_DEBIT, DACd40, DCCNative, DCMMACed},
@ -85,10 +82,11 @@ static const AllowedChannelModesS AllowedChannelModes[] = {
{MFDES_CHANGE_KEY, DACd40, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY, DACd40, DCCNative, DCMEncryptedPlain},
{MFDES_CHANGE_KEY_EV2, DACd40, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACd40, DCCNative, DCMEncryptedPlain},
{MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMPlain}, // EV1 and EV2 channel
{MFDES_GET_FREE_MEMORY, DACEV1, DCCNative, DCMPlain},
{MFDES_SELECT_APPLICATION, DACEV1, DCCNative, DCMPlain}, {MFDES_SELECT_APPLICATION, DACEV1, DCCNative, DCMPlain},
{MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_FREE_MEMORY, DACEV1, DCCNative, DCMMACed},
{MFDES_CREATE_APPLICATION, DACEV1, DCCNative, DCMMACed}, {MFDES_CREATE_APPLICATION, DACEV1, DCCNative, DCMMACed},
{MFDES_DELETE_APPLICATION, DACEV1, DCCNative, DCMMACed}, {MFDES_DELETE_APPLICATION, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_APPLICATION_IDS, DACEV1, DCCNative, DCMMACed}, {MFDES_GET_APPLICATION_IDS, DACEV1, DCCNative, DCMMACed},
@ -118,8 +116,26 @@ static const AllowedChannelModesS AllowedChannelModes[] = {
{MFDES_CHANGE_KEY, DACEV1, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY, DACEV1, DCCNative, DCMEncryptedPlain},
{MFDES_CHANGE_KEY_EV2, DACEV1, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACEV1, DCCNative, DCMEncryptedPlain},
// EV2 channel separately
{MFDES_AUTHENTICATE_EV2F, DACEV2, DCCNative, DCMPlain}, {MFDES_AUTHENTICATE_EV2F, DACEV2, DCCNative, DCMPlain},
{MFDES_AUTHENTICATE_EV2NF, DACEV2, DCCNative, DCMPlain}, {MFDES_AUTHENTICATE_EV2NF, DACEV2, DCCNative, DCMPlain},
// ISO channel
{ISO7816_READ_BINARY, DACd40, DCCISO, DCMPlain},
{ISO7816_UPDATE_BINARY, DACd40, DCCISO, DCMPlain},
{ISO7816_READ_RECORDS, DACd40, DCCISO, DCMPlain},
{ISO7816_APPEND_RECORD, DACd40, DCCISO, DCMPlain},
{ISO7816_READ_BINARY, DACd40, DCCISO, DCMMACed},
{ISO7816_READ_RECORDS, DACd40, DCCISO, DCMMACed},
{ISO7816_READ_BINARY, DACEV1, DCCISO, DCMPlain},
{ISO7816_UPDATE_BINARY, DACEV1, DCCISO, DCMPlain},
{ISO7816_READ_RECORDS, DACEV1, DCCISO, DCMPlain},
{ISO7816_APPEND_RECORD, DACEV1, DCCISO, DCMPlain},
{ISO7816_READ_BINARY, DACEV1, DCCISO, DCMMACed},
{ISO7816_READ_RECORDS, DACEV1, DCCISO, DCMMACed},
}; };
#define CMD_HEADER_LEN_ALL 0xffff #define CMD_HEADER_LEN_ALL 0xffff
@ -147,6 +163,68 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) {
return 0; return 0;
} }
static const uint8_t EV1D40TransmitMAC[] = {
MFDES_WRITE_DATA,
MFDES_CREDIT,
MFDES_LIMITED_CREDIT,
MFDES_DEBIT,
MFDES_WRITE_RECORD,
MFDES_UPDATE_RECORD,
MFDES_COMMIT_READER_ID,
MFDES_INIT_KEY_SETTINGS,
MFDES_ROLL_KEY_SETTINGS,
MFDES_FINALIZE_KEY_SETTINGS,
};
static bool DesfireEV1D40TransmitMAC(DesfireContext *ctx, uint8_t cmd) {
if (ctx->secureChannel != DACd40 && ctx->secureChannel != DACEV1)
return true;
for (int i = 0; i < ARRAY_LENGTH(EV1D40TransmitMAC); i++)
if (EV1D40TransmitMAC[i] == cmd)
return true;
return false;
}
static const uint8_t D40ReceiveMAC[] = {
MFDES_READ_DATA,
MFDES_READ_DATA2,
MFDES_READ_RECORDS,
MFDES_READ_RECORDS2,
MFDES_GET_VALUE,
};
static bool DesfireEV1D40ReceiveMAC(DesfireContext *ctx, uint8_t cmd) {
if (ctx->secureChannel != DACd40)
return true;
for (int i = 0; i < ARRAY_LENGTH(D40ReceiveMAC); i++)
if (D40ReceiveMAC[i] == cmd)
return true;
return false;
}
static const uint8_t ISOChannelValidCmd[] = {
ISO7816_SELECT_FILE,
ISO7816_READ_BINARY,
ISO7816_UPDATE_BINARY,
ISO7816_READ_RECORDS,
ISO7816_APPEND_RECORD,
ISO7816_GET_CHALLENGE,
ISO7816_EXTERNAL_AUTHENTICATION,
ISO7816_INTERNAL_AUTHENTICATION
};
static bool DesfireISOChannelValidCmd(uint8_t cmd) {
for (int i = 0; i < ARRAY_LENGTH(ISOChannelValidCmd); i++)
if (ISOChannelValidCmd[i] == cmd)
return true;
return false;
}
static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t data[1024] = {0}; uint8_t data[1024] = {0};
size_t rlen = 0; size_t rlen = 0;
@ -166,22 +244,28 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
uint8_t mac[32] = {0}; uint8_t mac[32] = {0};
DesfireCryptoEncDecEx(ctx, true, data, srcmaclen, NULL, true, true, mac); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac);
memcpy(dstdata, srcdata, srcdatalen); if (DesfireEV1D40TransmitMAC(ctx, cmd)) {
memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx));
*dstdatalen = rlen; *dstdatalen = rlen;
} else if (ctx->commMode == DCMEncrypted) { }
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
if (srcdatalen <= hdrlen) if (srcdatalen <= hdrlen)
return; return;
rlen = padded_data_length(srcdatalen + 2 - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; // 2 - crc16 uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0;
rlen = padded_data_length(srcdatalen + 2 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; // 2 - crc16
memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen); memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen);
iso14443a_crc_append(data, srcdatalen - hdrlen); iso14443a_crc_append(data, srcdatalen - hdrlen);
// add padding
if (paddinglen > 0)
data[srcdatalen - hdrlen + 2] = 0x80;
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
//PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2)); //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2));
DesfireCryptoEncDec(ctx, true, data, rlen - hdrlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen - hdrlen, &dstdata[hdrlen], true);
*dstdatalen = rlen; *dstdatalen = rlen;
} else if (ctx->commMode == DCMEncryptedPlain) { } else if (ctx->commMode == DCMEncryptedPlain) {
@ -191,7 +275,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen;
memcpy(data, srcdata, srcdatalen); memcpy(data, srcdata, srcdatalen);
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
DesfireCryptoEncDec(ctx, true, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true);
*dstdatalen = rlen; *dstdatalen = rlen;
ctx->commMode = DCMEncrypted; ctx->commMode = DCMEncrypted;
} }
@ -216,20 +300,28 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
if (srcdatalen > hdrlen && ctx->commMode == DCMMACed) { if (ctx->commMode == DCMMACed && DesfireEV1D40TransmitMAC(ctx, cmd)) {
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx); *dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
} }
} else if (ctx->commMode == DCMEncrypted) { } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
rlen = padded_data_length(srcdatalen + 4 - hdrlen, desfire_get_key_block_length(ctx->keyType)); uint8_t paddinglen = (ctx->commMode == DCMEncryptedWithPadding) ? 1 : 0;
rlen = padded_data_length(srcdatalen + 4 + paddinglen - hdrlen, desfire_get_key_block_length(ctx->keyType));
data[0] = cmd; data[0] = cmd;
// crc
memcpy(&data[1], srcdata, srcdatalen); memcpy(&data[1], srcdata, srcdatalen);
desfire_crc32_append(data, srcdatalen + 1); desfire_crc32_append(data, srcdatalen + 1);
// add padding
if (paddinglen > 0)
data[srcdatalen + 1 + 4] = 0x80;
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
DesfireCryptoEncDec(ctx, true, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true);
*dstdatalen = hdrlen + rlen; *dstdatalen = hdrlen + rlen;
ctx->commMode = DCMEncrypted;
} else if (ctx->commMode == DCMEncryptedPlain) { } else if (ctx->commMode == DCMEncryptedPlain) {
if (srcdatalen <= hdrlen) if (srcdatalen <= hdrlen)
return; return;
@ -237,16 +329,47 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
memcpy(data, &srcdata[hdrlen], srcdatalen); memcpy(data, &srcdata[hdrlen], srcdatalen);
rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[hdrlen], true);
*dstdatalen = hdrlen + rlen; *dstdatalen = hdrlen + rlen;
ctx->commMode = DCMEncrypted; ctx->commMode = DCMEncrypted;
} }
} }
static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t data[1050] = {0};
size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
if (ctx->commMode == DCMMACed) {
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireEV2CalcCMAC(ctx, cmd, srcdata, srcdatalen, cmac);
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding || ctx->commMode == DCMEncryptedPlain) {
memcpy(dstdata, srcdata, hdrlen);
if (srcdatalen > hdrlen) {
rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen);
data[srcdatalen - hdrlen] = 0x80; // padding
DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx
DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[hdrlen], true);
}
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireEV2CalcCMAC(ctx, cmd, dstdata, hdrlen + rlen, cmac);
memcpy(&dstdata[hdrlen + rlen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx);
ctx->commMode = DCMEncrypted;
}
} }
void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
@ -280,30 +403,33 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
switch (ctx->commMode) { switch (ctx->commMode) {
case DCMMACed: { case DCMMACed: {
size_t maclen = DesfireGetMACLength(ctx); size_t maclen = DesfireGetMACLength(ctx);
if (srcdatalen > maclen) { if (srcdatalen > maclen && DesfireEV1D40ReceiveMAC(ctx, ctx->lastCommand)) {
uint8_t mac[16] = {0}; uint8_t mac[16] = {0};
rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType)); rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, srcdata, srcdatalen - maclen); memcpy(data, srcdata, srcdatalen - maclen);
DesfireCryptoEncDecEx(ctx, true, data, rlen, NULL, true, true, mac); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, rlen, NULL, true, true, mac);
if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) { if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) {
*dstdatalen = srcdatalen - maclen; *dstdatalen = srcdatalen - maclen;
if (GetAPDULogging())
PrintAndLogEx(INFO, "Received MAC OK");
} else { } else {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
//PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen)); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen));
//PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(mac, maclen)); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(mac, maclen));
} }
} }
break; break;
} }
case DCMEncrypted: case DCMEncrypted:
case DCMEncryptedWithPadding:
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
return; return;
} }
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false);
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2);
@ -345,17 +471,20 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata,
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac); DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx)));
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx)));
} else {
if (GetAPDULogging())
PrintAndLogEx(INFO, "Received MAC OK");
} }
} else if (ctx->commMode == DCMEncrypted) { } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
return; return;
} }
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false);
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4);
@ -377,9 +506,92 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata,
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
if (ctx->commMode == DCMMACed) {
if (srcdatalen < DesfireGetMACLength(ctx)) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
return;
}
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac);
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx)));
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx)));
} else {
if (GetAPDULogging())
PrintAndLogEx(INFO, "Received MAC OK");
}
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
if (srcdatalen < DesfireGetMACLength(ctx)) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
return;
}
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, cmac);
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx)));
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx)));
} else {
if (GetAPDULogging())
PrintAndLogEx(INFO, "Received MAC OK");
}
if (*dstdatalen >= desfire_get_key_block_length(ctx->keyType)) {
DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx
DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, *dstdatalen, dstdata, false);
size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen);
if (puredatalen != 0) {
*dstdatalen = puredatalen;
} else {
PrintAndLogEx(WARNING, "Padding search error.");
}
}
}
}
static void DesfireISODecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
uint8_t data[1050] = {0};
if (srcdatalen < DesfireGetMACLength(ctx))
return;
uint8_t maclen = DesfireGetMACLength(ctx);
if (DesfireIsAuthenticated(ctx)) {
memcpy(data, srcdata, srcdatalen - maclen);
data[*dstdatalen] = 0x00; // respcode
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireCryptoCMAC(ctx, data, srcdatalen - maclen + 1, cmac);
if (memcmp(&srcdata[srcdatalen - maclen], cmac, maclen) != 0) {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[srcdatalen - maclen], maclen));
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, maclen));
} else {
*dstdatalen = srcdatalen - maclen;
if (GetAPDULogging())
PrintAndLogEx(INFO, "Received MAC OK");
}
}
} }
void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
if (ctx->cmdSet == DCCISO) {
DesfireISODecode(ctx, srcdata, srcdatalen, dstdata, dstdatalen);
return;
}
switch (ctx->secureChannel) { switch (ctx->secureChannel) {
case DACd40: case DACd40:
DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen);
@ -406,9 +618,17 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De
// no security set // no security set
if (secureChannel == DACNone) if (secureChannel == DACNone)
return true; return true;
if (CommandCanUseAnyChannel(cmd)) if (CommandCanUseAnyChannel(cmd))
return true; return true;
// ISO commands
if (cmdSet == DCCISO) {
bool res = DesfireISOChannelValidCmd(cmd);
if (!res)
return false;
}
bool found = false; bool found = false;
for (int i = 0; i < ARRAY_LENGTH(AllowedChannelModes); i++) for (int i = 0; i < ARRAY_LENGTH(AllowedChannelModes); i++)
if (AllowedChannelModes[i].cmd == cmd) { if (AllowedChannelModes[i].cmd == cmd) {
@ -431,6 +651,15 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De
break; break;
} }
// ev2 like ev1
if (secureChannel == DACEV2 &&
AllowedChannelModes[i].secureChannel == DACEV1 &&
(AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) &&
AllowedChannelModes[i].commMode == commMode) {
found = true;
break;
}
} }
if (!found) if (!found)

View file

@ -269,6 +269,66 @@ static bool TestEV2IVEncode(void) {
return res; return res;
} }
// https://www.nxp.com/docs/en/application-note/AN12343.pdf
// page 54
static bool TestEV2MAC(void) {
bool res = true;
uint8_t key[] = {0x93, 0x66, 0xFA, 0x19, 0x5E, 0xB5, 0x66, 0xF5, 0xBD, 0x2B, 0xAD, 0x40, 0x20, 0xB8, 0x30, 0x02};
uint8_t ti[] = {0xE2, 0xD3, 0xAF, 0x69};
uint8_t cmd = 0x8D;
uint8_t cmddata[] = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
};
uint8_t macres[] = {0x68, 0xF2, 0xC2, 0x8C, 0x57, 0x5A, 0x16, 0x28};
// init
DesfireContext ctx = {0};
ctx.keyType = T_AES;
memcpy(ctx.sessionKeyMAC, key, 16);
memcpy(ctx.TI, ti, 4);
ctx.cmdCntr = 0;
// tx 1
uint8_t mac[16] = {0};
DesfireEV2CalcCMAC(&ctx, cmd, cmddata, sizeof(cmddata), mac);
res = res && (memcmp(mac, macres, sizeof(macres)) == 0);
// rx 1
memset(mac, 0, sizeof(mac));
uint8_t macres2[] = {0x08, 0x20, 0xF6, 0x88, 0x98, 0xC2, 0xA7, 0xF1};
uint8_t rc = 0;
ctx.cmdCntr++;
DesfireEV2CalcCMAC(&ctx, rc, NULL, 0, mac);
res = res && (memcmp(mac, macres2, sizeof(macres2)) == 0);
// tx 2
memset(mac, 0, sizeof(mac));
cmd = 0xAD;
uint8_t cmddata3[] = {0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00};
uint8_t macres3[] = {0x0D, 0x9B, 0xE1, 0x91, 0xD5, 0x96, 0x08, 0x34};
DesfireEV2CalcCMAC(&ctx, cmd, cmddata3, sizeof(cmddata3), mac);
res = res && (memcmp(mac, macres3, sizeof(macres3)) == 0);
// rx 2
rc = 0;
ctx.cmdCntr++;
uint8_t cmddata4[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t macres4[] = {0xA4, 0x9A, 0x44, 0x22, 0x2D, 0x92, 0x66, 0x66};
DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac);
res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0);
if (res)
PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail"));
return res;
}
bool DesfireTest(bool verbose) { bool DesfireTest(bool verbose) {
bool res = true; bool res = true;
@ -281,6 +341,7 @@ bool DesfireTest(bool verbose) {
res = res && TestCMACDES(); res = res && TestCMACDES();
res = res && TestEV2SessionKeys(); res = res && TestEV2SessionKeys();
res = res && TestEV2IVEncode(); res = res && TestEV2IVEncode();
res = res && TestEV2MAC();
PrintAndLogEx(INFO, "---------------------------"); PrintAndLogEx(INFO, "---------------------------");
if (res) if (res)

View file

@ -135,7 +135,7 @@ static int check_comm(void) {
char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors);
rl_set_prompt(prompt_filtered); rl_set_prompt(prompt_filtered);
rl_forced_update_display(); rl_redisplay();
#endif #endif
CloseProxmark(session.current_device); CloseProxmark(session.current_device);
} }

View file

@ -253,6 +253,55 @@ size_t removeParity(uint8_t *bits, size_t startIdx, uint8_t pLen, uint8_t pType,
return bitCnt; return bitCnt;
} }
static size_t removeEm410xParity(uint8_t *bits, size_t startIdx, bool isLong, bool *validShort, bool *validShortExtended, bool *validLong) {
uint32_t parityWd = 0;
size_t bitCnt = 0;
bool validColParity = false;
bool validRowParity = true;
bool validRowParitySkipColP = true;
*validShort = false;
*validShortExtended = false;
*validLong = false;
uint8_t bLen = isLong ? 110 : 55;
uint16_t parityCol[4] = { 0, 0, 0, 0 };
for (int word = 0; word < bLen; word += 5) {
for (int bit = 0; bit < 5; bit++) {
if (word + bit >= bLen) break;
parityWd = (parityWd << 1) | bits[startIdx + word + bit];
if ((word <= 50) && (bit < 4))
parityCol[bit] = (parityCol[bit] << 1) | bits[startIdx + word + bit];
bits[bitCnt++] = (bits[startIdx + word + bit]);
}
if (word + 5 > bLen) break;
bitCnt--; // overwrite parity with next data
validRowParity &= parityTest(parityWd, 5, 0) != 0;
if (word == 50) { // column parity nibble on short EM and on Electra
validColParity = parityTest(parityCol[0], 11, 0) != 0;
validColParity &= parityTest(parityCol[1], 11, 0) != 0;
validColParity &= parityTest(parityCol[2], 11, 0) != 0;
validColParity &= parityTest(parityCol[3], 11, 0) != 0;
} else {
validRowParitySkipColP &= parityTest(parityWd, 5, 0) != 0;
}
parityWd = 0;
}
if (!isLong && validRowParitySkipColP && validColParity) {
*validShort = true;
}
if (isLong && validRowParity) {
*validLong = true;
}
if (isLong && validRowParitySkipColP && validColParity) {
*validShortExtended = true;
}
if (*validShort || *validShortExtended || *validLong) {
return bitCnt;
} else {
return 0;
}
}
// by marshmellow // by marshmellow
// takes a array of binary values, length of bits per parity (includes parity bit), // takes a array of binary values, length of bits per parity (includes parity bit),
// Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) // Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run)
@ -2122,7 +2171,6 @@ int Em410xDecode(uint8_t *bits, size_t *size, size_t *start_idx, uint32_t *hi, u
if (bits[1] > 1) return -1; if (bits[1] > 1) return -1;
if (*size < 64) return -2; if (*size < 64) return -2;
uint8_t fmtlen;
*start_idx = 0; *start_idx = 0;
// preamble 0111111111 // preamble 0111111111
@ -2131,31 +2179,28 @@ int Em410xDecode(uint8_t *bits, size_t *size, size_t *start_idx, uint32_t *hi, u
if (!preambleSearch(bits, preamble, sizeof(preamble), size, start_idx)) if (!preambleSearch(bits, preamble, sizeof(preamble), size, start_idx))
return -4; return -4;
// (iceman) if the preamble doesn't find two occuriences, this identification fails. bool validShort = false;
fmtlen = (*size == 128) ? 22 : 10; bool validShortExtended = false;
bool validLong = false;
*size = removeEm410xParity(bits, *start_idx + sizeof(preamble), *size == 128, &validShort, &validShortExtended, &validLong);
//skip last 4bit parity row for simplicity if (validShort) {
*size = removeParity(bits, *start_idx + sizeof(preamble), 5, 0, fmtlen * 5);
switch (*size) {
case 40: {
// std em410x format // std em410x format
*hi = 0; *hi = 0;
*lo = ((uint64_t)(bytebits_to_byte(bits, 8)) << 32) | (bytebits_to_byte(bits + 8, 32)); *lo = ((uint64_t)(bytebits_to_byte(bits, 8)) << 32) | (bytebits_to_byte(bits + 8, 32));
break; // 1 = Short
}
case 88: {
// long em format
*hi = (bytebits_to_byte(bits, 24));
*lo = ((uint64_t)(bytebits_to_byte(bits + 24, 32)) << 32) | (bytebits_to_byte(bits + 24 + 32, 32));
break;
}
default:
return -6;
}
return 1; return 1;
} }
if (validShortExtended || validLong) {
// store in long em format
*hi = (bytebits_to_byte(bits, 24));
*lo = ((uint64_t)(bytebits_to_byte(bits + 24, 32)) << 32) | (bytebits_to_byte(bits + 24 + 32, 32));
// 2 = Long
// 4 = ShortExtended
return ((int)validShortExtended << 2) + ((int)validLong << 1);
}
return -6;
}
// loop to get raw HID waveform then FSK demodulate the TAG ID from it // loop to get raw HID waveform then FSK demodulate the TAG ID from it
int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo, int *waveStartIdx) { int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo, int *waveStartIdx) {

View file

@ -973,7 +973,7 @@
}, },
"help": { "help": {
"command": "help", "command": "help",
"description": "help use `<command> help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210731.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", "description": "help use `<command> help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210806.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save",
"notes": [ "notes": [
"auto" "auto"
], ],
@ -3990,7 +3990,13 @@
"command": "hf mfdes changekey", "command": "hf mfdes changekey",
"description": "change picc/application key. needs to provide keynum/key for a valid authentication (may get from default parameters).", "description": "change picc/application key. needs to provide keynum/key for a valid authentication (may get from default parameters).",
"notes": [ "notes": [
"hf mfdes changekey --aid 123456 -> execute with default factory setup" "change crypto algorithm for picc key is possible, but for app keys crypto algorithm is set by createapp command and can't be changed wo application delete",
"",
"hf mfdes changekey --aid 123456 -> execute with default factory setup. change des key 0 in the app 123456 from 00..00 to 00..00",
"hf mfdes changekey -t des --newalgo aes --newkey 11223344556677889900112233445566 --newver a5 -> change card master key to aes one",
"hf mfdes changekey --aid 123456 -t aes --key 00000000000000000000000000000000 --newkey 11223344556677889900112233445566 -> change app master key",
"hf mfdes changekey --aid 123456 -t des -n 0 --newkeyno 1 --oldkey 5555555555555555 --newkey 1122334455667788 -> change key 1 with auth from key 0",
"hf mfdes changekey --aid 123456 -t 3tdea --newkey 11223344556677889900112233445566778899001122334 -> change 3tdea key 0 from default 00..00 to provided"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4342,6 +4348,26 @@
], ],
"usage": "hf mfdes createvaluefile [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--amode <plain/mac/encrypt>] [--rawrights <access rights hex>] [--rrights <key0/../key13/free/deny>] [--wrights <key0/../key13/free/deny>] [--rwrights <key0/../key13/free/deny>] [--chrights <key0/../key13/free/deny>] [--no-auth] [--lower <hex>] [--upper <hex>] [--value <hex>] [--lcredit <dec>]" "usage": "hf mfdes createvaluefile [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--amode <plain/mac/encrypt>] [--rawrights <access rights hex>] [--rrights <key0/../key13/free/deny>] [--wrights <key0/../key13/free/deny>] [--rwrights <key0/../key13/free/deny>] [--chrights <key0/../key13/free/deny>] [--no-auth] [--lower <hex>] [--upper <hex>] [--value <hex>] [--lcredit <dec>]"
}, },
"hf mfdes default": {
"command": "hf mfdes default",
"description": "set default parameters for access to desfire card.",
"notes": [
"hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters"
],
"offline": false,
"options": [
"-h, --help this help",
"-n, --keyno <keyno> key number",
"-t, --algo <des/2tdea/3tdea/aes> crypt algo: des, 2tdea, 3tdea, aes",
"-k, --key <key> key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)",
"-f, --kdf <none/an10922/gallagher> key derivation function (kdf): none, an10922, gallagher",
"-i, --kdfi <kdfi> kdf input (hex 1-31 bytes)",
"-m, --cmode <plain/mac/encrypt> communicaton mode: plain/mac/encrypt",
"-c, --ccset <native/niso/iso> communicaton command set: native/niso/iso",
"-s, --schann <d40/ev1/ev2> secure channel: d40/ev1/ev2"
],
"usage": "hf mfdes default [-h] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>]"
},
"hf mfdes deleteapp": { "hf mfdes deleteapp": {
"command": "hf mfdes deleteapp", "command": "hf mfdes deleteapp",
"description": "delete application by its 3-byte aid. master key needs to be provided.", "description": "delete application by its 3-byte aid. master key needs to be provided.",
@ -4414,18 +4440,6 @@
], ],
"usage": "hf mfdes dump [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--no-auth]" "usage": "hf mfdes dump [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--no-auth]"
}, },
"hf mfdes enum": {
"command": "hf mfdes enum",
"description": "enumerate all aid's on mifare desfire tag",
"notes": [
"hf mfdes enum"
],
"offline": false,
"options": [
"-h, --help this help"
],
"usage": "hf mfdes enum [-h]"
},
"hf mfdes formatpicc": { "hf mfdes formatpicc": {
"command": "hf mfdes formatpicc", "command": "hf mfdes formatpicc",
"description": "format card. can be done only if enabled in the configuration. master key needs to be provided.", "description": "format card. can be done only if enabled in the configuration. master key needs to be provided.",
@ -4669,31 +4683,11 @@
}, },
"hf mfdes help": { "hf mfdes help": {
"command": "hf mfdes help", "command": "hf mfdes help",
"description": "help this help list list desfire (iso 14443a) history test test crypto --------------------------------------------------------------------------------------- hf mfdes default available offline: no set default parameters for access to desfire card.", "description": "help this help list list desfire (iso 14443a) history test test crypto --------------------------------------------------------------------------------------- hf mfdes info available offline: no get info from mifare desfire tags",
"notes": [
"hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters"
],
"offline": true,
"options": [
"-h, --help this help",
"-n, --keyno <keyno> key number",
"-t, --algo <des/2tdea/3tdea/aes> crypt algo: des, 2tdea, 3tdea, aes",
"-k, --key <key> key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)",
"-f, --kdf <none/an10922/gallagher> key derivation function (kdf): none, an10922, gallagher",
"-i, --kdfi <kdfi> kdf input (hex 1-31 bytes)",
"-m, --cmode <plain/mac/encrypt> communicaton mode: plain/mac/encrypt",
"-c, --ccset <native/niso/iso> communicaton command set: native/niso/iso",
"-s, --schann <d40/ev1/ev2> secure channel: d40/ev1/ev2"
],
"usage": "hf mfdes default [-h] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>]"
},
"hf mfdes info": {
"command": "hf mfdes info",
"description": "get info from mifare desfire tags",
"notes": [ "notes": [
"hf mfdes info" "hf mfdes info"
], ],
"offline": false, "offline": true,
"options": [ "options": [
"-h, --help this help" "-h, --help this help"
], ],
@ -4720,6 +4714,32 @@
], ],
"usage": "hf mfdes list [-h1fcrux] [--dict <file>]..." "usage": "hf mfdes list [-h1fcrux] [--dict <file>]..."
}, },
"hf mfdes lsapp": {
"command": "hf mfdes lsapp",
"description": "show application list. master key needs to be provided or flag --no-auth set (depend on cards settings).",
"notes": [
"hf mfdes lsapp -> show application list with defaults from `default` command",
"hf mfdes lsapp --files -> show application list and show each file type/settings/etc for each application"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyno <keyno> key number",
"-t, --algo <des/2tdea/3tdea/aes> crypt algo: des, 2tdea, 3tdea, aes",
"-k, --key <key> key for authenticate (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)",
"-f, --kdf <none/an10922/gallagher> key derivation function (kdf): none, an10922, gallagher",
"-i, --kdfi <kdfi> kdf input (hex 1-31 bytes)",
"-m, --cmode <plain/mac/encrypt> communicaton mode: plain/mac/encrypt",
"-c, --ccset <native/niso/iso> communicaton command set: native/niso/iso",
"-s, --schann <d40/ev1/ev2> secure channel: d40/ev1/ev2",
"--no-auth execute without authentication",
"--no-deep not to check authentication commands that avail for any application",
"--files scan files and print file settings for each application"
],
"usage": "hf mfdes lsapp [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--no-auth] [--no-deep] [--files]"
},
"hf mfdes lsfiles": { "hf mfdes lsfiles": {
"command": "hf mfdes lsfiles", "command": "hf mfdes lsfiles",
"description": "show file list. master key needs to be provided or flag --no-auth set (depend on cards settings).", "description": "show file list. master key needs to be provided or flag --no-auth set (depend on cards settings).",
@ -4748,8 +4768,17 @@
"command": "hf mfdes read", "command": "hf mfdes read",
"description": "read data from file. key needs to be provided or flag --no-auth set (depend on file settings).", "description": "read data from file. key needs to be provided or flag --no-auth set (depend on file settings).",
"notes": [ "notes": [
"it reads file via all command sets.",
"for iso command set it can be read by specifying full 2-byte iso id or 1-byte short iso id (first byte of the full iso id). iso id lays in the data in big endian format.",
"iso record commands: offset - record number (0-current, 1..ff-number, 1-lastest), length - if 0 - all records, if 1 - one",
"",
"hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command", "hf mfdes read --aid 123456 --fid 01 -> read file: app=123456, file=01, offset=0, all the data. use default channel settings from `default` command",
"hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command" "hf mfdes read --aid 123456 --fid 01 --type record --offset 000000 --length 000001 -> read one last record from record file. use default channel settings from `default` command",
"hf mfdes read --aid 123456 --fid 10 --type data -c iso -> read file via iso channel: app=123456, short iso id=10, offset=0.",
"hf mfdes read --aid 123456 --fileisoid 1000 --type data -c iso -> read file via iso channel: app=123456, iso id=1000, offset=0. select via native iso wrapper",
"hf mfdes read --appisoid 0102 --fileisoid 1000 --type data -c iso -> read file via iso channel: app iso id=0102, iso id=1000, offset=0. select via iso commands",
"hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000001 -> get one record (number 5) from file 1100 via iso commands",
"hf mfdes read --appisoid 0102 --fileisoid 1100 --type record -c iso --offset 000005 --length 000000 -> get all record (from 5 to 1) from file 1100 via iso commands"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4769,15 +4798,20 @@
"--no-auth execute without authentication", "--no-auth execute without authentication",
"--type <auto/data/value/record/mac> file type auto/data(standard/backup)/value/record(linear/cyclic)/mac). auto - check file settings and then read. default: auto", "--type <auto/data/value/record/mac> file type auto/data(standard/backup)/value/record(linear/cyclic)/mac). auto - check file settings and then read. default: auto",
"-o, --offset <hex> file offset (3 hex bytes, big endian). for records - record number (0 - lastest record). default 0", "-o, --offset <hex> file offset (3 hex bytes, big endian). for records - record number (0 - lastest record). default 0",
"-l, --length <hex> length to read (3 hex bytes, big endian -> 000000 = read all data). for records - records count (0 - all). default 0." "-l, --length <hex> length to read (3 hex bytes, big endian -> 000000 = read all data). for records - records count (0 - all). default 0.",
"--appisoid <isoid hex> application iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands.",
"--fileisoid <isoid hex> file iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands."
], ],
"usage": "hf mfdes read [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--no-auth] [--type <auto/data/value/record/mac>] [-o <hex>] [-l <hex>]" "usage": "hf mfdes read [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--no-auth] [--type <auto/data/value/record/mac>] [-o <hex>] [-l <hex>] [--appisoid <isoid hex>] [--fileisoid <isoid hex>]"
}, },
"hf mfdes selectapp": { "hf mfdes selectapp": {
"command": "hf mfdes selectapp", "command": "hf mfdes selectapp",
"description": "select application on the card. it selects app if it is a valid one or returns an error.", "description": "select application on the card. it selects app if it is a valid one or returns an error.",
"notes": [ "notes": [
"hf mfdes selectapp --aid 123456 -> select application 123456" "hf mfdes selectapp --aid 123456 -> select application 123456",
"hf mfdes selectapp --mf -> select master file (picc level)",
"hf mfdes selectapp --dfname aid123456 -> select application aid123456 by df name",
"hf mfdes selectapp --isoid 1111 -> select application 1111 by iso id"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4793,16 +4827,30 @@
"-c, --ccset <native/niso/iso> communicaton command set: native/niso/iso", "-c, --ccset <native/niso/iso> communicaton command set: native/niso/iso",
"-s, --schann <d40/ev1/ev2> secure channel: d40/ev1/ev2", "-s, --schann <d40/ev1/ev2> secure channel: d40/ev1/ev2",
"--aid <app id hex> application id of application for some parameters (3 hex bytes, big endian)", "--aid <app id hex> application id of application for some parameters (3 hex bytes, big endian)",
"--dfname <df name str> application df name (string, max 16 chars). selects application via iso select command" "--dfname <df name str> application df name (string, max 16 chars). selects application via iso select command",
"--isoid <isoid hex> application iso id (iso df id) (2 hex bytes, big endian)",
"--mf select mf (master file) via iso channel"
], ],
"usage": "hf mfdes selectapp [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--dfname <df name str>]" "usage": "hf mfdes selectapp [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--dfname <df name str>] [--isoid <isoid hex>] [--mf]"
}, },
"hf mfdes setconfig": { "hf mfdes setconfig": {
"command": "hf mfdes setconfig", "command": "hf mfdes setconfig",
"description": "set card configuration. warning! danger zone! needs to provide card's master key and works if not blocked by config.", "description": "set card configuration. warning! danger zone! needs to provide card's master key and works if not blocked by config.",
"notes": [ "notes": [
"hf mfdes setconfig --param 03 --data 0428 -> set parameter 03", "more about options mf2dlhx0.pdf. options list:",
"hf mfdes setconfig --param 02 --data 0875778102637264 -> set parameter 02" "00h picc configuration.",
"02h ats update.",
"03h sak update",
"04h secure messaging configuration.",
"05h capability data. (here change for lrp in the desfire light)",
"06h df name renaming",
"08h file renaming",
"09h value file configuration",
"0ah failed authentication counter setting",
"0bh hw configuration",
"",
"hf mfdes setconfig --param 03 --data 0428 -> set sak",
"hf mfdes setconfig --param 02 --data 0875778102637264 -> set ats (first byte - length)"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4825,7 +4873,7 @@
}, },
"hf mfdes test": { "hf mfdes test": {
"command": "hf mfdes test", "command": "hf mfdes test",
"description": "[=] ------ desfire tests ------ [!] no space for crc. pos: 1 [=] crc16............. passed [!] no space for crc. pos: 2 [=] crc32............. passed [=] cmac 3tdea........ passed [=] cmac 2tdea........ passed [=] cmac des.......... passed [=] ev2 session keys.. passed [=] ev2 iv calc....... passed [=] --------------------------- [+] tests [ ok ] ======================================================================================= hf seos { seos rfids... } --------------------------------------------------------------------------------------- hf seos help available offline: yes help this help list list seos history --------------------------------------------------------------------------------------- hf seos info available offline: no get info from seos tags", "description": "[=] ------ desfire tests ------ [!] no space for crc. pos: 1 [=] crc16............. passed [!] no space for crc. pos: 2 [=] crc32............. passed [=] cmac 3tdea........ passed [=] cmac 2tdea........ passed [=] cmac des.......... passed [=] ev2 session keys.. passed [=] ev2 iv calc....... passed [=] ev2 mac calc...... passed [=] --------------------------- [+] tests [ ok ] ======================================================================================= hf seos { seos rfids... } --------------------------------------------------------------------------------------- hf seos help available offline: yes help this help list list seos history --------------------------------------------------------------------------------------- hf seos info available offline: no get info from seos tags",
"notes": [ "notes": [
"hf seos info" "hf seos info"
], ],
@ -4876,7 +4924,9 @@
"hf mfdes write --aid 123456 --fid 01 -d 01020304 -> write data to record file with `auto` type", "hf mfdes write --aid 123456 --fid 01 -d 01020304 -> write data to record file with `auto` type",
"hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 -> write data to record file", "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 -> write data to record file",
"hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 --updaterec 0 -> update record in the record file. record 0 - lastest record.", "hf mfdes write --aid 123456 --fid 01 --type record -d 01020304 --updaterec 0 -> update record in the record file. record 0 - lastest record.",
"hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command" "hf mfdes write --aid 123456 --fid 01 --type record --offset 000000 -d 11223344 -> write record to record file. use default channel settings from `default` command",
"hf mfdes write --appisoid 1234 --fileisoid 1000 --type data -c iso -d 01020304 -> write data to std/backup file iso commandset",
"hf mfdes write --appisoid 1234 --fileisoid 2000 --type record -c iso -d 01020304 -> aend record to record file via iso commandset"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4899,9 +4949,11 @@
"-d, --data <hex> data for write (data/record file), credit/debit(value file)", "-d, --data <hex> data for write (data/record file), credit/debit(value file)",
"--debit use for value file debit operation instead of credit", "--debit use for value file debit operation instead of credit",
"--commit commit needs for backup file only. for the other file types and in the `auto` mode - command set it automatically.", "--commit commit needs for backup file only. for the other file types and in the `auto` mode - command set it automatically.",
"--updaterec <record number dec> record number for update record command. updates record instead of write. lastest record - 0" "--updaterec <record number dec> record number for update record command. updates record instead of write. lastest record - 0",
"--appisoid <isoid hex> application iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands.",
"--fileisoid <isoid hex> file iso id (iso df id) (2 hex bytes, big endian). works only for iso read commands."
], ],
"usage": "hf mfdes write [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--no-auth] [--type <auto/data/value/record/mac>] [-o <hex>] [-d <hex>] [--debit] [--commit] [--updaterec <record number dec>]" "usage": "hf mfdes write [-hav] [-n <keyno>] [-t <des/2tdea/3tdea/aes>] [-k <key>] [-f <none/an10922/gallagher>] [-i <kdfi>] [-m <plain/mac/encrypt>] [-c <native/niso/iso>] [-s <d40/ev1/ev2>] [--aid <app id hex>] [--fid <file id hex>] [--no-auth] [--type <auto/data/value/record/mac>] [-o <hex>] [-d <hex>] [--debit] [--commit] [--updaterec <record number dec>] [--appisoid <isoid hex>] [--fileisoid <isoid hex>]"
}, },
"hf mfp auth": { "hf mfp auth": {
"command": "hf mfp auth", "command": "hf mfp auth",
@ -9839,6 +9891,6 @@
"metadata": { "metadata": {
"commands_extracted": 587, "commands_extracted": 587,
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2021-07-31T13:44:52" "extracted_on": "2021-08-06T20:40:15"
} }
} }

View file

@ -503,26 +503,26 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf mfdes help `|Y |`This help` |`hf mfdes help `|Y |`This help`
|`hf mfdes info `|N |`Tag information`
|`hf mfdes getuid `|N |`Get uid from card`
|`hf mfdes default `|N |`Set defaults for all the commands` |`hf mfdes default `|N |`Set defaults for all the commands`
|`hf mfdes auth `|N |`MIFARE DesFire Authentication` |`hf mfdes auth `|N |`MIFARE DesFire Authentication`
|`hf mfdes chk `|N |`[old]Check keys` |`hf mfdes chk `|N |`[old]Check keys`
|`hf mfdes enum `|N |`[old]Tries enumerate all applications`
|`hf mfdes formatpicc `|N |`Format PICC`
|`hf mfdes freemem `|N |`Get free memory size` |`hf mfdes freemem `|N |`Get free memory size`
|`hf mfdes getuid `|N |`Get uid from card`
|`hf mfdes setconfig `|N |`Set card configuration` |`hf mfdes setconfig `|N |`Set card configuration`
|`hf mfdes info `|N |`[old]Tag information` |`hf mfdes formatpicc `|N |`Format PICC`
|`hf mfdes list `|Y |`List DESFire (ISO 14443A) history` |`hf mfdes list `|Y |`List DESFire (ISO 14443A) history`
|`hf mfdes changekey `|N |`Change Key` |`hf mfdes lsapp `|N |`Show all applications with files list`
|`hf mfdes chkeysettings `|N |`Change Key Settings` |`hf mfdes getaids `|N |`Get Application IDs list`
|`hf mfdes getkeysettings`|N |`Get Key Settings` |`hf mfdes getappnames `|N |`Get Applications list`
|`hf mfdes getkeyversions`|N |`Get Key Versions`
|`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce` |`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce`
|`hf mfdes createapp `|N |`Create Application` |`hf mfdes createapp `|N |`Create Application`
|`hf mfdes deleteapp `|N |`Delete Application` |`hf mfdes deleteapp `|N |`Delete Application`
|`hf mfdes selectapp `|N |`Select Application ID` |`hf mfdes selectapp `|N |`Select Application ID`
|`hf mfdes getaids `|N |`Get Application IDs list` |`hf mfdes changekey `|N |`Change Key`
|`hf mfdes getappnames `|N |`Get Applications list` |`hf mfdes chkeysettings `|N |`Change Key Settings`
|`hf mfdes getkeysettings`|N |`Get Key Settings`
|`hf mfdes getkeyversions`|N |`Get Key Versions`
|`hf mfdes getfileids `|N |`Get File IDs list` |`hf mfdes getfileids `|N |`Get File IDs list`
|`hf mfdes getfileisoids `|N |`Get File ISO IDs list` |`hf mfdes getfileisoids `|N |`Get File ISO IDs list`
|`hf mfdes lsfiles `|N |`Show all files list` |`hf mfdes lsfiles `|N |`Show all files list`