Merge pull request #22 from RfidResearchGroup/master

Update
This commit is contained in:
Bjoern Kerler 2020-04-10 23:01:52 +02:00 committed by GitHub
commit 52b41fc883
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 510 additions and 350 deletions

View file

@ -5,3 +5,4 @@ PLATFORM=PM3RDV4
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces: # If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
#PLATFORM_EXTRAS=BTADDON #PLATFORM_EXTRAS=BTADDON
#STANDALONE=LF_SAMYRUN #STANDALONE=LF_SAMYRUN
STANDALONE=LF_ICEHID

View file

@ -2672,8 +2672,10 @@ void ReaderIso14443a(PacketCommandNG *c) {
uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t par[MAX_PARITY_SIZE] = {0x00}; uint8_t par[MAX_PARITY_SIZE] = {0x00};
if ((param & ISO14A_CONNECT)) if ((param & ISO14A_CONNECT)) {
iso14_pcb_blocknum = 0;
clear_trace(); clear_trace();
}
set_tracing(true); set_tracing(true);

View file

@ -29,7 +29,7 @@
# define FWT_TIMEOUT_14B 35312 # define FWT_TIMEOUT_14B 35312
#endif #endif
#ifndef ISO14443B_DMA_BUFFER_SIZE #ifndef ISO14443B_DMA_BUFFER_SIZE
# define ISO14443B_DMA_BUFFER_SIZE 256 # define ISO14443B_DMA_BUFFER_SIZE 512 //changed this from 256
#endif #endif
#ifndef RECEIVE_MASK #ifndef RECEIVE_MASK
# define RECEIVE_MASK (ISO14443B_DMA_BUFFER_SIZE-1) # define RECEIVE_MASK (ISO14443B_DMA_BUFFER_SIZE-1)
@ -37,7 +37,7 @@
// Guard Time (per 14443-2) // Guard Time (per 14443-2)
#ifndef TR0 #ifndef TR0
# define TR0 0 # define TR0 32 //this value equals 8 ETU = 32 ssp clk (w/ 424 khz)
#endif #endif
// Synchronization time (per 14443-2) // Synchronization time (per 14443-2)
@ -261,6 +261,10 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
// 80/fs < TR1 < 200/fs // 80/fs < TR1 < 200/fs
// 10 ETU < TR1 < 24 ETU // 10 ETU < TR1 < 24 ETU
// Send TR1.
// 10-11 ETU * 4times samples ONES
for (int i = 0; i < 10; i++) { SEND4STUFFBIT(1); }
// Send SOF. // Send SOF.
// 10-11 ETU * 4times samples ZEROS // 10-11 ETU * 4times samples ZEROS
for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); }
@ -307,7 +311,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) {
//for(i = 0; i < 10; i++) { ToSendStuffBit(0); } //for(i = 0; i < 10; i++) { ToSendStuffBit(0); }
// why this? // why this?
for (int i = 0; i < 40; i++) { SEND4STUFFBIT(1); } for (int i = 0; i < 2; i++) { SEND4STUFFBIT(1); }
//for(i = 0; i < 40; i++) { ToSendStuffBit(1); } //for(i = 0; i < 40; i++) { ToSendStuffBit(1); }
// Convert from last byte pos to length // Convert from last byte pos to length

View file

@ -133,6 +133,9 @@ void MifareDesfireGetInformation() {
set_tracing(true); set_tracing(true);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// reset the pcb_blocknum,
pcb_blocknum = 0;
// card select - information // card select - information
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card"); if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card");

View file

@ -709,7 +709,6 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
pos++; pos++;
for (uint8_t i = 0; i < 2; i++, pos++) { for (uint8_t i = 0; i < 2; i++, pos++) {
switch (cmd[pos]) { switch (cmd[pos]) {
case MFDES_CREATE_APPLICATION: case MFDES_CREATE_APPLICATION:
snprintf(exp, size, "CREATE APPLICATION"); snprintf(exp, size, "CREATE APPLICATION");
@ -822,6 +821,9 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case MFDES_ADDITIONAL_FRAME: case MFDES_ADDITIONAL_FRAME:
snprintf(exp, size, "AUTH FRAME / NEXT FRAME"); snprintf(exp, size, "AUTH FRAME / NEXT FRAME");
break; break;
case MFDES_READSIG:
snprintf(exp, size, "READ SIGNATURE");
break;
default: default:
break; break;
} }

View file

@ -52,12 +52,13 @@ typedef enum {
typedef enum { typedef enum {
UNKNOWN = 0, UNKNOWN = 0,
MF3ICD40, DESFIRE_MF3ICD40,
EV1, DESFIRE_EV1,
EV2, DESFIRE_EV2,
EV3, DESFIRE_EV3,
LIGHT, DESFIRE_LIGHT,
} desfire_cardtype_t; PLUS_EV1,
} nxp_cardtype_t;
typedef struct { typedef struct {
uint8_t aid[3]; uint8_t aid[3];
@ -68,14 +69,65 @@ typedef struct {
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/* /*
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; The 7 MSBits (= n) code the storage size itself based on 2^n,
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); the LSBit is set to '0' if the size is exactly 2^n
and set to '1' if the storage size is between 2^n and 2^(n+1).
if (!res && datalen > 1 && data[0] == 0x09) { For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
SLmode = 0;
}
*/ */
static char *getCardSizeStr(uint8_t fsize) {
static char buf[40] = {0x00};
char *retStr = buf;
uint16_t usize = 1 << ((fsize >> 1) + 1);
uint16_t lsize = 1 << (fsize >> 1);
// is LSB set?
if (fsize & 1)
sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
return buf;
}
static char *getProtocolStr(uint8_t id, bool hw) {
static char buf[50] = {0x00};
char *retStr = buf;
if (id == 0x04) {
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id);
} else if (id == 0x05) {
if (hw)
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
} else {
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
}
return buf;
}
static char *getVersionStr(uint8_t major, uint8_t minor) {
static char buf[40] = {0x00};
char *retStr = buf;
if (major == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
else if (major == 0x01 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
else if (major == 0x12 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
// else if (major == 0x13 && minor == 0x00)
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
else if (major == 0x30 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
else
sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
return buf;
}
int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) { int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) {
@ -121,7 +173,7 @@ int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t
if (sw) if (sw)
*sw = isw; *sw = isw;
if (isw != 0x9000 && isw != status(MFDES_OPERATION_OK) && isw != status(MFDES_SIGNATURE) && isw != status(MFDES_ADDITIONAL_FRAME) && isw != status(MFDES_NO_CHANGES)) { if (isw != 0x9000 && isw != status(MFDES_S_OPERATION_OK) && isw != status(MFDES_S_SIGNATURE) && isw != status(MFDES_S_ADDITIONAL_FRAME) && isw != status(MFDES_S_NO_CHANGES)) {
if (GetAPDULogging()) { if (GetAPDULogging()) {
if (isw >> 8 == 0x61) { if (isw >> 8 == 0x61) {
PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff); PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
@ -254,15 +306,23 @@ static char *GetErrorString(int res, uint16_t *sw) {
return ""; return "";
} }
static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) { static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) {
if (g_debugMode > 1) { if (apdu == NULL) {
if (apdu == NULL) PrintAndLogEx(ERR, "APDU=NULL"); PrintAndLogEx(DEBUG, "APDU=NULL");
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); return PM3_EINVARG;
if (sw == NULL) PrintAndLogEx(ERR, "SW=NULL"); }
if (recv_len == NULL) PrintAndLogEx(ERR, "RECV_LEN=NULL"); if (dest == NULL) {
PrintAndLogEx(DEBUG, "DEST=NULL");
return PM3_EINVARG;
}
if (sw == NULL) {
PrintAndLogEx(DEBUG, "SW=NULL");
return PM3_EINVARG;
}
if (recv_len == NULL) {
PrintAndLogEx(DEBUG, "RECV_LEN=NULL");
return PM3_EINVARG;
} }
if (apdu == NULL || sw == NULL || recv_len == NULL) return PM3_EINVARG;
*sw = 0; *sw = 0;
uint8_t data[255 * 5] = {0x00}; uint8_t data[255 * 5] = {0x00};
@ -271,7 +331,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
int i = 1; int i = 1;
int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw); int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
if (g_debugMode > 1) GetErrorString(res, sw); PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
return res; return res;
} }
if (dest != NULL) { if (dest != NULL) {
@ -290,6 +350,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
} }
return res; return res;
} }
while (*sw == status(MFDES_ADDITIONAL_FRAME)) { while (*sw == status(MFDES_ADDITIONAL_FRAME)) {
apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF
apdu->Lc = 0; apdu->Lc = 0;
@ -298,9 +359,10 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw); res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
if (g_debugMode > 1) GetErrorString(res, sw); PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
return res; return res;
} }
if (dest != NULL) { if (dest != NULL) {
if (splitbysize) { if (splitbysize) {
memcpy(&dest[i * splitbysize], data, resplen); memcpy(&dest[i * splitbysize], data, resplen);
@ -310,33 +372,33 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
} }
} }
pos += resplen; pos += resplen;
if (*sw != status(MFDES_ADDITIONAL_FRAME)) break; if (*sw != status(MFDES_ADDITIONAL_FRAME)) break;
} }
if (splitbysize) *recv_len = i;
else {
*recv_len = pos;
}
return PM3_SUCCESS;
*recv_len = (splitbysize) ? i : pos;
return PM3_SUCCESS;
} }
static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) { static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
if (major == 0x00) if (major == 0x00)
return MF3ICD40; return DESFIRE_MF3ICD40;
else if (major == 0x01 && minor == 0x00) if (major == 0x01 && minor == 0x00)
return EV1; return DESFIRE_EV1;
else if (major == 0x12 && minor == 0x00) if (major == 0x12 && minor == 0x00)
return EV2; return DESFIRE_EV2;
// else if (major == 0x13 && minor == 0x00) // if (major == 0x13 && minor == 0x00)
// return EV3; // return DESFIRE_EV3;
else if (major == 0x30 && minor == 0x00) if (major == 0x30 && minor == 0x00)
return LIGHT; return DESFIRE_LIGHT;
else if (major == 0x11 && minor == 0x00 )
return UNKNOWN; return PLUS_EV1;
return UNKNOWN;
} }
//none, verified // -- test if card supports 0x0A
static int test_desfire_authenticate() { static int test_desfire_authenticate() {
uint8_t data[] = {0x00}; uint8_t data[] = {0x00};
sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0 sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0
@ -345,7 +407,7 @@ static int test_desfire_authenticate() {
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
} }
// none, verified // -- test if card supports 0x1A
static int test_desfire_authenticate_iso() { static int test_desfire_authenticate_iso() {
uint8_t data[] = {0x00}; uint8_t data[] = {0x00};
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0 sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0
@ -354,7 +416,7 @@ static int test_desfire_authenticate_iso() {
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
} }
//none, verified // -- test if card supports 0xAA
static int test_desfire_authenticate_aes() { static int test_desfire_authenticate_aes() {
uint8_t data[] = {0x00}; uint8_t data[] = {0x00};
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0 sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0
@ -363,37 +425,44 @@ static int test_desfire_authenticate_aes() {
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false); return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
} }
// --- FREE MEM, verified // --- GET FREE MEM
static int desfire_print_freemem(uint32_t free_mem) { static int desfire_print_freemem(uint32_t free_mem) {
PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem); PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// init / disconnect, verified
static int get_desfire_freemem(uint32_t *free_mem) { static int get_desfire_freemem(uint32_t *free_mem) {
if (free_mem == NULL) return PM3_EINVARG; if (free_mem == NULL) return PM3_EINVARG;
sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E
*free_mem = 0;
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
uint8_t fmem[4] = {0}; uint8_t fmem[4] = {0};
int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true); int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true);
if (res == PM3_SUCCESS) {
*free_mem = le24toh(fmem); if (res != PM3_SUCCESS )
return res; return res;
}
*free_mem = 0; if (sw != status(MFDES_S_OPERATION_OK))
return PM3_ESOFT;
*free_mem = le24toh(fmem);
return res; return res;
} }
// --- GET SIGNATURE
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) {
// --- GET SIGNATURE, verified if (uid == NULL) {
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, desfire_cardtype_t card_type) { PrintAndLogEx(DEBUG, "UID=NULL");
if (g_debugMode > 1) { return PM3_EINVARG;
if (uid == NULL) PrintAndLogEx(ERR, "UID=NULL"); }
if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL"); if (signature == NULL) {
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
return PM3_EINVARG;
} }
if (uid == NULL || signature == NULL) return PM3_EINVARG;
// DESFire Ev3 - wanted // DESFire Ev3 - wanted
// ref: MIFARE Desfire Originality Signature Validation // ref: MIFARE Desfire Originality Signature Validation
@ -403,7 +472,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"}, {"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
{"DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} {"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
}; };
@ -427,8 +496,8 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); // PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); // PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16);
@ -443,35 +512,34 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// init / disconnect, verified
static int get_desfire_signature(uint8_t *signature, size_t *signature_len) { static int get_desfire_signature(uint8_t *signature, size_t *signature_len) {
if (g_debugMode > 1) {
if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL"); if (signature == NULL) {
if (signature_len == NULL) PrintAndLogEx(ERR, "SIGNATURE_LEN=NULL"); PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
return PM3_EINVARG;
} }
if (signature == NULL || signature_len == NULL) return PM3_EINVARG; if (signature_len == NULL) {
uint8_t c = 0x00; PrintAndLogEx(DEBUG, "SIGNATURE_LEN=NULL");
sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, 0x01, &c}; // 0x3C return PM3_EINVARG;
}
uint8_t c[] = {0x00};
sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, sizeof(c), c}; // 0x3C
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true); int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
if (recv_len != 56) { if (recv_len != 56) {
*signature_len = 0; *signature_len = 0;
DropField(); res = PM3_ESOFT;
return PM3_ESOFT;
} else { } else {
*signature_len = recv_len; *signature_len = recv_len;
} }
DropField();
return PM3_SUCCESS;
} }
DropField(); DropField();
return res; return res;
} }
// --- KEY SETTING // --- KEY SETTING
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) { static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
@ -504,23 +572,29 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// none, verified
static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) {
if (g_debugMode > 1) { if (key_settings == NULL) {
if (key_settings == NULL) PrintAndLogEx(ERR, "KEY_SETTINGS=NULL"); PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL");
if (num_keys == NULL) PrintAndLogEx(ERR, "NUM_KEYS=NULL"); return PM3_EINVARG;
}
if (num_keys == NULL) {
PrintAndLogEx(DEBUG, "NUM_KEYS=NULL");
return PM3_EINVARG;
} }
if (key_settings == NULL || num_keys == NULL) return PM3_EINVARG;
sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45 sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
uint8_t data[2] = {0}; uint8_t data[2] = {0};
int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true); int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true);
if (res != PM3_SUCCESS) return res;
if (res != PM3_SUCCESS )
return res;
if (sw != status(MFDES_S_OPERATION_OK))
return PM3_ESOFT;
*key_settings = data[0]; *key_settings = data[0];
*num_keys = data[1]; *num_keys = data[1];
return PM3_SUCCESS; return res;
} }
// --- KEY VERSION // --- KEY VERSION
@ -529,37 +603,52 @@ static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// none, verified
static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
if (g_debugMode > 1) { if (num_versions == NULL) {
if (num_versions == NULL) PrintAndLogEx(ERR, "NUM_VERSIONS=NULL"); PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL");
return PM3_EINVARG;
} }
if (num_versions == NULL) return PM3_EINVARG;
sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
if (res != PM3_SUCCESS )
return res;
if (sw != status(MFDES_S_OPERATION_OK))
return PM3_ESOFT;
return res; return res;
} }
// --- GET APPIDS
// init / disconnect, verified
static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) { static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) {
if (g_debugMode > 1) { if (dest == NULL) {
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); PrintAndLogEx(DEBUG, "DEST=NULL");
if (app_ids_len == NULL) PrintAndLogEx(ERR, "APP_IDS_LEN=NULL"); return PM3_EINVARG;
} }
if (dest == NULL || app_ids_len == NULL) return PM3_EINVARG; if (app_ids_len == NULL) {
PrintAndLogEx(DEBUG, "APP_IDS_LEN=NULL");
return PM3_EINVARG;
}
sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true); int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true);
if (res != PM3_SUCCESS) return res;
if (res != PM3_SUCCESS )
return res;
if (sw != status(MFDES_S_OPERATION_OK))
return PM3_ESOFT;
*app_ids_len = (uint8_t)recv_len & 0xFF; *app_ids_len = (uint8_t)recv_len & 0xFF;
return res; return res;
} }
// init, verified // --- GET DF NAMES
static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) { static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
if (g_debugMode > 1) { if (g_debugMode > 1) {
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL"); if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
@ -570,13 +659,14 @@ static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
int recv_len = 0; int recv_len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true); int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true);
if (res != PM3_SUCCESS) return res; if (res != PM3_SUCCESS)
return res;
if (sw != status(MFDES_S_OPERATION_OK))
return PM3_ESOFT;
*dfname_count = recv_len; *dfname_count = recv_len;
return res; return res;
} }
// init, verified
static int get_desfire_select_application(uint8_t *aid) { static int get_desfire_select_application(uint8_t *aid) {
if (g_debugMode > 1) { if (g_debugMode > 1) {
if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL"); if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL");
@ -646,7 +736,7 @@ static int get_desfire_createapp(aidhdr_t *aidhdr) {
sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA
uint16_t sw = 0; uint16_t sw = 0;
int recvlen = 0; int recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true); int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw)); PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
DropField(); DropField();
@ -660,7 +750,7 @@ static int get_desfire_deleteapp(uint8_t *aid) {
sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, aid}; // 0xDA sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, aid}; // 0xDA
uint16_t sw = 0; uint16_t sw = 0;
int recvlen = 0; int recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true); int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw)); PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
DropField(); DropField();
@ -669,6 +759,116 @@ static int get_desfire_deleteapp(uint8_t *aid) {
return res; return res;
} }
int getKeySettings(uint8_t *aid) {
if (aid == NULL) return PM3_EINVARG;
int res = 0;
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
// CARD MASTER KEY
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
res = get_desfire_select_application(aid);
if (res != PM3_SUCCESS) return res;
// KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
res = get_desfire_keysettings(&key_setting, &num_keys);
if (res == PM3_SUCCESS) {
// number of Master keys (0x01)
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
} else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
}
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
// 2 MSB denotes
switch (num_keys >> 6) {
case 0:
PrintAndLogEx(SUCCESS, str, "(3)DES");
break;
case 1:
PrintAndLogEx(SUCCESS, str, "3K3DES");
break;
case 2:
PrintAndLogEx(SUCCESS, str, "AES");
break;
default:
break;
}
uint8_t cmk_num_versions = 0;
if (get_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
PrintAndLogEx(INFO, " ----------------------------------------------------------");
}
// Authentication tests
int res = test_desfire_authenticate();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
res = test_desfire_authenticate_iso();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
res = test_desfire_authenticate_aes();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
} else {
// AID - APPLICATION MASTER KEYS
//PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
res = get_desfire_select_application(aid);
if (res != PM3_SUCCESS) return res;
// KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
res = get_desfire_keysettings(&key_setting, &num_keys);
if (res == PM3_SUCCESS) {
desfire_print_keysetting(key_setting, num_keys);
} else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
}
// KEY VERSION - AMK
uint8_t num_version = 0;
if (get_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, " Application keys");
desfire_print_keyversion(0, num_version);
} else {
PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
}
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
num_keys &= 0x3F;
if (num_keys > 1) {
for (uint8_t i = 0x01; i < num_keys; ++i) {
if (get_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
desfire_print_keyversion(i, num_version);
} else {
PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
}
}
}
}
DropField();
return PM3_SUCCESS;
}
static int CmdHF14ADesCreateApp(const char *Cmd) { static int CmdHF14ADesCreateApp(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
@ -929,13 +1129,12 @@ static int CmdHF14ADesInfo(const char *Cmd) {
struct p *package = (struct p *) resp.data.asBytes; struct p *package = (struct p *) resp.data.asBytes;
if (resp.status != PM3_SUCCESS) { if (resp.status != PM3_SUCCESS) {
switch (package->isOK) { switch (package->isOK) {
case 1: case 1:
PrintAndLogEx(WARNING, "Can't select card"); PrintAndLogEx(WARNING, "Can't select card");
break; break;
case 2: case 2:
PrintAndLogEx(WARNING, "Card is most likely not Desfire. Its UID has wrong size"); PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID");
break; break;
case 3: case 3:
default: default:
@ -945,6 +1144,12 @@ static int CmdHF14ADesInfo(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
nxp_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]);
if (cardtype == PLUS_EV1) {
PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`"));
return PM3_SUCCESS;
}
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
@ -958,7 +1163,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]);
PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4])); PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4]));
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6])); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6], true));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0])); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0]));
@ -966,7 +1171,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]);
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]); PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]);
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6])); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6], false));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities")); PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities"));
@ -990,32 +1195,36 @@ static int CmdHF14ADesInfo(const char *Cmd) {
if (major == 0 && minor == 2) if (major == 0 && minor == 2)
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
// Signature originality check if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) {
uint8_t signature[56] = {0}; // Signature originality check
size_t signature_len = 0; uint8_t signature[56] = {0};
desfire_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]); size_t signature_len = 0;
if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) PrintAndLogEx(NORMAL, "");
desfire_print_signature(package->uid, signature, signature_len, cardtype); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
else { if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) {
PrintAndLogEx(WARNING, "--- " _YELLOW_("Couldn't verify signature. Unknown public key ?")); desfire_print_signature(package->uid, signature, signature_len, cardtype);
} else {
PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd");
}
} }
// Master Key settings // Master Key settings
uint8_t master_aid[3] = {0x00, 0x00, 0x00}; uint8_t master_aid[3] = {0x00, 0x00, 0x00};
getKeySettings(master_aid); getKeySettings(master_aid);
// Free memory on card if (cardtype != DESFIRE_LIGHT) {
PrintAndLogEx(NORMAL, ""); // Free memory on card
PrintAndLogEx(INFO, "--- " _CYAN_("Free memory")); PrintAndLogEx(NORMAL, "");
uint32_t free_mem = 0; PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
if (get_desfire_freemem(&free_mem) == PM3_SUCCESS) { uint32_t free_mem = 0;
desfire_print_freemem(free_mem); if (get_desfire_freemem(&free_mem) == PM3_SUCCESS) {
} else { desfire_print_freemem(free_mem);
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd"); } else {
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
}
PrintAndLogEx(INFO, "-------------------------------------------------------------");
} }
PrintAndLogEx(INFO, "-------------------------------------------------------------");
/* /*
Card Master key (CMK) 0x00 AID = 00 00 00 (card level) Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
Application Master Key (AMK) 0x00 AID != 00 00 00 Application Master Key (AMK) 0x00 AID != 00 00 00
@ -1035,167 +1244,6 @@ static int CmdHF14ADesInfo(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/*
The 7 MSBits (= n) code the storage size itself based on 2^n,
the LSBit is set to '0' if the size is exactly 2^n
and set to '1' if the storage size is between 2^n and 2^(n+1).
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
*/
char *getCardSizeStr(uint8_t fsize) {
static char buf[40] = {0x00};
char *retStr = buf;
uint16_t usize = 1 << ((fsize >> 1) + 1);
uint16_t lsize = 1 << (fsize >> 1);
// is LSB set?
if (fsize & 1)
sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
return buf;
}
char *getProtocolStr(uint8_t id) {
static char buf[40] = {0x00};
char *retStr = buf;
if (id == 0x05)
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
return buf;
}
char *getVersionStr(uint8_t major, uint8_t minor) {
static char buf[40] = {0x00};
char *retStr = buf;
if (major == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
else if (major == 0x01 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
else if (major == 0x12 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
// else if (major == 0x13 && minor == 0x00)
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
else if (major == 0x30 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
else
sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
return buf;
}
int getKeySettings(uint8_t *aid) {
if (aid == NULL) return PM3_EINVARG;
int res = 0;
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
// CARD MASTER KEY
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
res = get_desfire_select_application(aid);
if (res != PM3_SUCCESS) return res;
// KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
res = get_desfire_keysettings(&key_setting, &num_keys);
if (res == PM3_SUCCESS) {
// number of Master keys (0x01)
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
} else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
}
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
// 2 MSB denotes
switch (num_keys >> 6) {
case 0:
PrintAndLogEx(SUCCESS, str, "(3)DES");
break;
case 1:
PrintAndLogEx(SUCCESS, str, "3K3DES");
break;
case 2:
PrintAndLogEx(SUCCESS, str, "AES");
break;
default:
break;
}
uint8_t cmk_num_versions = 0;
if (get_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
PrintAndLogEx(INFO, " ----------------------------------------------------------");
}
// Authentication tests
int res = test_desfire_authenticate();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
res = test_desfire_authenticate_iso();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
res = test_desfire_authenticate_aes();
if (res == PM3_ETIMEOUT) return res;
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
} else {
// AID - APPLICATION MASTER KEYS
//PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
res = get_desfire_select_application(aid);
if (res != PM3_SUCCESS) return res;
// KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
res = get_desfire_keysettings(&key_setting, &num_keys);
if (res == PM3_SUCCESS) {
desfire_print_keysetting(key_setting, num_keys);
} else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
}
// KEY VERSION - AMK
uint8_t num_version = 0;
if (get_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, " Application keys");
desfire_print_keyversion(0, num_version);
} else {
PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
}
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
num_keys &= 0x3F;
if (num_keys > 1) {
for (uint8_t i = 0x01; i < num_keys; ++i) {
if (get_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
desfire_print_keyversion(i, num_version);
} else {
PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
}
}
}
}
DropField();
return PM3_SUCCESS;
}
static void DecodeFileType(uint8_t filetype) { static void DecodeFileType(uint8_t filetype) {
switch (filetype) { switch (filetype) {
@ -1238,8 +1286,10 @@ static void DecodeComSet(uint8_t comset) {
} }
static char *DecodeAccessValue(uint8_t value) { static char *DecodeAccessValue(uint8_t value) {
char *car = (char *)malloc(255); char *car = (char *)calloc(255, sizeof(char));
memset(car, 0x0, 255); if (car == NULL)
return NULL;
switch (value) { switch (value) {
case 0xE: case 0xE:
strcat(car, "(Free Access)"); strcat(car, "(Free Access)");
@ -1260,9 +1310,17 @@ static void DecodeAccessRights(uint16_t accrights) {
int write_access = (accrights >> 8) & 0xF; int write_access = (accrights >> 8) & 0xF;
int read_access = (accrights >> 12) & 0xF; int read_access = (accrights >> 12) & 0xF;
char *car = DecodeAccessValue(change_access_rights); char *car = DecodeAccessValue(change_access_rights);
if (car == NULL) return;
char *rwa = DecodeAccessValue(read_write_access); char *rwa = DecodeAccessValue(read_write_access);
if (rwa == NULL) return;
char *wa = DecodeAccessValue(write_access); char *wa = DecodeAccessValue(write_access);
if (wa == NULL) return;
char *ra = DecodeAccessValue(read_access); char *ra = DecodeAccessValue(read_access);
if (ra == NULL) return;
PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra); PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra);
free(car); free(car);
free(rwa); free(rwa);
@ -1270,23 +1328,23 @@ static void DecodeAccessRights(uint16_t accrights) {
free(ra); free(ra);
} }
static int DecodeFileSettings(uint8_t *filesettings, int fileset_len, int maclen) { static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) {
uint8_t filetype = filesettings[0]; uint8_t filetype = src[0];
uint8_t comset = filesettings[1]; uint8_t comset = src[1];
uint16_t accrights = (filesettings[4] << 8) + filesettings[3]; uint16_t accrights = (src[4] << 8) + src[3];
if (fileset_len == 1 + 1 + 2 + 3 + maclen) { if (src_len == 1 + 1 + 2 + 3 + maclen) {
int filesize = (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5]; int filesize = (src[7] << 16) + (src[6] << 8) + src[5];
DecodeFileType(filetype); DecodeFileType(filetype);
DecodeComSet(comset); DecodeComSet(comset);
DecodeAccessRights(accrights); DecodeAccessRights(accrights);
PrintAndLogEx(INFO, " Filesize: %d", filesize); PrintAndLogEx(INFO, " Filesize: %d", filesize);
return PM3_SUCCESS; return PM3_SUCCESS;
} else if (fileset_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) { } else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) {
int lowerlimit = (filesettings[8] << 24) + (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5]; int lowerlimit = (src[8] << 24) + (src[7] << 16) + (src[6] << 8) + src[5];
int upperlimit = (filesettings[12] << 24) + (filesettings[11] << 16) + (filesettings[10] << 8) + filesettings[9]; int upperlimit = (src[12] << 24) + (src[11] << 16) + (src[10] << 8) + src[9];
int limitcredvalue = (filesettings[16] << 24) + (filesettings[15] << 16) + (filesettings[14] << 8) + filesettings[13]; int limitcredvalue = (src[16] << 24) + (src[15] << 16) + (src[14] << 8) + src[13];
uint8_t limited_credit_enabled = filesettings[17]; uint8_t limited_credit_enabled = src[17];
DecodeFileType(filetype); DecodeFileType(filetype);
DecodeComSet(comset); DecodeComSet(comset);
DecodeAccessRights(accrights); DecodeAccessRights(accrights);
@ -1590,6 +1648,5 @@ static int CmdHelp(const char *Cmd) {
int CmdHFMFDes(const char *Cmd) { int CmdHFMFDes(const char *Cmd) {
// flush // flush
clearCommandBuffer(); clearCommandBuffer();
//g_debugMode=2;
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }

View file

@ -14,10 +14,11 @@
int CmdHFMFDes(const char *Cmd); int CmdHFMFDes(const char *Cmd);
/*
char *getCardSizeStr(uint8_t fsize); char *getCardSizeStr(uint8_t fsize);
char *getProtocolStr(uint8_t id);
char *getVersionStr(uint8_t major, uint8_t minor); char *getVersionStr(uint8_t major, uint8_t minor);
int getKeySettings(uint8_t *aid); int getKeySettings(uint8_t *aid);
*/
// Ev1 card limits // Ev1 card limits
#define MAX_NUM_KEYS 0x0F #define MAX_NUM_KEYS 0x0F
@ -26,6 +27,14 @@ int getKeySettings(uint8_t *aid);
#define MAX_FRAME_SIZE 60 #define MAX_FRAME_SIZE 60
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) #define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
// Ev2 card limits
// Ev3 card limits
// Light card limits
// Light Ev1 card limits
#define NOT_YET_AUTHENTICATED 0xFF #define NOT_YET_AUTHENTICATED 0xFF

View file

@ -27,11 +27,19 @@
#include "protocols.h" #include "protocols.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
typedef enum {
MFP_UNKNOWN = 0,
DESFIRE_MF3ICD40,
DESFIRE_EV1,
DESFIRE_EV2,
DESFIRE_EV3,
DESFIRE_LIGHT,
PLUS_EV1,
} nxp_cardtype_t;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/* /*
@ -56,15 +64,21 @@ static char *getCardSizeStr(uint8_t fsize) {
return buf; return buf;
} }
static char *getProtocolStr(uint8_t id) { static char *getProtocolStr(uint8_t id, bool hw) {
static char buf[40] = {0x00}; static char buf[50] = {0x00};
char *retStr = buf; char *retStr = buf;
if (id == 0x05) if (id == 0x04) {
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id);
else } else if (id == 0x05) {
if (hw)
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
} else {
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id); sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
}
return buf; return buf;
} }
@ -91,6 +105,59 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
return buf; return buf;
} }
static char *getTypeStr(uint8_t type) {
static char buf[40] = {0x00};
char *retStr = buf;
switch (type) {
case 1:
sprintf(retStr, "0x%02X ( " _YELLOW_("DESFire") ")", type);
break;
case 2:
sprintf(retStr, "0x%02X ( " _YELLOW_("Plus") ")", type);
break;
case 3:
sprintf(retStr, "0x%02X ( " _YELLOW_("Ultralight") ")", type);
break;
case 4:
sprintf(retStr, "0x%02X ( " _YELLOW_("NTAG") ")", type);
break;
default:
break;
}
return buf;
}
static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
// DESFire MF3ICD40
if (major == 0x00 && minor == 0x00 )
return DESFIRE_MF3ICD40;
// DESFire EV1
if (major == 0x01 && minor == 0x00 )
return DESFIRE_EV1;
// DESFire EV2
if (major == 0x12 && minor == 0x00 )
return DESFIRE_EV2;
// DESFire EV3
// if (major == 0x13 && minor == 0x00 )
// return DESFIRE_EV3;
// DESFire Light
if (major == 0x30 && minor == 0x00 )
return DESFIRE_LIGHT;
// Plus EV1
if (major == 0x11 && minor == 0x00 )
return PLUS_EV1;
return MFP_UNKNOWN;
}
// --- GET SIGNATURE // --- GET SIGNATURE
static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) { static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
@ -115,13 +182,15 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature
if (is_valid) if (is_valid)
break; break;
} }
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false) { if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys[i].desc); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_plus_public_keys[i].value); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_plus_public_keys[i].value);
PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 16); PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 16);
@ -162,19 +231,19 @@ static int plus_print_version(uint8_t *version) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1]));
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]);
PrintAndLogEx(INFO, " Version: %s", getVersionStr(version[3], version[4])); PrintAndLogEx(INFO, " Version: %s", getVersionStr(version[3], version[4]));
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6])); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8]));
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]);
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), version[3], version[4]); PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), version[10], version[11]);
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5])); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[12]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6])); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int get_plus_version(uint8_t *version, int *version_len) { static int get_plus_version(uint8_t *version, int *version_len) {
@ -236,16 +305,27 @@ static int CmdHFMFPInfo(const char *Cmd) {
PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint")); PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint"));
if (supportVersion && supportSignature) { bool isPlus = false;
PrintAndLogEx(INFO, " Tech: " _GREEN_("MIFARE Plus EV1"));
} else { if (supportVersion) {
PrintAndLogEx(INFO, " Tech: " _YELLOW_("MIFARE Plus SE/X"));
int cardtype = getCardType(version[3], version[4]);
if (cardtype == 6) {
if (supportSignature) {
PrintAndLogEx(INFO, " Tech: " _GREEN_("MIFARE Plus EV1"));
} else {
PrintAndLogEx(INFO, " Tech: " _YELLOW_("MIFARE Plus SE/X"));
}
isPlus = true;
} else {
}
} }
// MIFARE Type Identification Procedure // MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf // https://www.nxp.com/docs/en/application-note/AN10833.pdf
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8); uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
bool isPlus = false;
if (ATQA & 0x0004) { if (ATQA & 0x0004) {
PrintAndLogEx(INFO, " SIZE: " _GREEN_("2K") "(%s UID)", (ATQA & 0x0040) ? "7" : "4"); PrintAndLogEx(INFO, " SIZE: " _GREEN_("2K") "(%s UID)", (ATQA & 0x0040) ? "7" : "4");
@ -289,6 +369,10 @@ static int CmdHFMFPInfo(const char *Cmd) {
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false); int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false);
// DESFire answers 0x1C
// Plus answers 0x0B, 0x09
PrintAndLogEx(INFO, "ICEE: %s", sprint_hex(data, datalen));
if (memcmp(data, "\x67\x00", 2) == 0) { if (memcmp(data, "\x67\x00", 2) == 0) {
PrintAndLogEx(INFO, "\tMost likely a MIFARE DESFire tag"); PrintAndLogEx(INFO, "\tMost likely a MIFARE DESFire tag");
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`")); PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`"));
@ -1105,10 +1189,13 @@ static int CmdHFMFPChk(const char *Cmd) {
if (keyListLen == 0) { if (keyListLen == 0) {
PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); PrintAndLogEx(ERR, "Key list is empty. Nothing to check.");
return PM3_EINVARG; return PM3_EINVARG;
} else {
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%zu") "keys", keyListLen);
} }
if (!verbose) if (!verbose)
printf("Search keys:"); printf("Search keys:");
while (true) { while (true) {
res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose);
if (res == PM3_EOPABORTED) if (res == PM3_EOPABORTED)

View file

@ -212,7 +212,6 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex
sprintf(tmp, " "); sprintf(tmp, " ");
// remove last space // remove last space
--tmp;
*tmp = '\0'; *tmp = '\0';
return; return;
} }

View file

@ -349,16 +349,12 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
// 6x xx = ERROR // 6x xx = ERROR
// MIFARE DESFire command set: // MIFARE DESFire command set:
#define MFDES_GET_VERSION 0x60
#define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE #define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE
#define MFDES_AUTHENTICATE_ISO 0x1A // AUTHENTICATE_STANDARD #define MFDES_AUTHENTICATE_ISO 0x1A // AUTHENTICATE_STANDARD
#define MFDES_AUTHENTICATE_AES 0xAA #define MFDES_AUTHENTICATE_AES 0xAA
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_CREDIT 0x0C #define MFDES_CREDIT 0x0C
#define MFDES_LIMITED_CREDIT 0x1C #define MFDES_LIMITED_CREDIT 0x1C
#define MFDES_DEBIT 0xDC
#define MFDES_WRITE_RECORD 0x3B #define MFDES_WRITE_RECORD 0x3B
#define MFDES_READSIG 0x3C #define MFDES_READSIG 0x3C
#define MFDES_WRITE_DATA 0x3D #define MFDES_WRITE_DATA 0x3D
@ -366,6 +362,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_CHANGE_KEY_SETTINGS 0x54 #define MFDES_CHANGE_KEY_SETTINGS 0x54
#define MFDES_SELECT_APPLICATION 0x5A #define MFDES_SELECT_APPLICATION 0x5A
#define MFDES_CHANGE_FILE_SETTINGS 0x5F #define MFDES_CHANGE_FILE_SETTINGS 0x5F
#define MFDES_GET_VERSION 0x60
#define MFDES_GET_ISOFILE_IDS 0x61 #define MFDES_GET_ISOFILE_IDS 0x61
#define MFDES_GET_KEY_VERSION 0x64 #define MFDES_GET_KEY_VERSION 0x64
#define MFDES_GET_APPLICATION_IDS 0x6A #define MFDES_GET_APPLICATION_IDS 0x6A
@ -373,15 +370,32 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_GET_FREE_MEMORY 0x6E #define MFDES_GET_FREE_MEMORY 0x6E
#define MFDES_GET_DF_NAMES 0x6D #define MFDES_GET_DF_NAMES 0x6D
#define MFDES_GET_FILE_IDS 0x6F #define MFDES_GET_FILE_IDS 0x6F
#define MFDES_ABORT_TRANSACTION 0xA7
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_READ_RECORDS 0xBB #define MFDES_READ_RECORDS 0xBB
#define MFDES_READ_DATA 0xBD #define MFDES_READ_DATA 0xBD
#define MFDES_ABORT_TRANSACTION 0xA7 #define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1
#define MFDES_CHANGE_KEY 0xC4
#define MFDES_COMMIT_TRANSACTION 0xC7
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB
#define MFDES_CREATE_VALUE_FILE 0xCC
#define MFDES_CREATE_STD_DATA_FILE 0xCD
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_DEBIT 0xDC
#define MFDES_DELETE_FILE 0xDF
#define MFDES_CLEAR_RECORD_FILE 0xEB
#define MFDES_GET_FILE_SETTINGS 0xF5
#define MFDES_FORMAT_PICC 0xFC
// MIFARE DESFire status set:
#define MFDES_OPERATION_OK 0x00 // MIFARE DESFire status & error codes:
#define MFDES_NO_CHANGES 0x0C #define MFDES_S_OPERATION_OK 0x00
#define MFDES_ADDITIONAL_FRAME 0xAF #define MFDES_S_NO_CHANGES 0x0C
#define MFDES_S_SIGNATURE 0x90
#define MFDES_S_ADDITIONAL_FRAME 0xAF
#define MFDES_E_OUT_OF_EEPROM 0x0E #define MFDES_E_OUT_OF_EEPROM 0x0E
#define MFDES_E_ILLEGAL_COMMAND_CODE 0x1C #define MFDES_E_ILLEGAL_COMMAND_CODE 0x1C
#define MFDES_E_INTEGRITY_ERROR 0x1E #define MFDES_E_INTEGRITY_ERROR 0x1E
@ -401,26 +415,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_E_EEPROM 0xEE #define MFDES_E_EEPROM 0xEE
#define MFDES_E_FILE_NOT_FOUND 0xF0 #define MFDES_E_FILE_NOT_FOUND 0xF0
#define MFDES_E_FILE_INTEGRITY 0xF1 #define MFDES_E_FILE_INTEGRITY 0xF1
#define MFDES_SIGNATURE 0x90
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1
#define MFDES_CHANGE_KEY 0xC4
#define MFDES_COMMIT_TRANSACTION 0xC7
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB
#define MFDES_CREATE_VALUE_FILE 0xCC
#define MFDES_CREATE_STD_DATA_FILE 0xCD
#define MFDES_CLEAR_RECORD_FILE 0xEB
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_DELETE_FILE 0xDF
#define MFDES_GET_FILE_SETTINGS 0xF5
#define MFDES_FORMAT_PICC 0xFC
// LEGIC Commands // LEGIC Commands
#define LEGIC_MIM_22 0x0D #define LEGIC_MIM_22 0x0D
#define LEGIC_MIM_256 0x1D #define LEGIC_MIM_256 0x1D