mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 14:23:50 -07:00
Merge pull request #1410 from merlokk/desf_ls
Desfire lsfiles and lsapp
This commit is contained in:
commit
b34681b484
10 changed files with 959 additions and 1029 deletions
|
@ -222,6 +222,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/loclass/hash1_brute.c
|
||||
${PM3_ROOT}/client/src/loclass/ikeys.c
|
||||
${PM3_ROOT}/client/src/mifare/mad.c
|
||||
${PM3_ROOT}/client/src/mifare/aiddesfire.c
|
||||
${PM3_ROOT}/client/src/mifare/mfkey.c
|
||||
${PM3_ROOT}/client/src/mifare/mifare4.c
|
||||
${PM3_ROOT}/client/src/mifare/mifaredefault.c
|
||||
|
@ -236,7 +237,6 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/uart/uart_win32.c
|
||||
${PM3_ROOT}/client/src/ui/overlays.ui
|
||||
${PM3_ROOT}/client/src/ui/image.ui
|
||||
${PM3_ROOT}/client/src/aiddesfire.c
|
||||
${PM3_ROOT}/client/src/aidsearch.c
|
||||
${PM3_ROOT}/client/src/cmdanalyse.c
|
||||
${PM3_ROOT}/client/src/cmdcrc.c
|
||||
|
|
|
@ -474,7 +474,7 @@ POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d && $(TOUCH) $@
|
|||
# enumerations #
|
||||
################
|
||||
|
||||
SRCS = aiddesfire.c \
|
||||
SRCS = mifare/aiddesfire.c \
|
||||
aidsearch.c \
|
||||
cmdanalyse.c \
|
||||
cmdcrc.c \
|
||||
|
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load diff
329
client/src/mifare/aiddesfire.c
Normal file
329
client/src/mifare/aiddesfire.c
Normal 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;
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
const char *nxp_cluster_to_text(uint8_t cluster);
|
||||
int AIDDFDecodeAndPrint(uint8_t aid[3]);
|
||||
|
||||
#endif // _AIDDESFIRE_H_
|
|
@ -32,6 +32,8 @@
|
|||
#include "util_posix.h" // msleep
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "desfiresecurechan.h"
|
||||
#include "mifare/mad.h"
|
||||
#include "mifare/aiddesfire.h"
|
||||
|
||||
const CLIParserOption DesfireAlgoOpts[] = {
|
||||
{T_DES, "des"},
|
||||
|
@ -694,9 +696,15 @@ static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, s
|
|||
static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t dstdatalen) {
|
||||
size_t len = 0;
|
||||
for (int i = 0; i < *blockdatacount; i++) {
|
||||
memset(&blockdata[i * blockdatasize + 1], 0, blockdatasize - 1);
|
||||
size_t tlen = len + blockdata[i * blockdatasize];
|
||||
if (tlen > dstdatalen)
|
||||
if (tlen > dstdatalen) {
|
||||
tlen = dstdatalen;
|
||||
if (tlen >= len)
|
||||
blockdata[i * blockdatasize] = tlen - len;
|
||||
else
|
||||
blockdata[i * blockdatasize] = 0;
|
||||
}
|
||||
if (len == tlen) {
|
||||
*blockdatacount = i;
|
||||
break;
|
||||
|
@ -764,6 +772,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
|
|||
size_t resplen = 0;
|
||||
uint8_t respcode = 0;
|
||||
|
||||
ctx->secureChannel = DACNone;
|
||||
int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true, 0);
|
||||
if (res == PM3_SUCCESS) {
|
||||
if (resplen != 0)
|
||||
|
@ -800,6 +809,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
|
|||
size_t resplen = 0;
|
||||
uint8_t respcode = 0;
|
||||
|
||||
ctx->secureChannel = DACNone;
|
||||
int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
|
||||
if (res == PM3_SUCCESS) {
|
||||
if (resplen != 0)
|
||||
|
@ -809,11 +819,28 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
|
|||
if (respcode != MFDES_S_OPERATION_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
DesfireClearSession(ctx);
|
||||
ctx->appSelected = (aid != 0x000000);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void DesfirePrintAIDFunctions(uint32_t appid) {
|
||||
uint8_t aid[3] = {0};
|
||||
DesfireAIDUintToByte(appid, aid);
|
||||
if ((aid[2] >> 4) == 0xF) {
|
||||
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
|
||||
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
|
||||
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8));
|
||||
MADDFDecodeAndPrint(short_aid);
|
||||
} else {
|
||||
AIDDFDecodeAndPrint(aid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
|
||||
if (verbose)
|
||||
DesfirePrintContext(dctx);
|
||||
|
@ -1344,6 +1371,279 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
|
|||
return 100;
|
||||
}
|
||||
|
||||
static bool DesfireCheckAuthCmd(uint32_t appAID, uint8_t keyNum, uint8_t authcmd) {
|
||||
size_t recv_len = 0;
|
||||
uint8_t respcode = 0;
|
||||
uint8_t recv_data[256] = {0};
|
||||
|
||||
DesfireContext dctx = {0};
|
||||
dctx.keyNum = keyNum;
|
||||
dctx.commMode = DCMPlain;
|
||||
dctx.cmdSet = DCCNative;
|
||||
|
||||
// if cant select - return false
|
||||
int res = DesfireSelectAIDHex(&dctx, appAID, false, 0);
|
||||
if (res != PM3_SUCCESS)
|
||||
return false;
|
||||
|
||||
uint8_t data[] = {keyNum, 0x00};
|
||||
res = DesfireExchangeEx(false, &dctx, authcmd, data, (authcmd == MFDES_AUTHENTICATE_EV2F) ? 2 : 1, &respcode, recv_data, &recv_len, false, 0);
|
||||
DropField();
|
||||
return (res == PM3_SUCCESS && respcode == 0xaf);
|
||||
}
|
||||
|
||||
static bool DesfireCheckISOAuthCmd(uint32_t appAID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorythm keytype) {
|
||||
|
||||
DesfireContext dctx = {0};
|
||||
dctx.keyNum = keyNum;
|
||||
dctx.commMode = DCMPlain;
|
||||
dctx.cmdSet = DCCISO;
|
||||
|
||||
bool app_level = (appAID != 0x000000);
|
||||
int res = 0;
|
||||
if (dfname == NULL || strnlen(dfname, 16) == 0) {
|
||||
if (appAID == 0x000000) {
|
||||
res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, NULL, NULL);
|
||||
if (res != PM3_SUCCESS)
|
||||
return false;
|
||||
} else {
|
||||
res = DesfireSelectAIDHex(&dctx, appAID, false, 0);
|
||||
if (res != PM3_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
res = DesfireISOSelectDF(&dctx, dfname, NULL, NULL);
|
||||
if (res != PM3_SUCCESS)
|
||||
return false;
|
||||
app_level = true;
|
||||
}
|
||||
|
||||
uint8_t rndlen = DesfireGetRndLenForKey(keytype);
|
||||
|
||||
uint8_t piccrnd[64] = {0};
|
||||
size_t xlen = 0;
|
||||
res = DesfireISOGetChallenge(&dctx, keytype, piccrnd, &xlen);
|
||||
if (res != PM3_SUCCESS || xlen != rndlen)
|
||||
return false;
|
||||
|
||||
uint8_t resp[250] = {0};
|
||||
size_t resplen = 0;
|
||||
|
||||
uint16_t sw = 0;
|
||||
uint8_t p1 = DesfireKeyToISOKey(keytype);
|
||||
uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum;
|
||||
res = DesfireExchangeISO(false, &dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw);
|
||||
DropField();
|
||||
return (sw == 0x9000 || sw == 0x6982);
|
||||
}
|
||||
|
||||
void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck) {
|
||||
memset(authCmdCheck, 0, sizeof(AuthCommandsChk));
|
||||
|
||||
authCmdCheck->auth = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE);
|
||||
authCmdCheck->authISO = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_ISO);
|
||||
authCmdCheck->authAES = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_AES);
|
||||
authCmdCheck->authEV2 = DesfireCheckAuthCmd(appAID, keyNum, MFDES_AUTHENTICATE_EV2F);
|
||||
authCmdCheck->authISONative = DesfireCheckISOAuthCmd(appAID, dfname, keyNum, T_DES);
|
||||
authCmdCheck->checked = true;
|
||||
}
|
||||
|
||||
void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck) {
|
||||
PrintAndLogEx(NORMAL, "auth: %s auth iso: %s auth aes: %s auth ev2: %s auth iso native: %s",
|
||||
authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"),
|
||||
authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"),
|
||||
authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"),
|
||||
authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"),
|
||||
authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO")
|
||||
);
|
||||
}
|
||||
|
||||
int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode) {
|
||||
uint8_t buf[250] = {0};
|
||||
size_t buflen = 0;
|
||||
|
||||
uint32_t freemem = 0;
|
||||
int res = DesfireGetFreeMem(dctx, &freemem);
|
||||
if (res == PM3_SUCCESS)
|
||||
PICCInfo->freemem = freemem;
|
||||
else
|
||||
PICCInfo->freemem = 0xffffffff;
|
||||
|
||||
PICCInfo->keySettings = 0;
|
||||
PICCInfo->numKeysRaw = 0;
|
||||
PICCInfo->keyVersion0 = 0;
|
||||
res = DesfireGetKeySettings(dctx, buf, &buflen);
|
||||
if (res == PM3_SUCCESS && buflen >= 2) {
|
||||
PICCInfo->keySettings = buf[0];
|
||||
PICCInfo->numKeysRaw = buf[1];
|
||||
PICCInfo->numberOfKeys = PICCInfo->numKeysRaw & 0x1f;
|
||||
if (PICCInfo->numKeysRaw > 0) {
|
||||
uint8_t keyNum0 = 0;
|
||||
res = DesfireGetKeyVersion(dctx, &keyNum0, 1, buf, &buflen);
|
||||
if (res == PM3_SUCCESS && buflen > 0) {
|
||||
PICCInfo->keyVersion0 = buf[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// field on-off zone
|
||||
if (deepmode)
|
||||
DesfireCheckAuthCommands(0x000000, NULL, 0, &PICCInfo->authCmdCheck);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) {
|
||||
for (int i = 0; i < appcount; i++)
|
||||
if (AppList[i].appNum == appNum)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles) {
|
||||
uint8_t buf[250] = {0};
|
||||
size_t buflen = 0;
|
||||
|
||||
int res = DesfireGetAIDList(dctx, buf, &buflen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PICCInfo->appCount = buflen / 3;
|
||||
for (int i = 0; i < buflen; i += 3)
|
||||
appList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]);
|
||||
|
||||
// result bytes: 3, 2, 1-16. total record size = 24
|
||||
res = DesfireGetDFList(dctx, buf, &buflen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res);
|
||||
} else if (buflen > 1) {
|
||||
for (int i = 0; i < buflen; i++) {
|
||||
int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), appList, PICCInfo->appCount);
|
||||
if (indx >= 0) {
|
||||
appList[indx].appISONum = MemBeToUint2byte(&buf[i * 24 + 1 + 3]);
|
||||
memcpy(appList[indx].appDFName, &buf[i * 24 + 1 + 5], strnlen((char *)&buf[i * 24 + 1 + 5], 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// field on-off zone
|
||||
DesfireFillPICCInfo(dctx, PICCInfo, deepmode);
|
||||
|
||||
if (PICCInfo->appCount > 0) {
|
||||
for (int i = 0; i < PICCInfo->appCount; i++) {
|
||||
if (i == 0)
|
||||
res = DesfireSelectAIDHex(dctx, appList[i].appNum, false, 0);
|
||||
else
|
||||
res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum);
|
||||
if (res != PM3_SUCCESS)
|
||||
continue;
|
||||
|
||||
DesfireGetKeySettings(dctx, buf, &buflen);
|
||||
if (res == PM3_SUCCESS && buflen >= 2) {
|
||||
appList[i].keySettings = buf[0];
|
||||
appList[i].numKeysRaw = buf[1];
|
||||
appList[i].numberOfKeys = appList[i].numKeysRaw & 0x1f;
|
||||
appList[i].isoFileIDEnabled = ((appList[i].numKeysRaw & 0x20) != 0);
|
||||
appList[i].keyType = DesfireKeyTypeToAlgo(appList[i].numKeysRaw >> 6);
|
||||
|
||||
if (appList[i].numberOfKeys > 0)
|
||||
for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
|
||||
res = DesfireGetKeyVersion(dctx, &keyn, 1, buf, &buflen);
|
||||
if (res == PM3_SUCCESS && buflen > 0) {
|
||||
appList[i].keyVersions[keyn] = buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
appList[i].filesReaded = false;
|
||||
if (readFiles) {
|
||||
res = DesfireFillFileList(dctx, appList[i].fileList, &appList[i].filesCount, &appList[i].isoPresent);
|
||||
appList[i].filesReaded = (res == PM3_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// field on-off zone
|
||||
if (PICCInfo->appCount > 0 && deepmode) {
|
||||
for (int i = 0; i < PICCInfo->appCount; i++) {
|
||||
DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck);
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) {
|
||||
PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------");
|
||||
if (PICCInfo->freemem == 0xffffffff)
|
||||
PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount);
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem);
|
||||
PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF);
|
||||
if (PICCInfo->authCmdCheck.checked)
|
||||
DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck);
|
||||
if (PICCInfo->numberOfKeys > 0) {
|
||||
PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true);
|
||||
PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0);
|
||||
}
|
||||
}
|
||||
|
||||
void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList) {
|
||||
if (PICCInfo->appCount == 0)
|
||||
return;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------");
|
||||
|
||||
for (int i = 0; i < PICCInfo->appCount; i++) {
|
||||
PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02x") " iso id: " _GREEN_("0x%04x") " name: " _GREEN_("%s"), appList[i].appNum, appList[i].appISONum, appList[i].appDFName);
|
||||
|
||||
DesfirePrintAIDFunctions(appList[i].appNum);
|
||||
|
||||
if (PICCInfo->authCmdCheck.checked) {
|
||||
PrintAndLogEx(SUCCESS, "Auth commands: " NOLF);
|
||||
DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck);
|
||||
PrintAndLogEx(SUCCESS, "");
|
||||
}
|
||||
|
||||
if (appList[i].numberOfKeys > 0) {
|
||||
PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true);
|
||||
|
||||
if (appList[i].numberOfKeys > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1);
|
||||
for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
|
||||
PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
}
|
||||
|
||||
if (appList[i].filesReaded) {
|
||||
PrintAndLogEx(SUCCESS, "Application have " _GREEN_("%zu") " files", appList[i].filesCount);
|
||||
|
||||
if (appList[i].filesCount > 0) {
|
||||
for (int fnum = 0; fnum < appList[i].filesCount; fnum++) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("File %02x") " ----------------------------------", appList[i].fileList[fnum].fileNum);
|
||||
PrintAndLogEx(SUCCESS, "File ID : " _GREEN_("%02x"), appList[i].fileList[fnum].fileNum);
|
||||
if (appList[i].isoPresent) {
|
||||
if (appList[i].fileList[fnum].fileISONum != 0)
|
||||
PrintAndLogEx(SUCCESS, "File ISO ID : %04x", appList[i].fileList[fnum].fileISONum);
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "File ISO ID : " _YELLOW_("n/a"));
|
||||
}
|
||||
DesfirePrintFileSettingsExtended(&appList[i].fileList[fnum].fileSettings);
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) {
|
||||
if (resplen)
|
||||
*resplen = 0;
|
||||
|
@ -1397,6 +1697,26 @@ int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem) {
|
|||
return res;
|
||||
}
|
||||
|
||||
int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen) {
|
||||
*resplen = 0;
|
||||
|
||||
uint8_t xresp[257] = {0};
|
||||
size_t xresplen = 0;
|
||||
uint8_t respcode = 0xff;
|
||||
|
||||
int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen);
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
|
||||
if (respcode != 0x90)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
memcpy(resp, xresp, xresplen);
|
||||
*resplen = xresplen;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
|
||||
return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1);
|
||||
}
|
||||
|
@ -1610,46 +1930,18 @@ int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uin
|
|||
return DesfireCommandTxData(dctx, MFDES_UPDATE_RECORD, xdata, 10 + len);
|
||||
}
|
||||
|
||||
uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) {
|
||||
switch (keyType) {
|
||||
case T_DES:
|
||||
return 0x00;
|
||||
case T_3DES:
|
||||
return 0x00;
|
||||
case T_3K3DES:
|
||||
return 0x01;
|
||||
case T_AES:
|
||||
return 0x02;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void PrintKeyType(uint8_t keytype) {
|
||||
switch (keytype) {
|
||||
case 00:
|
||||
PrintAndLogEx(SUCCESS, "Key: 2TDEA");
|
||||
break;
|
||||
case 01:
|
||||
PrintAndLogEx(SUCCESS, "Key: 3TDEA");
|
||||
break;
|
||||
case 02:
|
||||
PrintAndLogEx(SUCCESS, "Key: AES");
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keytype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
||||
PrintAndLogEx(SUCCESS, "PICC level rights:");
|
||||
PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
||||
PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
||||
PrintAndLogEx(SUCCESS, "");
|
||||
|
||||
if (print2ndbyte)
|
||||
if (print2ndbyte) {
|
||||
DesfirePrintCardKeyType(numkeys >> 6);
|
||||
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
|
||||
|
@ -1676,14 +1968,14 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print
|
|||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? "NO" : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
|
||||
PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
||||
PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
|
||||
PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
|
||||
PrintAndLogEx(SUCCESS, "");
|
||||
|
||||
if (print2ndbyte) {
|
||||
PrintKeyType(numkeys >> 6);
|
||||
DesfirePrintCardKeyType(numkeys >> 6);
|
||||
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
|
||||
if (numkeys & 0x20)
|
||||
PrintAndLogEx(SUCCESS, "iso file id: enabled");
|
||||
|
@ -1701,6 +1993,7 @@ void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool
|
|||
static const char *DesfireUnknownStr = "unknown";
|
||||
static const char *DesfireDisabledStr = "disabled";
|
||||
static const char *DesfireFreeStr = "free";
|
||||
static const char *DesfireNAStr = "n/a";
|
||||
static const DesfireCreateFileCommandsS DesfireFileCommands[] = {
|
||||
{0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true},
|
||||
{0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true},
|
||||
|
@ -1771,6 +2064,32 @@ const char *GetDesfireAccessRightStr(uint8_t right) {
|
|||
return DesfireUnknownStr;
|
||||
}
|
||||
|
||||
const char *AccessRightShortStr[] = {
|
||||
"key0",
|
||||
"key1",
|
||||
"key2",
|
||||
"key3",
|
||||
"key4",
|
||||
"key5",
|
||||
"key6",
|
||||
"key7",
|
||||
"key8",
|
||||
"key9",
|
||||
"keyA",
|
||||
"keyB",
|
||||
"keyC",
|
||||
"keyD",
|
||||
"free",
|
||||
"deny"
|
||||
};
|
||||
|
||||
const char *GetDesfireAccessRightShortStr(uint8_t right) {
|
||||
if (right > 0x0f)
|
||||
return DesfireNAStr;
|
||||
|
||||
return AccessRightShortStr[right];
|
||||
}
|
||||
|
||||
void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch) {
|
||||
mode[0] = (ch & 0x0f) | ((rw << 4) & 0xf0);
|
||||
mode[1] = (w & 0x0f) | ((r << 4) & 0xf0);
|
||||
|
@ -1863,10 +2182,7 @@ void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsett
|
|||
}
|
||||
}
|
||||
|
||||
void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
|
||||
PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
|
||||
PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
|
||||
|
||||
static void DesfirePrintShortFileTypeSettings(FileSettingsS *fsettings) {
|
||||
switch (fsettings->fileType) {
|
||||
case 0x00:
|
||||
case 0x01: {
|
||||
|
@ -1874,13 +2190,13 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
|
|||
break;
|
||||
}
|
||||
case 0x02: {
|
||||
PrintAndLogEx(NORMAL, "[%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF,
|
||||
PrintAndLogEx(NORMAL, "value [%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF,
|
||||
fsettings->lowerLimit, fsettings->upperLimit, fsettings->limitedCredit, fsettings->value, fsettings->value);
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
case 0x04: {
|
||||
PrintAndLogEx(NORMAL, "%d/%d record size: %d [0x%x]b " NOLF,
|
||||
PrintAndLogEx(NORMAL, "record count %d/%d size: %d [0x%x]b " NOLF,
|
||||
fsettings->curRecordCount, fsettings->maxRecordCount, fsettings->recordSize, fsettings->recordSize);
|
||||
break;
|
||||
}
|
||||
|
@ -1891,13 +2207,50 @@ void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
|
|||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings) {
|
||||
PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
|
||||
PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
|
||||
|
||||
DesfirePrintShortFileTypeSettings(fsettings);
|
||||
|
||||
PrintAndLogEx(NORMAL, "(%s %s %s %s)",
|
||||
GetDesfireAccessRightStr(fsettings->rAccess),
|
||||
GetDesfireAccessRightStr(fsettings->wAccess),
|
||||
GetDesfireAccessRightStr(fsettings->rwAccess),
|
||||
GetDesfireAccessRightStr(fsettings->chAccess));
|
||||
GetDesfireAccessRightShortStr(fsettings->rAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->wAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->rwAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->chAccess));
|
||||
}
|
||||
|
||||
void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings) {
|
||||
if (printheader) {
|
||||
PrintAndLogEx(SUCCESS, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings ");
|
||||
PrintAndLogEx(SUCCESS, "----------------------------------------------------------------------------------------------------------");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id);
|
||||
if (isoidavail) {
|
||||
if (isoid != 0)
|
||||
PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " |" NOLF);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "0x%02x " _CYAN_("%-13s") " |" NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
|
||||
PrintAndLogEx(NORMAL, " %-5s |" NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
|
||||
|
||||
PrintAndLogEx(NORMAL, "%04x, %-4s %-4s %-4s %-4s |" NOLF,
|
||||
fsettings->rawAccessRights,
|
||||
GetDesfireAccessRightShortStr(fsettings->rAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->wAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->rwAccess),
|
||||
GetDesfireAccessRightShortStr(fsettings->chAccess));
|
||||
|
||||
PrintAndLogEx(NORMAL, " " NOLF);
|
||||
DesfirePrintShortFileTypeSettings(fsettings);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings) {
|
||||
|
|
|
@ -85,6 +85,48 @@ typedef struct {
|
|||
|
||||
typedef FileListElmS FileListS[32];
|
||||
|
||||
typedef struct {
|
||||
bool checked;
|
||||
bool auth;
|
||||
bool authISO;
|
||||
bool authAES;
|
||||
bool authEV2;
|
||||
bool authISONative;
|
||||
} AuthCommandsChk;
|
||||
|
||||
typedef struct {
|
||||
uint32_t appNum;
|
||||
uint16_t appISONum;
|
||||
char appDFName[16];
|
||||
AuthCommandsChk authCmdCheck;
|
||||
|
||||
uint8_t keySettings;
|
||||
uint8_t numKeysRaw;
|
||||
bool isoFileIDEnabled; // from numKeysRaw
|
||||
uint8_t numberOfKeys; // from numKeysRaw
|
||||
DesfireCryptoAlgorythm keyType; // from numKeysRaw
|
||||
|
||||
uint8_t keyVersions[16];
|
||||
|
||||
bool filesReaded;
|
||||
size_t filesCount;
|
||||
bool isoPresent;
|
||||
FileListS fileList;
|
||||
} AppListElmS;
|
||||
typedef AppListElmS AppListS[64];
|
||||
|
||||
typedef struct {
|
||||
size_t appCount;
|
||||
uint32_t freemem;
|
||||
AuthCommandsChk authCmdCheck;
|
||||
|
||||
uint8_t keySettings;
|
||||
uint8_t numKeysRaw;
|
||||
uint8_t numberOfKeys; // from numKeysRaw
|
||||
|
||||
uint8_t keyVersion0;
|
||||
} PICCInfoS;
|
||||
|
||||
typedef enum {
|
||||
RFTAuto,
|
||||
RFTData,
|
||||
|
@ -111,20 +153,29 @@ void DesfirePrintContext(DesfireContext *ctx);
|
|||
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen);
|
||||
int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize);
|
||||
|
||||
int DesfireReadSignature(DesfireContext *dctx, uint8_t sid, uint8_t *resp, size_t *resplen);
|
||||
|
||||
int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
|
||||
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
|
||||
int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid);
|
||||
void DesfirePrintAIDFunctions(uint32_t appid);
|
||||
|
||||
const char *DesfireAuthErrorToStr(int error);
|
||||
int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose);
|
||||
int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose);
|
||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose);
|
||||
void DesfireCheckAuthCommands(uint32_t appAID, char *dfname, uint8_t keyNum, AuthCommandsChk *authCmdCheck);
|
||||
void DesfireCheckAuthCommandsPrint(AuthCommandsChk *authCmdCheck);
|
||||
|
||||
int DesfireFormatPICC(DesfireContext *dctx);
|
||||
int DesfireGetFreeMem(DesfireContext *dctx, uint32_t *freemem);
|
||||
int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode);
|
||||
int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles);
|
||||
void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo);
|
||||
void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList);
|
||||
|
||||
int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen);
|
||||
int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid);
|
||||
|
@ -133,7 +184,6 @@ int DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *data, size_t len, uint8_
|
|||
int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len);
|
||||
void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte);
|
||||
uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType);
|
||||
|
||||
int DesfireChangeKeyCmd(DesfireContext *dctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen);
|
||||
int DesfireChangeKey(DesfireContext *dctx, bool change_master_key, uint8_t newkeynum, DesfireCryptoAlgorythm newkeytype, uint32_t newkeyver, uint8_t *newkey, DesfireCryptoAlgorythm oldkeytype, uint8_t *oldkey, bool verbose);
|
||||
|
@ -147,6 +197,7 @@ int DesfireGetFileISOIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen
|
|||
|
||||
void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettingsS *fsettings);
|
||||
void DesfirePrintFileSettingsOneLine(FileSettingsS *fsettings);
|
||||
void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettingsS *fsettings);
|
||||
void DesfirePrintFileSettingsExtended(FileSettingsS *fsettings);
|
||||
int DesfireGetFileSettings(DesfireContext *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen);
|
||||
int DesfireGetFileSettingsStruct(DesfireContext *dctx, uint8_t fileid, FileSettingsS *fsettings);
|
||||
|
@ -154,6 +205,7 @@ int DesfireChangeFileSettings(DesfireContext *dctx, uint8_t *data, size_t datale
|
|||
|
||||
const DesfireCreateFileCommandsS *GetDesfireFileCmdRec(uint8_t type);
|
||||
const char *GetDesfireAccessRightStr(uint8_t right);
|
||||
const char *GetDesfireAccessRightShortStr(uint8_t right);
|
||||
void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch);
|
||||
void DesfireDecodeFileAcessMode(uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch);
|
||||
void DesfirePrintAccessRight(uint8_t *data);
|
||||
|
|
|
@ -353,6 +353,50 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key) {
|
|||
return version;
|
||||
}
|
||||
|
||||
DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType) {
|
||||
switch (keyType) {
|
||||
case 00:
|
||||
return T_3DES;
|
||||
case 01:
|
||||
return T_3K3DES;
|
||||
case 02:
|
||||
return T_AES;
|
||||
default:
|
||||
return T_3DES; // unknown....
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) {
|
||||
switch (keyType) {
|
||||
case T_DES:
|
||||
return 0x00;
|
||||
case T_3DES:
|
||||
return 0x00;
|
||||
case T_3K3DES:
|
||||
return 0x01;
|
||||
case T_AES:
|
||||
return 0x02;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DesfirePrintCardKeyType(uint8_t keyType) {
|
||||
switch (keyType) {
|
||||
case 00:
|
||||
PrintAndLogEx(SUCCESS, "Key: 2TDEA");
|
||||
break;
|
||||
case 01:
|
||||
PrintAndLogEx(SUCCESS, "Key: 3TDEA");
|
||||
break;
|
||||
case 02:
|
||||
PrintAndLogEx(SUCCESS, "Key: AES");
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keyType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode) {
|
||||
DesfireCommunicationMode mode = DCMNone;
|
||||
switch (file_comm_mode & 0x03) {
|
||||
|
|
|
@ -107,6 +107,10 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen,
|
|||
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version);
|
||||
uint8_t DesfireDESKeyGetVersion(uint8_t *key);
|
||||
|
||||
DesfireCryptoAlgorythm DesfireKeyTypeToAlgo(uint8_t keyType);
|
||||
uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType);
|
||||
void DesfirePrintCardKeyType(uint8_t keyType);
|
||||
|
||||
DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode);
|
||||
uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue